You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 19:40:22