吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 256|回复: 6
上一主题 下一主题
收起左侧

[C&C++ 原创] 浅析结构体的内存存储形式

[复制链接]
跳转到指定楼层
楼主
stribik 发表于 2024-11-15 19:58 回帖奖励
本帖最后由 stribik 于 2024-11-16 15:18 编辑

从一个简单demo来说说c里面的结构体构成(其实c++也差不多),然后顺便了解一下他在内存中的存储形式。
【看了下,汇编部分的理解可能错的很多,欢迎下面一起讨论】

这里的这个小demo仅仅用来分析,不存在攻击点。

demo代码:

```java
#include <stdio.h>

// 定义学生结构体
struct Student {
    char name[50];  // 姓名
    int id;         // 学号
};

int main() {
    int n;

    // 输入要处理的学生数量
    printf("请输入要输入的学生数量: ");
    scanf("%d", &n);

    // 创建一个学生结构体数组,用于存储多个学生的信息
    struct Student students[n];

    // 输入每个学生的姓名和学号
    for (int i = 0; i < n; i++) {
        printf("\n请输入第 %d 个学生的信息:\n", i + 1);
        printf("姓名: ");
        scanf("%s", students.name);
        printf("学号: ");
        scanf("%d", &students.id);
    }

    // 输出所有学生的信息
    printf("\n所有学生的信息:\n");
    for (int i = 0; i < n; i++) {
        printf("学生 %d - 姓名: %s, 学号: %d\n", i + 1, students.name, students.id);
    }

    return 0;
}

```

编译选项:

```java
gcc struct.c -o struct
```

简单解释一下代码逻辑:

在一开始实现了结构体中每一项的创建,然后可以读入对应的结构体的具体信息

先看到伪代码:

![]()

两边可以非常明显的看到我们的伪代码还是非常不一样的...

红框部分就是我们的两次输入,所以也就比较耗堪我们这个玩意。大概就是使用一个全局的变量来实现结构体的表示,然后使用一个数组实现内存中的读入(其实这里大概也就看得出来)

开启动态调试,其实栈里面重要的还是这个:

(进行第一次读入操作)

![]()

(第二次读入)

![]()

看读玩之后完整的栈:

![]()

看看两个对应的:

![]()

至于这个偏移量怎么来的。这里主要要满足两个点:1)结构体本身要对齐 2)每一个结构体元素有自己的空间。(我也没想明白,真要追究原因还是伪代码中的v11[56]这里开始,这个56其实还是好理解的,这个就是结构体整体对齐的方式导致的50+2(填充)+4(int对象))

同时我们也可以看到,在d630的位置其实已经写下了我们的数组的位置,相当用这个方式变相的实现了地址的访问。(比较像指针的实现了)

接下来我们可以结合汇编的代码简单的看一下(我也不完全懂,先来一个自己胡编的解释版本了)



第一部分:初始化【初始化结构还有循环,其实这样说不太对,但是我们的主要目的是为了研究结构体,就放一起了】

![]()

先看到第一段用来读的,

重点看到红框部分:

```java
.text:00000000000011E7 lea rax, [rbp+var_54]
.text:00000000000011EB mov rsi, rax
.text:00000000000011EE lea rax, unk_202C
.text:00000000000011F5 mov rdi, rax
.text:00000000000011F8 mov eax, 0
.text:00000000000011FD call ___isoc99_scanf
```

+ `lea rax, [rbp+var_54]`:计算局部变量 `var_54` 的地址,并将其加载到 `rax` 中。
+ `mov rsi, rax`:将 `rax` 的值存储到 `rsi` 中,作为 `scanf` 函数的第二个参数。
+ `lea rax, unk_202C`:将未知数据的地址 `unk_202C` 加载到 `rax` 中。
+ `mov rdi, rax`:将 `rax` 的值存储到 `rdi` 中,作为 `scanf` 函数的第一个参数。
+ `mov eax, 0`:清空 `eax` 寄存器。
+ `call ___isoc99_scanf`:调用 `scanf` 函数进行输入

这里记两个点:scanf的第一个参数(unk_202C),这个偏向于是一个标记字符,格式化字符;第二个参数([rbp+var_54],这个变相从rax最后传到了rsi上面,所以对应的第二个参数)

主要还是格式化字符串读数据,不重要

接下来我们继续看第二段:

