逆向基础2. C语言数据结构的汇编结构

C语言数据结构的汇编结构

局部变量的分配和访问

1
2
3
4
5
6
7
8
9
10
long long var()
{
char a = 0x1;
short b = 0x10;
int c = 0x11;
long d = 0x100;
long long e = 0x101;

return a + b + c + d + e;
}

已剔除保护代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sub    rsp, 0x20                      ; 分配空间
mov byte ptr [rsp], 0x1 ; byte
mov eax, 0x10
mov word ptr [rsp + 0x4], ax ; short
mov dword ptr [rsp + 0x8], 0x11 ; int
mov dword ptr [rsp + 0xc], 0x100 ; long
mov qword ptr [rsp + 0x10], 0x101 ; long long

movsx eax, byte ptr [rsp] ; a
movsx ecx, word ptr [rsp + 0x4] ; b
mov edx, dword ptr [rsp + 0x8] ; c
add edx, eax
mov eax, edx
add ecx, eax
mov eax, ecx
add eax, dword ptr [rsp + 0xc] ; d
cdqe
add rax, qword ptr [rsp + 0x10] ; e
add rsp, 0x20
pop rdi
ret

可得到局部变量分配的结构如下:

类型偏移栈大小汇编

byte

0

4

byte ptr

short

4

4

word ptr

int

8

4

dword ptr

long

c

4

dword ptr

long long

10

8

qword ptr

访问也是根据栈来的

结构体的分配和访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
typedef struct {
char a;
short b;
int c;
long d;
long long e;
} my_struct;

long long struct_foo()
{
my_struct s = {};
s.a = 0x1;
s.b = 0x10;
s.c = 0x11;
s.d = 0x100;
s.e = 0x101;

return s.a + s.b + s.c + s.d + s.e;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
push   rdi
sub rsp, 0x50 ; 分配栈空间
lea rdi, [rsp + 0x20]

; 初始化栈空间
mov ecx, 0xc
mov eax, 0xcccccccc
rep stosd dword ptr es:[rdi], eax

; rdi = rsp + 0x28, 循环24(0x18)次, 写入byte 0, 初始化结构体
lea rax, [rsp + 0x28]
mov rdi, rax
xor eax, eax
mov ecx, 0x18
rep stosb byte ptr es:[rdi], al

; 给结构体内数据进行赋值
mov byte ptr [rsp + 0x28], 0x1 ; a
mov eax, 0x10
mov word ptr [rsp + 0x2a], ax ; 0x2a = 0x28 + 0x2 (长2)
mov dword ptr [rsp + 0x2c], 0x11 ; 0x2c = 0x28 + 0x4 (长4)
mov dword ptr [rsp + 0x30], 0x100 ; 0x30 = 0x28 + 0x8 (长8)
mov qword ptr [rsp + 0x38], 0x101 ; 0x38 = 0x28 + 0x10 (长8)

; 将数据相加在一起
movsx eax, byte ptr [rsp + 0x28]
movsx ecx, word ptr [rsp + 0x2a]
mov edx, dword ptr [rsp + 0x2c]
add edx, eax
mov eax, edx
add ecx, eax
mov eax, ecx
add eax, dword ptr [rsp + 0x30]
cdqe
add rax, qword ptr [rsp + 0x38]

可得到结构体分配的结构如下:

类型偏移对齐后大小

byte

28

2

short

2a

2

int

2c

4

long

30

8

long long

38

8

结构体指针的数据访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <cstdlib>

typedef struct {
char a;
short b;
int c;
long d;
long long e;
} my_struct;


long long struct_foo_(my_struct *s)
{
s->a = 0x1;
s->b = 0x10;
s->c = 0x11;
s->d = 0x100;
s->e = 0x101;
return s->a + s->b + s->c + s->d + s->e;
}

int main()
{
auto *s = (my_struct *) malloc(sizeof(my_struct));
struct_foo_(s);
free(s);
return 0;
}

指针的传递

1
2
mov    rcx, qword ptr [rsp + 0x20]
call 0x140001276 ; 将结构体指针通过rcx传递给函数

汇编:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
struct_foo_(my_struct *):
; 将结构体指针传递到 rsp+0x8 位置
mov qword ptr [rsp + 0x8], rcx
push rdi

; a = 0x1, 由于push rdi, 偏移变成了 0x8 + 0x8 = 0x10
; 此时[rsp + 0x10]放的是结构体指针
mov rax, qword ptr [rsp + 0x10]
mov byte ptr [rax], 0x1

; b = 0x10, rcx = rsp + 0x10, 再加0x2得到b地址
mov eax, 0x10
mov rcx, qword ptr [rsp + 0x10]
mov word ptr [rcx + 0x2], ax
mov rax, qword ptr [rsp + 0x10]

; c = 0x11
mov dword ptr [rax + 0x4], 0x11
mov rax, qword ptr [rsp + 0x10]

; d = 0x100
mov dword ptr [rax + 0x8], 0x100
mov rax, qword ptr [rsp + 0x10]

; e = 0x101
mov qword ptr [rax + 0x10], 0x101

; 计算
mov rax, qword ptr [rsp + 0x10]
movsx eax, byte ptr [rax]
mov rcx, qword ptr [rsp + 0x10]
movsx ecx, word ptr [rcx + 0x2]
add eax, ecx
mov rcx, qword ptr [rsp + 0x10]
add eax, dword ptr [rcx + 0x4]
mov rcx, qword ptr [rsp + 0x10]
add eax, dword ptr [rcx + 0x8]
cdqe
mov rcx, qword ptr [rsp + 0x10]
add rax, qword ptr [rcx + 0x10]
pop rdi
ret

逆向基础2. C语言数据结构的汇编结构
https://simonkimi.githubio.io/2024/07/27/逆向基础2-C语言数据结构的汇编结构/
作者
simonkimi
发布于
2024年7月27日
许可协议