原始代码来自PE权威指南
;------------------------
; 获取kernel32.dll的基址
; 从PEB结构中搜索kernel32.dll的基地址
; 戚利
; 2010.6.27
;------------------------
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;数据段
.data
szText db 'kernel32.dll的基地址为%08x',0
szOut db '%08x',0dh,0ah,0
szBuffer db 256 dup(0)
;代码段
.code
start:
assume fs:nothing
mov eax,fs:[30h] ;获取PEB所在地址
mov eax,[eax+0ch] ;获取PEB_LDR_DATA 结构指针
mov esi,[eax+1ch] ;获取InInitializationOrderModuleList 链表头
;第一个LDR_MODULE节点InInitializationOrderModuleList成员的指针
lodsd ;获取双向链表当前节点后继的指针
mov eax,[eax+8] ;获取kernel32.dll的基地址
;输出模块基地址
invoke wsprintf,addr szBuffer,addr szText,eax
invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
ret
end start
这个是网上找的神图
可以看到fs:[30]放着PEB指针, [fs:[30]+0ch]存放ldr
ldr的后三个LIST_ENTRY类型的成员, 是一个双向链表
_LIST_ENTRY中的FLnk对应着_LDR_DATA_TABLE_ENTRY的相应LIST_ENTRY成员
上Debuger
执行完第一条指令我们就可以看到eax已经指向的PEB了
0:000> t
eax=00288000 ebx=00288000 ecx=00401000 edx=00401000 esi=00401000 edi=00401000
eip=00401006 esp=0019ff74 ebp=0019ff80 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
pebkernelbase+0x1006:
00401006 8b400c mov eax,dword ptr [eax+0Ch] ds:002b:0028800c={ntdll!PebLdr (7730dca0)}
0:000> u
pebkernelbase+0x1006:
00401006 8b400c mov eax,dword ptr [eax+0Ch]
00401009 8b701c mov esi,dword ptr [eax+1Ch]
0040100c ad lods dword ptr [esi]
0040100d 8b4008 mov eax,dword ptr [eax+8]
00401010 50 push eax
00401011 6800304000 push offset pebkernelbase+0x3000 (00403000)
00401016 6822304000 push offset pebkernelbase+0x3022 (00403022)
0040101b e814000000 call pebkernelbase+0x1034 (00401034)
0:000> dt _PEB 00288000
0:000> dt _PEB 00288000
ntdll!_PEB
+0x000 InheritedAddressSpace : 0 ''
+0x001 ReadImageFileExecOptions : 0 ''
+0x002 BeingDebugged : 0x1 ''
+0x003 BitField : 0 ''
+0x003 ImageUsesLargePages : 0y0
+0x003 IsProtectedProcess : 0y0
+0x003 IsImageDynamicallyRelocated : 0y0
+0x003 SkipPatchingUser32Forwarders : 0y0
+0x003 IsPackagedProcess : 0y0
+0x003 IsAppContainer : 0y0
+0x003 IsProtectedProcessLight : 0y0
+0x003 IsLongPathAwareProcess : 0y0
+0x004 Mutant : 0xffffffff Void
+0x008 ImageBaseAddress : 0x00400000 Void
+0x00c Ldr : 0x7730dca0 _PEB_LDR_DATA 我们主要看这个,它的类型_PEB_LDR_DATA可以从上图看到
主要看绿色的成员
0:000> dx -r1 ((ntdll!_PEB_LDR_DATA *)0x7730dca0)
((ntdll!_PEB_LDR_DATA *)0x7730dca0) : 0x7730dca0 [Type: _PEB_LDR_DATA *]
[+0x000] Length : 0x30 [Type: unsigned long]
[+0x004] Initialized : 0x1 [Type: unsigned char]
[+0x008] SsHandle : 0x0 [Type: void *]
[+0x00c] InLoadOrderModuleList [Type: _LIST_ENTRY]
[+0x014] InMemoryOrderModuleList [Type: _LIST_ENTRY]
[+0x01c] InInitializationOrderModuleList [Type: _LIST_ENTRY] 它的VA为0X7730DCBC 点击这个继续看下面
[+0x024] EntryInProgress : 0x0 [Type: void *]
[+0x028] ShutdownInProgress : 0x0 [Type: unsigned char]
[+0x02c] ShutdownThreadId : 0x0 [Type: void *]
可以看到这个双向链表有11个节点, 从0x463268 ~ 0x469b50 (看InInitializationOrderModuleList )
0:000> dx -r1 (*((ntdll!_LIST_ENTRY *)0x7730dcbc))
(*((ntdll!_LIST_ENTRY *)0x7730dcbc)) [Type: _LIST_ENTRY]
[+0x000] Flink : 0x463268 [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x469b50 [Type: _LIST_ENTRY *]
0:000> dx -r1 ((ntdll!_LIST_ENTRY *)0x463268)
((ntdll!_LIST_ENTRY *)0x463268) : 0x463268 [Type: _LIST_ENTRY *]
[+0x000] Flink : 0x463b10 [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x7730dcbc [Type: _LIST_ENTRY *]
0:000> dx -r1 ((ntdll!_LIST_ENTRY *)0x463b10)
((ntdll!_LIST_ENTRY *)0x463b10) : 0x463b10 [Type: _LIST_ENTRY *]
[+0x000] Flink : 0x463750 [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x463268 [Type: _LIST_ENTRY *]
0:000> dx -r1 ((ntdll!_LIST_ENTRY *)0x463750)
((ntdll!_LIST_ENTRY *)0x463750) : 0x463750 [Type: _LIST_ENTRY *]
[+0x000] Flink : 0x464948 [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x463b10 [Type: _LIST_ENTRY *]
0:000> dx -r1 ((ntdll!_LIST_ENTRY *)0x464948)
((ntdll!_LIST_ENTRY *)0x464948) : 0x464948 [Type: _LIST_ENTRY *]
[+0x000] Flink : 0x465670 [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x463750 [Type: _LIST_ENTRY *]
0:000> dx -r1 ((ntdll!_LIST_ENTRY *)0x465670)
((ntdll!_LIST_ENTRY *)0x465670) : 0x465670 [Type: _LIST_ENTRY *]
[+0x000] Flink : 0x465398 [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x464948 [Type: _LIST_ENTRY *]
0:000> dx -r1 ((ntdll!_LIST_ENTRY *)0x465398)
((ntdll!_LIST_ENTRY *)0x465398) : 0x465398 [Type: _LIST_ENTRY *]
[+0x000] Flink : 0x4650a8 [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x465670 [Type: _LIST_ENTRY *]
0:000> dx -r1 ((ntdll!_LIST_ENTRY *)0x4650a8)
((ntdll!_LIST_ENTRY *)0x4650a8) : 0x4650a8 [Type: _LIST_ENTRY *]
[+0x000] Flink : 0x464b88 [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x465398 [Type: _LIST_ENTRY *]
0:000> dx -r1 ((ntdll!_LIST_ENTRY *)0x464b88)
((ntdll!_LIST_ENTRY *)0x464b88) : 0x464b88 [Type: _LIST_ENTRY *]
[+0x000] Flink : 0x464698 [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x4650a8 [Type: _LIST_ENTRY *]
0:000> dx -r1 ((ntdll!_LIST_ENTRY *)0x464698)
((ntdll!_LIST_ENTRY *)0x464698) : 0x464698 [Type: _LIST_ENTRY *]
[+0x000] Flink : 0x469b50 [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x464b88 [Type: _LIST_ENTRY *]
0:000> dx -r1 ((ntdll!_LIST_ENTRY *)0x469b50)
((ntdll!_LIST_ENTRY *)0x469b50) : 0x469b50 [Type: _LIST_ENTRY *]
[+0x000] Flink : 0x7730dcbc [Type: _LIST_ENTRY *]
[+0x004] Blink : 0x464698 [Type: _LIST_ENTRY *]
用!peb指令看下, 系统默认dump出来的东东,看下面的绿色
0:000> !peb
PEB at 00288000
InheritedAddressSpace: No
ReadImageFileExecOptions: No
BeingDebugged: Yes
ImageBaseAddress: 00400000
NtGlobalFlag: 70
NtGlobalFlag2: 0
Ldr 7730dca0
Ldr.Initialized: Yes
Ldr.InInitializationOrderModuleList: 00463268 . 00469b50 !!!!!!!!
Ldr.InLoadOrderModuleList: 00463360 . 00469b40
Ldr.InMemoryOrderModuleList: 00463368 . 00469b48
Base TimeStamp Module
400000 4d5b904f Feb 16 16:52:31 2011 D:\技术书籍\随书代码\Windows_PE权威指南》source\《Windows_PE权威指南》source\chapter11\pebkernelbase.exe
771f0000 C:\WINDOWS\SYSTEM32\ntdll.dll
74a60000 7b5427ec Jul 27 09:33:32 2035 C:\WINDOWS\System32\KERNEL32.DLL
76b80000 54734dee Nov 24 23:25:34 2014 C:\WINDOWS\System32\KERNELBASE.dll
768e0000 C:\WINDOWS\System32\user32.dll
755b0000 6b5c1b19 Jan 29 12:52:41 2027 C:\WINDOWS\System32\win32u.dll
74c40000 527faf7f Nov 11 00:08:31 2013 C:\WINDOWS\System32\GDI32.dll
76eb0000 C:\WINDOWS\System32\gdi32full.dll
75930000 47892406 Jan 13 04:33:10 2008 C:\WINDOWS\System32\msvcp_win.dll
75d10000 6dbf7eae May 07 06:52:30 2028 C:\WINDOWS\System32\ucrtbase.dll
75750000 60562aa5 Mar 21 01:02:29 2021 C:\WINDOWS\System32\IMM32.DLL
可以看到每个节点都有前驱和后继
仍然用第一个LDR说明InIntializationOrderModuleList说明
我们知道_LIST_ENTRY结构包含两个指针成员, 作为双向链表的链, 同时这两个指针又对应着下面这个结构体中的相应LIST_ENTRY
对第一个节点的Flink,看下面的数据, FLINK作为_LIST_ENTRY结构总共为8bytes, 由于当前我们的LIST_ENTRY来自的是InInitializationOrderModuleList, 所以它指向_LDR_DATA_TRABLE_ENTRY中的第三个成员InInitializationOrderLinks。 如果LIST_ENTRY来自_PEB_LDR_DATA中的InLoadOrderModuleList,那么FLINK就指向的是_LDR_DATA_TABLE_ENTRY中的InLoadOrderLinker成员
所以0x463268 +8 后就是_LDR_DATA_TABLE_ENTRY的dllbase 了, 可以看到是771F0000 对应着上面!peb中的ntdll。。。 名字来自的是FULLDLLName。 从InInitializationOrderLinks开始偏移为 +8(List_entry) +4(DLLBASE)+4(Entrypoint)+4(SizeOfImage)+4(_Unicode_string的后4Bytes才是Buffer)
FullDllName就是下面的00463138
0:000> dd 0x463268 ntdll.dll
00463268 00463b10 7730dcbc 771f0000 00000000
00463278 0019a000 003c003a 00463138 00140012
00463288 771f9270 0000a2c4 0000ffff 7730db40
0:000> dt _unicode_string
ntdll!_UNICODE_STRING
+0x000 Length : Uint2B
+0x002 MaximumLength : Uint2B
+0x004 Buffer : Ptr32 Uint2B
刚好对应了ntdll.dll的fullName
0:000> db 00463138
00463138 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O.
00463148 57 00 53 00 5c 00 53 00-59 00 53 00 54 00 45 00 W.S.\.S.Y.S.T.E.
00463158 4d 00 33 00 32 00 5c 00-6e 00 74 00 64 00 6c 00 M.3.2.\.n.t.d.l.
00463168 6c 00 2e 00 64 00 6c 00-6c 00 00 00 ab ab ab ab l...d.l.l.......
同理771F9270对应着baseDllname
0:000> db 771F9270
771f9270 6e 00 74 00 64 00 6c 00-6c 00 2e 00 64 00 6c 00 n.t.d.l.l.
0x463268 指向的下一个LIST_ENTRY结点中的Flink为463b10, 来看这个FLink对应的_LDR_DATA_TABLE_ENTRY
0:000> dd 0x463b10 kernalBase.dll
00463b10 00463750 00463268 76b80000 76c6d6e0 绿色对应kernalBase的基地址
00463b20 001fd000 00460044 00463c08 001e001c
00463b30 00463c30 0008a2cc 0000ffff 7730dac0
00463b40 7730dac0 54734dee 00000000 00000000
00463b50 00463bc0 00463bc0 00463bc0 00000000
00463b60 74a60000 771f1304 004656c8 004632c0
00463b70 004649a0 004633d4 004649ac 004637b5
00463b80 76b80000 00000000 3724d21d 01d5f2f1
0:000> db 00463c08
00463c08 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O.
00463c18 57 00 53 00 5c 00 53 00-79 00 73 00 74 00 65 00 W.S.\.S.y.s.t.e.
00463c28 6d 00 33 00 32 00 5c 00-4b 00 45 00 52 00 4e 00 m.3.2.\.K.E.R.N.
00463c38 45 00 4c 00 42 00 41 00-53 00 45 00 2e 00 64 00 E.L.B.A.S.E...d.
00463c48 6c 00 6c 00 00 00 ab ab-ab ab ab ab ab ab ee fe l.l
---------------------------
同理我们遍历上面的双链表各个结点
0:000> dd 0x463750 kernal32.dll
00463750 00464948 00463b10 74a60000 74a75f70
00463760 000e0000 00420040 00463848 001a0018
00463770 00463870 000ca2cc 0000ffff 7730db30
00463780 7730db30 7b5427ec 00000000 00000000
00463790 00463800 00463800 00463800 00000000
004637a0 00000000 771f1304 004633c8 00464be0
004637b0 004649a0 00463b74 004646fc 00000000
004637c0 74a60000 00000000 3724d21d 01d5f2f1
0:000> db 00463848
00463848 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O.
00463858 57 00 53 00 5c 00 53 00-79 00 73 00 74 00 65 00 W.S.\.S.y.s.t.e.
00463868 6d 00 33 00 32 00 5c 00-4b 00 45 00 52 00 4e 00 m.3.2.\.K.E.R.N.
00463878 45 00 4c 00 33 00 32 00-2e 00 44 00 4c 00 4c 00 E.L.3.2...D.L.L.
---------------------
0:000> dd 0x464948 win32u.dll
00464948 00465670 00463750 755b0000 00000000
00464958 00017000 003e003c 00464a40 00160014
00464968 00464a68 8008a2ec 00000006 004650d4
00464978 7730db20 6b5c1b19 00000000 00000000
0:000> db 00464a40
00464a40 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O.
00464a50 57 00 53 00 5c 00 53 00-79 00 73 00 74 00 65 00 W.S.\.S.y.s.t.e.
00464a60 6d 00 33 00 32 00 5c 00-77 00 69 00 6e 00 33 00 m.3.2.\.w.i.n.3.
00464a70 32 00 75 00 2e 00 64 00-6c 00 6c 00 00 00 ab ab 2.u...d.l.l.....
--------------------
0:000> dd 0x465670 ucrtbase.dll
00465670 00465398 00464948 75d10000 75d37670
00465680 0011f000 00420040 00465768 001a0018
00465690 00465790 8008a2ec 00000006 7730db58
0:000> db 00465768
00465768 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O.
00465778 57 00 53 00 5c 00 53 00-79 00 73 00 74 00 65 00 W.S.\.S.y.s.t.e.
00465788 6d 00 33 00 32 00 5c 00-75 00 63 00 72 00 74 00 m.3.2.\.u.c.r.t.
00465798 62 00 61 00 73 00 65 00-2e 00 64 00 6c 00 6c 00 b.a.s.e...d.l.l.
-------------------
0:000> dd 0x465398 msvcp_win.dll
00465398 004650a8 00465670 75930000 75946760
004653a8 0007c000 00440042 00465490 001c001a
004653b8 004654b8 800ca2ec 00000006 7730db20
004653c8 004650d4 47892406 00000000 00000000
0:000> db 00465490
00465490 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O.
004654a0 57 00 53 00 5c 00 53 00-79 00 73 00 74 00 65 00 W.S.\.S.y.s.t.e.
004654b0 6d 00 33 00 32 00 5c 00-6d 00 73 00 76 00 63 00 m.3.2.\.m.s.v.c.
004654c0 70 00 5f 00 77 00 69 00-6e 00 2e 00 64 00 6c 00 p._.w.i.n...d.l.
-------------------------
0:000> dd 0x4650a8 gdi32full.dll
004650a8 00464b88 00465398 76eb0000 76f70e50
004650b8 0015a000 00440042 004651a0 001c001a
004650c8 004651c8 800ca2ec 00000006 004653c4
004650d8 00464974 b22d992c 00000000 00000000
0:000> db 004651a0
004651a0 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O.
004651b0 57 00 53 00 5c 00 53 00-79 00 73 00 74 00 65 00 W.S.\.S.y.s.t.e.
004651c0 6d 00 33 00 32 00 5c 00-67 00 64 00 69 00 33 00 m.3.2.\.g.d.i.3.
004651d0 32 00 66 00 75 00 6c 00-6c 00 2e 00 64 00 6c 00 2.f.u.l.l...d.l.
004651e0 6c 00 00 00 ab ab ab ab-ab ab ab ab ee fe ee fe l...............
----------------------
0:000> dd 0x464b88 gdi32.dll
00464b88 00464698 004650a8 74c40000 74c44b50
00464b98 00021000 003c003a 00464c80 00140012
00464ba8 00464ca8 800ca2ec 00000006 7730daa8
0:000> db 00464c80
00464c80 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O.
00464c90 57 00 53 00 5c 00 53 00-79 00 73 00 74 00 65 00 W.S.\.S.y.s.t.e.
00464ca0 6d 00 33 00 32 00 5c 00-47 00 44 00 49 00 33 00 m.3.2.\.G.D.I.3.
00464cb0 32 00 2e 00 64 00 6c 00-6c 00 00 00 ab ab ab ab 2...d.l.l.......
-----------
0:000> dd 0x464698 user32.dll
00464698 00469b50 00464b88 768e0000 7690c630
004646a8 00197000 003e003c 00464790 00160014
004646b8 004647b8 800ca2ec 00000006 7730daa0
0:000> db 00464790
00464790 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O.
004647a0 57 00 53 00 5c 00 53 00-79 00 73 00 74 00 65 00 W.S.\.S.y.s.t.e.
004647b0 6d 00 33 00 32 00 5c 00-75 00 73 00 65 00 72 00 m.3.2.\.u.s.e.r.
004647c0 33 00 32 00 2e 00 64 00-6c 00 6c 00 00 00 ab ab 3.2...d.l.l.....
-------------------
0:000> dd 0x469b50 imm32.dll
00469b50 7730dcbc 00464698 75750000 75754390
00469b60 00025000 003c003a 00469c48 00140012
00469b70 00469c70 8008a2cc 00000006 7730db90
0:000> db 00469c48
00469c48 43 00 3a 00 5c 00 57 00-49 00 4e 00 44 00 4f 00 C.:.\.W.I.N.D.O.
00469c58 57 00 53 00 5c 00 53 00-79 00 73 00 74 00 65 00 W.S.\.S.y.s.t.e.
00469c68 6d 00 33 00 32 00 5c 00-49 00 4d 00 4d 00 33 00 m.3.2.\.I.M.M.3.
00469c78 32 00 2e 00 44 00 4c 00-4c 00 00 00 ab ab ab ab 2...D.L.L
------------------------
注意链表最后一个结点有意思, 它只是作为一个结束标记。 可以看到DLLBASE DLLname等关键字段都是null
0:000> dd 0x7730dcbc
7730dcbc 00463268 00469b50 00000000 00000000
7730dccc 00000000 00000002 00000000 00000000
7730dcdc 00000000 00000000 00000000 00000000
上面可以看到装载过程中的所有dll和!peb 的dump出来的信息一样, 0x7730dcbc 这个结点的base和dllname貌似直接来自!peb中的ImageBaseAddress和ImagePathName?!
上面就是如何求装载的dll名字, 以及装载基地址的过程。。。。
最后再注意: LDR中的下面字段几个list_entry分别指向_ldr_data_table_entry中同名的list_entry.
所以计算的时候一定注意 正确求出偏移地址。。。e.g. 通过Ldr.InInitializationOrderModuleList找DLL加载地址偏移应该是+8 (从最靠近DLLBASE的LIST_ENTRY),也就是上面我们计算式的黄色标注
Ldr.InLoadOrderModuleList找DLL加载偏移地址为0X18 (与DLLBASE间隔3个LIST_ENTRY)
Ldr.InMemoryOrderModuleList找DLL加载偏移地址为0X10 (与DLLBASE讲个两个LIST_ENTRY)
Sizeof(LIST_ENTRY) == 8
OK,在不同OS上面,汇编生成的PE返回不同的基地址, 这个自己调试就可以知道为什么有时候不是kernel32.dll的基地址了。。。我用的是win10