```java
mov     ecx, [rbp+var_54]
.text:0000000000001205                 movsxd  rax, ecx
.text:0000000000001208                 sub     rax, 1
.text:000000000000120C                 mov     [rbp+var_48], rax
.text:0000000000001210                 movsxd  rax, ecx
.text:0000000000001213                 mov     r14, rax
.text:0000000000001216                 mov     r15d, 0
.text:000000000000121C                 imul    rdx, r15, 1C0h
.text:0000000000001223                 imul    rax, r14, 0
.text:0000000000001227                 lea     rsi, [rdx+rax]
.text:000000000000122B                 mov     eax, 1C0h
.text:0000000000001230                 mul     r14
.text:0000000000001233                 add     rsi, rdx
.text:0000000000001236                 mov     rdx, rsi
.text:0000000000001239                 movsxd  rdx, ecx
.text:000000000000123C                 mov     rax, rdx
.text:000000000000123F                 shl     rax, 3
.text:0000000000001243                 sub     rax, rdx
.text:0000000000001246                 shl     rax, 3
.text:000000000000124A                 movsxd  rax, ecx
.text:000000000000124D                 mov     r12, rax
.text:0000000000001250                 mov     r13d, 0
.text:0000000000001256                 imul    rdx, r13, 1C0h
.text:000000000000125D                 imul    rax, r12, 0
.text:0000000000001261                 lea     rsi, [rdx+rax]
.text:0000000000001265                 mov     eax, 1C0h
.text:000000000000126A                 mul     r12
.text:000000000000126D                 add     rsi, rdx
.text:0000000000001270                 mov     rdx, rsi
.text:0000000000001273                 movsxd  rdx, ecx
.text:0000000000001276                 mov     rax, rdx
.text:0000000000001279                 shl     rax, 3
.text:000000000000127D                 sub     rax, rdx
.text:0000000000001280                 shl     rax, 3
.text:0000000000001284                 mov     rdx, rax
.text:0000000000001287                 mov     eax, 10h
.text:000000000000128C                 sub     rax, 1
.text:0000000000001290                 add     rax, rdx
.text:0000000000001293                 mov     edi, 10h
.text:0000000000001298                 mov     edx, 0
.text:000000000000129D                 div     rdi
.text:00000000000012A0                 imul    rax, 10h
.text:00000000000012A4                 mov     rcx, rax
.text:00000000000012A7                 and     rcx, 0FFFFFFFFFFFFF000h
.text:00000000000012AE                 mov     rdx, rsp
.text:00000000000012B1                 sub     rdx, rcx
```

这个就主要是为了处理结构体中的数据的初始化,以我薄弱的汇编知识简单解释一下这个:

![]()

存var_48,变相加载我们的var_54(所以我觉得这个var_54用来定位了我们栈帧中存入数据的位置),初始化其他寄存器

> 顺便简单说一下这个1C0怎么来的:
>
> 还记得我们前面所说的结构体整体大小的计算吗?1C0=56*8,这个是符合我们前面所说的整体的大小的
>

![]()

位移实现数组定位(相当于我们找地址中的一个大的位置)

![]()

唯一实现数组元素定位(相当于在定位小的门牌号)

![]()

继续结构体的计算...

![]()

这段最最主要的目的是为了实现结构体整体的对齐。

mov eax, 1C0h 这里相当于一个结构体块的大小,然后往后就是在对齐栈、对齐结构体本身(调整偏移量)

movsxd rdx, ecx  这里可能存了数组的偏移量,后续就是大概计算数组的偏移量,然后调整对齐对齐对齐...

到这里为止初始化完成了...[就是最最外面对应的for循环部分的初始化QAQ,这里实际上还没涉及我们的结构体正式部分]

这里我首先还原了IDA中的结构体部分并重命名了数据信息:

![]()

然后重点看到后面:

![]()



第二部分:结构体的读入

这个红框才是我们正式结构体的部分:

