首发于奇安信攻防社区
文章地址:https://forum.butian.net/share/817
前言
最近在研究某数字杀软的时候看到有个配置选项:
img
这个自我保护实际上是加载360SelfProtection.sys驱动(看这名字应该还有360SelfProtection_win10.sys文件),丰告网在0环通过hook等手段保护注册表项,重要进程进程等。
img
比如这里要结束某核心进程,会显示无法结束,拒绝访问。
img
img
这个并不是说权限不够的问题,即便是system权限也不行。而是由于在底层,杀死进程的API已经被hook了,这里应该是内核hook,当想要结束的进程为核心进程时,就直接返回一个无法终止进程的弹窗。本文就如何实现一个进程保护功能进行探究,驱动就不写了,就写一个用户层的。
实现原理
windows提供了一个可以杀死其他进程的API:TerminateProcess。如果是结束本身进程为:ExitProcess。
BOOL TerminateProcess(
[in] HANDLE hProcess,
[in] UINT uExitCode
);
通过命令taskkill或者通过任务管理器等GUI工具去结束进程,本质上都是调用的TerminateProcess,有些可能是调用更为底层的ZwTerminateProcess,但是本质都差不多,只是看该进程用的什么API,品渡雅创 这里为了方便就使用TerminateProcess进行演示。
通过hook TerminateProcess让执行该函数时直接返回没有权限。
获取API地址并创建新的hook函数
static BOOL(WINAPI* OldTerminateProcess)(
HANDLE hProcess,
UINT uExitCode) = TerminateProcess;
BOOL WINAPI New_TerminateProcess(
_In_ HANDLE hProcess,
_In_ UINT uExitCode
) {
unhookTerminateProcess();
MessageBox(NULL,L"该进程受保护!", L"Access Denied",NULL);
hookTerminateProcess();
returnfalse;
}
这里是64位的进程,要改变的硬编码是12个字节,而且不需要去算偏移。
48 b8 _dwNewAddress(0x1122334455667788)
ff e0
mov rax, _dwNewAddress(0x1122334455667788)
jmp rax
将原来函数的调转地址改为我们自己函数的跳转地址
void hookTerminateProcess() {
DWORD dwTerminateProcessOldProtect;
BYTE pData[12] = { 0x48,0xb8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF,0xE0};
ULONGLONG ullNewFuncAddr = (ULONGLONG)New_TerminateProcess;
//保存本来的字节
::RtlCopyMemory(g_OldTerminateProcess, OldTerminateProcess, sizeof(pData));
//更改权限
VirtualProtect(OldTerminateProcess, 12, PAGE_EXECUTE_READWRITE, &dwTerminateProcessOldProtect);
//更改原来的机器码,改为我们自己函数的地址
::RtlCopyMemory(&pData[2], &ullNewFuncAddr, sizeof(ullNewFuncAddr));
::RtlCopyMemory(OldTerminateProcess, pData, sizeof(pData));
//恢复属性
VirtualProtect(OldTerminateProcess, 12, dwTerminateProcessOldProtect, &dwTerminateProcessOldProtect);
}
恢复硬编码,还原调转地址。
void unhookTerminateProcess() {
DWORD dwOldProtect = NULL;
//改为可写属性
VirtualProtect(OldTerminateProcess, 12, PAGE_EXECUTE_READWRITE, &dwOldProtect);
//还原原来的硬编码
RtlCopyMemor