在 Windows 系统中,本文将探讨一种更为隐蔽的方法,通过利用 .data 段的特性进行钩子通信,以绕过反作弊检测。
寻找目标 API:
首先,需要在内核模块中找到一个可以通过用户模式调用的 API。这些 API 通常是 Nt 或 Zw 开头的函数,它们被用户模式的 DLL(例如 win32u.dll)导出。
常见的候选模块包括 ntoskrnl.exe、win32k.sys、win32kbase.sys 等。
win32k.sys 的特殊性: win32k.sys 是一个特殊的内核驱动程序,它在会话空间中加载,这意味着它的内存映射方式与其他内核模块不同。它被映射到 GUI 进程(例如资源管理器或 Winlogon),因此只能由 GUI 进程的线程访问。
定位 .DATA 段中的函数指针:
反汇编分析目标模块 (如 win32k.sys) , 找到要 hook 的目标函数,以及在 .data 段中指向这个函数的指针。
这些指针通常被定义为全局变量或静态变量,可以通过反汇编或调试工具找到。
附加到 GUI 进程:
由于 win32k.sys 的特殊性,它的内存映射仅在 GUI 进程中可用,为了修改 .data 段的函数指针, 需要使用 KeStackAttachProcess 函数,将驱动程序附加到 GUI 进程的上下文中(例如资源管理器或者 Winlogon)。
通过附加到 GUI 进程的上下文, 驱动程序可以获得 GUI 进程的页面目录,从而可以修改 win32k.sys 的 .data 段中的函数指针。
修改 .data 段的函数指针:
在 GUI 进程的上下文中,通过目标进程的虚拟地址找到需要修改的指针地址, 修改 .data 段中的函数指针,让它指向你的自定义函数。
自定义函数可以执行恶意代码或者将控制权转移到另一个地方。
恢复原始指针:
在自定义函数执行完毕后,可以选择将函数指针恢复为原始值,这样可以避免对程序的正常运行造成影响。
先找到win32k.sys模块地址

上图为win32k.sys函数

上图为win32u.dll其中的函数
这正是我们符合要求的一个函数 (当然这种函数还有很多很多...)

利用挂靠到一个GUI进程 比如 explorer.exe 替换对应的qword_677A8也就是data_ptr,里面存的就是NtUserQueryDisplayConfig函数原本的地址
为了挂接 .data 函数指针,我们必须使用 InterlockedExchangePointer。这是一个原子函数,即一个不能被调度器中断的函数。我们为
什么需要它呢?这是一个全局指针,很可能被多个线程访问。我们必须进行同步操作以避免错误。
IDA中Win32k.sys的a1就是通信传递数据的关键,只要3环传入一个结构体 0环接后处理 即可完成一个通信.
Ring3中只需要调用"NtUserQueryDisplayConfig(a1的数据结构体)" 即可.
PVOID get_sys_module(UNICODE_STRING& name) {
if
(PsLoadedModuleList !
=
NULL) {
for
(PLIST_ENTRY pListEntry
=
PsLoadedModuleList
-
>Flink; pListEntry !
=
PsLoadedModuleList; pListEntry
=
pListEntry
-
>Flink) {
auto pEntry
=
CONTAINING_RECORD(pListEntry, _KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if
(wcsstr(pEntry
-
>FullDllName.
Buffer
, name.
Buffer
) !
=
NULL) {
/
/
LOG(
"[+]Driver Entry Found: 0x%llx\n"
, (ULONG64)pEntry);
return
pEntry
-
>DllBase;
}
}
}
return
NULL;
}
PVOID get_sys_module(UNICODE_STRING& name) {
if
(PsLoadedModuleList !
=
NULL) {
for
(PLIST_ENTRY pListEntry
=
PsLoadedModuleList
-
>Flink; pListEntry !
=
PsLoadedModuleList; pListEntry
=
pListEntry
-
>Flink) {
auto pEntry
=
CONTAINING_RECORD(pListEntry, _KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if
(wcsstr(pEntry
-
>FullDllName.
Buffer
, name.
Buffer
) !
=
NULL) {
/
/
LOG(
"[+]Driver Entry Found: 0x%llx\n"
, (ULONG64)pEntry);
return
pEntry
-
>DllBase;
}
}
}
return
NULL;
}
KeStackAttachProcess((PRKPROCESS)gui_process, &state);
original_qword
=
(fQword)InterlockedExchangePointer((PVOID
*
)data_ptr, (PVOID)NtUserQueryDisplayConfig_hk);
KeUnstackDetachProcess(&state);
[培训]科锐逆向工程师培训第53期2025年7月8日开班!
最后于 2025-1-29 21:34
被S极客编辑
,原因: