文章目录
正文
有一个问题,比如在游戏里
这些东西放到数组里肯定是不行的,因为数组要求数据类型是一样的
但是结构体,想存多少存多少,想存多少字节存多少个
struct AA
{
int 生命;
int 魔法;
int 技能;
.
.
.
int 移动速度;
char name[0x20];//十个中文
}
int AA char double
是等级的,int用在哪AA就可以在哪,AA只是我定义新的一个东西,上述的代码也是定义
基址:全局变量
偏移:血值的
AA y;
y //所有的人物信息
+4//魔法,y最开始对应生命
+4//技能
AA与int平级,但是里面如果都是int的话,那我们AA里面可不可以在弄一个
struct Point
{
float x;
float y;
float z;
char name[0x20];//十个中文
}
struct AA
{
int 生命;
int 魔法;
int 技能;
Point 坐标;
.
.
.
int 移动速度;
char name[0x20];//十个中文
}
比如我们得到一个地址
AA gamer 【0x41234567】
生命 +4
魔法 +8
技能 +c
坐标 +10
//+4 x
//+8 y
//+c z
上面的偏移,是一级偏移,注释掉的就是二级偏移
除了自己以外,可以用任何东西,就比如AA里面不能用AA,定义结构体struct不会分配内存空间的,什么时候分配内存空间:比如
这个时候,x就分配了4个字节,y不分配空间,在调用函数的时候才给y分配在ebp-4
给结构体分配空间比如:st x;
才会给分配空间
定义各种类型的结构体
给结构体赋值
给函数取出来,这里printf是变参函数,想写多少个都可以
打印结果:10 20 30 1 2 3 4
在x.a = 10;
处下断点
function反汇编:
我们看到,这里的地址都写死了,就直接给写出来了,全局变量一开始编译的时候都分好了,数组的反汇编就是等宽连续的,数组和结构体不同就是数组是等宽的,但如果结构体中都是等宽的,逆向可以成数组,只要明白其思想就行了
前面讲,返回值16位放ax,32位放eax,64位放eax+edx(win32),但这个结构体可以定义100字节,那这个怎么传?
反汇编:
这个时候,如果只看反汇编,不能看到它是不是结构体,只知道三个局部变量,但是如果不是同一个类型就可以看出来如果
反汇编
而下面这个是int类型的结构体,定义在局部变量
分的空间一样的,但是结构体此时和数组一样,都是从上往下分配的
如果是这样写的话,把结构体当作参数
这么一大堆怎么存进去?那就来分析,首先提升栈顶,ecx为6,就是执行某个指令6次,后面取ebp-18的地址,因为提升堆栈提升18,然后令edi为esp,读入6次到edi里面,这样就完成了传入参数的过程
把结构体当作返回值
这里注意到,平时我们用的时候,返回值存到eax里,堆栈里面就都变成垃圾了,所以不影响返回值传递,但是这里就有个矛盾,那么大一堆,不可能放到寄存器啊
复制到返回值
之前都是一大部分都放到一个地方,此处同理
如图,先将eax = ebp-30,然后再push eax,调用函数前编译器就考虑到这个是一大堆
看到有将eax = 0xcccccccc的,eax被覆盖,但是丢了不要紧,因为这里ebp+8就是eax那个值,因为之前push eax,后面就把ebp+8的值给了eax,ecx = ebp - 10然后ecx的值给到eax的地址,后面也是一样,分别到eax+4,eax+8.。。。里面了