0x00 简介
Windows 中有窗口的程序就有可能 ring0 直接调用 ring3的程序,KernelCallbackTable 就用于从内核回调用户空间的函数,因此可以用于 ring0 执行 ring3 代码
0x01 调用
KeUserModeCallback 函数原型:
NTSTATUS
KeUserModeCallback (
IN ULONG ApiNumber,
IN PVOID InputBuffer,
IN ULONG InputLength,
OUT PVOID *OutputBuffer,
IN PULONG OutputLength
);
KeUserModeCallback 调用过程:
重点:
-
回调函数的第一个参数是 KeUserModeCallback 的第二个参数InputBuffer,第二个参数是 KeUserModeCallback 的第三个参数InputLength
-
KeUserModeCallback 必须在用户进程的线程上下文中被调用才能成功,因为需要用户堆栈空间
0x02 寻找 KernelCallbackTable
KernelCallbackTable 的结果在 PEB 中能找到,因此需要先找到一个进程的 PEB:
查看 peb 结构dt _peb 000000c191a7c000
找到 KernelCallbackTable:
dps 会显示给定范围的内存内容。当该内存是符号表中的一系列地址时,相应的符号也会显示出来
0x03 寻找指定回调函数偏移
根据 0x02 使用 dps 看到的 KernelCallbackTable 内容,找到 USER32!_xxxClientAllocWindowClassExtraBytes 函数地址:
计算偏移:
因此如果需要在代码里调用或 hook USER32!_xxxClientAllocWindowClassExtraBytes,则代码应为:
typedef NTSTATUS(WINAPI* FxxxClientAllocWindowClassExtraBytes)(unsigned int* pSize);
FxxxClientAllocWindowClassExtraBytes g_fxxxClientAllocWindowClassExtraBytes = NULL;
ULONG_PTR pKernelCallbackTable = (ULONG_PTR) *(ULONG_PTR*)(__readgsqword(0x60) + 0x58); // gs:[0x60] 指向进程 PEB,PEB 结构体偏移 0x58 为 KernelCallbackTable
g_fxxxClientAllocWindowClassExtraBytes = (FxxxClientAllocWindowClassExtraBytes)*(ULONG_PTR*)((PBYTE)pKernelCallbackTable + 0x3D8); //KernelCallbackTable 偏移0x3D8 为 user32!_xxxClientAllocWindowClassExtraBytes
*(ULONG_PTR*)((PBYTE)pKernelCallbackTable + 0x3D8) = (ULONG_PTR)MyxxxClientAllocWindowClassExtraBytes; // hook user32!_xxxClientAllocWindowClassExtraBytes 为自定义函数 MyxxxClientAllocWindowClassExtraBytes