在前面的系列教程如《驱动开发:内核枚举DpcTimer定时器》
或者《驱动开发:内核枚举IoTimer定时器》
里面LyShark
大量使用了特征码定位
这一方法来寻找符合条件的汇编指令
集,总体来说这种方式只能定位特征较小的指令如果特征值扩展到5位以上那么就需要写很多无用的代码,本章内容中将重点分析,并实现一个通用
特征定位函数。
如下是一段特征码搜索片段,可以看到其实仅仅只是将上章中的搜索方式变成了一个SearchSpecialCode
函数,如下函数,用户传入一个扫描起始地址
以及搜索特征码的字节数组,即可完成搜索工作,具体的参数定义如下。
- pSearchBeginAddr 扫描的内存(内核)起始地址
- ulSearchLength 需要扫描的长度
- pSpecialCode 扫描特征码,传入一个UCHAR类型的字节数组
- ulSpecialCodeLength 特征码长度,传入字节数组长度
// By: LyShark.com
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength)
{
PVOID pDestAddr = NULL;
PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr;
PUCHAR pEndAddr = pBeginAddr + ulSearchLength;
PUCHAR i = NULL;
ULONG j = 0;
for (i = pBeginAddr; i <= pEndAddr; i++)
{
// 遍历特征码
for (j = 0; j < ulSpecialCodeLength; j++)
{
// 判断地址是否有效
if (FALSE == MmIsAddressValid((PVOID)(i + j)))
{
break;
}
// 匹配特征码
if (*(PUCHAR)(i + j) != pSpecialCode[j])
{
break;
}
}
// 匹配成功
if (j >= ulSpecialCodeLength)
{
pDestAddr = (PVOID)i;
break;
}
}
return pDestAddr;
}
那么这个简单的特征码扫描函数该如何使用,这里我们就用《驱动开发:内核枚举IoTimer定时器》
中枚举IopTimerQueueHead
链表头部地址为案例进行讲解,如果你忘记了如何寻找链表头部可以去前面的文章中学习,这里只给出实现流程。
我们首先通过MmGetSystemRoutineAddress
得到IoInitializeTimer
首地址,然后在偏移长度为0x7e
范围内搜索特征码48 8d 0d
特征,其代码可以总结为如下样子。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint(("hello lyshark.com \n"));
// 得到基址
PUCHAR IoInitializeTimer = GetIoInitializeTimerAddress();
DbgPrint("IoInitializeTimer Address = %p \n", IoInitializeTimer);
// ---------------------------------------------------
// LyShark 开始定位特征
// 设置起始位置
PUCHAR StartSearchAddress = (PUCHAR)IoInitializeTimer;
// 设置结束位置
PUCHAR EndSearchAddress = StartSearchAddress + 0x7e;
DbgPrint("[LyShark 搜索区间] 起始地址: 0x%X --> 结束地址: 0x%X \n", StartSearchAddress, EndSearchAddress);
// 设置搜索长度
LONGLONG size = EndSearchAddress - StartSearchAddress;
DbgPrint("[LyShark 搜索长度] 长度: %d \n", size);
PVOID ptr;
// 指定特征码
UCHAR pSpecialCode[256] = { 0 };
// 指定特征码长度
ULONG ulSpecialCodeLength = 3;
pSpecialCode[0] = 0x48;
pSpecialCode[1] = 0x8d;
pSpecialCode[2] = 0x0d;
// 开始搜索,找到后返回首地址
ptr = SearchSpecialCode(StartSearchAddress, size, pSpecialCode, ulSpecialCodeLength);
DbgPrint("搜索特征码首地址: 0x%p \n", ptr);
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
代码运行后你会发现可以直接定位到我们所需要的位置上,如下图所示:
如上图可以看到,这个特征码定位函数返回的是内存地址,而我们需要得到地址内的数据,此时就需要提取以下。
例如当指令是:
fffff80206185c00 488d0dd9ddcdff lea rcx,[nt!IopTimerQueueHead (fffff80205e639e0)]
那么就需要RtlCopyMemory
跳过前三个字节,并在第四个字节开始取数据,并将读入的数据放入到IopTimerQueueHead_LyShark_Code
变量内。
// 开始搜索,找到后返回首地址
ptr = SearchSpecialCode(StartSearchAddress, size, pSpecialCode, ulSpecialCodeLength);
DbgPrint("搜索特征码首地址: 0x%p \n", ptr);
// 提取特征
// fffff802`06185c00 488d0dd9ddcdff lea rcx,[nt!IopTimerQueueHead (fffff802`05e639e0)]
ULONG64 iOffset = 0;
ULONG64 IopTimerQueueHead_LyShark_Code = 0;
__try
{
// 拷贝内存跳过lea,向后四字节
RtlCopyMemory(&iOffset, (ULONG64)ptr + 3, 4);
// 取出后面的IopTimerQueueHead内存地址 LyShark.com
IopTimerQueueHead_LyShark_Code = iOffset + (ULONG64)ptr + 7;
DbgPrint("提取数据: 0x%p \n", IopTimerQueueHead_LyShark_Code);
}
__except (1)
{
DbgPrint("[LySHark] 拷贝内存异常 \n");
}
这样即可得到我们所需要的地址,如下结果所示:
原文地址:http://www.cnblogs.com/LyShark/p/16798318.html
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,请务用于商业用途!
3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员!
8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载
声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性