选择地址来改变内存中的值

时间:2016-03-31 13:09:14

标签: gdb

关于SO的

This问题/答案显示了如何使用GDB来更改内存中的值,但在给出的示例中,它选择了一个地址来设置以前未使用的值

例如,要将返回值更改为22,作者

set {unsigned char}0x00000000004004b9 = 22

但是,为什么这个地址0x00000000004004b9会成为要更改的地址?如果查看disas/r的输出,地址0x00000000004004b9未被使用,那么为什么要使用此设置为22?我试图了解如何知道哪个地址需要更改(在此示例中)更改返回值,如果disas/r的输出未显示它。

代码

$ cat t.c
int main()
{
  return 42;
}

$ gcc t.c && ./a.out; echo $?
42

$ gdb --write -q  ./a.out
(gdb) disas/r main
Dump of assembler code for function main:
   0x00000000004004b4 <+0>:     55      push   %rbp
   0x00000000004004b5 <+1>:     48 89 e5        mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     b8 2a 00 00 00  mov    $0x2a,%eax
   0x00000000004004bd <+9>:     5d      pop    %rbp
   0x00000000004004be <+10>:    c3      retq   
End of assembler dump.
(gdb) set {unsigned char}0x00000000004004b9 = 22
(gdb) disas/r main
Dump of assembler code for function main:
   0x00000000004004b4 <+0>:     55      push   %rbp
   0x00000000004004b5 <+1>:     48 89 e5        mov    %rsp,%rbp
   0x00000000004004b8 <+4>:     b8 16 00 00 00  mov    $0x16,%eax  <<< ---changed
   0x00000000004004bd <+9>:     5d      pop    %rbp
   0x00000000004004be <+10>:    c3      retq   
End of assembler dump.
(gdb) q

$ ./a.out; echo $?
22    <<<--- Just as desired

1 个答案:

答案 0 :(得分:1)

  

我试图了解如何知道哪个地址需要更改(在本例中)更改返回值,如果disas / r的输出没有显示它。

要理解这一点,您需要了解instruction encoding。这里的指令是“立即移动32位常数到寄存器”。常量是指令的 part (这就是“立即”的含义)。编译它可能会有所帮助:

int foo() { return 0x41424344; }
int bar() { return 0x45464748; }
int main() { return foo() + bar(); }

当你编译它时,你应该看到类似的东西:

(gdb) disas/r foo
Dump of assembler code for function foo:
   0x00000000004004ed <+0>:     55      push   %rbp
   0x00000000004004ee <+1>:     48 89 e5        mov    %rsp,%rbp
   0x00000000004004f1 <+4>:     b8 44 43 42 41  mov    $0x41424344,%eax
   0x00000000004004f6 <+9>:     5d      pop    %rbp
   0x00000000004004f7 <+10>:    c3      retq   
End of assembler dump.
(gdb) disas/r bar
Dump of assembler code for function bar:
   0x00000000004004f8 <+0>:     55      push   %rbp
   0x00000000004004f9 <+1>:     48 89 e5        mov    %rsp,%rbp
   0x00000000004004fc <+4>:     b8 48 47 46 45  mov    $0x45464748,%eax
   0x0000000000400501 <+9>:     5d      pop    %rbp
   0x0000000000400502 <+10>:    c3      retq   
End of assembler dump.

现在你可以清楚地看到直接常量的每个字节所在的指令流中的位置(以及x86对它们使用小端编码)。

x86指令编码的标准参考是英特尔instruction set reference。您可以在第3-528页找到0xB8说明。