c++按偏移量访问PEB_LDR_DATA结构成员



我是c++的新手,正在尝试访问PEB_LDR_DATA结构中的InLoadOrderModuleList成员。

我试过这个:

// the ldrData data type is PPEB_LDR_DATA 
PLIST_ENTRY firstitem_InMemoryOrderModuleList = ((PLIST_ENTRY)(pebLdrData + 0x0010)-> Flink);

没有成功。我应该如何访问它?

LIST_ENTRY是Windows在内部执行链表的方式。如果你需要更多的细节,网上有很多关于它们的信息,但这里有两件事你需要知道:

  1. 是next/back指针不指向对象的头部(这在大多数实现中很常见(;因此,为了到达对象的头部,您必须根据LIST_ENTRY成员的偏移量对指针进行修正。这就是CONTAINING_RECORD宏开始使用的地方
  2. 就是你不想在PEB_LDR_DATA对象中的第一个LIST_ENTRY上进行这种修复,把它们想象成"头"指针,你需要在到达你关心的数据之前移动Flink

示例代码:

LIST_ENTRY *current_record = NULL;
LIST_ENTRY *start = &(pebLdrData->InLoadOrderModuleList);
// move off the initial list entry to the first actual object
current_record = start->Flink;
while (true)
{
// find the head of the object
LDR_DATA_TABLE_ENTRY *module_entry = (LDR_DATA_TABLE_ENTRY*) 
CONTAINING_RECORD(current_record, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
printf("%wZn", &module_entry->BaseDllName);
// advance to the next object
current_record = current_record->Flink;
if (current_record == start)
{
break;
}
}

解决方案是用其完整结构声明LDR_DATA_TABLE_ENTRY和PEB_LDR_DATA的typedef结构。

感谢fusu的回答,解决方案是为LDR_DATA_TABLE_ENTRY、PEB_LDR_DATA和PEB声明我自己的自定义typedef结构。程序输出

Kernel32.dll基地址:0x75C80000

#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%pn", (void*)kernel32Base);
return 0;
}

票据

InLoadOrderModuleList此列表按模块加载到流程中的顺序包含模块。通常,可执行文件本身是第一个条目,然后是重要的系统dll,如ntdll.dll和kernel32.dll。

InMemoryOrderModuleList此列表按模块在内存中的排列顺序包含模块。它不一定与加载顺序相同,尽管它通常是相似的。

最新更新