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

C语言函数调用

1.简单调用

总览

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

1
2
3
4
5
6
7
8
9
10
11
12
#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);
}

其产生的汇编代码如下

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

1
2
3
push   rdi
....
pop rdi

参数传递

1
2
3
mov    edx, 0x2
mov ecx, 0x1
call 0x1400012c1 ; plus(int,int)

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

函数内处理

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
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.多参数调用

1
2
3
4
5
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;
}

调用方

1
2
3
4
5
6
7
8
9
10
11
12
13
; 将后面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

函数内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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日
许可协议