在汇编中查找Main 我有简单的C++程序: #include <iostream> using namespace std; void main() { cout << "Hello, world, from Visual C++!" << endl; } #包括 使用名称空间std; void main() { cout

在汇编中查找Main 我有简单的C++程序: #include <iostream> using namespace std; void main() { cout << "Hello, world, from Visual C++!" << endl; } #包括 使用名称空间std; void main() { cout,c++,debugging,assembly,reverse-engineering,C++,Debugging,Assembly,Reverse Engineering,一般来说,你不能 编译程序时,会得到二进制和(可选)调试符号 如果您有调试符号,让IDA或您的调试器加载它们,然后您应该能够以符号方式将main计算到函数的地址(例如,在IDA中,只需按g并写入main,您就会在那里。在WinDbg或gdb中,您可以键入b main) 但是,更常见的情况是在没有调试符号的二进制文件上找到main函数。在这种情况下,您不知道main函数在哪里,也不知道它是否在那里。二进制文件可能不使用入口点执行初始化然后执行c的公共libc实践allingmain(int-arg

一般来说,你不能

编译程序时,会得到二进制和(可选)调试符号

如果您有调试符号,让IDA或您的调试器加载它们,然后您应该能够以符号方式将
main
计算到函数的地址(例如,在IDA中,只需按
g
并写入
main
,您就会在那里。在WinDbg或gdb中,您可以键入
b main

但是,更常见的情况是在没有调试符号的二进制文件上找到
main
函数。在这种情况下,您不知道
main
函数在哪里,也不知道它是否在那里。二进制文件可能不使用入口点执行初始化然后执行c的公共
libc
实践alling
main(int-argc,char*argv[],char*envp[])

但因为您是一个聪明人,我建议您阅读您认为正在使用的编译器/平台的
libc
实现,并遵循平台定义入口点的逻辑,直到看到
callmain
指令


(请注意,.NET二进制文件和其他类型的二进制文件的行为可能完全不同。)

如果您调试自己的代码(最好在调试器下的某个位置停止),请使用下一个代码

if(IsDebuggerPresent())\uu调试中断();

因此,您可以将其插入到
main
的开头或任何其他位置

如果您调试的不是自己的二进制代码-二进制代码可能根本不包含
c/c++
CRT
代码-所以这个问题变得毫无意义。然而,如果
CRT
代码存在,尽管有许多不同的实现-所有这些都使用通用模式,并且经过一些实践-可能在
CRT
代码调用
main
中找到>
对于标准windows二进制文件,存在
pdb
文件-这根本不是问题

尽管入口点通常不是可执行文件中定义的
main
,这仅仅是因为编译器通常使用一些初始化代码来包装
main

在大多数情况下,初始化代码非常相似,每个编译器只有几个版本。大多数函数都有一个,使用IDA打开二进制文件将自动为您定义一个
WinMain
main
,等等函数。您也可以使用IDA的免费(试用)版本

如果不是这样的话,那么从入口点到
main
是非常直接的,方法是在入口点函数内部的几个调用之后执行一级深度。
main
调用通常接近入口点函数的末尾

下面是一个示例,
main
函数在底部附近被选中(请注意,这是一个使用mingw为windows编译的unix可执行文件,因此它与大多数本机win32可执行文件有些不同)


只是迂腐:它是
intmain(intargc,char**argv)
intmain()
,而不是
void main()
。一些可执行文件包含初始化环境的代码,然后调用
main
。如果调试器找不到
main
,则需要在调试模式下编译所有文件(以便可执行文件包含符号信息)。如果您有源代码,请告诉编译器(或链接器)生成一个
map
文件。map文件将包含符号及其地址。在map文件中搜索
main
@ThomasMatthews:OP显然使用的是Microsoft的编译器/链接器,默认情况下不会使用嵌入符号信息。它生成程序数据库文件(PDB)。这与在调试模式(甚至不存在)下编译无关。如果您正在学习RE,并且您期望“目标”去掉调试信息并进行优化,就这样了。入口点和猜猜游戏。如果目标至少是由某个常用编译器+使用的常用入口初始值设定项构建的,那么您可能可以将其与将收集的已知初始值集进行比较,这样您就可以快速找到最终的
调用main
指令。(我认为(不确定),实际上输入代码超出了优化过程,因此它将针对特定版本的编译器进行修复)。