汇编逆向c语言项目,逆向知识第14课,(C语言的结尾)汇编中的结构表达

2-810-jpg_6-1080-0-0-1080.jpg

首先,了解结构是什么,并计算结构成员的值和总大小(类也是如此)

结构特征

1. 结构是由一系列相同或不同类型的数据组成的数据集

2. 在C语言中,struct是指数据结构,它是C语言中的一种聚合数据类型.

3. 可以将结构声明为变量,指针或数组等,以实现更复杂的数据结构. 结构也是元素的集合. 这些元素称为结构的成员,并且这些成员可以具有不同的类型. 通常按名称访问成员.

高级代码:

structTagList

{charch;intnumber1;short intnumber2;doubledbl;floatflt;

};

上面是一个简单的结构,然后介绍如何计算我们的结构在内存中的偏移量.

公式:

以下是原因,如果您不想看到它,可以跳至摘要以查看摘要.

成员补偿的公式

alg设alg为编译器的值,offset是结构的第一个地址的偏移量,从0开始.

成员偏移量%min(alg,sizeof(成员类型)== 0;该公式用于在结构的第一个地址处查找成员的偏移量

例如,要计算成员的flt位与结构的第一个地址之间的偏移量,我们必须首先从第一个成员进行计算

将alg对齐值设置为4

offset%min(4,sizeof(ch))== 0;

0%min(4,1)== 0结论是ch变量位于结构的第一个地址的偏移量为0处,占1个字节+0 1

offset%min(4,sizeof(number1))== 0

因为上面计算出ch的大小,它占用了1个字节,所以偏移量+1变成了1的位置

然后现在偏移量= 1,继续替换公式

1%min(4,4)== 0,不是,偏移继续++

2%min(4,4)== 0,不是,偏移继续++

.....

直到偏移量为4为止都满足,因此偏移量为4时,放置number1 + 4 4

计算数字2的偏移量

offset%min(4,sizeof(member type))== 0;

8%min(4,2)== 0,建立+8 2

计算dbl的位置

443931d9bc1fb2648f84ba46f40275f9.png

offset%min(4,sizeof(member type))== 0;

10%(4,8)== 0,不是真的

11%(4,8)== 0c 计算结构体大小,不是真的

12%(4,8)== 0;确定,所以在+12 8

计算浮点位置

offset%min(4,sizeof(member type))== 0;

20%min(4,4)== 0;正确+20 4

然后计算每个成员的偏移量.

float成员位从结构中偏移+20,并占用4个字节.

计算结构的总体尺寸

公式:

sizeof(struct)%min(最大字体大小,alg);

我们上面计算的结构大小为24个字节

MAX类型是结构中最大成员的数据类型大小,现在是两倍,即8个字节

alg是编译器对齐值,现在为4

所以用公式代替

24%4 == 6 ... 0

因此,总大小为24个字节.

摘要:

编译器对齐值设置为alg,MeMber偏移量从0开始计算,其中每次需要将成员偏移量替换为公式,再加上其自身成员占用的字节大小,继续参与下一个操作.

设置或查看VC6.0版本编译器的值项目->设置-> C / C ++->类别(类型)->代码生成(代码生成)->结构成员对齐(结构对齐值)<

结构成员偏移的计算公式: MeMber偏移%min(alg,sizeof(成员类型))== 0

用于计算结构总大小的公式: sizeof(struct)%min(最大类型大小,alg)== 0;

查看程序存储器.

25ed35b01f87ecb052e80fa5d1654e2e.png

根据内存窗口分配,您可以获取结构成语与结构之间的偏移量

第一个成员,偏移位置为+0,占1个字节

第二个成员,+ 4偏移位置,4个字节

e145e80157b387c645df498d28b7d83a.png

第三个成员+8偏移位置,占用2个字节

第四个成员+12个偏移位置,占8个字节

PS: 成员的成员偏移从零开始. 计算完成时,需要增加占用的字节大小,然后继续参与操作. 如果未建立操作,则偏移量会继续增加,直到建立偏移量为止.

例如:

例如,我们计算第二个会员位置的偏移量

公式:

成员偏移量%min(alg,sizeof(成员类型大小)== 0;

0%1 == 0 +0输入第一个成员

成员偏移=成员偏移+字节大小,(1)

寻求第二位成员的职位

1%4 == 0;当偏移量为1时,不正确,偏移量会继续增加

2%4 == 0,如果没有建立,则继续增加

3%4 == 0,如果没有建立,则继续增加

4%4 == 0;建立,因此在+4位置放4个字节,这是第二个成员位置.

二,当结构作为参数传递并且是指针时

void MyFun(struct TagList *pThis)

{

pThis->ch = 'b';

}int main(int argc, char*argv[])

{struct TagList text ={'a',1,2,3.14,0.0};

MyFun(&text);

printf("%d\r\n",text.number1);return 0;

}

在Debug下汇编代码

96ac1fce5ea3e6f7db0d2b05cd4b37db.png

生成寻址公式,其中eax是数组的第一个地址,ebp +8是参数,外部是结构的第一个地址,因此ebp +8是数组的第一个

所以ebp +8是结构的第一个地址

mov byte ptr [eax],这句话62h直接产生+0位置偏移,并且为内容分配了字符

mov ecx,[ebp + 8]

mov dword ptr [ecx +4],2这句话产生+4的偏移量分配2,因此可以确定

1. 结构第一个地址ebp + 8(参数1)

2. 结构+0的第一个成员的偏移量被分配了一个字符

3. 结构+4的第二个成员的偏移量分配为2

根据发布进行编译

f72f9d64cdbb960b82587aaef90b426b.png

1-810-jpg_6-1080-0-0-1080.jpg

当主函数调用结构地址时,只需要三行汇编

lea eax,[esp + 20h +Var_20]

push eax

call MyFun

以上是流水线的优化

看看MyFun内部

1971ff5f844bf0a2ccb9e46c64f97c85.png

结构类似于Debug

1. 获取结构的第一个地址

2. +0偏移位置分配字符

3. + 4偏移位置c 计算结构体大小,分配值为2

三,将结构作为参数传递时,就结构本身而言

高级代码:

void MyFun(struct TagList pThis)    //这个地方变了.不是指针了

{

pThis.ch= 'b';

pThis.number1= 2;

}int main(int argc, char*argv[])

{struct TagList text ={'a',1,2,3.14,0.0};

MyFun(text);//传参不用取地址了

printf("%d\r\n",text.number1);return 0;

}

在调试下进行组装

f7dbe73426a32cdf9dc7eb2be07bb825.png

传递参数之前的操作

很明显

1. 首先提起纸叠

2. 循环6次,每次4字节4字节复制

3. 获取结构的第一个地址

4. 将堆栈顶部分配给edi,这意味着从堆栈顶部进行复制.

5. 执行字符串操作指令,rep movsd将esi的内容复制到堆栈的顶部位置,

由于要复制24个字节,因此堆栈的顶部必须为+24,因此此部分是存储结构的成员.

在MyFun内部

e5b45b1c8515ebdb5ca3ba70f2004596.png

1. 传递参数后,esp的位置是数组的第一个地址,即+0 position的偏移量

2. 进入函数后按返回地址,然后堆栈esp -4,然后按ebp,继续esp -4

3.mov ebp,esp,保存寻址,当前的ebp + 8只是在外部进行字符串复制时结构的第一个地址.

4.mov字节ptr [ebp +8],62h,相当于为我们的结构成员分配+0个成员

a43eca1ce90dc9af6b450bde6d24f976.jpg

5.mov dword ptr [ebp + 0ch],2只是我们的第二个成员.

因此,为了解释这两行汇编代码,您需要查看在外部传递参数的堆栈环境.

9abbbbac0a76714d1408c705596b748b.png

根据发布进行编译

43b791bcb6edd54faa45e87bccc7135c.png

像调试一样,字符串复制也是必需的

MyFun内部功能

0546c8cadeea7b55f160d633ce65ce75.png

我发现我们没有使用它,因此我们直接对其进行了优化.

三,当函数返回值是结构时

1. 作为指针返回时,请将其直接放在eax中

返回值是结构的情况

三种情况

1. 当结构的大小小于(4个数量不确定)字节时,请使用eax直接返回

2. 当结构的大小小于(8个数量不确定)字节时,直接使用edx,eax返回

3. 如果结构的大小大于8个字节(不确定,取决于编译器).

最后一种高级代码:

structTagList MyFun()

{struct TagList text ={'a',1,2,3.0,4.0,

};returntext;

}int main(int argc, char*argv[])

{structTagList text;

text=MyFun();

printf("%c\r\n",text.ch);return 0;

}

在Debug下汇编代码

7dff3d64fa1111dfd9846dbb8d29319a.png

1. 我们的函数没有参数,但是Debug会生成上面的代码并传入,为什么?由于无法安装返回值eax等,因此请将该存储区域用作返回值

f67fc8445bc4217b042afa675ddcecb8.png

2. 在函数退出之前,它还将在其上执行字符串操作指令,因为它需要返回到该存储区,因此将其写入内存.

3. 返回值之前,第一个地址将保存到eax

4. 查看eax是否在外部使用,如果可以使用,则可以判断返回的对象是一个对象(当然,可以省略此步骤,但是上面的三个步骤和一个步骤都不是返回的对象)

参数问题:

默认情况下,它将为我们生成一个参数,然后,如果我们有一个参数,它将紧随其后.

发布的汇编代码是相同的.

转载于:

作者: IBinary

来源:

本文来自电脑杂谈,转载请注明本文网址:

http://www.pc-fly.com/a/jisuanjixue/article-244953-1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值