一、传参方法对比
1. 32位程序
- 系统调用 (Linux)
使用int 0x80
指令触发系统调用
寄存器传参顺序:
eax = 系统调用号
ebx = 第1个参数
ecx = 第2个参数
edx = 第3个参数
esi = 第4个参数
edi = 第5个参数
- 普通函数调用 (C语言)
栈传递参数:参数从右向左压栈
调用者负责清理栈空间(如cdecl
约定)
示例汇编:
push arg3 ; 最后1个参数先压栈
push arg2
push arg1
call function
add esp, 12 ; 清理栈
2. 64位程序
-
系统调用 (Linux)
-
使用
syscall
指令触发系统调用 -
寄存器传参顺序:
rax = 系统调用号 rdi = 第1个参数 rsi = 第2个参数 rdx = 第3个参数 r10 = 第4个参数 r8 = 第5个参数 r9 = 第6个参数
-
-
普通函数调用 (System V AMD64 ABI)
-
寄存器+栈传递:前6个参数通过寄存器传递,后续参数压栈
-
寄存器顺序:
rdi = 第1个参数 rsi = 第2个参数 rdx = 第3个参数 rcx = 第4个参数 r8 = 第5个参数 r9 = 第6个参数
-
调用时需对齐栈到16字节边界
-
-
Windows x64调用约定
-
前4个参数:
rcx, rdx, r8, r9
-
需预留32字节"影子空间"(Shadow Space)
-
二、虚拟机调试工具命令
1. GDB 常用命令
命令 | 作用 |
---|---|
info registers |
查看所有寄存器值 |
print $rax |
查看特定寄存器值 |
disas |
反汇编当前函数 |
x/10x $rsp |
查看栈顶10个十六进制值 |
x/s 0x404000 |
查看地址0x404000处的字符串 |
break *0x401000 |
在地址0x401000设置断点 |
stepi (si ) |
单步执行一条指令 |
2. 高级调试技巧
-
查看内存布局:
cat /proc/[pid]/maps # Linux查看进程内存映射 vmmap [pid] # macOS查看内存布局
-
动态跟踪参数传递:
strace -e trace=execve ./program # 跟踪系统调用 ltrace ./program # 跟踪库函数调用
三、虚拟机调试环境配置
1. 跨架构调试(如ARM程序)
# 使用qemu模拟其他架构
qemu-arm -g 1234 ./program_arm # 启动ARM程序并监听调试端口
# GDB连接
gdb-multiarch
(gdb) target remote :1234
2. 典型问题排查流程
-
使用
checksec
检查程序保护机制 -
在关键函数/系统调用处设置断点
-
单步跟踪观察寄存器变化
-
结合反汇编分析参数传递路径
-
修改寄存器值测试漏洞利用(如
set $rip=0x401000
)
四、示例对比
32位 vs 64位 write系统调用
; 32位: 输出 "Hello" (4字节写)
mov eax, 4 ; sys_write
mov ebx, 1 ; fd=1(stdout)
mov ecx, msg ; 字符串地址
mov edx, 5 ; 长度
int 0x80
; 64位: 相同功能
mov rax, 1 ; sys_write
mov rdi, 1 ; fd
mov rsi, msg
mov rdx, 5
syscall
时光匆匆,一篇博客又到了结尾处啦。真心感谢每一位愿意花时间阅读我文字的朋友,希望你们每天都过得开开心心的,生活顺顺利利哦,咱们下次再通过文字'相遇'呀。