写一个SSDTShadow Hook

http://hi.baidu.com/ejoywx/item/b9149cf75d1f7f1ce2e3bdf4

 

我本菜鸟,班门弄斧之辈,大牛不要笑话。

以下程序名称为BugHook,是在Win7sp1X64上对SSDTShadow::NtUserFindWindowEx进行Hook:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
#include "BugHook.h"
   
#pragma intrinsic(__readcr0)
#pragma intrinsic(__writecr0)
#pragma intrinsic(_disable)
#pragma intrinsic(_enable)
#pragma intrinsic(__readmsr)
   
extern  PUSHORT  NtBuildNumber;
static  PFN_NTUSERFINDWINDOWEX g_NtUserFindWindowEx;
   
KIRQL FORCEINLINE WPOFF( )
{
     KIRQL    Irql = KeRaiseIrqlToDpcLevel();
     UINT_PTR  cr0  = __readcr0();
       
     cr0 &= ~0x10000;
     __writecr0( cr0 );
     _disable();
   
     return  Irql;
}
   
VOID  FORCEINLINE WPON( KIRQL Irql )
{
     UINT_PTR  cr0 = __readcr0();
       
     cr0 |= 0x10000;
     _enable();  
     __writecr0( cr0 );
   
     KeLowerIrql( Irql );
}
   
PVOID  SearchHookPoint(  PVOID  StartPoint,  PUCHAR   EndPoint )
{
     PVOID    HookPoint= NULL;
     PUCHAR   pCurPoint = ( PUCHAR )StartPoint;
       
     __try
     {
         while ( ++pCurPoint < ( PUCHAR )EndPoint ) 
         {   
             if ( ( ( ULONG_PTR )pCurPoint %  sizeof ( PVOID ) ) == 0 && //考虑地址对齐
                 *( PULONG_PTR )(pCurPoint+0) == 0 &&  //期望搜索到当前(.text)节的尾部
                 *( PULONG_PTR )(pCurPoint+1) == 0 &&
                 *( PULONG_PTR )(pCurPoint+2) == 0 && 
                 *( PULONG_PTR )(pCurPoint+3) == 0 
               )
             {
                 HookPoint = ( PVOID )pCurPoint;
                 break ;
             }
         }       
     }
     __except( EXCEPTION_EXECUTE_HANDLER )
     {
     }
       
     return  HookPoint;
}
   
VOID  PatchHookPoint(  PVOID  HookPos,  PVOID  FakeNtFunc ) //perfect! Infact, do not do that!
{
     KIRQL     Irql;
     UCHAR      jmp_code[] =  "\x48\xB8\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xE0" ; //mov rax, xxx ; jmp rax
     *( PULONGLONG )( jmp_code + 2 ) = ( ULONGLONG )FakeNtFunc;
   
     Irql = WPOFF();        
     RtlFillMemory( HookPos, 16, 0xCC );
     RtlMoveMemory( HookPos, jmp_code, 12 );        
     WPON( Irql );
}
   
PEPROCESS LookupCsrssProcess( )
{    
     PEPROCESS   CsrssProcess = NULL;
     NTSTATUS    Status ;
     PEPROCESS   Process;
     ULONG        Index  ;
   
     for  ( Index = 8; Index < 0x1000; Index += 4 )
     {
         Status = PsLookupProcessByProcessId( ( HANDLE )Index, &Process );
         if  ( !NT_SUCCESS(Status) )
         {
             continue ;
         }
   
         if  ( !_stricmp( PsGetProcessImageFileName(Process),  "csrss.exe"  ) )
         {
             CsrssProcess = Process;
             Index = 0x20000;
         }
   
         ObDereferenceObject( Process );
     }
   
     return  CsrssProcess;
}
   
