• 使用gdb进行写操作


    使用gdb调试程序,读写操作是很普遍的事情。其中,读操作包括:

    • 读取某个变量的值
    • 读取某个内存地址里的内容
    • 读取某个寄存器的值

    对应地,写操作包括:

    • 修改某个变量的值
    • 修改某个内存地址里的内容
    • 修改某个寄存器的值

    本文将首先简单介绍一下读操作,然后重点介绍一下写操作。

    1. 读操作

    • 读取某个变量的值: p <var>
    • 读取某个内存地址里的内容: x /NFU <memaddr>
    • 读取某个寄存器的值: info r <register>

    2. 写操作

    先上个例子// foo.c

     1 #include <stdio.h>
     2 
     3 typedef enum {false, true} bool;
     4 
     5 static bool g_verbose = 0;
     6 
     7 static void
     8 dump(int a[], int n)
     9 {
    10         for (int i = 0; i < n; i++)
    11                 printf("%-2d ", a[i]);
    12         printf("
    ");
    13 }
    14 
    15 int main(int argc, char *argv[])
    16 {
    17         int a[] = {0x1, 0x2, 0x3, 0x4, 0x5};
    18         int n = sizeof(a) / sizeof(int);
    19 
    20         if (g_verbose) {
    21                 printf("Now dump a[] ...
    ");
    22                 dump(a, n);
    23         }
    24 
    25         int m = 0;
    26         for (int i = 0; i < n; i++)
    27                 m += a[i];
    28 
    29         return m;
    30 }

    在上面的代码中,第5行我们定义了一个变量g_verbose, 其值为false。现在,我们将通过gdb在第20行将其修改为true,给出三种方法,贯穿了修改变量的值,修改内存地址内容和修改寄存器。

    2.1 修改某个变量的值

    set var <name> = <value>

    e.g.

    $ gcc -g -Wall -std=c99 -o foo foo.c
    
    $ gdb foo
    GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1
    ...<snip>.......................................................................
    (gdb) l main
    11                      printf("%-2d ", a[i]);
    12              printf("
    ");
    13      }
    14
    15      int main(int argc, char *argv[])
    16      {
    17              int a[] = {0x1, 0x2, 0x3, 0x4, 0x5};
    18              int n = sizeof(a) / sizeof(int);
    19
    20              if (g_verbose) {
    (gdb) b 20
    Breakpoint 1 at 0x8048500: file foo.c, line 20.
    (gdb) r
    Starting program: /tmp/foo
    
    Breakpoint 1, main (argc=1, argv=0xbffff054) at foo.c:20
    20              if (g_verbose) {
    (gdb) p g_verbose
    $1 = false
    (gdb) set var g_verbose = true
    (gdb) p g_verbose
    $2 = true
    (gdb) c
    Continuing.
    Now dump a[] ...
    1  2  3  4  5
    [Inferior 1 (process 5544) exited with code 017]
    (gdb)

    2.2 修改某个内存地址里的内容

    set *(unsigned char      *)<memaddr> = <value>  ; write 1 byte
    set *(unsigned short     *)<memaddr> = <value>  ; write 2 bytes
    set *(unsigned int       *)<memaddr> = <value>  ; write 4 bytes
    set *(unsigned long long *)<memaddr> = <value>  ; write 8 bytes
    
    or
    
    set *(char      *)<memaddr> = <value>           ; write 1 byte
    set *(short     *)<memaddr> = <value>           ; write 2 bytes
    set *(int       *)<memaddr> = <value>           ; write 4 bytes
    set *(long long *)<memaddr> = <value>           ; write 8 bytes

    e.g.

    $ gdb foo
    GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1
    ...<snip>.......................................................................
    (gdb) l main
    11                      printf("%-2d ", a[i]);
    12              printf("
    ");
    13      }
    14
    15      int main(int argc, char *argv[])
    16      {
    17              int a[] = {0x1, 0x2, 0x3, 0x4, 0x5};
    18              int n = sizeof(a) / sizeof(int);
    19
    20              if (g_verbose) {
    (gdb)
    21                      printf("Now dump a[] ...
    ");
    22                      dump(a, n);
    23              }
    24
    25              int m = 0;
    26              for (int i = 0; i < n; i++)
    27                      m += a[i];
    28
    29              return m;
    30      }
    (gdb) b 20
    Breakpoint 1 at 0x8048500: file foo.c, line 20.
    (gdb) r
    Starting program: /tmp/foo
    
    Breakpoint 1, main (argc=1, argv=0xbffff054) at foo.c:20
    20              if (g_verbose) {
    (gdb) #
    (gdb)
    (gdb) p &g_verbose
    $1 = (bool *) 0x804a02c <g_verbose>
    (gdb) #
    (gdb)
    (gdb) x /x 0x804a02c
    0x804a02c <g_verbose>:  0x00000000
    (gdb) #
    (gdb)
    (gdb) set *(unsigned int *)0x804a02c = 0x1
    (gdb) #
    (gdb)
    (gdb) x /x 0x804a02c
    0x804a02c <g_verbose>:  0x00000001
    (gdb) #
    (gdb)
    (gdb) c
    Continuing.
    Now dump a[] ...
    1  2  3  4  5
    [Inferior 1 (process 5731) exited with code 017]
    (gdb) q

    2.3 修改某个寄存器的值

    set $<register> = <value>

    e.g.

    $ gdb foo
    GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1
    ...<snip>.......................................................................
    (gdb) display /i $eip
    (gdb) set disassembly-flavor intel
    (gdb) disas /m main
    Dump of assembler code for function main:
    16      {
       0x080484c7 <+0>:     push   ebp
       0x080484c8 <+1>:     mov    ebp,esp
       0x080484ca <+3>:     and    esp,0xfffffff0
       0x080484cd <+6>:     sub    esp,0x30
    
    17              int a[] = {0x1, 0x2, 0x3, 0x4, 0x5};
       0x080484d0 <+9>:     mov    DWORD PTR [esp+0x1c],0x1
       0x080484d8 <+17>:    mov    DWORD PTR [esp+0x20],0x2
       0x080484e0 <+25>:    mov    DWORD PTR [esp+0x24],0x3
       0x080484e8 <+33>:    mov    DWORD PTR [esp+0x28],0x4
       0x080484f0 <+41>:    mov    DWORD PTR [esp+0x2c],0x5
    
    18              int n = sizeof(a) / sizeof(int);
       0x080484f8 <+49>:    mov    DWORD PTR [esp+0x18],0x5
    
    19
    20              if (g_verbose) {
       0x08048500 <+57>:    mov    eax,ds:0x804a02c
       0x08048505 <+62>:    test   eax,eax
       0x08048507 <+64>:    je     0x8048529 <main+98>
    
    21                      printf("Now dump a[] ...
    ");
       0x08048509 <+66>:    mov    DWORD PTR [esp],0x80485f6
       0x08048510 <+73>:    call   0x8048340 <puts@plt>
    
    22                      dump(a, n);
       0x08048515 <+78>:    mov    eax,DWORD PTR [esp+0x18]
       0x08048519 <+82>:    mov    DWORD PTR [esp+0x4],eax
       0x0804851d <+86>:    lea    eax,[esp+0x1c]
       0x08048521 <+90>:    mov    DWORD PTR [esp],eax
       0x08048524 <+93>:    call   0x804847d <dump>
    23              }
    24
    25              int m = 0;
       0x08048529 <+98>:    mov    DWORD PTR [esp+0x10],0x0
    
    26              for (int i = 0; i < n; i++)
       0x08048531 <+106>:   mov    DWORD PTR [esp+0x14],0x0
       0x08048539 <+114>:   jmp    0x804854c <main+133>
       0x08048547 <+128>:   add    DWORD PTR [esp+0x14],0x1
       0x0804854c <+133>:   mov    eax,DWORD PTR [esp+0x14]
       0x08048550 <+137>:   cmp    eax,DWORD PTR [esp+0x18]
       0x08048554 <+141>:   jl     0x804853b <main+116>
    
    27                      m += a[i];
       0x0804853b <+116>:   mov    eax,DWORD PTR [esp+0x14]
       0x0804853f <+120>:   mov    eax,DWORD PTR [esp+eax*4+0x1c]
       0x08048543 <+124>:   add    DWORD PTR [esp+0x10],eax
    
    28
    29              return m;
       0x08048556 <+143>:   mov    eax,DWORD PTR [esp+0x10]
    
    30      }
       0x0804855a <+147>:   leave
       0x0804855b <+148>:   ret
    
    End of assembler dump.
    (gdb) b 20
    Breakpoint 1 at 0x8048500: file foo.c, line 20.
    (gdb) r
    Starting program: /tmp/foo
    
    Breakpoint 1, main (argc=1, argv=0xbffff054) at foo.c:20
    20              if (g_verbose) {
    1: x/i $eip
    => 0x8048500 <main+57>: mov    eax,ds:0x804a02c
    (gdb) #
    (gdb)
    (gdb) info r eax
    eax            0x1      1
    (gdb) ni
    0x08048505      20              if (g_verbose) {
    1: x/i $eip
    => 0x8048505 <main+62>: test   eax,eax
    (gdb) info r eax
    eax            0x0      0
    (gdb) #
    (gdb) set $eax = 0x1
    (gdb) #
    (gdb)
    (gdb) info r eax
    eax            0x1      1
    (gdb) c
    Continuing.
    Now dump a[] ...
    1  2  3  4  5
    [Inferior 1 (process 25323) exited with code 017]
    (gdb) q

    总结: 熟练掌握了gdb的读写操作,对于调试那种release版本的程序bug是相当有帮助的。最近两天,我在一个测试环境中调试一个跟子网掩码有关的bug。TNND可执行程序的符号表已经被删除,而且测试环境中不能clone源代码进行修改后编译(因为源代码保护)。幸运地是,还可以自己安装gdb。 有了gdb, 通过修改某个寄存器的值快速地把debug信息打印了出来,从而有效地缩小了bug存在的代码范围。一句话,gdb很好使,你值得拥有!

  • 相关阅读:
    大话设计模式学习笔记简单工厂 工厂 抽象工厂
    910月总序(update 1)
    虚表思考再探虚表布局
    深入浅出 (代码+图示)递归反转一个栈 lp 专题讲解
    算法导论笔记 二叉查找树问题
    叹 尽然把vs2008 crash!!
    关于二叉查找树的讨论+ 我的误解
    算法情景分析 二叉排序树 前驱+后缀 测试用列
    iBatis.NET中使用时间的注意事项
    JDK和JRE官方下载地址
  • 原文地址:https://www.cnblogs.com/idorax/p/7286870.html
Copyright © 2020-2023  润新知