其实很简单,由于驱动本来就在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) 编译驱动,并扔到测试机中跑