PowerTool x64驅動模組逆向分析(持續更新)
比賽打完了,來繼續搞了,因為那個主動防禦正在寫,所以想找找思路正好想到可以來逆向一下PT的驅動模組看看pt大大是怎麼寫的程式。
PT x64版本的驅動模組是這個kEvP64.sys。
0x0
先來看看DriverEntry
1 //IDA虛擬碼 2 __int64 __fastcall sub_3A010(struct _DRIVER_OBJECT *a1, __int64 a2) 3 { 4 char *v2; // rdi@1 5 signed __int64 i; // rcx@1 6 char *v4; // rdi@4 7 __int64 v5; // rsi@4 8 signed __int64 j; // rcx@4 9 _UNKNOWN *v7; // rdi@7 10 char *v8; // rsi@7 11 signed __int64 k; // rcx@7 12 __int64 result; // rax@11 13 unsigned int v11; // [sp+48h] [bp-A0h]@10 14 NTSTATUS v12; // [sp+48h] [bp-A0h]@12 15 NTSTATUS v13; // [sp+48h] [bp-A0h]@14 16 char v14; // [sp+ACh] [bp-3Ch]@1 17 char v15; // [sp+C0h] [bp-28h]@4 18 struct _DRIVER_OBJECT *DriverObject; // [sp+F0h] [bp+8h]@1 19 20 DriverObject = a1; 21 v2 = &v14; 22 for ( i = 4i64; i; --i ) 23 *v2++ = 0; 24 v4 = &v15; 25 v5 = a2; 26 for ( j = 16i64; j; --j ) 27 *v4++ = *(_BYTE *)v5++; 28 v7 = &unk_37C60; 29 v8 = &v15; 30 for ( k = 16i64; k; --k ) 31 { 32 *(_BYTE *)v7 = *v8++; 33 v7 = (char *)v7 + 1; 34 } 35 RtlGetVersion(&unk_37AE0); 36 v11 = sub_19A30(); 37 if ( (v11 & 0x80000000) == 0 ) 38 { 39 sub_39010(); 40 DriverObject->DriverUnload = (PDRIVER_UNLOAD)sub_29870; 41 RtlInitUnicodeString(&DeviceName, L"\\Device\\kEvP64"); 42 v12 = IoCreateDevice(DriverObject, 0, &DeviceName, 0x22u, 0x100u, 0, &DeviceObject); 43 if ( v12 >= 0 ) 44 { 45 DriverObject->MajorFunction[0] = (PDRIVER_DISPATCH)sub_298F0; 46 DriverObject->MajorFunction[2] = (PDRIVER_DISPATCH)sub_298F0; 47 DriverObject->MajorFunction[14] = (PDRIVER_DISPATCH)sub_29940; 48 RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\kEvP64"); 49 v13 = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName); 50 if ( v13 >= 0 ) 51 { 52 FltRegisterFilter(DriverObject, &unk_300C0, &qword_37AA8); 53 *((_DWORD *)DriverObject->DriverSection + 26) |= 0x20u; 54 qword_37C28 = (__int64)DriverObject; 55 result = 0i64; 56 } 57 else 58 { 59 IoDeleteDevice(DeviceObject); 60 result = (unsigned int)v13; 61 } 62 } 63 else 64 { 65 result = (unsigned int)v12; 66 } 67 } 68 else 69 { 70 result = v11; 71 } 72 return result; 73 }
函式的26、27行把程式的登錄檔目錄的字串儲存到了區域性陣列中,然後又存在了一個全域性的緩衝區裡,應該是一個全域性陣列。
然後是進行系統版本的判斷,對於驅動模組來說判斷系統很重要,否則很容易造成藍色畫面。
使用RtlGetVersion獲得一個有關係統資訊的結構,WDK中對這個函式的描述如下
RtlGetVersion
The RtlGetVersion routine returns version information about the currently running operating system.
NTSTATUS
RtlGetVersion(
IN OUT PRTL_OSVERSIONINFOW lpVersionInformation
);
來看看pt是怎麼對版本進行的判斷,
首先是對IRQL進行的判斷,程式碼如下
1 if ( (signed int)(unsigned __int8)sub_11030() > 1 ) 2 { 3 v0 = sub_11030(); 4 DbgPrint("EX: Pageable code called at IRQL %d\n", v0); 5 sub_11020(); 6 }
其中sub_11030的反彙編如下
剛開始沒明白是什麼意思,後來查了一下原來X64的IRQL儲存在CR8裡,這個以前還真的不知道,學到了。
判斷了一下IRQL是否合理,然後就是具體的判斷了。
1 v2 = dword_37964; 2 v4 = dword_37968; 3 v3 = (unsigned __int16)word_37A74; 4 DbgPrint( 5 "[kEvP64]Windows %d.%d, SP%d.%d, build %d\n", 6 (unsigned int)dword_37964, 7 (unsigned int)dword_37968, 8 (unsigned __int16)word_37A74); 9 dword_37908 = 0; 10 dword_378E0 = 0; 11 if ( v2 == 5 && v4 == 1 ) 12 { 13 dword_378FC = 51; 14 if ( !v3 ) 15 return 3221225659i64; 16 if ( v3 == 1 ) 17 return 3221225659i64; 18 if ( v3 != 2 && v3 != 3 ) 19 return 3221225659i64; 20 return 0i64; 21 } 22 if ( v2 == 5 && v4 == 2 ) 23 { 24 dword_378FC = 52; 25 if ( v3 && v3 != 1 && v3 != 2 ) 26 return 3221225659i64; 27 return 0i64; 28 } 29 if ( v2 == 6 && !v4 ) 30 { 31 dword_378FC = 60; 32 if ( v3 ) 33 { 34 if ( v3 == 1 ) 35 { 36 dword_37C40 = 16; 37 dword_37C50 = 40; 38 } 39 else 40 { 41 if ( v3 != 2 ) 42 return 3221225659i64; 43 dword_37C40 = 16; 44 dword_37C50 = 40; 45 } 46 } 47 else 48 { 49 dword_37C40 = 120; 50 dword_37C50 = 144; 51 } 52 dword_37C58 = 20; 53 dword_37C70 = 352; 54 dword_37C54 = 876; 55 dword_378E4 = 11; 56 dword_37A90 = 216; 57 dword_378F8 = 16; 58 dword_378F0 = 632; 59 dword_37AC0 = 24; 60 dword_37C44 = 104; 61 dword_37C48 = 992; 62 dword_37BF4 = 856; 63 dword_37930 = 115; 64 dword_378F4 = 340; 65 dword_37AB0 = 904; 66 dword_37C4C = 896; 67 dword_37920 = 904; 68 dword_37AC4 = 896; 69 dword_37BF8 = 339; 70 dword_37888 = 1056; 71 dword_37908 = 48; 72 dword_377CC = 580; 73 dword_37894 = 48; 74 dword_377C4 = 41; 75 dword_377B0 = 32; 76 dword_377B4 = 370; 77 dword_377B8 = 79; 78 dword_377BC = 80; 79 dword_377C0 = 22; 80 dword_3788C = 440; 81 dword_37890 = 712; 82 dword_37898 = 2416; 83 dword_3789C = 2424; 84 dword_378A0 = 56; 85 return 0i64; 86 } 87 if ( v2 == 6 && v4 == 1 ) 88 { 89 dword_378FC = 61; 90 if ( v3 && v3 != 1 ) 91 return 3221225659i64; 92 dword_37C58 = 20; 93 dword_37C70 = 512; 94 dword_37C54 = 1084; 95 dword_378E4 = 11; 96 dword_37A90 = 376; 97 dword_378F8 = 16; 98 dword_37C40 = 16; 99 dword_37C50 = 40; 100 dword_378F0 = 800; 101 dword_37AC0 = 24; 102 dword_37C44 = 112; 103 dword_37C48 = 1040; 104 dword_37BF4 = 904; 105 dword_37C30 = 1048; 106 dword_37C14 = 912; 107 dword_37930 = 123; 108 dword_378F4 = 356; 109 dword_37BF8 = 502; 110 dword_37888 = 1056; 111 dword_37AB0 = 960; 112 dword_37C4C = 952; 113 dword_37920 = 952; 114 dword_37AC4 = 944; 115 dword_37908 = 48; 116 dword_377CC = 620; 117 dword_37894 = 48; 118 dword_377C4 = 41; 119 dword_377B0 = 32; 120 dword_377B4 = 379; 121 dword_377B8 = 79; 122 dword_377BC = 80; 123 dword_377C0 = 22; 124 dword_3788C = 600; 125 dword_37890 = 744; 126 dword_37898 = 1352; 127 dword_3789C = 1360; 128 dword_378A0 = 64; 129 DbgPrint("[kEvP64]Initialized version-specific data for Windows 7 SP%d\n", v3); 130 return 0i64; 131 } 132 if ( v2 == 6 && v4 == 2 ) 133 { 134 dword_378FC = 62; 135 dword_37C58 = 20; 136 dword_37C70 = 1032; 137 dword_37C54 = -1; 138 dword_378E4 = -1; 139 dword_37A90 = 456; 140 dword_378F8 = 16; 141 dword_37C40 = 16; 142 dword_37C50 = 40; 143 dword_378F0 = 1048; 144 dword_37AC0 = 24; 145 dword_37908 = 48; 146 dword_37C10 = 19; 147 dword_378E0 = 20; 148 dword_37C44 = 184; 149 dword_37C48 = 1008; 150 dword_37BF4 = 880; 151 dword_37C30 = 1008; 152 dword_37C14 = 880; 153 dword_37930 = 195; 154 dword_378F4 = 388; 155 dword_37BF8 = 562; 156 dword_37888 = 1024; 157 dword_37AB0 = 928; 158 dword_37C4C = 920; 159 dword_37920 = 928; 160 dword_37AC4 = 920; 161 dword_377CC = 644; 162 dword_37894 = 48; 163 dword_377C4 = 42; 164 dword_377B0 = 33; 165 dword_377B4 = 402; 166 dword_377B8 = 80; 167 dword_377BC = 81; 168 dword_377C0 = 23; 169 dword_3788C = 920; 170 dword_37890 = 784; 171 dword_37898 = 328; 172 dword_3789C = 336; 173 dword_378A0 = 72; 174 DbgPrint("[kEvP64]Initialized version-specific data for Windows 8 SP%d\n", v3); 175 return 0i64; 176 } 177 if ( v2 == 6 && v4 == 3 ) 178 { 179 dword_378FC = 63; 180 dword_37C54 = -1; 181 dword_378E4 = -1; 182 dword_37C58 = 20; 183 dword_378F8 = 16; 184 dword_37C70 = 1032; 185 dword_37A90 = 728; 186 dword_37C40 = 16; 187 dword_37C50 = 40; 188 dword_378F0 = 1048; 189 dword_37AC0 = 24; 190 dword_37908 = 48; 191 dword_37C10 = 16; 192 dword_378E0 = 17; 193 dword_37C44 = 184; 194 dword_37C48 = 1656; 195 dword_37BF4 = 1528; 196 dword_37C30 = 1656; 197 dword_37C14 = 1528; 198 dword_37930 = 195; 199 dword_378F4 = 388; 200 dword_37BF8 = 562; 201 dword_37888 = 760; 202 dword_37AB0 = 1576; 203 dword_37C4C = 1568; 204 dword_37920 = 1576; 205 dword_37AC4 = 1568; 206 dword_377CC = 644; 207 dword_37894 = 48; 208 dword_377C4 = 43; 209 dword_377B0 = 34; 210 dword_377B4 = 408; 211 dword_377B8 = 81; 212 dword_377BC = 82; 213 dword_377C0 = 24; 214 dword_3788C = 920; 215 dword_37890 = 784; 216 dword_37898 = 328; 217 dword_3789C = 336; 218 dword_378A0 = 72; 219 DbgPrint("[kEvP64]Initialized version-specific data for Windows 8.1 SP%d\n", v3); 220 return 0i64; 221 } 222 if ( v2 == 10 && !v4 ) 223 { 224 dword_378FC = 100; 225 dword_37C54 = -1; 226 dword_378E4 = -1; 227 dword_37C58 = 20; 228 dword_378F8 = 16; 229 dword_37C70 = 1048; 230 dword_37A90 = 736; 231 dword_378F0 = 1064; 232 dword_37C40 = 16; 233 dword_37C50 = 40; 234 dword_37AC0 = 24; 235 dword_37908 = 48; 236 dword_37C10 = 16; 237 dword_378E0 = 17; 238 dword_37C44 = 184; 239 dword_37C48 = 1664; 240 dword_37BF4 = 1536; 241 dword_37C30 = 1664; 242 dword_37C14 = 1536; 243 dword_37930 = 195; 244 dword_378F4 = 388; 245 dword_37BF8 = 562; 246 dword_37888 = 760; 247 dword_37AB0 = 1584; 248 dword_37C4C = 1576; 249 dword_37920 = 1584; 250 dword_37AC4 = 1576; 251 dword_377CC = 644; 252 dword_37894 = 48; 253 dword_377C4 = 44; 254 dword_377B0 = 35; 255 dword_377B4 = 416; 256 dword_377B8 = 82; 257 dword_377BC = 83; 258 dword_377C0 = 25; 259 dword_3788C = 936; 260 dword_37890 = 784; 261 dword_37898 = 328; 262 dword_3789C = 336; 263 dword_378A0 = 72; 264 return 0i64; 265 } 266 if ( v2 == 10 && v4 || v2 > 0xA ) 267 { 268 dword_378FC = -1; 269 result = 3221225659i64; 270 } 271 else 272 { 273 result = 3221225659i64; 274 } 275 return result; 276 }
其中v2,v3,v4都是結構體中的成員,就是上面用RtlGetVersion獲取到的結構體。
類似於return 3221225659i64;這種是NTSTATUS值,0就是STATUS_SUCESS,下面還可以看到
(v11 & 0x80000000) == 0
這種寫法就是NT_SUCESS()宏
來具體看下這種判斷過程是怎麼個意思
dword_37960 = 284; v2 = RtlGetVersion(&dword_37960);
這個是指定使用了RTL_OSVERSIONINFOEXW結構,因為RtlGetVersion這個函式其實可以支援兩種格式的輸出。
根據反彙編的結果還原了一下C的原始碼,應該是根據不同的系統版本設定了全域性變數不同的值,但是目前還不知道這些變數的作用,判斷系統方法比較簡單,根據dwMajorVersion判斷主版本號,dwMinorVersion判斷副版本號,再根據需要去判斷wServicePackMajor的值就可以實現了。
1 RTL_OSVERSIONINFOEXW Struct={284}; 2 ULONG Version; 3 NTSTATUS CheckVersion(void) 4 { 5 ULONG MajorVersion; 6 ULONG MinorVersion; 7 ULONG ServicePackMajor; 8 ULONG IRQL; 9 ULONG result; 10 RtlGetVersion(&Struct); 11 if(KeGetCurrentirql()>PASSIVE_LEVEL) 12 { 13 IRQL=KeGetCurrentirql(); 14 DbgPrint("EX: Pageable code called at IRQL %d\n", IRQL); 15 _asm{int 0x2c}; 16 } 17 MajorVersion=Struct.dwMajorVersion; 18 MinorVersion=Struct.dwMinorVersion; 19 ServicePackMajor=Struct.wServicePackMajor; 20 DbgPrint( 21 "[kEvP64]Windows %d.%d, SP%d.%d, build %d\n",Struct.dwMajorVersion,Struct.dwMinorVersion,Struct.wServicePackMajor); 22 if(MajorVersion==5&&MinorVersion==1) 23 { 24 //WINDOWS_XP 25 Version=51; 26 if(!ServicePackMajor) 27 return 3221225659; 28 if(ServicePackMajor==1) 29 return 3221225659; 30 if(ServicePackMajor!=2&&ServicePackMajor!=3) 31 return 3221225659; 32 return STATUS_SUCCESS; 33 } 34 if(MajorVersion==5&&MinorVersion==2) 35 { 36 //WINDOWS_2003 37 Version=52; 38 if(ServicePackMajor&&ServicePackMajor!=1&&ServicePackMajor!=2) 39 return 3221225659; 40 return STATUS_SUCCESS; 41 } 42 if(MajorVersion==6&&!MinorVersion) 43 { 44 //WINDOWS_2003 45 Version=60; 46 if(ServicePackMajor) 47 { 48 if(ServicePackMajor==1) 49 { 50 dword_37C40 = 16; 51 dword_37C50 = 40; 52 } 53 else 54 { 55 if(ServicePackMajor!=2) 56 return 3221225659; 57 dword_37C40 = 16; 58 dword_37C50 = 40; 59 } 60 } 61 else 62 { 63 dword_37C40 = 120; 64 dword_37C50 = 144; 65 } 66 dword_37C58 = 20; 67 dword_37C70 = 352; 68 dword_37C54 = 876; 69 dword_378E4 = 11; 70 dword_37A90 = 216; 71 dword_378F8 = 16; 72 dword_378F0 = 632; 73 dword_37AC0 = 24; 74 dword_37C44 = 104; 75 dword_37C48 = 992; 76 dword_37BF4 = 856; 77 dword_37930 = 115; 78 dword_378F4 = 340; 79 dword_37AB0 = 904; 80 dword_37C4C = 896; 81 dword_37920 = 904; 82 dword_37AC4 = 896; 83 dword_37BF8 = 339; 84 dword_37888 = 1056; 85 dword_37908 = 48; 86 dword_377CC = 580; 87 dword_37894 = 48; 88 dword_377C4 = 41; 89 dword_377B0 = 32; 90 dword_377B4 = 370; 91 dword_377B8 = 79; 92 dword_377BC = 80; 93 dword_377C0 = 22; 94 dword_3788C = 440; 95 dword_37890 = 712; 96 dword_37898 = 2416; 97 dword_3789C = 2424; 98 dword_378A0 = 56; 99 return STATUS_SUCCESS; 100 } 101 if(MajorVersion==6&&MinorVersion==1) 102 { 103 //WINDOWS_7 104 Version=61; 105 if(ServicePackMajor&&ServicePackMajor!=1) 106 return 3221225659; 107 dword_37C58 = 20; 108 dword_37C70 = 512; 109 dword_37C54 = 1084; 110 dword_378E4 = 11; 111 dword_37A90 = 376; 112 dword_378F8 = 16; 113 dword_37C40 = 16; 114 dword_37C50 = 40; 115 dword_378F0 = 800; 116 dword_37AC0 = 24; 117 dword_37C44 = 112; 118 dword_37C48 = 1040; 119 dword_37BF4 = 904; 120 dword_37C30 = 1048; 121 dword_37C14 = 912; 122 dword_37930 = 123; 123 dword_378F4 = 356; 124 dword_37BF8 = 502; 125 dword_37888 = 1056; 126 dword_37AB0 = 960; 127 dword_37C4C = 952; 128 dword_37920 = 952; 129 dword_37AC4 = 944; 130 dword_37908 = 48; 131 dword_377CC = 620; 132 dword_37894 = 48; 133 dword_377C4 = 41; 134 dword_377B0 = 32; 135 dword_377B4 = 379; 136 dword_377B8 = 79; 137 dword_377BC = 80; 138 dword_377C0 = 22; 139 dword_3788C = 600; 140 dword_37890 = 744; 141 dword_37898 = 1352; 142 dword_3789C = 1360; 143 dword_378A0 = 64; 144 DbgPrint("[kEvP64]Initialized version-specific data for Windows 7 SP%d\n", ServicePackMajor); 145 return STATUS_SUCCESS; 146 147 } 148 if(MajorVersion==6&&MinorVersion==2) 149 { 150 //WINDOWS_8 151 dword_378FC = 62; 152 dword_37C58 = 20; 153 dword_37C70 = 1032; 154 dword_37C54 = -1; 155 dword_378E4 = -1; 156 dword_37A90 = 456; 157 dword_378F8 = 16; 158 dword_37C40 = 16; 159 dword_37C50 = 40; 160 dword_378F0 = 1048; 161 dword_37AC0 = 24; 162 dword_37908 = 48; 163 dword_37C10 = 19; 164 dword_378E0 = 20; 165 dword_37C44 = 184; 166 dword_37C48 = 1008; 167 dword_37BF4 = 880; 168 dword_37C30 = 1008; 169 dword_37C14 = 880; 170 dword_37930 = 195; 171 dword_378F4 = 388; 172 dword_37BF8 = 562; 173 dword_37888 = 1024; 174 dword_37AB0 = 928; 175 dword_37C4C = 920; 176 dword_37920 = 928; 177 dword_37AC4 = 920; 178 dword_377CC = 644; 179 dword_37894 = 48; 180 dword_377C4 = 42; 181 dword_377B0 = 33; 182 dword_377B4 = 402; 183 dword_377B8 = 80; 184 dword_377BC = 81; 185 dword_377C0 = 23; 186 dword_3788C = 920; 187 dword_37890 = 784; 188 dword_37898 = 328; 189 dword_3789C = 336; 190 dword_378A0 = 72; 191 DbgPrint("[kEvP64]Initialized version-specific data for Windows 8 SP%d\n", ServicePackMajor); 192 return STATUS_SUCCESS; 193 } 194 if ( MajorVersion == 6 && MinorVersion == 3 ) 195 { 196 //WINDOWS_8.1 197 dword_378FC = 63; 198 dword_37C54 = -1; 199 dword_378E4 = -1; 200 dword_37C58 = 20; 201 dword_378F8 = 16; 202 dword_37C70 = 1032; 203 dword_37A90 = 728; 204 dword_37C40 = 16; 205 dword_37C50 = 40; 206 dword_378F0 = 1048; 207 dword_37AC0 = 24; 208 dword_37908 = 48; 209 dword_37C10 = 16; 210 dword_378E0 = 17; 211 dword_37C44 = 184; 212 dword_37C48 = 1656; 213 dword_37BF4 = 1528; 214 dword_37C30 = 1656; 215 dword_37C14 = 1528; 216 dword_37930 = 195; 217 dword_378F4 = 388; 218 dword_37BF8 = 562; 219 dword_37888 = 760; 220 dword_37AB0 = 1576; 221 dword_37C4C = 1568; 222 dword_37920 = 1576; 223 dword_37AC4 = 1568; 224 dword_377CC = 644; 225 dword_37894 = 48; 226 dword_377C4 = 43; 227 dword_377B0 = 34; 228 dword_377B4 = 408; 229 dword_377B8 = 81; 230 dword_377BC = 82; 231 dword_377C0 = 24; 232 dword_3788C = 920; 233 dword_37890 = 784; 234 dword_37898 = 328; 235 dword_3789C = 336; 236 dword_378A0 = 72; 237 DbgPrint("[kEvP64]Initialized version-specific data for Windows 8.1 SP%d\n", ServicePackMajor); 238 return STATUS_SUCCESS; 239 } 240 if ( MajorVersion == 10 && !MinorVersion ) 241 { 242 //WINDOWS_10 243 dword_378FC = 100; 244 dword_37C54 = -1; 245 dword_378E4 = -1; 246 dword_37C58 = 20; 247 dword_378F8 = 16; 248 dword_37C70 = 1048; 249 dword_37A90 = 736; 250 dword_378F0 = 1064; 251 dword_37C40 = 16; 252 dword_37C50 = 40; 253 dword_37AC0 = 24; 254 dword_37908 = 48; 255 dword_37C10 = 16; 256 dword_378E0 = 17; 257 dword_37C44 = 184; 258 dword_37C48 = 1664; 259 dword_37BF4 = 1536; 260 dword_37C30 = 1664; 261 dword_37C14 = 1536; 262 dword_37930 = 195; 263 dword_378F4 = 388; 264 dword_37BF8 = 562; 265 dword_37888 = 760; 266 dword_37AB0 = 1584; 267 dword_37C4C = 1576; 268 dword_37920 = 1584; 269 dword_37AC4 = 1576; 270 dword_377CC = 644; 271 dword_37894 = 48; 272 dword_377C4 = 44; 273 dword_377B0 = 35; 274 dword_377B4 = 416; 275 dword_377B8 = 82; 276 dword_377BC = 83; 277 dword_377C0 = 25; 278 dword_3788C = 936; 279 dword_37890 = 784; 280 dword_37898 = 328; 281 dword_3789C = 336; 282 dword_378A0 = 72; 283 return STATUS_SUCCESS; 284 } 285 if ( MajorVersion == 10 && MajorVersion || MinorVersion > 0xA ) 286 { 287 dword_378FC = -1; 288 result = 3221225659; 289 } 290 else 291 { 292 result = 3221225659; 293 } 294 return result; 295 }
因為程式碼比較長,我預設摺疊了,想看的可以看下。
我們繼續往下看了,接下來主要做了如下幾件事:
- 建立一個裝置
- 建立符號連結
- 設定裝置分發函式
- 註冊一個過濾驅動
首先作者實現了一個獲取匯出函式地址的函式,我想這是因為作者想使用一些已經匯出但是沒有在WDK文件中的函式吧。我這裡取名為GetFuncAddress了。我用C重寫了一下這個函式,如下
//根據反彙編寫的 PVOID GetFuncAddress(WCHAR *Name) { ULONG IRQL; UNICODE_STRING UnicodeFindName; WCHAR *BufPointer=Name; if(KeGetCurrentirql()>1) { IRQL=KeGetCurrentirql(); DbgPrint("EX: Pageable code called at IRQL %d\n", IRQL); _asm{int 0x2C}; } RtlInitUnicodeString(&UnicodeFindName,BufPointer); return MmGetSystemRoutineAddress(&UnicodeFindName); }
然後作者用這個函式獲取一些函式的地址(先判斷了一下系統的版本),函式的列表如下
"ExfUnblockPushLock" "ObGetObjectType" "ObDereferenceObject" "PsAcquireProcessExitSynchronization" "PsIsProtectedProcess" "PsReleaseProcessExitSynchronization" "PsResumeProcess" "PsSuspendProcess" "KeSetAffinityThread"
這些部分都在第39行的sub_39010();函式中,程式判斷完系統版本後馬上就執行了這個函式。
這個函式的虛擬碼如下
1 __int64 sub_39010() 2 { 3 unsigned __int8 v0; // al@2 4 __int64 result; // rax@15 5 6 if ( (signed int)(unsigned __int8)sub_11030() > 1 ) 7 { 8 v0 = sub_11030(); 9 DbgPrint("EX: Pageable code called at IRQL %d\n", v0); 10 sub_11020(); 11 } 12 if ( (unsigned int)dword_378FC >= 0x3E ) 13 qword_37AB8 = (__int64)sub_392B0(L"ExfUnblockPushLock"); 14 qword_37928 = (__int64)sub_392B0(L"ObGetObjectType"); 15 qword_378E8 = (__int64)sub_392B0(L"ObDereferenceObject"); 16 qword_378D8 = (__int64)sub_392B0(L"PsAcquireProcessExitSynchronization"); 17 qword_37A98 = (__int64)sub_392B0(L"PsIsProtectedProcess"); 18 qword_37C38 = (__int64)sub_392B0(L"PsReleaseProcessExitSynchronization"); 19 qword_37900 = (__int64)sub_392B0(L"PsResumeProcess"); 20 qword_37C20 = (__int64)sub_392B0(L"PsSuspendProcess"); 21 qword_378B8 = (__int64)sub_392B0(L"KeSetAffinityThread"); 22 sub_26AD0((__int64)qword_39A00, (__int64)"KfdClassify2"); 23 sub_26AD0((__int64)qword_39A00, (__int64)"GetCalloutEntry "); 24 sub_26AD0((__int64)qword_39A00, (__int64)"InitDefaultCallout "); 25 qword_377F8 = sub_26AD0((__int64)qword_39A70, (__int64)"KeInsertQueueApc"); 26 if ( !qword_377F8 ) 27 qword_377F8 = (__int64)sub_392B0(L"KeInsertQueueApc"); 28 qword_37800 = sub_26AD0((__int64)qword_39A70, (__int64)"PsSetCreateProcessNotifyRoutine"); 29 if ( !qword_37800 ) 30 qword_37800 = (__int64)sub_392B0(L"PsSetCreateProcessNotifyRoutine"); 31 qword_37808 = sub_26AD0((__int64)qword_39A70, (__int64)"PsSetCreateThreadNotifyRoutine"); 32 if ( !qword_37808 ) 33 qword_37808 = (__int64)sub_392B0(L"PsSetCreateThreadNotifyRoutine"); 34 qword_37810 = sub_26AD0((__int64)qword_39A70, (__int64)"PsSetLoadImageNotifyRoutine"); 35 if ( !qword_37810 ) 36 qword_37810 = (__int64)sub_392B0(L"PsSetLoadImageNotifyRoutine"); 37 qword_37818 = sub_26AD0((__int64)qword_39A70, (__int64)"CmUnRegisterCallback"); 38 if ( !qword_37818 ) 39 qword_37818 = (__int64)sub_392B0(L"CmUnRegisterCallback"); 40 result = sub_26AD0((__int64)qword_39A70, (__int64)"IoRegisterShutdownNotification"); 41 qword_37820 = result; 42 if ( !result ) 43 { 44 result = (__int64)sub_392B0(L"IoRegisterShutdownNotification"); 45 qword_37820 = result; 46 } 47 return result; 48 }
這個函式首先判斷了一下IRQL這個在之前就已經分析過了,然後判斷了一下系統版本,透過驗證之後用自己實現的GetFuncAddress函式來獲取這些函式的地址,並把地址儲存在全域性變數中sub_392B0就是GetFuncAddress(),然後又呼叫了sub_26AD0()這個函式,這個函式中又呼叫了這個函式
1 //IDA虛擬碼,被sub_39010()呼叫 2 PVOID __fastcall sub_260D0(unsigned int a1) 3 { 4 PVOID result; // rax@3 5 int v2; // [sp+20h] [bp-28h]@4 6 int v3; // [sp+24h] [bp-24h]@4 7 SIZE_T NumberOfBytes; // [sp+28h] [bp-20h]@1 8 PVOID P; // [sp+30h] [bp-18h]@2 9 unsigned int v6; // [sp+50h] [bp+8h]@1 10 11 v6 = a1; 12 for ( LODWORD(NumberOfBytes) = 256; ; LODWORD(NumberOfBytes) = v3 + 256 ) 13 { 14 P = ExAllocatePool(0, (unsigned int)NumberOfBytes); 15 if ( !P ) 16 return 0i64; 17 v3 = 0; 18 v2 = ZwQuerySystemInformation(v6, P, (unsigned int)NumberOfBytes, &v3); 19 if ( v2 == -1073741820 ) 20 { 21 ExFreePoolWithTag(P, 0); 22 P = 0i64; 23 if ( v3 ) 24 continue; 25 } 26 break; 27 } 28 if ( v2 >= 0 ) 29 { 30 result = P; 31 } 32 else 33 { 34 sub_199F0(P); 35 result = 0i64; 36 } 37 return result; 38 }
這是呼叫ZwQuerySystemInformation()函式的11號功能也就是SystemModuleInformation功能,這個函式經常在安全類程式中呼叫,作為一個常規的列舉模組的方法。用迴圈是為了讓ZwQuerySystemInformation返回需要的合適的大小。這個函式返回的結構如下
1 typedef struct _SYSTEM_MODULE_INFORMATION { 2 ULONG Count; 3 SYSTEM_MODULE_INFORMATION_ENTRY Module[1]; 4 } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
Count為個數,有多少Count就有多少的SYSTEM_MODULE_INFORMATION_ENTRY,其中這個陣列中的項的結構如下:
typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY { HANDLE Section; PVOID MappedBase; PVOID Base; ULONG Size; ULONG Flags; USHORT LoadOrderIndex; USHORT InitOrderIndex; USHORT LoadCount; USHORT PathLength; CHAR ImageName[256]; } SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;
注意這個呼叫返回的第一個模組一定是ntoskrnl.exe模組,很多人就是透過這個呼叫去獲取核心模組的資訊的。
1 __int64 __fastcall sub_21DB0(const char *a1) 2 { 3 __int64 result; // rax@2 4 UNICODE_STRING String1; // [sp+20h] [bp-108h]@3 5 UNICODE_STRING String2; // [sp+30h] [bp-F8h]@12 6 NTSTATUS v4; // [sp+40h] [bp-E8h]@1 7 PCWSTR v5; // [sp+48h] [bp-E0h]@1 8 __int64 v6; // [sp+50h] [bp-D8h]@1 9 __int64 v7; // [sp+58h] [bp-D0h]@1 10 __int64 v8; // [sp+60h] [bp-C8h]@1 11 __int64 v9; // [sp+68h] [bp-C0h]@1 12 __int64 v10; // [sp+70h] [bp-B8h]@1 13 unsigned int i; // [sp+78h] [bp-B0h]@1 14 UNICODE_STRING v12; // [sp+80h] [bp-A8h]@1 15 UNICODE_STRING v13; // [sp+90h] [bp-98h]@19 16 STRING v14; // [sp+A0h] [bp-88h]@3 17 STRING v15; // [sp+B0h] [bp-78h]@8 18 PCWSTR v16; // [sp+C0h] [bp-68h]@1 19 __int64 v17; // [sp+C8h] [bp-60h]@1 20 __int64 v18; // [sp+D0h] [bp-58h]@1 21 __int64 v19; // [sp+D8h] [bp-50h]@1 22 UNICODE_STRING UnicodeString; // [sp+E0h] [bp-48h]@8 23 int j; // [sp+F0h] [bp-38h]@1 24 PVOID v22; // [sp+F8h] [bp-30h]@1 25 UNICODE_STRING DestinationString; // [sp+100h] [bp-28h]@1 26 __int64 v24; // [sp+110h] [bp-18h]@1 27 PCSZ SourceString; // [sp+130h] [bp+8h]@1 28 29 SourceString = a1; 30 v24 = 0i64; 31 v4 = 0; 32 i = 0; 33 j = 0; 34 v5 = L"hal.dll"; 35 v6 = (__int64)L"halacpi.dll"; 36 v7 = (__int64)L"halapic.dll"; 37 v8 = (__int64)L"halmps.dll"; 38 v9 = (__int64)L"halaacpi.dll"; 39 v10 = (__int64)L"halmacpi.dll"; 40 v16 = L"ntoskrnl.exe"; 41 v17 = (__int64)L"ntkrnlpa.exe"; 42 v18 = (__int64)L"ntkrnlmp.exe"; 43 v19 = (__int64)L"ntkrpamp.exe"; 44 v22 = 0i64; 45 RtlInitUnicodeString(&DestinationString, L"hal.dll"); 46 RtlInitUnicodeString(&v12, L"ntoskrnl.exe"); 47 v22 = sub_260D0(11u); 48 if ( v22 ) 49 { 50 RtlInitAnsiString(&v14, SourceString); 51 v4 = RtlAnsiStringToUnicodeString(&String1, &v14, 1u); 52 if ( v4 >= 0 ) 53 { 54 for ( i = 0; ; ++i ) 55 { 56 if ( i < *(_DWORD *)v22 ) 57 { 58 RtlInitAnsiString(&v15, (PCSZ)v22 + 296 * i + *((_WORD *)v22 + 148 * i + 23) + 48); 59 v4 = RtlAnsiStringToUnicodeString(&UnicodeString, &v15, 1u); 60 if ( v4 < 0 ) 61 continue; 62 if ( RtlEqualUnicodeString(&String1, &DestinationString, 0) ) 63 { 64 for ( j = 0; j < 6; ++j ) 65 { 66 RtlInitUnicodeString(&String2, (&v5)[4 * j]); 67 if ( RtlEqualUnicodeString(&UnicodeString, &String2, 0) ) 68 { 69 v24 = *((_QWORD *)v22 + 37 * i + 3); 70 break; 71 } 72 } 73 } 74 else if ( RtlEqualUnicodeString(&String1, &v12, 0) ) 75 { 76 for ( j = 0; j < 4; ++j ) 77 { 78 RtlInitUnicodeString(&v13, (&v16)[4 * j]); 79 if ( RtlEqualUnicodeString(&UnicodeString, &v13, 0) ) 80 { 81 v24 = *((_QWORD *)v22 + 37 * i + 3); 82 break; 83 } 84 } 85 } 86 else if ( RtlEqualUnicodeString(&String1, &UnicodeString, 0) ) 87 { 88 v24 = *((_QWORD *)v22 + 37 * i + 3); 89 } 90 RtlFreeUnicodeString(&UnicodeString); 91 if ( !v24 ) 92 continue; 93 } 94 break; 95 } 96 RtlFreeUnicodeString(&String1); 97 sub_199F0(v22); 98 result = v24; 99 } 100 else 101 { 102 result = 0i64; 103 } 104 } 105 else 106 { 107 result = 0i64; 108 } 109 return result; 110 }
這個是遍歷剛才得到的結果,就是剛才得到的SYSTEM_MODULE_INFORMATION結構。如果要得到的目標模組是nt核心模組或是hal.dll的話就特殊處理
0x1
接下來就是進入正題了,來看看PT的分發例程,在看分發例程之前先總結下,如下圖
圖中的真正的功能函式就是我們要分析的重點,PT的大部分功能都在這裡完成。
0x2
我們來看switch語句,這個語句由最後的一個 DbgPrint("[kEvP64] Unknown IOCTL: 0x%X (%04X,%04X)\r\n", v37, (v37 & 0xFFFF0000) >> 16, (v37 >> 2) & 0xFFF);就可以看出是DeviceIoControl函式來傳送的一些自定義的IOCTL。但是我們沒有辦法知道具體的含義,因為這些都是自定義的,在C中定義IOCTL也只是用一個宏來完成。
來看下這裡
1 //IDA虛擬碼 2 Irp = a2; 3 v35 = -1073741808; 4 v27 = 0i64; 5 v28 = sub_11100((__int64)a2);
注意第5行的sub_11100,引數a2是Irp指標,它的反彙編如下圖
只是一個簡單的移位操作是吧。我猜這個應該就是IoGetCurrentIrpStackLocation()這個函式,可見IRP中是存有當前IRP棧的指標的。首先是對比Irp棧的總層數是不是大於當前層數,然後就是取出當前棧的指標(這個指標在Irp結構中)返回了。
而我們常用的操作就是
PIO_STACK_LOCATION irpSp; IoControlCode=irpSp->Parameters.DeviceIoControl.IoControlCode; switch(IoControlCode) { …… }
相關文章
- JVM(持續更新。。。)2019-04-18JVM
- FastApi持續更新2021-07-04ASTAPI
- 元件形式來分析 Laravel 思想 持續更新中2019-05-30元件Laravel
- 資料分析面試|SQL真題持續更新2020-12-29面試SQL
- Blender 雕刻 持續更新2024-10-27
- 移動端經驗總結(持續更新)2017-03-03
- MySql報錯(持續更新)2019-06-23MySql
- Pycharm快捷鍵持續更新2018-10-05PyCharm
- Xcode 技巧 持續更新2018-10-19XCode
- AI面試題(持續更新)2020-11-09AI面試題
- Hbase面試題(持續更新)2020-11-28面試題
- git使用、持續更新中2021-01-02Git
- 踩坑記[持續更新]2017-09-26
- litepal筆記(持續更新)2017-12-18筆記
- leetcode(持續更新......)2017-12-20LeetCode
- thymeleaf的坑(持續更新。。。)2018-01-01
- LevOJ平臺 - 持續更新2024-10-02
- go 常用包整理 (持續更新)2020-01-03Go
- 前端知識點(持續更新)2019-04-02前端
- Flutter資源收集(持續更新)2019-05-24Flutter
- Flutter 問題集,持續更新2019-01-13Flutter
- LINUX進階(持續更新)2020-12-10Linux
- 有用的網站(持續更新)2020-11-12網站
- 前端程式碼集合(持續更新)2021-10-09前端
- 開發常識 持續更新~~2018-06-27
- 陣列總結,持續更新~2018-06-20陣列
- JAVA系列合集(持續更新中)2018-02-06Java
- DDos/DoS工具集(持續更新)2017-01-14
- 【持續更新】Eclipse使用教程2017-11-29Eclipse
- 【持續更新】重要FLIP總結2024-06-21
- Blender 修改器 持續更新2024-10-27
- 軟考筆記 --- 持續更新2024-04-05筆記
- idea快捷鍵(持續更新)2024-05-28Idea
- 【持續更新】創新實訓2024-05-29
- 以醫為本驅動行業可持續發展2022-08-17行業
- PHP 的自動載入(持續學習更新中)2022-02-15PHP
- goCms-持續更新,希望能堅持下去2020-10-03Go
- Flutter踩坑日記(持續更新...)2020-05-20Flutter