ULONG_PTR  GetSSDTShadow64( )
{
/*
                                         KiSystemServiceRepeat proc near
4C 8D 15 C7 20 23 00                    lea     r10, KeServiceDescriptorTable
4C 8D 1D 00 21 23 00                    lea     r11, KeServiceDescriptorTableShadow
F7 83 00 01 00 00 80 00 00 00           test    dword ptr [rbx+100h], 80h
*/
     PUCHAR       pStartSearchAddress   = ( PUCHAR )__readmsr(0xC0000082); //得到KiSystemCall64
     PUCHAR       pEndSearchAddress     = ( PUCHAR )( (( ULONG_PTR )pStartSearchAddress + PAGE_SIZE) & (~0x0FFF) );
     PULONG       pFindCodeAddress      = NULL;
     ULONG_PTR    pSSDTShadow = 0;
   
     while  ( ++pStartSearchAddress < pEndSearchAddress )
     {
         if  ( (*( PULONG )pStartSearchAddress & 0xFFFFFF00) == 0x83f70000 )
         {
             //-12得到KeServiceDescriptorTable;-5得到KeServiceDescriptorTableShadow
             pFindCodeAddress = ( PULONG )(pStartSearchAddress - 5);
             pSSDTShadow = ( ULONG_PTR )pFindCodeAddress +
                 ( ( (*( PULONG )pFindCodeAddress) >> 24 ) + 7 ) +  //ae
                     ( ULONG_PTR )( ( ( *( PULONG )(pFindCodeAddress + 1) ) & 0x0FFFF ) << 8 );  //id4c
             break ;
         }
     }
   
     return  pSSDTShadow;
}
   
ULONG      FORCEINLINE GetSSDTEntry(  PULONG  KiServiceTable,  PVOID  FuncAddress )
{
     return  ( ( ULONG )(( ULONGLONG )FuncAddress-( ULONGLONG )KiServiceTable) ) << 4;
}
   
ULONG_PTR  FORCEINLINE GetSSDTFunc(  PULONG  KiServiceTable,  ULONG  ServiceId )
{
     return  ( LONGLONG )( KiServiceTable[ServiceId] >> 4 ) 
             + ( ULONGLONG )KiServiceTable;
}
   
