windows:根据特征码查找内核任意函数

在windows平台做逆向、外挂等,经常需要调用很多未导出的内核函数,怎么方便、快速查找了?可以先用IDA等工具查看硬编码,再根据硬编码定位到需要调用的函数。整个思路大致如下:

1、先查找目标模块

   遍历模块的方式有多种。既然通过驱动在内核编程,这里选择遍历driverObject的DriverSection字段来遍历内核所有模块,核心代码如下:

 1 /*
 2   可以用来动态查找内核模块的基址,后续用于:
 3   1、PTEPDE等base计算
 4   2、其他函数、变量精确位置的计算(IDA静态分析只能查到偏移)
 5 */
 6 PVOID FindMould(PDRIVER_OBJECT pDriverObject, PWCHAR moudName, PULONG pSize)
 7 {
 8     // 从PDRIVER_OBJECT获取DriverSection,便可获得驱动模块链表
 9     PLDR_DATA_TABLE_ENTRY pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
10     // 开始遍历双向链表
11     PLDR_DATA_TABLE_ENTRY pFirstDriverData = pDriverData;
12     do
13     {
14         if ((0 < pDriverData->BaseDllName.Length) ||
15             (0 < pDriverData->FullDllName.Length))
16         {
17             // 显示
18             DbgPrint("BaseDllName=%ws,	DllBase=0x%p,	SizeOfImage=0x%X,	FullDllName=%ws
",
19                 pDriverData->BaseDllName.Buffer, pDriverData->DllBase,
20                 pDriverData->SizeOfImage, pDriverData->FullDllName.Buffer);
21             //BaseDllName.Buffer是PWCH,也就是宽字符串,所以自己定义的moudName也要是PWCHAR类型
22             if (!_stricmp(moudName, (PCHAR)pDriverData->BaseDllName.Buffer))
23             {
24                 DbgPrint("find target : BaseDllName=%ws,	DllBase=0x%p,	SizeOfImage=0x%X,	FullDllName=%ws
",
25                     pDriverData->BaseDllName.Buffer, pDriverData->DllBase,
26                     pDriverData->SizeOfImage, pDriverData->FullDllName.Buffer);
27                 *pSize = pDriverData->SizeOfImage;
28                 return pDriverData->DllBase;
29             }
30 
31         }
32         // 下一个
33         pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverData->InLoadOrderLinks.Flink;
34 
35     } while (pFirstDriverData != pDriverData);
36 
37     return NULL;
38 }

  传入driverObject、模块名称,得到模块基址(返回值)和模块长度(参数);

2、得到模块基址后,再进一步根据特征码查找目标函数:

 1 PVOID FindFun(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength)
 2 {
 3     PVOID pDestAddr = NULL;
 4     PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr;
 5     PUCHAR pEndAddr = pBeginAddr + ulSearchLength;
 6     PUCHAR i = NULL;
 7     ULONG j = 0;
 8 
 9     for (i = pBeginAddr; i <= pEndAddr; i++)
10     {
11         // 遍历特征码
12         for (j = 0; j < ulSpecialCodeLength; j++)
13         {
14             // 判断地址是否有效  ntoskrnl.exe有时地址无效,蓝屏报错:PAGE FAULED IN NONPAGED AREA
15             if (FALSE == MmIsAddressValid((PVOID)(i + j)))
16             {
17                 break;
18             }
19             // 匹配特征码
20             if (*(PUCHAR)(i + j) != pSpecialCode[j])
21             {
22                 break;
23             }
24         }
25         // 匹配成功
26         if (j >= ulSpecialCodeLength)
27         {
28             pDestAddr = (PVOID)i;
29             break;
30         }
31     }
32 
33     return pDestAddr;
34 }

  这里特征码搜索可以继续改进,比如用正则做模糊匹配~~~

3、用法举例:强行杀死线程时,需要调用 PspTerminateThreadByPointer 函数,但此函数并未导出,可以通过IDA查看汇编代码,也可以在windbg通过U PspTerminateThreadByPointer,如下:

kd> u nt!PspTerminateThreadByPointer 

nt!PspTerminateThreadByPointer:

fffff803`d01c6210 48895c2408      mov     qword ptr [rsp+8],rbx

fffff803`d01c6215 48896c2410      mov     qword ptr [rsp+10h],rbp

fffff803`d01c621a 4889742418      mov     qword ptr [rsp+18h],rsi

fffff803`d01c621f 57              push    rdi

fffff803`d01c6220 4883ec30        sub     rsp,30h

fffff803`d01c6224 8b81d0060000    mov     eax,dword ptr [rcx+6D0h]

fffff803`d01c622a 418ae8          mov     bpl,r8b

fffff803`d01c622d 488bb920020000  mov     rdi,qword ptr [rcx+220h]

由于大多数函数刚开始都是初始化堆栈代码,这里特征码重合度较高,为了避免找到其他函数,建议从稍微靠后几行代码处提取特征码,比如这里从第7行开始提取 418ae8488bb920020000 10个字节,找到后再减去26字节就回到了PspTerminateThreadByPointer入口;

 1 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
 2 {
 3     DbgPrint("Enter DriverEntry
");
 4 
 5     NTSTATUS status = STATUS_SUCCESS;
 6     pDriverObject->DriverUnload = DriverUnload;
 7     for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
 8     {
 9         pDriverObject->MajorFunction[i] = DriverDefaultHandle;
10     }
11 
12     ULONG mouldSize = 0;
13     PWCHAR mouldName = L"ntkrnlmp.exe";
14     PVOID mouldBase = FindMould(pDriverObject, mouldName, &mouldSize);
15 
16
17     DbgPrint("mould name = %ws ;   mould base = 0x%p;   mould size = 0x%X
", mouldName, mouldBase, mouldSize);
18 
19     UCHAR pSpecialCode[256] = { 0 };
20     /*418ae8488bb920020000*/
21     pSpecialCode[0] = 0x41;
22     pSpecialCode[1] = 0x8a;
23     pSpecialCode[2] = 0xe8;
24     pSpecialCode[3] = 0x48;
25     pSpecialCode[4] = 0x8b;
26     pSpecialCode[5] = 0xb9;
27     pSpecialCode[6] = 0x20;
28     pSpecialCode[7] = 0x02;
29     pSpecialCode[8] = 0x00;
30     pSpecialCode[9] = 0x00;
31 
32     PVOID FunAddress = FindFun(mouldBase, mouldSize, pSpecialCode, 4);
33     DbgPrint("Finally function address = 0x%p;
", FunAddress-26);
34 
35     return status;
36 }

原文地址:https://www.cnblogs.com/theseventhson/p/13024325.html