x86_64汇编调试程序初步

2018-12-24 10:18:29 浏览数 (1)

寄存器说明:

代码语言: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解决方案》。

0 人点赞