获取Kernel32.dll基址的方法:跨Windows版本鲁棒性探究
关于通过PEB/LDR链获取Kernel32.dll基址的跨Windows版本鲁棒性分析
我正在实验在C shellcode中获取Kernel32.dll基址的方法,已实现如下方案,该方案在我的Windows 11 Pro设备上可正常运行,但想了解该方法在不同Windows版本中的鲁棒性如何。
实现代码
#include <intrin.h> #include <stdint.h> #include <stdio.h> #ifdef _WIN64 #define PEB_OFFSET_FROM_GS 0x60 #define PEB __readgsqword(PEB_OFFSET_FROM_GS) #define LDR_DATA_IN_PEB_OFFSET 24 #define IN_LOAD_ORDER_MODULE_LIST_OFFSET 16 #define DLL_BASE_OFFSET 48 #else #define PEB_OFFSET_FROM_FS 0x30 #define PEB __readfsdword(PEB_OFFSET_FROM_FS) #define LDR_DATA_IN_PEB_OFFSET 12 #define IN_LOAD_ORDER_MODULE_LIST_OFFSET 12 #define DLL_BASE_OFFSET 24 #endif // 进程中加载的模块通常遵循以下顺序: // [可执行镜像], [ntdll.dll], [kernel32.dll]. #define KERNEL32_BASE_ADDRESS *(uintptr_t*)(*(uintptr_t*)(*(uintptr_t*)(*(uintptr_t*)(*(uintptr_t*)(PEB + LDR_DATA_IN_PEB_OFFSET) + IN_LOAD_ORDER_MODULE_LIST_OFFSET))) + DLL_BASE_OFFSET) int main() { printf("Kernel32.dll Base Address: 0x%p\n", (void*)KERNEL32_BASE_ADDRESS); }
对应x86反汇编代码
... mov eax,dword ptr fs:[00000030h] ; eax = PEB地址 mov ecx,dword ptr [eax+0Ch] ; ecx = Ldr地址 mov edx,dword ptr [ecx+0Ch] ; edx = 第一个模块条目地址 mov eax,dword ptr [edx] ; eax = 第二个模块条目地址 mov ecx,dword ptr [eax] ; ecx = 第三个模块条目地址 mov edx,dword ptr [ecx+18h] ; edx = kernel32.dll基址 ...
通用x86/x64混淆宏
#define KERNEL32_BASE_ADDRESS *(uintptr_t*)(*(uintptr_t*)(*(uintptr_t*)(*(uintptr_t*)(*(uintptr_t*)((sizeof(uintptr_t) == 4 ? __readfsdword(0x30) : __readgsqword(0x60)) + (sizeof(uintptr_t) == 4 ? 12 : 24)) + (sizeof(uintptr_t) == 4 ? 12 : 16)))) + (sizeof(uintptr_t) == 4 ? 24 : 48))
跨版本鲁棒性分析
- PEB寄存器偏移:x86架构下
FS:[0x30]、x64架构下GS:[0x60]的PEB偏移从Windows XP到Windows 11始终未变,这部分完全稳定。 - PEB中Ldr成员偏移:x86下为0xC(12)、x64下为0x18(24),该偏移从Windows XP到Windows 11的PEB结构中均保持一致,无变更记录。
- LDR结构中模块链表偏移:
InLoadOrderModuleList在x86下偏移0xC(12)、x64下偏移0x10(16),从Vista到Win11的LDR结构里这个值稳定,XP时代也同样适用。 - 模块加载顺序的隐患:当前方法依赖「可执行镜像→ntdll.dll→kernel32.dll」的固定加载顺序,这在普通桌面进程里大概率成立,但存在例外:
- 部分系统核心进程(如csrss.exe、smss.exe)的模块加载顺序不同,kernel32并非第三个加载的模块。
- 若进程被调试器、钩子工具注入了第三方DLL,加载顺序会被打乱。
- 未来Windows版本若调整默认模块加载逻辑,该方法会直接失效。
- 模块节点中DllBase偏移:x86下0x18(24)、x64下0x30(48),这个偏移从XP到Win11的模块链表节点结构中均未改变,稳定性有保障。
总结
该方法在普通桌面进程、无特殊调试/钩子环境下,从Windows XP到Windows 11的x86/x64版本都能正常工作,但依赖固定加载顺序的特性存在鲁棒性短板。若要提升可靠性,建议遍历InLoadOrderModuleList链表,通过匹配模块名称字符串来定位kernel32.dll,而非依赖固定位置。
内容的提问来源于stack exchange,提问作者vengy
相关产品推荐
相关产品推荐

