驱动开发:内核特征码搜索函数封装

[复制链接]
发表于 2022-10-17 12:06:34 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
在前面的系列教程如《驱动开发:内核枚举DpcTimer定时器》或者《驱动开发:内核枚举IoTimer定时器》里面LyShark大量使用了特征码定位这一方法来寻找符合条件的汇编指令集,总体来说这种方式只能定位特征较小的指令如果特征值扩展到5位以上那么就需要写很多无用的代码,本章内容中将重点分析,并实现一个通用特征定位函数。
如下是一段特征码搜索片段,可以看到其实仅仅只是将上章中的搜索方式变成了一个SearchSpecialCode函数,如下函数,用户传入一个扫描起始地址以及搜索特征码的字节数组,即可完成搜索工作,具体的参数定义如下。

  • pSearchBeginAddr 扫描的内存(内核)起始地址
  • ulSearchLength 需要扫描的长度
  • pSpecialCode 扫描特征码,传入一个UCHAR类型的字节数组
  • ulSpecialCodeLength 特征码长度,传入字节数组长度
  1. // By: LyShark.com
  2. PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength)
  3. {
  4.   PVOID pDestAddr = NULL;
  5.   PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr;
  6.   PUCHAR pEndAddr = pBeginAddr + ulSearchLength;
  7.   PUCHAR i = NULL;
  8.   ULONG j = 0;
  9.   for (i = pBeginAddr; i <= pEndAddr; i++)
  10.   {
  11.     // 遍历特征码
  12.     for (j = 0; j < ulSpecialCodeLength; j++)
  13.     {
  14.       // 判断地址是否有效
  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.   return pDestAddr;
  33. }
复制代码
那么这个简单的特征码扫描函数该如何使用,这里我们就用《驱动开发:内核枚举IoTimer定时器》中枚举IopTimerQueueHead链表头部地址为案例进行讲解,如果你忘记了如何寻找链表头部可以去前面的文章中学习,这里只给出实现流程。

我们首先通过MmGetSystemRoutineAddress得到IoInitializeTimer首地址,然后在偏移长度为0x7e范围内搜索特征码48 8d 0d特征,其代码可以总结为如下样子。
  1. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  2. {
  3.         DbgPrint(("hello lyshark.com \n"));
  4.         // 得到基址
  5.         PUCHAR IoInitializeTimer = GetIoInitializeTimerAddress();
  6.         DbgPrint("IoInitializeTimer Address = %p \n", IoInitializeTimer);
  7.         // ---------------------------------------------------
  8.         // LyShark 开始定位特征
  9.         // 设置起始位置
  10.         PUCHAR StartSearchAddress = (PUCHAR)IoInitializeTimer;
  11.         // 设置结束位置
  12.         PUCHAR EndSearchAddress = StartSearchAddress + 0x7e;
  13.         DbgPrint("[LyShark 搜索区间] 起始地址: 0x%X --> 结束地址: 0x%X \n", StartSearchAddress, EndSearchAddress);
  14.         // 设置搜索长度
  15.         LONGLONG size = EndSearchAddress - StartSearchAddress;
  16.         DbgPrint("[LyShark 搜索长度] 长度: %d \n", size);
  17.         PVOID ptr;
  18.         // 指定特征码
  19.         UCHAR pSpecialCode[256] = { 0 };
  20.         // 指定特征码长度
  21.         ULONG ulSpecialCodeLength = 3;
  22.         pSpecialCode[0] = 0x48;
  23.         pSpecialCode[1] = 0x8d;
  24.         pSpecialCode[2] = 0x0d;
  25.         // 开始搜索,找到后返回首地址
  26.         ptr = SearchSpecialCode(StartSearchAddress, size, pSpecialCode, ulSpecialCodeLength);
  27.         DbgPrint("搜索特征码首地址: 0x%p \n", ptr);
  28.         Driver->DriverUnload = UnDriver;
  29.         return STATUS_SUCCESS;
  30. }
复制代码
代码运行后你会发现可以直接定位到我们所需要的位置上,如下图所示:

如上图可以看到,这个特征码定位函数返回的是内存地址,而我们需要得到地址内的数据,此时就需要提取以下。
例如当指令是:
  1. fffff80206185c00 488d0dd9ddcdff  lea rcx,[nt!IopTimerQueueHead (fffff80205e639e0)]
复制代码
那么就需要RtlCopyMemory跳过前三个字节,并在第四个字节开始取数据,并将读入的数据放入到IopTimerQueueHead_LyShark_Code变量内。
  1.         // 开始搜索,找到后返回首地址
  2.         ptr = SearchSpecialCode(StartSearchAddress, size, pSpecialCode, ulSpecialCodeLength);
  3.         DbgPrint("搜索特征码首地址: 0x%p \n", ptr);
  4.         // 提取特征
  5.         // fffff802`06185c00 488d0dd9ddcdff  lea     rcx,[nt!IopTimerQueueHead (fffff802`05e639e0)]
  6.         ULONG64 iOffset = 0;
  7.         ULONG64 IopTimerQueueHead_LyShark_Code = 0;
  8.         __try
  9.         {
  10.                 // 拷贝内存跳过lea,向后四字节
  11.                 RtlCopyMemory(&iOffset, (ULONG64)ptr + 3, 4);
  12.                 // 取出后面的IopTimerQueueHead内存地址 LyShark.com
  13.                 IopTimerQueueHead_LyShark_Code = iOffset + (ULONG64)ptr + 7;
  14.                 DbgPrint("提取数据: 0x%p \n", IopTimerQueueHead_LyShark_Code);
  15.         }
  16.         __except (1)
  17.         {
  18.                 DbgPrint("[LySHark] 拷贝内存异常 \n");
  19.         }
复制代码
这样即可得到我们所需要的地址,如下结果所示:

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表