DIRECTORY_ENTRY_IMPORT
内容,它里面定义了我们需要初始化导入的 dll,我们可以用 dt r3
展开一下,然后一直点点点就好了,简化后如下:
0:000> dt -r3 0x400000+0n232 _IMAGE_NT_HEADERSConsoleApplication3!_IMAGE_NT_HEADERS+0x000 Signature: 0x4550+0x004 FileHeader: _IMAGE_FILE_HEADER+0x000 Machine: 0x14c...+0x012 Characteristics: 0x103+0x018 OptionalHeader: _IMAGE_OPTIONAL_HEADER+0x000 Magic: 0x10b+0x002 MajorLinkerVersion : 0xe ''...+0x05c NumberOfRvaAndSizes : 0x10+0x060 DataDirectory: [16] _IMAGE_DATA_DIRECTORY+0x000 VirtualAddress: 0+0x004 Size: 00:000> dx -r1 (*((ConsoleApplication3!_IMAGE_DATA_DIRECTORY (*)[16])0x400160))(*((ConsoleApplication3!_IMAGE_DATA_DIRECTORY (*)[16])0x400160))[Type: _IMAGE_DATA_DIRECTORY [16]][0][Type: _IMAGE_DATA_DIRECTORY][1][Type: _IMAGE_DATA_DIRECTORY][2][Type: _IMAGE_DATA_DIRECTORY]...[15][Type: _IMAGE_DATA_DIRECTORY]0:000> dx -r1 (*((ConsoleApplication3!_IMAGE_DATA_DIRECTORY *)0x400168))(*((ConsoleApplication3!_IMAGE_DATA_DIRECTORY *)0x400168))[Type: _IMAGE_DATA_DIRECTORY][+0x000] VirtualAddress: 0x1b1cc [Type: unsigned long][+0x004] Size: 0x50 [Type: unsigned long]
从输出的 VirtualAddress=0x1b1cc
中可以看到,我们 PPEE 截图二中的 DIRECTORY_ENTRY_IMPORT
真实内容是在偏移 0x1b1cc
处,它是一个 combase!_IMAGE_IMPORT_DESCRIPTOR
结构体,输出如下:
0:005> dt 0x400000+0x1b1cc combase!_IMAGE_IMPORT_DESCRIPTOR+0x000 Characteristics: 0x1b21c+0x000 OriginalFirstThunk : 0x1b21c+0x004 TimeDateStamp: 0+0x008 ForwarderChain: 0+0x00c Name: 0x1b40c+0x010 FirstThunk: 0x1b000
【WinDBG详解进程初始化dll是如何加载的】到这里就很关键了,涉及到如下几点信息:
- 加载的 dll 名字是什么?
Name
字段提取,参考如下代码:0:005> da 0x400000+0x1b40c0041b40c"KERNEL32.dll"
- 加载的 方法名 是什么?
OriginalFirstThunk
字段,这里是一个 _IMAGE_IMPORT_BY_NAME
类型的指针数组,代码如下:0:005> dp 0x400000+0x1b21c0041b21c0001b3e8 0001b3fc 0001b954 0001b9420041b22c0001b934 0001b924 0001b912 0001b9060041b23c0001b8fa 0001b8ea 0001b8d6 0001b8ba...0:005> dt 0x400000+0x0001b3e8 combase!_IMAGE_IMPORT_BY_NAME+0x000 Hint: 0x382+0x002 Name: [1]"I"0:005> da 0x400000+0x0001b3e8+0x20041b3ea"IsDebuggerPresent"
结合上面的输出,我们知道 IsDebuggerPresent()
是属于 KERNEL32.dll
下的,有了这两点信息,Windows 加载器就可以用 LoadLibrary
和 GetProcAddress
方法将其加载到进程中了,转化为 C 代码大概是这样的 。typedef BOOL(CALLBACK* DeubbgerFunc)();int main(intargc, char* argv[]){ HMODULE hModule = LoadLibrary(L"KERNEL32.dll"); DeubbgerFunc func = (DeubbgerFunc)GetProcAddress(hModule, "IsDebuggerPresent"); BOOL b= func();}
- func 函数地址会保存吗?
_IMAGE_IMPORT_DESCRIPTOR
结构下的 FirstThunk
字段中,这是一个函数地址的指针数组,可以用 dds 观察 。0:005> dt 0x400000+0x1b1cc combase!_IMAGE_IMPORT_DESCRIPTOR+0x000 Characteristics: 0x1b21c+0x000 OriginalFirstThunk : 0x1b21c+0x004 TimeDateStamp: 0+0x008 ForwarderChain: 0+0x00c Name: 0x1b40c+0x010 FirstThunk: 0x1b0000:005> dds 0x400000+0x1b0000041b000753c20d0 KERNEL32!IsDebuggerPresentStub0041b004753c16c0 KERNEL32!LoadLibraryWStub0041b008753c2e80 KERNEL32!GetCurrentProcess0041b00c753bf550 KERNEL32!GetProcAddressStub0041b05c753b9910 KERNEL32!TerminateProcessStub...
还有一点要注意,如果你在代码中使用 IsDebuggerPresent()
方法的话,它会从 0041b000
位置上取函数地址,参考如下汇编代码:
经验总结扩展阅读
- 80年属猴人2023年每月运势及运程详解
- 无悔华夏8月11日渔樵问答答案详解
- LOL英雄联盟乌迪尔技能重做调整详解
- 四两四钱男命婚姻详解一生 结婚较晚值得依靠
- 叫我大掌柜2022巅峰商会战活动详解攻略
- 百变大侦探罗夫尔斯庄园谜案剧本真相详解
- kubernetes之kubectl与YAML详解1
- 航海王热小队决战活动玩法详解攻略
- jvm双亲委派机制详解
- 网络协议之:redis protocol 详解