C语言代码逆向基础-结构体与类

C语言代码逆向基础-结构体与类

对象的内存布局

对象中先定义的数据成员再低地址处,后定义的数据成员再高地址处。

一般情况下,对象长度=sizeof(数据成员1)+…+sizeof(数据成员)

但仍有三种情况:空类、内存对齐、静态数据成员

空类

空类中没有任何成员数据,但需要实例化,所以为1字节

内存对齐

数据成员是根据再类或结构体中的顺序来一次申请内存空间的,由于数据类型不同,占用内存空间不同,实际对齐值q=min(M,N),M为数据成员长度,N为指定对齐值,其成员地址安排再q的倍数上。VC++6.0默认对齐值为8。

静态数据成员

与静态局部变量类似,存放的位置和全局变量一致。再作用域之外不可见,同类对象将共同享用静态数据成员的空间。

this指针

this属于指针变量,再32位环境下占4字节,保存的是数据地址信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
class test{
public:
void setnumber(int number)
{
nint = number;
}
public:
int nint;
};

void main()
{
test a;
a.setnumber(5);
printf("test: %d \r\n",a.nint);
}

main()反汇编关键代码如下,取出test的首地址存入ecx,然后调用setnumber()中m_nint的数据存入eax中。

setnumber()函数关键反汇编代码如下,这里的eax保存的是对象的首地址,即this指针,然后将地址传递给[ebp-4]地址处,取出地址保存在eax中,取出参数中的数据保存再ecx中,最后将ecx的数据保存再对象首地址,即对nint进行赋值。

在成员函数中访问数据成员通过this指针间接访问的。this指针关键点是在函数过程中使用了ecx作为第一个参数,在ecx中保存对象首地址。

对象作为函数参数

对象作为函数的参数时,先将对象中的所有数据进行备份,然后将复制的数据作为形参传递到调用函数中使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
class test{
public:
int none;
int ntwo;
};

void setnumber(test a)
{
printf("%d %d\r\n",a.none,a.ntwo);
}

void main()
{
test b;
b.none=1;
b.ntwo=2;
setnumber(b);

}

main()关键代码如下

将对象的两个成员变量一次压栈(按照先定义的数据成员最后压栈,后定义的数据先压栈),他们除了数据相同外,与对象中的两个数据成员没有关系。

对象作为返回值

对象作为返回值时,进入函数之前将申请返回对象使用的栈空间,在退出函数时,将返回对象中的数据复制到临时的栈空间中,以这个临时栈空间的首地址作为返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<stdio.h>
class test{
public:
int number;
int array[5];
};
test gettest()
{
test a;
a.number = 0;
for(int i=0;i<5;i++)
{
a.array[i] = i+1;
}
return a;
}

void main()
{
test b;
b = gettest();
printf("%d %d %d\r\n",b.number,b.array[0],b.array[4]);
}

获取返回对象的栈空间首地址,然后将对象的首地址压入栈中,用于保存返回对象的数据。

在函数调用结束后进行了数据复制,将局部对象的数据复制到这个返回对象的空间中,再将这个返回的对象复制给目标对象。

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2021-2024 John Doe
  • 访问人数: | 浏览次数:

让我给大家分享喜悦吧!

微信