前言:以X86、Windows环境下的C语言为例,编写好的源程序通过编译器(compiler)和汇编器(assembler)生成了功能等价的机器码,再通过链接器(linker)解决文件的外部依赖,最后生成可执行的PE格式文件。当用户执行程序时,操作系统的加载器(loader)将程序按指定的格式加载至内存。
书籍资料1:
加载器是操作系统的一部分,它负责将可执行程序从外部存储器(如硬盘)加载到内存中,包括遍历IDT加载函数依赖模块、遍历IAT绑定动态调用函数(和PE文件的知识相关联),对基地址冲突的模块执行调整工作,其中NTDLL.DLL中以Ldr开头的函数负责相关工作。----《软件调试》
书籍资料2:VC++开发的程序,在调试时总从main或WinMain函数开始,这就让开发者误认为它们是程序的第一条指令执行处,这个认识是错误的。在应用程序被操作系统加载时,操作系统会分析执行文件内的数据,分配相关资源,读取执行文件中的代码和数据到合适的内存单元,然后才是执行入口代码,入口代码通常是mainCRTstartup等。 -----《C++反汇编与逆向分析技术揭秘》
实验验证:
- 编写好源代码后按F11进入调试窗口,Alt+7打开堆栈,右键点击“显示外部代码”,如下图所示:
-从后往前依次是ntdll.dll中的一个函数、kernel32.dll中的一个函数和mainCRTStartup()函数。
总结:纸上得来终觉浅,绝知此事要躬行。