逆向基础1. C语言函数调用

C语言函数调用

1.简单调用

总览

对于一个简单的C语言程序, 其代码如下

cpp
#include <iostream>

int plus(int a, int b)
{
    auto data = a + b;
    return data;
}
int main()
{
    auto data = plus(1, 2);
    printf("data: %d\n", data);
}

其产生的汇编代码如下

asm
main():
    push   rdi
    sub    rsp, 0x30
    mov    edx, 0x2
    mov    ecx, 0x1
    call   0x1400012c1                ; plus(int,int)
    mov    dword ptr [rsp + 0x20], eax
    mov    edx, dword ptr [rsp + 0x20]
    lea    rcx, [rip + 0x916c]
    call   0x1400012cb                ; printf
    nop
    xor    eax, eax
    add    rsp, 0x30
    pop    rdi
    ret
plus(int, int):
    plus(int,int):
    mov    dword ptr [rsp + 0x10], edx
    mov    dword ptr [rsp + 0x8], ecx
    push   rdi
    sub    rsp, 0x10
    mov    eax, dword ptr [rsp + 0x28]
    mov    ecx, dword ptr [rsp + 0x20]
    add    ecx, eax
    mov    eax, ecx
    mov    dword ptr [rsp], eax
    mov    eax, dword ptr [rsp]
    add    rsp, 0x10
    pop    rdi
    ret

函数调用分析

函数的环境保存
会将一些寄存器的值保存到栈中, 以便在函数调用结束后恢复, 一个push对应一个pop

asm
    push   rdi
    ....
    pop    rdi

参数传递

asm
    mov    edx, 0x2
    mov    ecx, 0x1
    call   0x1400012c1                ; plus(int,int)

将参数从右向左依次放入寄存器中, 然后调用函数
最后将返回值放入eax和栈中进行返回

函数内处理

asm
plus(int,int):
    ; 将参数保存到栈中
    mov    dword ptr [rsp + 0x10], edx
    mov    dword ptr [rsp + 0x8], ecx

    push   rdi  ; 保存环境
    sub    rsp, 0x10  ; 为局部变量分配空间

    ; 从栈中取出参数, 经历过一次push, 一次sub
    ; 0x28 = 0x10(初始偏移) + 0x8(push) + 0x10(sub)
    ; 0x20 = 0x8(初始偏移) + 0x8(push) + 0x10(sub)
    mov    eax, dword ptr [rsp + 0x28]
    mov    ecx, dword ptr [rsp + 0x20]

    ; 计算放入eax
    add    ecx, eax
    mov    eax, ecx

    ; 将结果保存到栈中
    mov    dword ptr [rsp], eax
    mov    eax, dword ptr [rsp]

    add    rsp, 0x10 ; 恢复栈
    pop    rdi  ; 恢复环境
    ret

2.多参数调用

cpp
int plus(int a, int b, int c, int d, int e, int f, int g, int h)
{
    auto data = a + b + c + d + e + f + g + h;
    return data;
}

调用方

asm

    ; 将后面4个参数放入栈中
    sub    rsp, 0x50
    mov    dword ptr [rsp + 0x38], 0x8
    mov    dword ptr [rsp + 0x30], 0x7
    mov    dword ptr [rsp + 0x28], 0x6
    mov    dword ptr [rsp + 0x20], 0x5

    ; 前4个参数放入寄存器
    mov    r9d, 0x4
    mov    r8d, 0x3
    mov    edx, 0x2
    mov    ecx, 0x1
    call   0x14000117c

函数内

asm
plus(int,int,int,int,int,int,int,int):
    ; 将寄存器内的值转移到栈中
    mov    dword ptr [rsp + 0x20], r9d
    mov    dword ptr [rsp + 0x18], r8d
    mov    dword ptr [rsp + 0x10], edx
    mov    dword ptr [rsp + 0x8], ecx
    push   rdi                              ; 保存环境
    sub    rsp, 0x10                        ; 局部变量分配空间
    mov    eax, dword ptr [rsp + 0x28]      ; 从栈中取出参数, 0x28 = 0x10(sub) + 0x8(push) + 0x10(初始偏移) = edx = 2
    mov    ecx, dword ptr [rsp + 0x20]
    add    ecx, eax
    mov    eax, ecx
    add    eax, dword ptr [rsp + 0x30]
    add    eax, dword ptr [rsp + 0x38]
    add    eax, dword ptr [rsp + 0x40]
    add    eax, dword ptr [rsp + 0x48]
    add    eax, dword ptr [rsp + 0x50]
    add    eax, dword ptr [rsp + 0x58]
    mov    dword ptr [rsp], eax
    mov    eax, dword ptr [rsp]
    add    rsp, 0x10
    pop    rdi
    ret

逆向基础1. C语言函数调用
https://simonkimi.githubio.io/2024/07/26/逆向基础1-C语言函数调用/
作者
simonkimi
发布于
2024年7月26日
许可协议