从逆向工程的角度来看C++ (二) C++ 之 友元关系
(二) C++ 之 友元关系
来CPP代码:
代码:
#include "stdafx.h"
#include <iostream>
struct X;
struct Y
{
void f(X*);
};
struct X
{
private:
int i;
public:
void initialize();
friend void g(X*,int);
friend void Y::f(X*);
friend struct Z;
friend void h();
};
void X::initialize(){i=0;}
void g(X* x,int i){x->i = i;}
void Y::f(X* x){x->i = 9;}
struct Z
{
private:
int j;
public:
void initialize();
void g(X*);
};
void Z::initialize(){j = 8;}
void Z::g(X* x)
{
x->i += this->j;
}
void h(){X x;x.i = 4 ;}
int main(int argc, char* argv[])
{
X x; Y y; Z z;
__asm int 3
printf("sizeof X , Y , Z : %d %d %d\n",sizeof(x),sizeof(y),sizeof(z));
z.g(&x);
return 0;
}
////看反汇编 (Debug版本的)
00401409 6A 04 push 4
0040140B 6A 01 push 1 ; 还是注意,奇异抽象结构长度在此为1
0040140D 6A 04 push 4
0040140F 68 1C104300 push Lesson2.0043101C ; ASCII "sizeof X , Y , Z : %d %d %d",LF
00401414 E8 47700000 call Lesson2.printf
00401419 83C4 10 add esp,10
0040141C 8D45 FC lea eax,dword ptr ss:[ebp-4]
0040141F 50 push eax
00401420 8D4D F4 lea ecx,dword ptr ss:[ebp-C] ; 进入类成员函数之前,ecx传this指针是主旋律
00401423 E8 E2FBFFFF call Lesson2.0040100A
00401428 33C0 xor eax,eax
0040142A 5F pop edi
0040142B 5E pop esi
0040142C 5B pop ebx
0040142D 83C4 4C add esp,4C
00401430 3BEC cmp ebp,esp
00401432 E8 C96E0000 call Lesson2._chkesp
00401437 8BE5 mov esp,ebp
00401439 5D pop ebp
0040143A C3 retn
////下面也是Debug版本才有的,看看当前模块有什么函数一清二楚了.
00401005 /E9 26030000 jmp Lesson2.Z::initialize
0040100A |E9 61030000 jmp Lesson2.Z::g
0040100F |E9 AC030000 jmp Lesson2.h
00401014 |E9 77040000 jmp Lesson2.std::ctype<unsigned short>::>
00401019 |E9 12050000 jmp Lesson2.std::ctype<unsigned short>::>
0040101E |E9 CD030000 jmp Lesson2.main
00401023 |E9 98020000 jmp Lesson2.g
00401028 |E9 53020000 jmp Lesson2.X::initialize
0040102D |E9 BE020000 jmp Lesson2.Y::f
////
00401370 > 55 push ebp
00401371 8BEC mov ebp,esp
00401373 83EC 44 sub esp,44
00401376 53 push ebx
00401377 56 push esi
00401378 57 push edi
00401379 51 push ecx
0040137A 8D7D BC lea edi,dword ptr ss:[ebp-44]
0040137D B9 11000000 mov ecx,11
00401382 B8 CCCCCCCC mov eax,CCCCCCCC
00401387 F3:AB rep stos dword ptr es:[edi] ; 填充一下, 以后这些简单的就不说了.
00401389 59 pop ecx
0040138A 894D FC mov dword ptr ss:[ebp-4],ecx ; 第一个局部变量放this指针
0040138D 8B45 08 mov eax,dword ptr ss:[ebp+8] ; 传进来的x的地址
00401390 8B08 mov ecx,dword ptr ds:[eax] ; x.i 成员
00401392 8B55 FC mov edx,dword ptr ss:[ebp-4] ; this放到edx中
00401395 030A add ecx,dword ptr ds:[edx] ; ecx += this.j
00401397 8B45 08 mov eax,dword ptr ss:[ebp+8] ; 传进来的x的地址, 执行了2遍
0040139A 8908 mov dword ptr ds:[eax],ecx ; 完成赋值了,.
0040139C 5F pop edi
0040139D 5E pop esi
0040139E 5B pop ebx
0040139F 8BE5 mov esp,ebp
004013A1 5D pop ebp
004013A2 C2 0400 retn 4
再来看一下Release版本的:
////
00401097 6A 04 push 4
00401099 6A 01 push 1
0040109B 6A 04 push 4
0040109D 68 A0D04000 push Lesson2.0040D0A0 ; ASCII "sizeof X , Y , Z : %d %d %d",LF
004010A2 E8 B82A0000 call Lesson2.00403B5F
004010A7 83C4 10 add esp,10
004010AA 8D45 FC lea eax,dword ptr ss:[ebp-4]
004010AD 8D4D F8 lea ecx,dword ptr ss:[ebp-8]
004010B0 50 push eax
004010B1 E8 CAFFFFFF call Lesson2.00401080
004010B6 33C0 xor eax,eax
004010B8 8BE5 mov esp,ebp
004010BA 5D pop ebp
004010BB C3 retn
////省了jmp 了. Release版本的就是简洁啊.
00401080 8B4424 04 mov eax,dword ptr ss:[esp+4]
00401084 8B09 mov ecx,dword ptr ds:[ecx]
00401086 0108 add dword ptr ds:[eax],ecx
00401088 C2 0400 retn 4
小结
C++ 的友元其实对于逆向来说没有多大价值它更多的是为了编译器服务的, 是与信息封装相反的一种思想它是作用于C++的编译器的, 友元的关键字friend 其实跟 extern 一样只是一个声明, 定义一个符号而已。
对于最终的 exe,还是 ecx 传 this 指针是主旋律。还有就是一个类的多个成员函数编译器其实也是把它当成普通的函数去编译而已,是一样的。只不过去调用一个对象的成员函数的时候,会先传 ecx 进去,然后在函数内部便于定位各数据成员。
识别二维码
打开新世界