在汇编中查找 Main

Find Main in Assembly

我有简单的 C++ 程序:

#include <iostream>  
using namespace std;  
void main()  
{  
    cout << "Hello, world, from Visual C++!" << endl;  
}

使用以下命令编译:cl /EHsc hello.cpp

我想开始调试可执行文件,如何在调试器中找到这个main函数对应的汇编代码? (我正在使用 x64dbg)

入口点与 Main 函数不同。 我找到了主要功能,它离入口点不近,我有字符串,我很容易找到它。

是否有任何方法或规则或最佳实践来猜测 main 对应的汇编代码在哪里?

编辑:

我有源代码,但我只是在学习 RE。

一般不能。

当你编译一个程序时,你会得到一个二进制文件和(可选的)调试符号。

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

然而,更常见的情况是在您没有调试符号的二进制文件上找到 main 函数。在这种情况下,您不知道 main 函数在哪里,甚至不知道它是否存在。二进制文件可能不会使用入口点执行初始化然后调用 main(int argc, char *argv[], char *envp[]).

的常见 libc 做法

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

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

如果您调试自己的代码 - 在调试器下停止某处的最佳方式 - 使用下一个代码

if (IsDebuggerPresent()) __debugbreak();

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

如果您调试的不是自己的二进制代码 - 二进制代码根本不包含 c/c++ CRT 代码 - 所以问题变得毫无意义。然而,如果 CRT 代码存在,尽管有许多不同的实现 - 都使用通用模式并且经过一些练习 - 可能会在 CRT 代码调用 main 的地方找到。

如果标准 windows 二进制文件存在 pdb 个文件 - 这根本不是问题

虽然入口点通常不是在您的可执行文件中定义的 main,但这仅仅是因为编译器用一些初始化代码包装 main 是很常见的。

在大多数情况下,初始化代码非常相似,并且每个编译器都有少数几个版本之一。这些函数中的大多数都有一个 IDA FLIRT signature,用 IDA 打开二进制文件会自动为您定义一个 WinMainmain 等函数。您也可以为此使用 IDA 的免费(试用)版本。

如果不是这种情况,通过跟踪入口点函数内部一层深度的几次调用,从入口点到达 main 非常简单。 main 调用通常接近入口点函数的末尾。

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