c 程序的启动过程的反汇编分析
0x01 工具准备
1.最简c代码一只
1 | int main() |
2.ollydbg
3.VC++6.0
4.GCC(mingw)
0x02 代码分析
1 | int main() |
在gcc下,添加-nostdlib编译选项,即链接器不链接标准库,会提示以下错误信息:
1 | D:\Backup\我的文档\src>gcc main.c -nostdlib-o main.exe |
关于-nostdlib编译选项,只有命令行指定的项才传递给链接器。标准启动文件和库都不会传递给链接器。该选项隐式打开选项-nostartfiles 和-nodefaultlibs。该选项也可以写作–no-standard-libraries。
在gcc执行汇编之后,在链接部分,当只打开选项-nostartfiles时,结果正常,未出现错误信息。而在-nodefaultlibs选项中,提示很多错误信息。
说明main函数,依赖了一些系统标准库文件,在链接的时候,需要到了一些函数,例如pre_cpp_init、check_managed_app、pre_c_init、_tmainCRTStartup、_InterlockedCompareExchangePointer、duplicate_ppstrings、WinMainCRTStartup、mainCRTStartup、_mingw_prepare_except_fr_msvcr80_and_higher….
汇编里面的_main就是C语言里面的main,是因为汇编器和C编译器对符号的命名差一个下划线。
链接器会在系统标准库文件,类似于/lib/crt2.o的文件中,寻找_start符号,然后在_start中执行创建堆对象,栈,打开系统预先提供的设备,将argv,argc参数传入main函数,然后调用main函数。
0x03 vc main函数反汇编分析
1 | 1: int main() |
Vc查看调用栈,可以看到在main函数之前,系统还启动了mainCRTStartup函数,这个函数是控制台环境下多字节编码的启动函数。在kernel32.dll中地址7c816fd7处调用了mainCRTStartup函数。
1 | main() line 2 |
0x04 ollydbg反汇编分析
Od载入,如图所示。
堆栈窗口如图所示。
通过堆栈,可以看到kelnel32调用了入口函数(mainCRTStartup),对于od来说,main函数并不是Entry point,而是mainCRTStartup函数。
一直单步,单步到00401146处,od分析为调用GetVersion函数,获取当前运行平台的版本号,因为是控制台程序,所以获取版本号为ms-dos的版本信息。
继续单步,单步到0040119E处,单步进入,可以看到有HeapCreate申请堆空间函数,大小由传递的参数决定,并且该call里有HeapDestroy销毁堆函数。因此0040119E为初始化堆空间,如图所示。
在004011C0处,od分析为GetCommandLineA函数,获取命令行参数信息的首地址。
进入下面的那个call后,可以看到GetEnvironmentStringsW和GetEnvironmentStrings函数,获取环境变量的首地址,如图所示。以Unicode编码形式返回到寄存器和堆栈中,最后采用WideCharToMultiByte函数将Unicode字符串到一个多字节字符串
并且后续有参数分析的一些函数,环境变量信息分析,从而得到main函数所需的参数,然后在00402D4B位置,将参数传到main函数中,从而执行main函数中的内容。
0x05 后记
最近在阅读《c++反汇编与逆向分析技术揭秘》,在阅读到第三章认识启动函数,找到用户入口时,得知main函数之前系统要做一些准备工作,再加上上学期学的C语言程序入口函数不是main函数,而是_start函数,这不禁引发了一些思考,到底编译器在编译和系统执行程序的时候发生了什么,因此想以实例进行一定的分析。在思考的过程中,有些涉及到了编译器的知识,包括它如何工作的,汇编之后又是如何链接的,这一部分内容不太熟悉,这一方面得掌握编译原理的知识,还得学习编译器的相关内容。那些东西还没学,因此不免有一些缺憾。了解反汇编的一些内容,可以更深层次的理解相对底层的一些东西,包括栈,堆和寄存器的数据交换。另外并未使用到神器IDA,利用IDA会更好地静态分析一些函数。
c 程序的启动过程的反汇编分析