zoukankan      html  css  js  c++  java
  • x86_64汇编调试程序初步

    寄存器说明:

    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 指向栈顶

     

    观察参数传递,被调试的源代码如下:

    /* 01 */ #include <string.h>

    /* 02 */ #include <unistd.h>

    /* 03 */ void f(int a, const char* b) {

    /* 04 */     write(1234, b, strlen(b));

    /* 05 */ }

    /* 06 */ int main() {

    /* 07 */     f(2018, "hello ");

    /* 08 */     return 0;

    /* 09 */ }

     

    优化方式编译程序:

    g++ -g -O2 -o x x.cpp

     

    实践目标:

    gdb中让write改写到标准输出。

     

    设置两个观察点,一是main函数,二是write函数:

    (gdb) b main

    (gdb) b write

     

    运行程序:

    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, "hello ");

    (gdb) disassemble

    Dump of assembler code for function main():

       0x0000000000400550 <+0>:     sub    $0x8,%rsp

    => 0x0000000000400554 <+4>:     mov    $0x400710,%esi // 0x400710为第二个参数的地址

       0x0000000000400559 <+9>:     mov    $0x7e2,%edi // 0x7e2为第一个参数的值

       0x000000000040055e <+14>:    callq  0x400660 <f(int, char const*)>

       0x0000000000400563 <+19>:    xor    %eax,%eax

       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 <f(int, char const*)>

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

    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解决方案》。

     

  • 相关阅读:
    机器学习面试
    网易有道2017内推编程题2道
    老曹眼中的网络编程基础
    MySQL索引背后的数据结构及算法原理
    [oracle] oracle-ibatis-整理
    [oracle] oracle-myibatis-整理
    [mysql] mysql-myibatis-整理
    [JS] selector 背景选择器
    [android] AndroidManifest.xml 详解
    [Eclipse] 项目编码
  • 原文地址:https://www.cnblogs.com/aquester/p/10069923.html
Copyright © 2011-2022 走看看