通过特征码定位内核中的未导出函数(以PspTerminateProcess函数为例)

其实很简单,由于驱动本来就在0环跑,所以不用担心权限不够,直接拿着函数的一堆特征码到内存中1字节1字节的比对就行,这里是以定位并调用未导出函数 PspTerminateProcess 为例:

 1 #include <ntifs.h>
 2 
 3 NTSTATUS PsLookupProcessByProcessId(IN HANDLE ProcessId,OUT PEPROCESS *Process);
 4 
 5 VOID DriverUnload(PDRIVER_OBJECT pDriverObject) {
 6     DbgPrint("已卸载!
");
 7 }
 8 
 9 PVOID GetUndocumentFunctionAddress(PUCHAR pStartAddress,PUCHAR pShellcode)
10 {
11     int index = 0;
12     int maxSize = 0x30000;
13 
14     if(!MmIsAddressValid(pStartAddress))
15     {
16         DbgPrint("地址不合法,或者地址指向内存不可读!
");
17         return NULL;
18     }
19 
20     DbgPrint("地址合法,开始查找...
");
21     PUCHAR tmp = pStartAddress;
22 
23     for(index=0;index<maxSize;index++)
24     {
25         tmp = pStartAddress + index;
26         for(int x=0;x<=17;x++)
27         {
28             if(tmp[x] == pShellcode[x])
29             {
30                 if(x == 17)
31                 {
32                     return tmp;
33                 }
34                 continue;
35             }
36             else
37                 break;
38         }
39     }
40 
41     DbgPrint("查找结束,最后查找的起始地址为:%x
",tmp);
42     return NULL;
43 }
44 
45 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) {
46 
47     DbgPrint("启动!
");
48     pDriverObject->DriverUnload = DriverUnload;
49 
50     UCHAR shellcode[19] = "x8bxffx55x8bxecx56x64xa1x24x01x00x00x8bx75x08x3bx70x44";
51 
52     PVOID p = GetUndocumentFunctionAddress((PUCHAR)0x805c0000,shellcode);
53 
54     if(p != NULL)
55     {
56         DbgPrint("成功找到函数首地址:%x
",p);
57         DbgPrint("开始尝试调用函数...
");
58         /****** 调用PspTerminateProcess(IN PEPROCESS Process, IN NTSTATUS ExitStatus)函数 ******/
59         PEPROCESS hProcess;
60         PsLookupProcessByProcessId((HANDLE)424,&hProcess);
61         _asm{
62             push 0;
63             push hProcess;
64             call p;
65         }
66         /****** 调用PspTerminateProcess(IN PEPROCESS Process, IN NTSTATUS ExitStatus)函数 ******/
67         DbgPrint("函数调用结束.
");
68     }
69     else
70         DbgPrint("查找失败!
");
71 
72     return STATUS_SUCCESS;
73 }

有一点需要注意,由于进程PID是硬编码进去的,所以测试的流程为:

  (1) 在系统中运行任意程序,并通过任务管理器查看PID

  (2) 把代码中的 PID 改成你自己在任务管理器中看到的

  (3) 编译驱动,并扔到测试机中跑

原文地址:https://www.cnblogs.com/dubh3/p/13283634.html