使用GDB中修改特定寄存器值及其原理

使用GDB中修改特定寄存器值及其原理

最近重新学习了一下gdb的使用,以前我只是熟悉特定的命令。现在配合听课和ppt。对于functions载入内存的过程有了一定的了解,结合我前面写的assemble笔记中那个linux中程序的栈帧分配图,会达到一个很好的效果。click me

首先我们知道64bit的机器,寄存器数量大大增加,%rsp是栈指针 %rip是顺序执行的指令指针,准确的来讲就是将要执行的下一条指令(instruction)。%rbp是frame的基地址。了解了这些就具备了我们要debug 程序的基础。 以下面程序为例:

> #include #include int foo1(void) { int i_foo1=4,j_foo2=5; printf("foo1\n"); return 1; } int foo2(void) { printf("foo2\n"); return 1; } int main(int argc ,char **argv) { int i=0,j=1,k=2; foo1(); //printf("Hello\n"); return 0; } </code></pre> 这个程序里面,既有main的全局变量,也有局部的变量。 编译的时候我们要加入一些option gcc -g3 -o test test.c 这样可以方便我们调试。 PS:在调试过程中,我们经常遇到segment fault或者是page fault 。如果我们要查看特定的错误,使用ulimit -u 20000之后,发生错误的时候,我们就可以在这个source code下面生成core.XXX的文件。使用 gdb sourcecode core.XXX就可以进入gdb查看最后出现错误的代码! 假如我们已经生成了一个调试版本的可执行二进制文件。

[root@localhost dslab]# gdb test1
GNU gdb (GDB) Fedora (7.5.1-38.fc18)
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to 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-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/lzz/dslab/test1...done.
(gdb) b foo1
Breakpoint 1 at 0x400534: file test1.c, line 5.
(gdb) b foo2
Breakpoint 2 at 0x400557: file test1.c, line 11.
(gdb) b main
Breakpoint 3 at 0x400577: file test1.c, line 16.
(gdb) r
Starting program: /home/lzz/dslab/test1
 
Breakpoint 3, main (argc=1, argv=0x7fffffffe0e8) at test1.c:16
warning: Source file is more recent than executable.
16      int i=0,j=1,k=2;
Missing separate debuginfos, use: debuginfo-install glibc-2.16-34.fc18.x86_64
(gdb) disassemble
Dump of assembler code for function main:
   0x0000000000400568 <+0>:   push   %rbp
   0x0000000000400569 <+1>:   mov    %rsp,%rbp
   0x000000000040056c <+4>:   sub    $0x20,%rsp
   0x0000000000400570 <+8>:   mov    %edi,-0x14(%rbp)
   0x0000000000400573 <+11>:  mov    %rsi,-0x20(%rbp)
=> 0x0000000000400577 <+15>:   movl   $0x0,-0x4(%rbp)
   0x000000000040057e <+22>:  movl   $0x1,-0x8(%rbp)
   0x0000000000400585 <+29>:  movl   $0x2,-0xc(%rbp)
   0x000000000040058c <+36>:  callq  0x40052c
   0x0000000000400591 <+41>:  mov    $0x0,%eax
   0x0000000000400596 <+46>:  leaveq
   0x0000000000400597 <+47>:  retq
End of assembler dump.
(gdb)
首先我们要先明白几个命令b (break)就是在特定的funtion上加break断点。 然后我们使用 r (run)来运行程序。 使用disassemble 来查看当前的汇编代码。如果在后面加 funtion 显示的是funtion的汇编代码。 我们可以通过自己计算偏移量来修改寄存器的值,比如 0×0000000000400573 <+11>: mov %rsi,-0×20(%rbp)就是在%rbp的地址上减去-0×20个单位 有时候我们也要打印某些寄存器的制,可是进制可能不是我们想要的,这个时候,可以显示寄存器可以使用的格式 p/格式 变量 格式 说明 x 显示为十六进制 d 显示为十进制 u 显示为无符号十进制(unsigned) o 显示为八进制 下面我们来修改某个寄存器的值。 set *addr value 其中*addr可以是地址的解引用或者是特定的某个寄存器的值。 下面我们来使用gdb脚本来强制让程序执行特定的路径。> #include #include #include <sys/types.h> #include <sys/stat.h> #include #define FILE "/home/lzz/dslab/exercise/file" int main(int argc,char **argv) { int fd = 0 ; fd = open(FILE,O_CREAT,440); if(-1 == fd) { printf("open file error!\n"); } else { printf("open file success!\n"); } return 0; } </code></pre> 上面的程序正常运行的话会打印open file success的语句,我们把gdb中单步调式的语句写在一个shellscript里面,例如:

#!/bin.bash //filename : gdbscript.sh
file a.out //file后面要跟你调式的文件
break 11
run
set fd =-1
c
q
然后后执行 gdb -x gdbscript.sh .gdb就会自动化执行我们写在脚本里面的操作。 打印信息: