我试图通过直接假设 kernel32.dll 始终是加载的第三个模块来查找 kernel32 基地址。
ModLoad: 00400000 024077eb image00400000
ModLoad: 77ad0000 77c7f000 ntdll.dll
ModLoad: 75c80000 75d70000 C:\WINDOWS\SysWOW64\KERNEL32.DLL
ModLoad: 77160000 773d3000 C:\WINDOWS\SysWOW64\KERNELBASE.dll
...
我确实有一个 for 循环来运行模块,但注意到 kernel32.dll 始终是第三个条目。
我可以假设这是可靠的吗?
C 程序输出
Kernel32.dll基地址:0x75C80000
#include <stdio.h>
#include <stdint.h>
#include <windows.h>
#include <winternl.h>
int main()
{
PPEB peb = (PPEB)__readfsdword(0x30);
uintptr_t kernel32Base = 0;
/* Skip first two entries as kernel32.dll is always the third entry */
PLIST_ENTRY ptr = peb->Ldr->InMemoryOrderModuleList.Flink->Flink->Flink;
PLDR_DATA_TABLE_ENTRY e = CONTAINING_RECORD(ptr, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
kernel32Base = (uintptr_t)e->DllBase;
printf("Kernel32.dll Base Address: 0x%p\n", (void*)kernel32Base);
return 0;
}
例如,windbg正在加载DbgView.exe
更新
根据乔希的回答,建议是使用InLoadOrderModuleList
折腾了一个小时终于成功了
Kernel32.dll基地址:0x75C80000
解决方案是为 LDR_DATA_TABLE_ENTRY、PEB_LDR_DATA 和 PEB 声明我自己的自定义 typedef 结构。
#include <stdio.h>
#include <stdint.h>
#include <windows.h>
typedef struct MY_PEB_LDR_DATA {
ULONG Length;
UCHAR Initialized;
VOID* SsHandle;
LIST_ENTRY InLoadOrderModuleList;
// ... other fields
} MY_PEB_LDR_DATA, *MY_PPEB_LDR_DATA;
typedef struct MY_LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
// ... other fields
} MY_LDR_DATA_TABLE_ENTRY, *MY_PLDR_DATA_TABLE_ENTRY;
typedef struct MY_PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
MY_PPEB_LDR_DATA Ldr;
// ... other fields
} MY_PEB, *MY_PPEB;
int main()
{
MY_PPEB peb = (MY_PPEB)__readfsdword(0x30);
uintptr_t kernel32Base = 0;
// Order of modules loaded into the process: [image][ntdll][kernel32]
// Skip first two entries as kernel32.dll is always the third entry.
PLIST_ENTRY ptr = peb->Ldr->InLoadOrderModuleList.Flink->Flink->Flink;
MY_PLDR_DATA_TABLE_ENTRY e = CONTAINING_RECORD(ptr, MY_LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
kernel32Base = (uintptr_t)e->DllBase;
printf("Kernel32.dll Base Address: 0x%p\n", (void*)kernel32Base);
return 0;
}
笔记
InLoadOrderModuleList
该列表包含按照加载到进程中的顺序排列的模块。通常,可执行文件本身是第一个条目,然后是重要的系统 DLL,如 ntdll.dll 和 kernel32.dll。
InMemoryOrderModuleList
该列表按照模块在内存中的排列顺序包含模块。它不一定与加载顺序相同,尽管它通常很相似。
您不会得到明确的“是”,因为您正在深入研究 Windows 内部结构,这些内部结构没有明确记录,并且可以在 Windows 版本之间发生变化。因此,沿着 PEB 行走比仅仅假设特定顺序更安全。
但是...以下是根据 Windows Internals 7th Edition(Pavel Yosifovich、Alex Ionescu、Mark E. Russinovich 和 David A. Solomon)提供的 Windows 10 详细信息。
映像 exe 将首先被映射。
Ntdll 被提前加载,因为那里存在很多加载器代码:
无论如何,考虑到 kernel32 都会提前出现,进行名称比较不会让您的速度减慢太多。
另外,正如评论中提到的,请务必使用
InLoadOrderModuleList
.