IA32注册地址

我有几个互相关联的问题让我失望。 我正在进行一项任务,我必须在gdb查看汇编代码,以找到使C程序正常工作的正确输入。 为了测试这个,我输入一个由一些数字组成的测试字符串,并逐步读取/读取程序集以预测其行为并找出解决方案。

这是主要问题:在某一点上,我的整个输入字符串存储在%eax寄存器中。 我打电话的时候:

 x/a $eax 

它返回一个hex,我假设它是%eax的地址。 此时,hex的最后一个字节会根据输入而变化。 程序在输入字符串上调用strtol()后不久,从字符串中删除第一个数字,并将缩短的字符串放回%eax

事情变得令人困惑:似乎无论原始输入有多长或附加输入有多长,当我在$eax上调用x/a时,返回的hex值的最后一个字节似乎总是等于32。是一个问题,因为在使用%eax地址的最后一个字节之后不久有一个cmp测试,而数字32会导致程序故意崩溃。

我误解了x/a的使用,事实上,我返回的hex根本不是一个地址吗? 输入的大小是否会影响注册表的地址? 任何其他有用的提示可以帮助我在这种情况下?

非常感谢

你的一条评论说“当我调用x/s $eax ,它会在调用strtol()之前返回我的整个输入字符串”。

如果是这种情况,则%eax包含字符串的地址, x $eax将尝试显示该地址的内容。

x/s $eax将内容显示为字符串,因此它将$eax处的字节解释为字符并显示它,对$eax + 1执行相同操作,依此类推,直到遇到终止空值。 根据你的评论,这正是当你做x/s $eax时会发生的事情。

x/a $eax将该地址的内容显示为另一个地址。 换句话说,它将占用字符串的前四个字节,并显示具有相同位模式的32位地址。 这种解释的“地址”值对您来说不太可能有任何意义。 换句话说,它可能看起来像一个地址,但它实际上不太可能是你的程序使用的任何地址,除非偶然。

如果%eax包含指针变量的地址, 那么在其上运行x/a将是有意义的,因为然后另一个地址实际上将存储在该寄存器中包含的地址中。

作为演示,请考虑以下程序:

 #include  void myfunc(char * c) { char * p = c; } int main(void) { char * c = "Hello, world!"; printf("Expected x/a output: 0x"); for ( size_t i = 8; i > 0; --i ) { printf("%X", c[i - 1]); } printf("\n"); myfunc(c); return 0; } 

在这种特殊情况下,参数将被传递给%eax寄存器中的myfunc() ,所以如果我们在行上打破char * p = c; 并运行x/s $eax ,我们应该看到"Hello, world!" 显示,因为%eax寄存器包含指向该字符串的char *变量的内容。

如果我们然后运行x/a $eax ,因为我在具有8字节地址的64位机器上运行它,我们将得到一个由'w'的ASCII代码组成的“地址”(即0x77 ),字符串的第8个字符,后跟' ' (即0x20 )的ASCII代码,字符串的第7个字符,后跟',' (即0x2C )的ASCII代码,依此类推通往'H'main()的循环计算它应该是什么样子。 它从后到前都是因为x86架构是小端的。

如果我们运行x/c ,我们将获得字符串的各个字符。

那么,让我们看一下gdb输出:

 paul@local:~/src/c/scratch$ gdb ./addr GNU gdb (GDB) 7.4.1-debian Copyright (C) 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later  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-linux-gnu". For bug reporting instructions, please see: ... Reading symbols from /home/paul/src/c/scratch/addr...done. (gdb) list 1 #include  2 3 void myfunc(char * c) { 4 char * p = c; 5 } 6 7 int main(void) { 8 char * c = "Hello, world!"; 9 printf("Expected x/a output: 0x"); 10 for ( size_t i = 8; i > 0; --i ) { (gdb) break 4 Breakpoint 1 at 0x400604: file addr.c, line 4. (gdb) run Starting program: /home/paul/src/c/scratch/addr Expected x/a output: 0x77202C6F6C6C6548 Breakpoint 1, myfunc (c=0x40073c "Hello, world!") at addr.c:4 4 char * p = c; (gdb) x/s $eax 0x40073c: "Hello, world!" (gdb) x/a $eax 0x40073c: 0x77202c6f6c6c6548 (gdb) x/c $eax 0x40073c: 72 'H' (gdb) x/c $eax + 1 0x40073d: 101 'e' (gdb) x/c $eax + 2 0x40073e: 108 'l' (gdb) 

我们完全看到了我们所期待的。

作为x/a实际上有意义的示例,让我们改变程序以传递指针指针,以便%eax包含的地址(实际上这里改为%rax ,因为我在64位系统上,并且需要完整的8字节寄存器来保存堆栈变量的地址,这将是相当高的 – 在第一个示例中,我传递了静态分配的字符串文字"Hello, world!"的地址,该地址存储在一个足够低的地址,很容易适应%rax寄存器的4字节部分,即x64处理器上的%eax )确实指向另一个地址:

 #include  void myfunc(char ** c) { char ** p = c; } int main(void) { char * c = "Hello, world!"; printf("Contents of c, and expected x/a output: %p\n", (void *)c); myfunc(&c); return 0; } 

和这次gdb输出:

 paul@thoth:~/src/c/scratch$ gdb ./addr2 GNU gdb (GDB) 7.4.1-debian Copyright (C) 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later  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-linux-gnu". For bug reporting instructions, please see: ... Reading symbols from /home/paul/src/c/scratch/addr2...done. (gdb) list 1 #include  2 3 void myfunc(char ** c) { 4 char ** p = c; 5 } 6 7 int main(void) { 8 char * c = "Hello, world!"; 9 printf("Contents of c, and expected x/a output: %p\n", (void *)c); 10 myfunc(&c); (gdb) break 4 Breakpoint 1 at 0x4005b4: file addr2.c, line 4. (gdb) run Starting program: /home/paul/src/c/scratch/addr2 Contents of c, and expected x/a output: 0x4006b0 Breakpoint 1, myfunc (c=0x7fffffffe478) at addr2.c:4 4 char ** p = c; (gdb) x/a $rax 0x7fffffffe478: 0x4006b0 (gdb) 

这里,参数 – 因此%rax寄存器 – 包含main()char * c的地址, c包含"Hello, world!"的地址"Hello, world!" 串。 因此,当我们显示%rax包含的地址的内容作为地址时,我们得到"Hello, world!"的地址"Hello, world!" 与上面的第一个例子不同,字符串实际上是一个有意义的地址。