NTSTATUS LoadSSDTShadowHook( IN  ULONG  ServiceId, IN  PVOID  NewFunc, OUT  PVOID * OldFunc )
{
     PKSERVICE_TABLE_DESCRIPTOR SSDTShadow;
     NTSTATUS       Status = STATUS_UNSUCCESSFUL;
       
     ULONG           SsdtEntry;
     PULONG          W32pServiceTable;
     PVOID           HookPoint;
       
     PEPROCESS      CsrssProcess;
     KAPC_STATE     ApcState;
     KIRQL          Irql;
     BOOLEAN         bNeedDetach = FALSE;
   
     do
     {     
         if ( ( LONG )ServiceId < 0x1000 )
         {
             break ;
         }
         ServiceId &= 0x0FFF;
           
         SSDTShadow = (PKSERVICE_TABLE_DESCRIPTOR)GetSSDTShadow64();
         if  ( !SSDTShadow )
         {
             break ;
         }
         W32pServiceTable = SSDTShadow[1].Base;
           
         CsrssProcess = LookupCsrssProcess( );
         if ( !CsrssProcess )
         {
             break ;
         }
           
         if ( PsGetCurrentProcess() != CsrssProcess )
         {
             KeStackAttachProcess( CsrssProcess, &ApcState );
             bNeedDetach = TRUE;
        
           
         HookPoint = SearchHookPoint( ( PVOID )W32pServiceTable, ( PUCHAR )W32pServiceTable + 0x4000000 );
         if  ( !HookPoint )
         {
             break ;
         }        
   
         if  ( OldFunc )
         {
             *OldFunc = ( PVOID )GetSSDTFunc( W32pServiceTable, ServiceId );            
             PatchHookPoint( HookPoint, NewFunc );
               
             SsdtEntry = GetSSDTEntry( W32pServiceTable, HookPoint );
             SsdtEntry &= 0xFFFFFFF0; //perfect!!!
             SsdtEntry += W32pServiceTable[ServiceId] & 0x0F;
         }
         else
         {
             SsdtEntry = GetSSDTEntry( W32pServiceTable, NewFunc );            
             SsdtEntry &= 0xFFFFFFF0;
             SsdtEntry += W32pServiceTable[ServiceId] & 0x0F;
         }        
           
         Irql = WPOFF();
         W32pServiceTable[ServiceId] = SsdtEntry;   
         WPON( Irql );     
           
         Status = STATUS_SUCCESS;
   
     while  ( FALSE );
       
     if ( bNeedDetach )
     {
         KeUnstackDetachProcess( &ApcState ); 
     }
       
     return  Status;
}
   
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
{
     NTSTATUS Status = STATUS_NOT_SUPPORTED;   
       
     if ( *NtBuildNumber == 7601 &&  sizeof ( PVOID ) == 8  )
     {
         DriverObject->DriverUnload = BugHookUnload;
         Status = LoadSSDTShadowHook( 0x106E, ( PVOID )ProxyNtUserFindWindowEx, ( PVOID *)&g_NtUserFindWindowEx );
     }
       
     KdPrintEx(( DPFLTR_IHVDRIVER_ID,DPFLTR_ERROR_LEVEL,  "[BugHook] DriverEntry is called with Status 0x%08X \n" , Status ));   
     return  Status;
}
   
VOID  BugHookUnload( IN PDRIVER_OBJECT DriverObject )
{
     LoadSSDTShadowHook( 0x106E, ( PVOID )g_NtUserFindWindowEx, NULL );
     KdPrintEx(( DPFLTR_IHVDRIVER_ID,DPFLTR_ERROR_LEVEL,  "[BugHook] BugHookUnload is called.\n" ));
}
   
HWND  NTAPI
ProxyNtUserFindWindowEx(
     IN  HWND  hwndParent,
     IN  HWND  hwndChild,
     IN PUNICODE_STRING pstrClassName,
     IN PUNICODE_STRING pstrWindowName,
     DWORD  dwType
     )                   
{
     if ( ExGetPreviousMode() == UserMode )
     {        
         UNICODE_STRING     CapturedClassName  = {0};
         UNICODE_STRING     CapturedWindowName = {0};
         WCHAR               NameBuffer[260]    = {0};
         WCHAR *             pNameBuf = NameBuffer;
   
         __try
         {
             if ( pstrClassName )
             {
                 ProbeAndReadUnicodeStringEx( &CapturedClassName, pstrClassName );
                 ProbeForRead(
                     CapturedClassName.Buffer,
                     CapturedClassName.Length,
                     sizeof ( WCHAR )
                     );
                   
                 RtlMoveMemory( pNameBuf, CapturedClassName.Buffer, CapturedClassName.Length ); //未判断缓冲区长度,巨大的安全隐患
                 pNameBuf += CapturedClassName.Length;
             }
               
             if ( pstrWindowName )
             {
                 ProbeAndReadUnicodeStringEx( &CapturedWindowName, pstrWindowName );
                 ProbeForRead(
                     CapturedWindowName.Buffer,
                     CapturedWindowName.Length,
                     sizeof ( WCHAR )
                     );
                   
                 RtlMoveMemory( pNameBuf, CapturedWindowName.Buffer, CapturedWindowName.Length ); //未判断缓冲区长度,巨大的安全隐患
                 pNameBuf += CapturedWindowName.Length;
             }
               
             if ( pNameBuf > NameBuffer ) 
             {
                 //
                 //Here, you can do something like analyzing NameBuffer.
                 //
                 KdPrintEx(( DPFLTR_IHVDRIVER_ID,DPFLTR_ERROR_LEVEL,  "[BugHook] NtUserFindWindowEx : %ws\n" , NameBuffer ));
            
         }
         __except( EXCEPTION_EXECUTE_HANDLER )
         {
             /* KdPrintEx(( DPFLTR_IHVDRIVER_ID,DPFLTR_ERROR_LEVEL, 
                         "[BugHook] Catch a bug with status : %08X\n", 
                             GetExceptionCode() ) ); */
         }
     }
       
     return  g_NtUserFindWindowEx( hwndParent, hwndChild, pstrClassName, pstrWindowName, dwType ) ;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#ifndef __BUGHHOK_H__
#define __BUGHHOK_H__
   
# include  <ntifs.h>
# include  <ntimage.h>
   
DRIVER_UNLOAD     BugHookUnload;
DRIVER_INITIALIZE DriverEntry;
   
typedef HANDLE HWND;
typedef ULONG  DWORD;
   
typedef HWND ( NTAPI *PFN_NTUSERFINDWINDOWEX)(  \
                  HWND  hwndParent,              \
                  HWND  hwndChildAfter,          \
                  PUNICODE_STRING  ucClassName,  \
                  PUNICODE_STRING  ucWindowName, \
                  DWORD dwType                   \
                  ) ;
                    
HWND NTAPI
ProxyNtUserFindWindowEx(
     HWND  hwndParent,
     HWND  hwndChildAfter,
     PUNICODE_STRING  ucClassName,
     PUNICODE_STRING  ucWindowName,
     DWORD dwType
     ) ;
   
//---------------------------------------------------------------------------------------
//copy from wrk
typedef struct _KSERVICE_TABLE_DESCRIPTOR {
     PULONG Base;
     PULONG Count;
     ULONG  Limit;
     PUCHAR  Number ;
} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
    
NTKERNELAPI
UCHAR *
PsGetProcessImageFileName(
     __in PEPROCESS Process
     );
    
# if  !defined(__cplusplus)
   
#define ProbeAndReadUnicodeString(Source)  \
     (((Source) >= (UNICODE_STRING *  const )MM_USER_PROBE_ADDRESS) ? \
     (*(volatile UNICODE_STRING *  const )MM_USER_PROBE_ADDRESS) : (*(volatile UNICODE_STRING *)(Source)))
   
#endif
   
   
# if  defined(_AMD64_)
   
FORCEINLINE
VOID
ProbeAndReadUnicodeStringEx (
                              OUT PUNICODE_STRING Destination,
                              IN PUNICODE_STRING Source
                              )
   
{
   
     if  (Source >= (UNICODE_STRING *  const )MM_USER_PROBE_ADDRESS) {
         Source = (UNICODE_STRING *  const )MM_USER_PROBE_ADDRESS;
     }
   
     _ReadWriteBarrier();
     *Destination = *((volatile UNICODE_STRING *)Source);
     return ;
}
   
# else
   
#define ProbeAndReadUnicodeStringEx(Dst, Src) *(Dst) = ProbeAndReadUnicodeString(Src)
   
#endif
//---------------------------------------------------------------------------------------
   
#endif //__BUGHHOK_H__
本实例由VS2008开发,在提供了一套驱动开发框架的同时,又演示了如何获取Shadow SSDT表函数原始地址的办法。 主要函数:ULONG GetShadowSSDT_Function_OriAddr(ULONG index); 原理说明: 根据特征码搜索导出函数KeAddSystemServiceTable来获取Shadow SSDT基址,以及通过ZwQuerySystemInformation()函数获取win32k.sys基址,然后解析PE定位到Shadow SSDT在win32k.sys的偏移地址,并通过进一步计算来得到Shadow SSDT表函数的原始地址。 这里只测试了三个函数:(460)NtUserMessageCall、(475)NtUserPostMessage和(502)NtUserSendInput,具体使用时可以举一反三,网上完整的源代码实例并不太多,希望可以帮到真正有需要的朋友。 系统环境: 在WinXP SP3系统 + 瑞星杀毒软件 打印输出: [ LemonInfo : Loading Shadow SSDT Original Address Driver... ] [ LemonInfo : 创建“设备”值为:0 ] [ LemonInfo : 创建“设备”成功... ] [ LemonInfo : 创建“符号链接”状态值为:0 ] [ LemonInfo : 创建“符号链接”成功... ] [ LemonInfo : 驱动加载成功... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP 开始... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP Enter IRP_MJ_DEVICE_CONTROL... ] [ LemonInfo : 获取ShadowSSDT表 (460)NtUserMessageCall 函数的“当前地址”为:0xB83ECFC4,“起源地址”为:0xBF80EE6B ] [ LemonInfo : 获取ShadowSSDT表 (475)NtUserPostMessage 函数的“当前地址”为:0xB83ECFA3,“起源地址”为:0xBF8089B4 ] [ LemonInfo : 获取ShadowSSDT表 (502)NtUserSendInput 函数的“当前地址”为:0xBF8C31E7,“起源地址”为:0xBF8C31E7 ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP_MJ_DEVICE_CONTROL 成功执行... ] [ LemonInfo : 派遣函数(DispatchRoutine) IRP 结束... ] [ LemonInfo : UnLoading Shadow SSDT Original Address Driver... ] [ LemonInfo : 删除“符号链接”成功... ] [ LemonInfo : 删除“设备”成功... ] [ LemonInfo : 驱动卸载成功... ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值