试图从“剥削艺术”中理解char_array2.c的例子

时间:2014-06-08 05:22:41

标签: c debugging assembly gdb

好的,所以我真的想要了解这个“剥削艺术”第二版的例子。我试图通过密切关注本书中GDB的输出来确切了解该示例的内容。我最大的问题是最后一部分,我把整个事情都包括在内,这样每个人都可以看到发生了什么。当然,我只有非常(非常)基本的汇编代码知识。我明白基本的C. 在最后一部分中,作者说,程序的第二次运行与strcpy()指向的地址中的最后一次运行存在细微的差别,而我却看不到它。

该计划只是

#include<stdio.h>
#include<string.h>

int main() {

  char str_a[20];
  strcpy(str_a, "Hello, world!\n");
  printf(str_a);
  }

在我使用必要的选项编译它以便能够调试它之后我加载它 GDB并包含以下内容:

(gdb) break 6
Breakpoint 1 at 0x80483c4: file char_array2.c, line 6.
(gdb) break strcpy

Function "strcpy" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (strcpy) pending.
(gdb) break 8
Breakpoint 3 at 0x80483d7: file char_array2.c, line 8.
(gdb)

我对此没有任何问题,这是我的理解 调试器只能使用用户定义的函数执行此类操作。我也知道如何使用gcc选项来解决这个问题。 我也知道,当程序运行时,strcpy断点得到解决。让我继续。

(gdb) run
Starting program: /home/reader/booksrc/char_array2
Breakpoint 4 at 0xb7f076f4
Pending breakpoint "strcpy" resolved

Breakpoint 1, main() at char_array2.c:7
7   strcpy(str_a, "Hello, world!\n");
(gdb) i r eip
eip 0x80483c4   0x80483c4 <main+16>
(gdb) x/5i $eip
0x80483c4   <main+16>:  mov    DWORD PTR [esp+4],0x80484c4
0x80483cc   <main+24>:  lea    eax,[ebp-40]
0x80483cf   <main+27>:  mov    DWORD PTR [esp],eax
0x80483d2   <main+30>:  call   0x80482c4 <strcpy@plt>
0x80483d7   <main+35>:  lea    eax,[ebp-40]
(gdb) continue
Continuing.


Breakpoint 4, 0xb7f076f4 in strcpy () from /lib/tls/i686/cmov/libc.so.6
(gdb) i r eip
eip    0xb7f076f4    0xb7f076f4 <strcpy+4>
(gdb) x/5i $eip
0xb7f076f4 <strcpy+4>:  mov   esi,DWORD PTR [ebp+8]
0xb7f076f7 <strcpy+7>:  mov   eax,DWORD PTR [ebp+12]
0xb7f076fa <strcpy+10>: mov   ecx,esi
0xb7f076fc <strcpy+12>: sub   ecx,eax
0xb7f076fe <strcpy+14>: mov   edx,eax
(gdb) continue
Continuing.

Breakpoint 3, main () at char_array2.c:8
8
printf(str_a);
(gdb) i r eip
eip    0x80483d7    0x80483d7 <main+35>
(gdb) x/5i $eip
0x80483d7 <main+35>:   lea    eax,[ebp-40]
0x80483da <main+38>:   mov    DWORD PTR [esp],eax
0x80483dd <main+41>:   call   0x80482d4 <printf@plt>
0x80483e2 <main+46>:   leave
0x80483e3 <main+47>:   ret
(gdb)

这是该程序的第二次运行,其中strcpy的地址与其他地址不同。

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/reader/booksrc/char_array2
Error in re-setting breakpoint 4:
Function "strcpy" not defined.

Breakpoint 1, main () at char_array2.c:7
7
strcpy(str_a, "Hello, world!\n");
(gdb) bt
#0 main () at char_array2.c:7
(gdb) cont
Continuing.

Breakpoint 4, 0xb7f076f4 in strcpy () from /lib/tls/i686/cmov/libc.so.6
(gdb) bt
#0 0xb7f076f4 in strcpy () from /lib/tls/i686/cmov/libc.so.6
#1 0x080483d7 in main () at char_array2.c:7
(gdb) cont
Continuing.

Breakpoint 3, main () at char_array2.c:8
8
printf(str_a);
(gdb) bt
#0 main () at char_array2.c:8
(gdb)

区别在哪里?我错误地认为0xb7f076f4是strcpy的地址吗?在第二次运行时,如果我是正确的,则表示地址为0xb7f076f4。

另外,是什么?我在本书前面的任何地方都找不到解释。如果有人能够从上到下向我解释这一点,我将非常感激,因为我不知道现实生活中的任何专家可以帮助我。我发现解释是模糊的,他解释变量和循环,就像他向5岁时解释它一样,但留下了大部分汇编代码让我们自己弄明白,我在这方面并不是很成功。 任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

显然gdb关闭ASLR调试进程,使(会话到会话)调试更容易。

来自https://sourceware.org/gdb/current/onlinedocs/gdb/Starting.html

set disable-randomization
set disable-randomization on
    This option (enabled by default in GDB) will turn off the native 
    randomization of the virtual address space of the started program. 
    This option is useful for multiple debugging sessions to make the 
    execution better reproducible and memory addresses reusable across
    debugging sessions.

set disable-randomization offgdb文件中设置.gdbinit,然后重试。现在,每次运行二进制文件时,Libc都应该加载到不同的地址。

运行watch -n 1 cat /proc/self/maps也很高兴看到二进制文件和库如何映射到“随机”地址。

答案 1 :(得分:1)

正如@Voo在上面的评论中所说,这本书可能是指ASLR(地址空间布局随机化),这是一个安全功能。它改变了地址空间用于每次执行的方式,因此您无法始终在同一个地方查找内容。

如果您在gdb中没有看到这意味着您已关闭ASLR。 gdb中的全局或本地。您可以使用cat /proc/sys/kernel/randomize_va_space检查前者,并在show disable-randomization提示符下使用gdb命令检查后者。