在开始分析程序之前,我们第一个要解决的问题,就是如何定位到main函数,想要从二进制逆向的角度分析出main函数,就必须要了解正向的代码下main函数的所有的细节和特
征。毕竟逆向的本质就是正向。
调用main()堆栈
样例代码
#include <stdio.h>int main()
{printf("Hello World!");return 0;
}
通过VS2019查看main()函数调用的堆栈空间
转到mainCRTStartup()的反汇编,这是C++程序执行的第一个函数
mainCRTStartup先调用__scrt_common_main函数
转到__scrt_common_main()的反汇编
在反汇编代码中,__scrt_common_main第二个调用函数是__scrt_common_main_seh
之后__scrt_common_main_seh调用invoke_main()
转到invoke_main()的反汇编,发现调用 _main()函数
回到源代码
这就到main函数了,这里就到了main函数了,这里main函数有三个参数,分别是
- __argc是参数个数
- __argv是参数列表
- 最后一个是环境指针
里面的每一个参数都是单独的一个函数
可以得出规律
- mainCRTStartup调用__scrt_common_main
- __scrt_common_main调用__scrt_common_main_seh,对应汇编是在第二个call上
- __scrt_common_main_seh调用invoke_main,对应在汇编的特征如下:
- int const main_result = invoke_main();源码是赋值给一个变量
- 这个函数参数是0个,后面会跟exit函数,而exit函数的参数 是 invoke_main 的返回值
- call指令后面必有一个mov [ebp-0xXXX],eax
- invoke_main调用main
x64dbg定位main函数
进入程序入口,调用mainCRTStartup函数
调用__scrt_common_main函数
调用_scrt_common_main_seh
调用invoke_main比较复杂,先分析一下它的特征,在scrt_common_main_seh
会把invoke_main的返回值给main_result
int const main_result = invoke_main();返回值会伴随一个exit 和 一个main_result,必然有一个ret
if (!__scrt_is_managed_app())exit(main_result);return main_result;
定位invoke_main方法:
- 找到第一个ret
- 定位到call XXXX
- call指令后面必有一个mov [ebp-0xXXX],eax
定位ret
定位invoke_main()
在这里会看到四个函数调用,最后一个才是 main 函数
定位到main()函数