反汇编就是将机器指令翻译为汇编指令的过程,编译器在编译时会将高级语言降级并转换为对应的机器指令,反汇编就是将机器指令汇编的过程,通过阅读汇编代码,我们可以更好的理解程序逻辑,从而推测出程序运作机理,下面的案例将使用VS2013 Express版本的编译器进行编译.
c语言使用printf函数输出,printf函数的输出方式很好理解,反汇编后会发现代码不过就那么几句,而C++则不同,C++输出数据时,使用了一种流的输出方式,通常是调用 ostream 类里面的cin或者是cout,你可以把输入输出理解为小河流水,如下反汇编代码,先来观察一下输出格式的变化。
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
int number =100 ;
int age = 33;
std::cin >> number >> age;
std::cout << "number: " << number << "age: "<< age << std::endl;
system("pause");
return 0;
}
cin接收参数看起来是这样
00415ED4 | 8D4D F8 | lea ecx,dword ptr ss:[ebp-0x8] |
00415ED7 | 51 | push ecx |
00415ED8 | 8B0D A8004200 | mov ecx,dword ptr ds:[<&?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A>] | 获取cin地址
00415EDE | FF15 A4004200 | call dword ptr ds:[<&??5?$basic_istream@DU?$char_traits@D@std@@@std@@QAEAAV01@AAH@Z>] | 第一次cin接收参数
00415EE4 | 3BFC | cmp edi,esp |
00415EE6 | E8 53B4FFFF | call 0x41133E |
00415EEB | 8BC8 | mov ecx,eax |
00415EED | FF15 A4004200 | call dword ptr ds:[<&??5?$basic_istream@DU?$char_traits@D@std@@@std@@QAEAAV01@AAH@Z>] | 第二次cin接收参数
00415EF3 | 3BF4 | cmp esi,esp |
00415EF5 | E8 44B4FFFF | call 0x41133E |
cout打印参数也是如此。。
00415F12 | 68 84CC4100 | push consoleapplication2.41CC84 | 41CC84:"number: "
00415F17 | 8B15 AC004200 | mov edx,dword ptr ds:[<&?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A>] | 获取cout地址
00415F1D | 52 | push edx |
00415F1E | E8 94B3FFFF | call 0x4112B7 |
00415F23 | 83C4 08 | add esp,0x8 |
00415F26 | 8BC8 | mov ecx,eax |
00415F28 | FF15 98004200 | call dword ptr ds:[<&??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z>] | 输出第一个参数
00415F2E | 3BDC | cmp ebx,esp |
00415F30 | E8 09B4FFFF | call 0x41133E |
00415F35 | 50 | push eax |
00415F36 | E8 7CB3FFFF | call 0x4112B7 |
00415F3B | 83C4 08 | add esp,0x8 |
00415F3E | 8BC8 | mov ecx,eax |
00415F40 | FF15 98004200 | call dword ptr ds:[<&??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z>] | 输出第二个参数
00415F46 | 3BFC | cmp edi,esp |
00415F48 | E8 F1B3FFFF | call 0x41133E |
00415F4D | 8BC8 | mov ecx,eax |
00415F4F | FF15 94004200 | call dword ptr ds:[<&??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV0 | 结束cout
ida 也同样可识别出来。
在C语言中我们学习过结构体类型,其实C++中的类就是在结构体这个数据类型的基础上衍生出来的,两者之间的反汇编代码几乎一致,结构体和类都具有构造函数,析构函数和成员函数,但两者之间还是会有细微的不同,首先结构体的访问控制默认是Public,而类的访问控制是Private,这些属性是由编译器在编译的时候进行检查和确认的,一旦编译成功,程序在执行过程中就不会在访问控制方面做任何检查和限制了.
简单地定义一个类: 首先我们来定义一个Student
学生类,然后赋予不同的属性,最后调用内部的成员函数,观察其反汇编代码.
#include <iostream>
using namespace std;
class Student
{
public:
int number;
char *name;
private: void p_display()
{
std::cout << "name:" << name << std::endl;
}
public:void display()
{
p_display();
std::cout << "num: " << number << std::endl;
}
};
int main(int argc, char* argv[])
{
Student student;
student.number = 22;
student.name = "lyshark";
student.display();
system("pause");
return 0;
}
通过反汇编这段代码,你会发现其实类这个东西并不存在于汇编层面,因为所谓的面向对象其实都是编译器来帮你映射成相应的C语言代码,换句话说,其实并不存在面向对象,你所写的面向对象代码最终都会被编译器降级为C语言代码,然后C代码又会被降级为机器指令,而中间的转换过程都是由编译器来完成的,只不过面向对象更易于使用,但是其本质上还是C代码.
008E12A6 | 68 E0198E00 | push <class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl std::en | main.cpp:27
008E12AB | 51 | push ecx | ecx:&"ALLUSERSPROFILE=C:\\ProgramData"
008E12AC | 8B0D 54308E00 | mov ecx,dword ptr ds:[<&?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A>] | ecx:&"ALLUSERSPROFILE=C:\\ProgramData"
008E12B2 | BA BC318E00 | mov edx,consoleapplication2.8E31BC | 8E31BC:"name:"
008E12B7 | E8 E4040000 | call <class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl std::op |
008E12BC | BA CC318E00 | mov edx,consoleapplication2.8E31CC | 8E31CC:"lyshark"
008E12C1 | 8BC8 | mov ecx,eax | ecx:&"ALLUSERSPROFILE=C:\\ProgramData"
008E12C3 | E8 D8040000 | call <class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl std::op |
008E12C8 | 83C4 04 | add esp,0x4 |
008E12CB | 8BC8 | mov ecx,eax | ecx:&"ALLUSERSPROFILE=C:\\ProgramData"
008E12CD | FF15 5C308E00 | call dword ptr ds:[<&??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV0 |
008E12D3 | 8B0D 54308E00 | mov ecx,dword ptr ds:[<&?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A>] | ecx:&"ALLUSERSPROFILE=C:\\ProgramData"
008E12D9 | BA C4318E00 | mov edx,consoleapplication2.8E31C4 | 8E31C4:"num: "
008E12DE | 68 E0198E00 | push <class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl std::en |
008E12E3 | 6A 16 | push 0x16 |
008E12E5 | E8 B6040000 | call <class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl std::op |
008E12EA | 8BC8 | mov ecx,eax | ecx:&"ALLUSERSPROFILE=C:\\ProgramData"
008E12EC | FF15 34308E00 | call dword ptr ds:[<&??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z>] |
008E12F2 | 8BC8 | mov ecx,eax | ecx:&"ALLUSERSPROFILE=C:\\ProgramData"
008E12F4 | FF15 5C308E00 | call dword ptr ds:[<&??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV0 |
008E12FA | 68 D4318E00 | push consoleapplication2.8E31D4 | main.cpp:29, 8E31D4:"pause"==L"慰獵e"
008E12FF | FF15 E0308E00 | call dword ptr ds:[<&system>] |
008E1305 | 83C4 04 | add esp,0x4
IDA 的识别更能说明这一点。
未完待续.......
原文:https://www.cnblogs.com/LyShark/p/12771924.html