Main()函数的前世今生

        在开始分析程序之前,我们第一个要解决的问题,就是如何定位到main函数,想要从二进制逆向的角度分析出main函数,就必须要了解正向的代码下main函数的所有的细节和特

征。毕竟逆向的本质就是正向。

调用main()堆栈

样例代码

#include 


int main()
{
	printf("Hello World!");

	return 0;
}

通过VS2019查看main()函数调用的堆栈空间

Main()函数的前世今生_第1张图片

转到mainCRTStartup()的反汇编,这是C++程序执行的第一个函数

Main()函数的前世今生_第2张图片

Main()函数的前世今生_第3张图片

mainCRTStartup先调用__scrt_common_main函数

Main()函数的前世今生_第4张图片

转到__scrt_common_main()的反汇编

Main()函数的前世今生_第5张图片

在反汇编代码中,__scrt_common_main第二个调用函数是__scrt_common_main_seh

之后__scrt_common_main_seh调用invoke_main()

Main()函数的前世今生_第6张图片

转到invoke_main()的反汇编,发现调用 _main()函数

Main()函数的前世今生_第7张图片

回到源代码

Main()函数的前世今生_第8张图片

这就到main函数了,这里就到了main函数了,这里main函数有三个参数,分别是

  • __argc是参数个数
  • __argv是参数列表
  • 最后一个是环境指针
里面的每一个参数都是单独的一个函数

Main()函数的前世今生_第9张图片

可以得出规律

  1. mainCRTStartup调用__scrt_common_main
  2. __scrt_common_main调用__scrt_common_main_seh,对应汇编是在第二个call上
  3. __scrt_common_main_seh调用invoke_main,对应在汇编的特征如下:
    1. int const main_result = invoke_main();源码是赋值给一个变量
    2. 这个函数参数是0个,后面会跟exit函数,exit函数的参数 是 invoke_main 的返回值
    3. call指令后面必有一个mov [ebp-0xXXX],eax
  4. invoke_main调用main

x64dbg定位main函数

进入程序入口,调用mainCRTStartup函数

Main()函数的前世今生_第10张图片

调用__scrt_common_main函数

Main()函数的前世今生_第11张图片

调用_scrt_common_main_seh

Main()函数的前世今生_第12张图片

调用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方法:

  1. 找到第一个ret
  2. 定位到call XXXX
  3. call指令后面必有一个mov [ebp-0xXXX],eax

定位ret

Main()函数的前世今生_第13张图片

定位invoke_main()

Main()函数的前世今生_第14张图片

在这里会看到四个函数调用,最后一个才是 main 函数

Main()函数的前世今生_第15张图片

定位到main()函数

Main()函数的前世今生_第16张图片

你可能感兴趣的:(C与汇编,c语言,c++)