windows:根据特征码查找内核任意函数
阅读原文时间:2023年07月13日阅读:1

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

1、先查找目标模块

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

/*
  可以用来动态查找内核模块的基址,后续用于:
  1、PTE\PDE等base计算
  2、其他函数、变量精确位置的计算(IDA静态分析只能查到偏移)
*/
PVOID FindMould(PDRIVER_OBJECT pDriverObject, PWCHAR moudName, PULONG pSize)
{
// 从PDRIVER_OBJECT获取DriverSection,便可获得驱动模块链表
PLDR_DATA_TABLE_ENTRY pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
// 开始遍历双向链表
PLDR_DATA_TABLE_ENTRY pFirstDriverData = pDriverData;
do
{
if (( < pDriverData->BaseDllName.Length) ||
( < pDriverData->FullDllName.Length))
{
// 显示
DbgPrint("BaseDllName=%ws,\tDllBase=0x%p,\tSizeOfImage=0x%X,\tFullDllName=%ws\n",
pDriverData->BaseDllName.Buffer, pDriverData->DllBase,
pDriverData->SizeOfImage, pDriverData->FullDllName.Buffer);
//BaseDllName.Buffer是PWCH,也就是宽字符串,所以自己定义的moudName也要是PWCHAR类型
if (!_stricmp(moudName, (PCHAR)pDriverData->BaseDllName.Buffer))
{
DbgPrint("find target : BaseDllName=%ws,\tDllBase=0x%p,\tSizeOfImage=0x%X,\tFullDllName=%ws\n",
pDriverData->BaseDllName.Buffer, pDriverData->DllBase,
pDriverData->SizeOfImage, pDriverData->FullDllName.Buffer);
*pSize = pDriverData->SizeOfImage;
return pDriverData->DllBase;
}

     }  
     // 下一个  
     pDriverData = (PLDR\_DATA\_TABLE\_ENTRY)pDriverData->InLoadOrderLinks.Flink;

 } while (pFirstDriverData != pDriverData);

 return NULL;  

}

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

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

PVOID FindFun(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength)
{
PVOID pDestAddr = NULL;
PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr;
PUCHAR pEndAddr = pBeginAddr + ulSearchLength;
PUCHAR i = NULL;
ULONG j = ;

 for (i = pBeginAddr; i <= pEndAddr; i++)  
 {  
     // 遍历特征码  
     for (j = ; j < ulSpecialCodeLength; j++)  
     {  
         // 判断地址是否有效  ntoskrnl.exe有时地址无效,蓝屏报错:PAGE FAULED IN NONPAGED AREA  
         if (FALSE == MmIsAddressValid((PVOID)(i + j)))  
         {  
             break;  
         }  
         // 匹配特征码  
         if (\*(PUCHAR)(i + j) != pSpecialCode\[j\])  
         {  
             break;  
         }  
     }  
     // 匹配成功  
     if (j >= ulSpecialCodeLength)  
     {  
         pDestAddr = (PVOID)i;  
         break;  
     }  
 }

 return pDestAddr;  

}

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

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入口;

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
DbgPrint("Enter DriverEntry\n");

 NTSTATUS status = STATUS\_SUCCESS;  
 pDriverObject->DriverUnload = DriverUnload;  
 for (ULONG i = ; i < IRP\_MJ\_MAXIMUM\_FUNCTION; i++)  
 {  
     pDriverObject->MajorFunction\[i\] = DriverDefaultHandle;  
 }

 ULONG mouldSize = ;  
 PWCHAR mouldName = L"ntkrnlmp.exe";  
 PVOID mouldBase = FindMould(pDriverObject, mouldName, &mouldSize);

 DbgPrint("mould name = %ws ;   mould base = 0x%p;   mould size = 0x%X\\n", mouldName, mouldBase, mouldSize);

 UCHAR pSpecialCode\[\] = {  };  
 /\*418ae8488bb920020000\*/  
 pSpecialCode\[\] = 0x41;  
 pSpecialCode\[\] = 0x8a;  
 pSpecialCode\[\] = 0xe8;  
 pSpecialCode\[\] = 0x48;  
 pSpecialCode\[\] = 0x8b;  
 pSpecialCode\[\] = 0xb9;  
 pSpecialCode\[\] = 0x20;  
 pSpecialCode\[\] = 0x02;  
 pSpecialCode\[\] = 0x00;  
 pSpecialCode\[\] = 0x00;

 PVOID FunAddress = FindFun(mouldBase, mouldSize, pSpecialCode, );  
 DbgPrint("Finally function address = 0x%p;\\n", FunAddress-);

 return status;  

}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章