```java
text:0000000000001314 ; ---------------------------------------------------------------------------
.text:0000000000001314
.text:0000000000001314 loc_1314:                               ; CODE XREF: main+225↓j
.text:0000000000001314                 mov     eax, [rbp+var_50]
.text:0000000000001317                 add     eax, 1
.text:000000000000131A                 mov     esi, eax
.text:000000000000131C                 lea     rax, asc_2030   ; "\n"
.text:0000000000001323                 mov     rdi, rax        ; format
.text:0000000000001326                 mov     eax, 0
.text:000000000000132B                 call    _printf
.text:0000000000001330                 lea     rax, asc_2056   ; "姓名: "
.text:0000000000001337                 mov     rdi, rax        ; format
.text:000000000000133A                 mov     eax, 0
.text:000000000000133F                 call    _printf
.text:0000000000001344                 mov     eax, [rbp+var_50]
.text:0000000000001347                 movsxd  rdx, eax
.text:000000000000134A                 mov     rax, rdx
.text:000000000000134D                 shl     rax, 3
.text:0000000000001351                 sub     rax, rdx
.text:0000000000001354                 shl     rax, 3
.text:0000000000001358                 mov     rdx, [rbp+var_40]
.text:000000000000135C                 add     rax, rdx
.text:000000000000135F                 mov     rsi, rax
.text:0000000000001362                 lea     rax, Student
.text:0000000000001369                 mov     rdi, rax
.text:000000000000136C                 mov     eax, 0
.text:0000000000001371                 call    ___isoc99_scanf
.text:0000000000001376                 lea     rax, Student.name+3
.text:000000000000137D                 mov     rdi, rax        ; format
.text:0000000000001380                 mov     eax, 0
.text:0000000000001385                 call    _printf
.text:000000000000138A                 mov     eax, [rbp+var_50]
.text:000000000000138D                 movsxd  rdx, eax
.text:0000000000001390                 mov     rax, rdx
.text:0000000000001393                 shl     rax, 3
.text:0000000000001397                 sub     rax, rdx
.text:000000000000139A                 shl     rax, 3
.text:000000000000139E                 lea     rdx, [rax+30h]
.text:00000000000013A2                 mov     rax, [rbp+var_40]
.text:00000000000013A6                 add     rax, rdx
.text:00000000000013A9                 add     rax, 4
.text:00000000000013AD                 mov     rsi, rax
.text:00000000000013B0                 lea     rax, cnt
.text:00000000000013B7                 mov     rdi, rax
.text:00000000000013BA                 mov     eax, 0
.text:00000000000013BF                 call    ___isoc99_scanf
.text:00000000000013C4                 add     [rbp+var_50], 1
.text:00000000000013C8
.text:00000000000013C8 loc_13C8:                               ; CODE XREF: main+166↑j
.text:00000000000013C8                 mov     eax, [rbp+var_54]
.text:00000000000013CB                 cmp     [rbp+var_50], eax
.text:00000000000013CE                 jl      loc_1314
.text:00000000000013D4                 lea     rax, Student.name+0Ch
.text:00000000000013DB                 mov     rdi, rax        ; s
.text:00000000000013DE                 call    _puts
.text:00000000000013E3                 mov     [rbp+var_4C], 0
.text:00000000000013EA                 jmp     short loc_144E
```



最后简单说一下:

![]()

这里大概就是在实现定位,找到对应的地方并写进去

![]()

rdi、rsi实现参数传入

![]()

实现逻辑和上面差不多,先一段格式化字符串输出,然后rdi、rsi实现数据读入。



然后就是实现循环执行....

基本就没有了。所以说从上面大概也看到得到,整个过程大概是什么样子的,总结就是不要想的太复杂,然后感觉unk开头的就比较像我们结构体的标识元素。本质上还是有点像一个大的tag标记结构体位置,通过内部偏移确定元素的位置(比如var_50这种,利用这种形式确定的内部位置),所以某种意义上结构体内部应该也是线性分布的(但其实也不影响,动态调试看得出来)

在一个要注意的点就是结构体的大小怎么来的。


【最后md图床识别不了QAQ,丢一个写好的pdf文档。但是错误挺多的,我也觉得没什么必要下载来看....检查页面源码可以看到对应的图片链接,详情在评论区顶置也说了,不过多赘述了QAQ
结构体的理解.zip (557.14 KB, 下载次数: 1)













发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 4#
 楼主| stribik 发表于 2024-11-16 14:22 |楼主
哎,我也不知道为什么这里图片链接的形式显示不出来,其实图片没有那么那么影响...真的需要这里可以查看网页源代码 【view-source:https://www.52pojie.cn/thread-1982267-1-1.html】
对应的<p><p>部分有图片的链接,实在实在觉得麻烦可以直接看pdf...本人水平也就这样QAQ,别骂我呜呜呜。有错误欢迎指正一起学习,只能说本质上其实也就不要想的太复杂。以上...
7#
苏紫方璇 发表于 2024-11-16 16:31
stribik 发表于 2024-11-16 16:07
原来如此...用的是某md软件自带的网站图源,估计防盗链搬了...(晚点我试着传github看看那边图片托管行不 ...

图片也可以传到论坛上的
可以参考这个
https://www.52pojie.cn/forum.php ... ;page=1#pid51478900
6#
 楼主| stribik 发表于 2024-11-16 16:07 |楼主
苏紫方璇 发表于 2024-11-16 15:30
你这个图片应该是防盗链的问题,f12网络可以看到图片返回403

原来如此...用的是某md软件自带的网站图源,估计防盗链搬了...(晚点我试着传github看看那边图片托管行不行)感谢大佬解答

点评

图片也可以传到论坛上的 可以参考这个 https://www.52pojie.cn/forum.php?mod=viewthread&tid=717627&page=1#pid51478900  详情 回复 发表于 2024-11-16 16:31
5#
苏紫方璇 发表于 2024-11-16 15:30
你这个图片应该是防盗链的问题,f12网络可以看到图片返回403
3#
 楼主| stribik 发表于 2024-11-16 13:36 |楼主
zixiangcode 发表于 2024-11-16 09:15
是我的问题吗?文章好像有点显示不全哎?

欸QAQ,好像我的图床崩掉了QAQ,走的是图床连接的形式,但是好像图床没有显示出来...我晚点看看怎么改QAQ
沙发
zixiangcode 发表于 2024-11-16 09:15
是我的问题吗?文章好像有点显示不全哎?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 09:48

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表