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

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

局部变量的分配和访问

cpp

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;
}

已剔除保护代码

asm
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

访问也是根据栈来的

结构体的分配和访问

cpp
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;
}
asm
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

结构体指针的数据访问

cpp
#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;
}

指针的传递

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

汇编:

asm
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日
许可协议