C++的逆向工程

5
今天我决定使用IDA Pro反编译一个简单的用Visual C++编写的“Hello world”程序。根据我的先前知识,我确定在可执行入口点不会找到立即调用printf的代码,而我是正确的。我发现了很多不是由我编写的代码,并且是编译过程中编译器添加的代码。我希望更好地理解在编译过程中添加的代码。它是做什么的?有没有什么“技巧”可以快速查找“main”,并跳过所有不必要的反汇编生成的代码?我找到的最好的答案是在这篇文章中:http://www.codeproject.com/Articles/4210/C-Reverse-Disassembly,它说使用Visual C++编译的可执行文件的执行顺序如下:1. CrtlStartUp 2. main 3. CrtlCleanUp。请问我能否得到更详细的答案?

5
很依赖于编译器和平台。我怀疑你不会得到你想要的确切答案。 - Matt
1
我推荐这篇帖子作为任何想成为逆向工程大师的人的路线图。 - karlphillip
1
我没有逆向工程的经验,但你不能简单地在 main 函数开头设置一个调试器断点来获取相对地址吗?或者,可以在可执行文件的对象转储中查找 main 函数。 - bjhend
C++中的逆向工程?微软制作了C++虚拟机还是什么?您可以从平台的本地代码进行逆向工程,生成代码的工具并不重要。 - mip
2个回答

4
有很多C++标准所需的内容,你可能会遇到。
最重要的是,在调用main函数之前,需要处理主翻译单元中任何静态变量的构造,并且在main结束后需要处理它们的销毁的函数。此外,标准还要求提供一个名为atexit的函数,允许您注册在main返回后调用的其他函数。
因此,至少需要启动代码能够构建这个数据结构,其中包含将在从main返回时调用的函数。这是一种动态数据结构,因为程序需要在运行时添加它,并且调用顺序与注册相反(因此通常需要一个使添加易于步行的数据结构)。
但是,此外,标准要求在执行该翻译单元中的任何函数之前创建其他翻译单元中的静态变量。通常,编译器会简单地将所有内容排列在链接器中,以便在main之前全部调用,但这并非必需。那些执行不同操作的编译器需要提供到链接的其他翻译单元代码中的初始化例程的占位符,将在第一次函数调用时调用。
如果使用任何标准库,仅此就会有很多工作。请记住,std::cout是一个静态对象(静态生命周期,而不是静态链接 - 令人困惑的重载词)。这意味着要构建与您的控制台输出所需的任何API相对应的通信。标准中有许多这样的对象。
然后,可能还有特定于您的平台和/或编译器的内容,以某种有用的方式准备进程,解析环境变量,加载“标准”动态/共享库或类似的内容。
通常,退出只是遍历该列表并以某种方式将main的返回值提供给环境,因为大多数现代操作系统在自己清理之后。但是,除此之外可能还有特定于系统的内容。

2

现今的编译器创建了巨大的可执行文件,即使您找到入口点,也需要花费一些时间才能理解并找到您实际需要的部分。

对于您的hello world应用程序,您可以在函数列表对话框中使用IDA查找入口点(我不记得确切的名称)。但是,除非应用程序非常小,否则我不建议使用这种方法。

我正在使用的方法称为“自上而下的方法”(c)

我将从分析应用程序当前行为开始,而不涉及任何工具。这是一个非常重要的步骤,它将节省很多时间,因为您将知道您正在寻找什么以及何时发生。然后确定“薄弱点”,例如可以使用静态分析工具(IDA)找到的字符串、常量值。

下一步是反汇编应用程序,并查找这些“薄弱点”(IDA中的字符串模块),然后查找它们使用的功能的引用(您可以使用新版IDA中的图形层次结构视图)

如果您仍然无法了解它是如何工作的或者该代码被多处调用,您不知道需要哪一个。您可以从运行时分析开始,并使用调试器(softice? :))像ollydbg。这将向您显示静态分析中看不见的东西,例如:虚拟函数/函数指针,例如:调用EAX。

然后您只需逐步处理,直到找到所需内容为止。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接