Reputation: 324
I am new to c++ and I am trying to access the InLoadOrderModuleList member in PEB_LDR_DATA structure.
I tried this:
// the ldrData data type is PPEB_LDR_DATA
PLIST_ENTRY firstitem_InMemoryOrderModuleList = ((PLIST_ENTRY)(pebLdrData + 0x0010)-> Flink);
without success. How should I accessing it?
Upvotes: 0
Views: 1664
Reputation: 2257
Thanks to fusu's answer, the solution is to declare my own custom typedef structures for LDR_DATA_TABLE_ENTRY, PEB_LDR_DATA and PEB. The program outputs
Kernel32.dll Base Address: 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%p\n", (void*)kernel32Base);
return 0;
}
Notes
InLoadOrderModuleList
This list contains the modules in the order they were loaded into the process. Typically, the executable itself is the first entry, followed by important system DLLs like ntdll.dll and kernel32.dll.
InMemoryOrderModuleList
This list contains the modules in the order they are laid out in memory. It is not necessarily the same as the load order, although it often is similar.
Upvotes: 0
Reputation: 324
The solution is to declare typedef structures of LDR_DATA_TABLE_ENTRY and PEB_LDR_DATA with its full structure.
Upvotes: 1
Reputation: 7479
LIST_ENTRY
is how Windows does linked lists internally. There is plenty of information about them online if you need more details, but there are two things you need to know here:
CONTAINING_RECORD
macro comes into use.Sample code:
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("%wZ\n", &module_entry->BaseDllName);
// advance to the next object
current_record = current_record->Flink;
if (current_record == start)
{
break;
}
}
Upvotes: 1