写一个SSDTShadow Hook

来源:互联网 发布:pigalle红磨坊 知乎 编辑:程序博客网 时间:2024/05/24 05:38

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__
原创粉丝点击