我需要通过PEB获取kernel32.dll的地址,当我尝试通过双向链接列表访问_LDR_DATA_TABLE_ENTRY结构时,事情变得复杂,这个列表给出了_PEB_LDR_DATA结构,这些列表是:
+0x00c InLoadOrderModuleList : _LIST_ENTRY
+0x014 InMemoryOrderModuleList : _LIST_ENTRY
+0x01c InInitializationOrderModuleList : _LIST_ENTRY
比如说InMemoryOrderModuleListy选中列表LDR_DATA_TABLE_ENTRY需要访问结构,那必须通过Flink show来完成,其结构如下:
0:000> dt ntdll!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
简而言之,不知道选择列表是否会是InMemoryOrderModuleList并直接指向第一个输入LDR_DATA_TABLE_ENTRY,因为这个列表是" LIST_ENTRY类型" Flink成员,偏移量为0,并指向该表。
这是我尝试理解的代码,它获取了kernel32的地址:
xor ebx, ebx //clear ebx
mov ebx, fs:[ 0x30 ] //get a pointer to the PEB
mov ebx, [ ebx + 0x0C ] //get PEB->Ldr
mov ebx, [ ebx + 0x14 ] //get PEB->Ldr.InMemoryOrderModuleList.Flink(1st entry) **here**
mov ebx, [ ebx ] //get the next entry(2nd entry)
mov ebx, [ ebx ] //get the next entry(3rd entry)
mov ebx, [ ebx + 0x10 ] //get the 3rd entries base address(kernel32.dll)
如第14行所示"此处"是什么让我感到困惑,因为移动的0x14只是我选择了InMemoryOrderModuleList列表的类型,但你可以在第一局中的评论中看到通过推出Flink所运用的那些。
我等待您的确认,提前谢谢!
答案 0 :(得分:3)
假设PEB处于1000h。
此处列出了PEB的第一个成员及其在内存中的地址
typedef struct _PEB {
/* 1000h + 000h = 1000h */ BYTE Reserved1[2];
/* 1000h + 002h = 1002h */ BYTE BeingDebugged;
/* 1000h + 003h = 1003h */ BYTE Reserved2[1];
/* 1000h + 004h = 1004h */ PVOID Reserved3[2];
/* 1000h + 00ch = 100ch */ PPEB_LDR_DATA Ldr;
...
} PEB, *PPEB;
Ldr
成员是指针,假设它指向2000h,
即PEB_LDR_DATA
位于2000h。
现在来自MSDN,PEB_LDR_DATA
具有这种结构(官方文档中省略了许多成员)
typedef struct _PEB_LDR_DATA {
/* 2000h + 000h = 2000h */ BYTE Reserved1[8];
/* 2000h + 008h = 2008h */ PVOID Reserved2[3];
/* 2000h + 014h = 2014h */ LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
正如您所看到的,成员InMemoryOrderModuleList
不是指针是结构,因此LIST_ENTRY
的所有成员都嵌入到PEB_LDR_DATA
结构中。<登记/>
这意味着在InMemoryOrderModuleList
的地址处有LIST_ENTRY
的第一个成员,此成员为Flink
,位于2014h。
Here the expanded structure
typedef struct _PEB_LDR_DATA {
/* 2000h + 000h = 2000h */ BYTE Reserved1[8];
/* 2000h + 008h = 2008h */ PVOID Reserved2[3];
/* 2000h + 014h = 2014h */ LIST_ENTRY InMemoryOrderModuleList;
/* 2000h + 014h = 2014h */ LIST_ENTRY* InMemoryOrderModuleList.Flink
/* 2000h + 018h = 2018h */ LIST_ENTRY* InMemoryOrderModuleList.Blink
} PEB_LDR_DATA, *PPEB_LDR_DATA;
注意现在Flink
和Blink
成员指针。
现在假设InMemoryOrderModuleList.Flink
指向3000h
在3000h处有一个LIST_ENTRY
结构,这是第一个条目。
假设此结构Flink
成员指向4000h,这是第二个条目
假设最后一个结构Flink
成员指向5000h,这是第三个条目。
现在除了PEB_LDR_DATA
中的列表头部之外,每个LIST_ENTRY
实际上都是LDR_DATA_TABLE_ENTRY
,这是可能的,因为后者与前者具有兼容的内存布局。
因此,当您访问感兴趣的条目时,您可以访问LDR_DATA_TABLE_ENTRY
结构的成员。
由于第三个条目是5000h而LDR_DATA_TABLE_ENTRY
具有此布局
typedef struct _LDR_DATA_TABLE_ENTRY {
/* 5000h + 000h = 5000h */ PVOID Reserved1[2];
/* 5000h + 008h = 5008h */ LIST_ENTRY InMemoryOrderLinks;
/* 5000h + 010h = 5010h */ PVOID Reserved2[2];
/* 5000h + 018h = 5018h */ PVOID DllBase;
...
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
丑陋的MS Paint情况图片
查看汇编代码
xor ebx, ebx //An useless instruction
mov ebx, fs:[ 0x30 ] //get a pointer to the PEB
;EBX is now 1000h
mov ebx, [ ebx + 0x0C ] //get PEB->Ldr
;This read from 100ch and EBX gets 2000h
mov ebx, [ ebx + 0x14 ] //get PEB->Ldr.InMemoryOrderModuleList.Flink(1st entry)
;This read from 2014h and EBX gets 3000h
mov ebx, [ ebx ] //get the next entry(2nd entry)
;This read from 3000h and EBX gets 4000h
mov ebx, [ ebx ] //get the next entry(3rd entry)
;This read from 4000h and EBX gets 5000h
mov ebx, [ ebx + 0x10 ] //get the 3rd entries base address(kernel32.dll)
;This read from 5010h, it seems that this DOES NOT read the correct member!
;Should be at offset 18h
答案 1 :(得分:0)
这是因为InMemoryOrderModuleList列表是LIST_ENTRY类型,其第一个成员是Flink,其位移 0x00 ?
0:000> dt ntdll!_LIST_ENTRY
**+0x000** Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
nMemoryOrderModuleList是一个双向链表,其第一个成员是Flink,其位移是0x00 ......这意味着如果我选择列表InMemoryOrderModuleList将直接指向InMemoryOrderModuleList成员_LDR_DATA_TABLE_ENTRY表?而不是_LDR_DATA_TABLE_ENTRY表的开头?
如果我不太懂英语,我很抱歉,抱歉