zoukankan      html  css  js  c++  java
  • 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 }

  • 相关阅读:
    window安装php的mongodb扩展
    Android NDK开发步骤(r9)
    osgViewer销毁bug
    C/C++ typedef用法
    Java并发编程:Lock
    java中构造器(Constructor)
    进程和线程关系及区别
    Java总结篇系列:Java泛型
    在powerdesigner中创建物理数据模型
    非常好的理解遗传算法的例子
  • 原文地址:https://www.cnblogs.com/theseventhson/p/13024325.html
Copyright © 2011-2022 走看看