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 }
View Code

因为代码比较长,我默认折叠了,想看的可以看下。

 我们继续往下看了,接下来主要做了如下几件事:

  1. 创建一个设备
  2. 创建符号链接
  3. 设置设备分发函数
  4. 注册一个过滤驱动

首先作者实现了一个获取导出函数地址的函数,我想这是因为作者想使用一些已经导出但是没有在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)
{
……  
}

 

posted @ 2016-05-23 15:29  Ox9A82  阅读(2290)  评论(0编辑  收藏  举报