我试图了解 Windows 如何在用户空间中递归加载 DLL。
以跟踪kernel32.ReadProcessMemory为例:
的第一步ReadProcessMemory是 IAT kernel32:
00007FF901F6AFA0 | 48:FF25 21D20500 | jmp qword ptr ds:[<&ReadProcessMemory>] |
哪个jmp是kernelbase.ReadProcessMemory:
00007FF9002D22F0 | 48:83EC 48 | sub rsp,48 |
00007FF9002D22F4 | 48:8D4424 30 | lea rax,qword ptr ss:[rsp+30] |
00007FF9002D22F9 | 48:894424 20 | mov qword ptr ss:[rsp+20],rax |
00007FF9002D22FE | 48:FF15 C3521400 | call qword ptr ds:[<&ZwReadVirtualMemory>] |
<snip>
这call是ntdll.ZwReadVirtualMemory:
00007FF902F5C840 | 4C:8BD1 | mov r10,rcx |
00007FF902F5C843 | B8 3F000000 | mov eax,3F | 3F:'?'
00007FF902F5C848 | F60425 0803FE7F 01 | test byte ptr ds:[7FFE0308],1 |
00007FF902F5C850 | 75 03 | jne ntdll.7FF902F5C855 |
00007FF902F5C852 | 0F05 | syscall |
00007FF902F5C854 | C3 | ret |
00007FF902F5C855 | CD 2E | int 2E |
00007FF902F5C857 | C3 | ret |
所以这个例子中用户模式的流程是:
kernel32.ReadProcessMemorykernelbase.ReadProcessMemoryntdll.ZwReadVirtualMemory
期望是上述每个 DLL 在加载时都可以根据它们的 IAT/从其他 DLL 导入的函数“找到”适当的函数。
使用dumpbin和跟踪IMPORTSthis 是正确的kernel32.ReadProcessMemory(哪里api-ms-win-core-memory-l1-1-0.dll是ApiSetfor kernelbase.dll):
api-ms-win-core-memory-l1-1-0.dll
180078178 Import Address Table
18009E120 Import Name Table
0 time date stamp
0 Index of first forwarder reference
35 VirtualQueryEx
<snip>
1C ReadProcessMemory
然而,这不是真的kernelbase.dll-NtReadVirtualMemory是进口的,但ZwReadVirtualMemory不是进口的:
ntdll.dll
1801A67C8 Import Address Table
180262A48 Import Name Table
0 time date stamp
0 Index of first forwarder reference
893 __C_specific_handler
<snip>
205 NtReadVirtualMemory
所以,我的问题是:在 DLL 加载过程中,如果没有导入,如何kernelbase.dll识别“位置” ?ZwReadVirtualMemory
该ZwReadVirtualMemory函数由 调用kernelbase.dll,所以它一定已经在某个时候被解析/存储在 IAT 中,但是这在技术上是如何发生的呢?
当这些函数解析到相同的地址时NtReadVirtualMemory,加载器映射到的地方是否有一些间接?ZwReadVirtualMemory