寄存器说明:
代码语言:javascript复制rdi 存第1个参数(值或地址)
rsi 存第2个参数
rdx 存第3个参数
rcx 存第4个参数
r8 存第5个参数
r9 存第6个参数
rax 第1个返回值
rdx 第2个返回值
rbx、rbp、r12、r13、r14、r15 用作数据存储,遵循被调用者使用规则,调用子函数之前需要先保存
r10、r11 用作数据存储,遵循调用者使用规则,使用之前需要先保存
rsp 指向栈顶
观察参数传递,被调试的源代码如下:
代码语言:javascript复制/* 01 */ #include
/* 02 */ #include
/* 03 */ void f(int a, const char* b) {
/* 04 */ write(1234, b, strlen(b));
/* 05 */ }
/* 06 */ int main() {
/* 07 */ f(2018, "hellon");
/* 08 */ return 0;
/* 09 */ }
优化方式编译程序:
代码语言:javascript复制g -g -O2 -o x x.cpp
实践目标:
在gdb中让write改写到标准输出。
设置两个观察点,一是main函数,二是write函数:
代码语言:javascript复制(gdb) b main
(gdb) b write
运行程序:
代码语言:javascript复制reakpoint 1, main () at x.cpp:6
6 /* 06 */ int main() {
Missing separate debuginfos, use: debuginfo-install glibc-2.17-196.tl2.3.x86_64 libgcc-4.8.5-4.el7.x86_64 libstdc -4.8.5-4.el7.x86_64
(gdb) n
7 /* 07 */ f(2018, "hellon");
(gdb) disassemble
Dump of assembler code for function main():
0x0000000000400550 < 0>: sub $0x8,%rsp
=> 0x0000000000400554 < 4>: mov $0x400710,%esi // 0x400710为第二个参数的地址
0x0000000000400559 < 9>: mov $0x7e2,�i // 0x7e2为第一个参数的值
0x000000000040055e < 14>: callq 0x400660 <f(int, char const*)>
0x0000000000400563 < 19>: xor �x,�x
0x0000000000400565 < 21>: add $0x8,%rsp
0x0000000000400569 < 25>: retq
End of assembler dump.
(gdb) p (char*)0x400710
$1 = 0x400710 "hello"
(gdb) p 0x7e2
$2 = 2018
(gdb) s
f (a=2018, b=0x400710 "hello") at x.cpp:3
3 /* 03 */ void f(int a, const char* b) {
(gdb) info reg
rax 0x400550 4195664
rbx 0x0 0
rcx 0x40 64
rdx 0x7fffffffe1a8 140737488347560
rsi 0x400710 4196112 // 第二个参数地址(4196112的十六进制为0x400710)
rdi 0x7e2 2018 // 第一个参数的值2018(2018的十六进制为0x7e2)
rbp 0x0 0x0
rsp 0x7fffffffe0a8 0x7fffffffe0a8
r8 0x7ffff75b5e80 140737343348352
r9 0x0 0
r10 0x7fffffffdd40 140737488346432
r11 0x7ffff7218b10 140737339558672
r12 0x40056c 4195692
r13 0x7fffffffe190 140737488347536
r14 0x0 0
r15 0x0 0
rip 0x400660 0x400660
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) c
Continuing.
Breakpoint 2, 0x00007ffff72e0840 in write () from /lib64/libc.so.6
(gdb) info reg
rax 0x5 5
rbx 0x0 0
rcx 0x10 16
rdx 0x5 5 // write的第三个参数值
rsi 0x400710 4196112 // write的第二个参数值
rdi 0x1234 4660 // write的第一个参数值
rbp 0x0 0x0
rsp 0x7fffffffe0a8 0x7fffffffe0a8
r8 0x7ffff75b5e80 140737343348352
r9 0x0 0
r10 0x7fffffffdc70 140737488346224
r11 0x7ffff72e0840 140737340377152
r12 0x40056c 4195692
r13 0x7fffffffe190 140737488347536
r14 0x0 0
r15 0x0 0
rip 0x7ffff72e0840 0x7ffff72e0840
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) p $rdi
$4 = 4660
(gdb) set $rdi=7777 // 修改寄存器rdi的值
(gdb) p $rdi
$6 = 7777
(gdb) set $rdi=1
(gdb) c
Continuing.
hello // 正常输出到了标准输出,如果不修改rdi的值,将看不到输出“hello”
[Inferior 1 (process 6722) exited normally]
掌握此基础,就可以用来修改无源代码的程序等,比如希望jstatd在指定的端口上监听,而不是一个值为0的随机端口号,请参见《防火墙内JVisualVM连接jstatd解决方案》。