利用gdb在汇编指令级调试C程序

来源:互联网 发布:lol登不进去网络异常 编辑:程序博客网 时间:2024/04/29 20:59

关于GDB调试C程序的常用命令与手段就不多说了,这里主要介绍一下如何对C程序做到汇编指令级别的调试。
首先是获取汇编代码,这可以通过disassemble命令或x命令或类似的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[root@localhost test]# gdb ./a.out -q
(gdb) list
1   #include<stdio.h>
2   #include<malloc.h>
3
4   int callee(int a, int b, int c, int d, int e)
5   {
6       return 1;
7   }
8
9   int main(){
10      callee(1,2,3,4,5);
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400463 <main+0>:  push   %rbp
0x0000000000400464 <main+1>:  mov    %rsp,%rbp
0x0000000000400467 <main+4>:  mov    $0x5,%r8d
0x000000000040046d <main+10>: mov    $0x4,%ecx
0x0000000000400472 <main+15>: mov    $0x3,%edx
0x0000000000400477 <main+20>: mov    $0x2,%esi
0x000000000040047c <main+25>: mov    $0x1,%edi
0x0000000000400481 <main+30>: callq  0x400448 <callee>
0x0000000000400486 <main+35>: mov    $0x2,%eax
0x000000000040048b <main+40>: leaveq
0x000000000040048c <main+41>: retq
End of assembler dump.
(gdb) x/10i main
0x400463 <main>:  push   %rbp
0x400464 <main+1>:    mov    %rsp,%rbp
0x400467 <main+4>:    mov    $0x5,%r8d
0x40046d <main+10>:   mov    $0x4,%ecx
0x400472 <main+15>:   mov    $0x3,%edx
0x400477 <main+20>:   mov    $0x2,%esi
0x40047c <main+25>:   mov    $0x1,%edi
0x400481 <main+30>:   callq  0x400448 <callee>
0x400486 <main+35>:   mov    $0x2,%eax
0x40048b <main+40>:   leaveq
(gdb)

接着,利用display命令自动显示当前正要执行的汇编指令,display命令可以在每次程序暂停时自动打印指定变量的值。而我们要显示的汇编指令在ip寄存器内(当然,ip寄存器内存储的是机器码),我们可以看看(先得把程序执行起来):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
(gdb) b main
Breakpoint 1 at 0x400467: file t3.5.c, line 10.
(gdb) r
Starting program: /root/test/a.out 
 
Breakpoint 1, main () at t3.5.c:10
10      callee(1,2,3,4,5);
(gdb) info reg
rax            0x3cd2153a60 261222644320
rbx            0x3cd101bbc0 261204589504
rcx            0x4004a0 4195488
rdx            0x7fffc5f6fa38   140736514685496
rsi            0x7fffc5f6fa28   140736514685480
rdi            0x1  1
rbp            0x7fffc5f6f940   0x7fffc5f6f940
rsp            0x7fffc5f6f940   0x7fffc5f6f940
r8             0x3cd21522d0 261222638288
r9             0x3cd0e0d620 261202433568
r10            0x0  0
r11            0x3cd1e1d8a0 261219276960
r12            0x0  0
r13            0x7fffc5f6fa20   140736514685472
r14            0x0  0
r15            0x0  0
rip            0x400467 0x400467 <main+4>
eflags         0x246    [ PF ZF IF ]
cs             0x33 51
ss             0x2b 43
ds             0x0  0
es             0x0  0
fs             0x0  0
gs             0x0  0
fctrl          0x37f    895
fstat          0x0  0
ftag           0xffff   65535
fiseg          0x0  0
fioff          0x0  0
foseg          0x0  0
fooff          0x0  0
fop            0x0  0
mxcsr          0x1f80   [ IM DM ZM OM UM PM ]
(gdb)

看汇编指令:

1
2
3
4
5
(gdb) p $rip
$2 = (void(*)()) 0x400467 <main+4>
(gdb) x/i $rip
0x400467 <main+4>:    mov    $0x5,%r8d
(gdb)

我们还可以利用一个名为pc的gdb内部变量:

1
2
3
4
5
(gdb) p $pc
$3 = (void(*)()) 0x400467 <main+4>
(gdb) x/i $pc
0x400467 <main+4>:    mov    $0x5,%r8d
(gdb)

结合display命令和寄存器或pc内部变量,我们做如下设置:

1
2
3
4
(gdb) display /i $pc
1: x/i $pc
0x400467 <main+4>:    mov    $0x5,%r8d
(gdb)

或同时显示多条汇编,比如3条:

1
2
3
4
5
6
7
8
9
10
11
12
13
(gdb) display /3i $pc
(gdb) b main
Breakpoint 1 at 0x400467: file t3.5.c, line 10.
(gdb) r
Starting program: /root/test/a.out 
 
Breakpoint 1, main () at t3.5.c:10
10      callee(1,2,3,4,5);
1: x/3i $pc
0x400467 <main+4>:    mov    $0x5,%r8d
0x40046d <main+10>:   mov    $0x4,%ecx
0x400472 <main+15>:   mov    $0x3,%edx
(gdb)

接下来,利用ni(nexti)或si(stepi)命令进行汇编指令级的调试,如下所示可以看到参数是如何传递的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(gdb) display /i $pc
1: x/i $pc
0x400467 <main+4>:    mov    $0x5,%r8d
(gdb) ni
0x000000000040046d  10      callee(1,2,3,4,5);
1: x/i $pc
0x40046d <main+10>:   mov    $0x4,%ecx
(gdb) ni
0x0000000000400472  10      callee(1,2,3,4,5);
1: x/i $pc
0x400472 <main+15>:   mov    $0x3,%edx
(gdb) ni
0x0000000000400477  10      callee(1,2,3,4,5);
1: x/i $pc
0x400477 <main+20>:   mov    $0x2,%esi
(gdb) ni
0x000000000040047c  10      callee(1,2,3,4,5);
1: x/i $pc
0x40047c <main+25>:   mov    $0x1,%edi
(gdb)

更简单直接的方法是利用layout显示汇编代码窗口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
(gdb) help layout
Change the layout of windows.
Usage: layout prev | next | <layout_name>
Layout names are:
   src   : Displays source and command windows.
   asm   : Displays disassembly and command windows.
   split : Displays source, disassembly and command windows.
   regs  : Displays registerwindow. If existing layout
           is source/command or assembly/command, the
           registerwindow is displayed. If the
           source/assembly/command (split) is displayed,
           theregisterwindow is displayed with
           the window that has current logical focus.
 
(gdb) layout asm   lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
   x0x400463 <main>                 push   %rbp                                                x
   x0x400464 <main+1>               mov    %rsp,%rbp                                           x
   x0x400467 <main+4>               mov    $0x5,%r8d                                           x
   x0x40046d <main+10>              mov    $0x4,%ecx                                           x
   x0x400472 <main+15>              mov    $0x3,%edx                                           x
   x0x400477 <main+20>              mov    $0x2,%esi                                           x
   x0x40047c <main+25>              mov    $0x1,%edi                                           x
   x0x400481 <main+30>              callq  0x400448 <callee>                                   x
   x0x400486 <main+35>              mov    $0x2,%eax                                           x
   x0x40048b <main+40>              leaveq                                                     x
   x0x40048c <main+41>              retq                                                       x
   x0x40048d                        nop                                                        x
   x0x40048e                        nop                                                        x
   x0x40048f                        nop                                                        x
   x0x400490 <__libc_csu_fini>      repz retq                                                  x
   x0x400492                        nopl   0x0(%rax)                                           x
   x0x400499                        nopl   0x0(%rax)                                           x
   x0x4004a0 <__libc_csu_init>      mov    %r12,-0x20(%rsp)                                    x
   x0x4004a5 <__libc_csu_init+5>    mov    %r13,-0x18(%rsp)                                    x
   x0x4004aa <__libc_csu_init+10>   lea    0x2001bb(%rip),%r12        # 0x60066c               x
   x0x4004b1 <__libc_csu_init+17>   mov    %r14,-0x10(%rsp)                                    x
   x0x4004b6 <__libc_csu_init+22>   mov    %r15,-0x8(%rsp)                                     x
   x0x4004bb <__libc_csu_init+27>   mov    %rsi,%r14                                           x
   x0x4004be <__libc_csu_init+30>   mov    %rbx,-0x30(%rsp)                                    x
   x0x4004c3 <__libc_csu_init+35>   mov    %rbp,-0x28(%rsp)                                    x
   x0x4004c8 <__libc_csu_init+40>   sub    $0x38,%rsp                                          x
 mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
exec No process In:                                                           Line: ??   PC: 0x0
(gdb)

如果是7.0版本以上的gdb,那么还有一个方法显示汇编:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[root@localhost gdb-7.4.1]# ./gdb/gdb -version | grep "(GDB)"
GNU gdb (GDB) 7.4.1
[root@localhost gdb-7.4.1]# ./gdb/gdb ~/test/a.out
GNU gdb (GDB) 7.4.1
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is freesoftware: you are freeto change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and"show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/test/a.out...done.
(gdb) set disassemble-next-line on
(gdb) b main
Breakpoint 1 at 0x400467: file t3.5.c, line 10.
(gdb) r
Starting program: /root/test/a.out
 
Breakpoint 1, main () at t3.5.c:10
10      callee(1,2,3,4,5);
=> 0x0000000000400467 <main+4>:    41 b8 05 00 00 00   mov    $0x5,%r8d
   0x000000000040046d <main+10>:  b9 04 00 00 00  mov    $0x4,%ecx
   0x0000000000400472 <main+15>:  ba 03 00 00 00  mov    $0x3,%edx
   0x0000000000400477 <main+20>:  be 02 00 00 00  mov    $0x2,%esi
   0x000000000040047c <main+25>:  bf 01 00 00 00  mov    $0x1,%edi
   0x0000000000400481 <main+30>:  e8 c2 ff ff ff  callq  0x400448 <callee>
(gdb) ni
0x000000000040046d  10      callee(1,2,3,4,5);
   0x0000000000400467 <main+4>:   41 b8 05 00 00 00   mov    $0x5,%r8d
=> 0x000000000040046d <main+10>:   b9 04 00 00 00  mov    $0x4,%ecx
   0x0000000000400472 <main+15>:  ba 03 00 00 00  mov    $0x3,%edx
   0x0000000000400477 <main+20>:  be 02 00 00 00  mov    $0x2,%esi
   0x000000000040047c <main+25>:  bf 01 00 00 00  mov    $0x1,%edi
   0x0000000000400481 <main+30>:  e8 c2 ff ff ff  callq  0x400448 <callee>
(gdb)

另外,7.0版本以上gdb的disas命令可以携带/m参数,让汇编与c源码同时显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) disas /m main
Dump of assembler code forfunction main:
9  intmain(){
   0x0000000000400463 <+0>:   push   %rbp
   0x0000000000400464 <+1>:   mov    %rsp,%rbp
 
10      callee(1,2,3,4,5);
   0x0000000000400467 <+4>:   mov    $0x5,%r8d
   0x000000000040046d <+10>:  mov    $0x4,%ecx
   0x0000000000400472 <+15>:  mov    $0x3,%edx
   0x0000000000400477 <+20>:  mov    $0x2,%esi
   0x000000000040047c <+25>:  mov    $0x1,%edi
   0x0000000000400481 <+30>:  callq  0x400448 <callee>
 
11     return2;
   0x0000000000400486 <+35>:  mov    $0x2,%eax
 
12  }
   0x000000000040048b <+40>:  leaveq
   0x000000000040048c <+41>:  retq  
 
End of assembler dump.
(gdb)

转载请保留地址:http://lenky.info/2012/05/30/%e5%88%a9%e7%94%a8gdb%e5%9c%a8%e6%b1%87%e7%bc%96%e6%8c%87%e4%bb%a4%e7%ba%a7%e8%b0%83%e8%af%95c%e7%a8%8b%e5%ba%8f/或 http://lenky.info/?p=1694


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来信讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

0 0
原创粉丝点击