汇编
- 打印寄存器的值:
i register
- 打印所有寄存器的值:
i all-registers
- 打印单个寄存器的值
i registers regname 或
p $regname”
- 修改寄存器的值
例子
1 2 3 4 5 6 7 8 9 10
| #include <stdio.h> int main(void) { int a =0;
a++; a++; printf("%d\n", a); return 0; }
|
PC寄存器会存储程序下一条要执行的指令,通过修改这个寄存器的值,可以达到改变程序执行流程的目的。上面的程序会输出“a=2”,下面介绍一下如何通过修改PC寄存器的值,改变程序执行流程。
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
| 4 int a =0; (gdb) disassemble main Dump of assembler code for function main: 0x08050921 <main+0>: push %ebp 0x08050922 <main+1>: mov %esp,%ebp 0x08050924 <main+3>: sub $0x8,%esp 0x08050927 <main+6>: and $0xfffffff0,%esp 0x0805092a <main+9>: mov $0x0,%eax 0x0805092f <main+14>: add $0xf,%eax 0x08050932 <main+17>: add $0xf,%eax 0x08050935 <main+20>: shr $0x4,%eax 0x08050938 <main+23>: shl $0x4,%eax 0x0805093b <main+26>: sub %eax,%esp 0x0805093d <main+28>: movl $0x0,-0x4(%ebp) 0x08050944 <main+35>: lea -0x4(%ebp),%eax 0x08050947 <main+38>: incl (%eax) 0x08050949 <main+40>: lea -0x4(%ebp),%eax 0x0805094c <main+43>: incl (%eax) 0x0805094e <main+45>: sub $0x8,%esp 0x08050951 <main+48>: pushl -0x4(%ebp) 0x08050954 <main+51>: push $0x80509b4 0x08050959 <main+56>: call 0x80507cc <printf@plt> 0x0805095e <main+61>: add $0x10,%esp 0x08050961 <main+64>: mov $0x0,%eax 0x08050966 <main+69>: leave 0x08050967 <main+70>: ret End of assembler dump. (gdb) info line 6 Line 6 of "a.c" starts at address 0x8050944 <main+35> and ends at 0x8050949 <main+40>. (gdb) info line 7 Line 7 of "a.c" starts at address 0x8050949 <main+40> and ends at 0x805094e <main+45>.
|
通过“info line 6”和“info line 7”命令可以知道两条“a++;”语句的汇编指令起始地址分别是0x8050944和0x8050949。
1 2 3 4 5
| (gdb) n 6 a++; (gdb) p $pc $3 = (void (*)()) 0x8050944 <main+35> (gdb) set var $pc=0x08050949
|
当程序要执行第一条“a++;”语句时,打印pc寄存器的值,看到pc寄存器的值为0x8050944,与“info line 6”命令得到的一致。接下来,把pc寄存器的值改为0x8050949,也就是通过“info line 7”命令得到的第二条“a++;”语句的起始地址。
1 2 3 4 5
| (gdb) n 8 printf("a=%d\n", a); (gdb) a=1 9 return 0;
|
接下来执行,可以看到程序输出“a=1”,也就是跳过了第一条“a++;”语句。