【问题标题】:Why does eip doesn't change in this buffer overflow attempt?为什么在这个缓冲区溢出尝试中 eip 没有改变?
【发布时间】:2013-11-14 09:57:58
【问题描述】:

我正在尝试处理缓冲区溢出。我不明白 eip 的值是怎么回事。

这是 C 代码:

void copy(char *arg) {
  char msg[256];
  strcpy(msg,arg);
}

它的装配:

0x804847d <copy+25>:    call   0x8048368 <strcpy@plt>
0x8048482 <copy+30>:    leave  
0x8048483 <copy+31>:    ret    

我输入了一个字符串作为参数,例如 "_\xAA\xBB\xCC\xDD",其大小计算为最后 4 个字节为 4 个字节在 $ebp 之后(为了覆盖真实的返回地址)。而且它似乎有效。

在 gdb 中:

(break before strcpy)
x/2wx $ebp
0xbffffb38: 0xbffffb58  0x080484d2
n
(just after strcpy execution)
x/2wx $ebp
0xbffffb38: 0x80cdd189  0x080484b6
...
n
...
x/2wx $ebp
0xbffffb38: 0x80cdd189  0x080484b6

所以返回地址是0x080484d2,溢出后是0x080484b6,这就是我想要的。但程序退出:“无法访问地址 0x80cdd18d 的内存”。

我不知道为什么 $eip 没有设置为我的地址,并且由于代码的地址在 0x08048... 我非常确信 $ebp+4 是包含返回地址的地方

我再次尝试使用小 4 个字节的字符串,这次它覆盖了 $ebp 而不是 $ebp+4,并且在返回后 $eip 被设置为 $ebp+4 中包含的值

有什么解释吗?

【问题讨论】:

  • 也许访问 0x80cdd18d 的尝试是在 0x80484b6 处运行指令的结果。你怎么知道它没有跳到那里?
  • 我一直在 gdb 上做“下一步”,它没有经过 0x80484b6 就进入了 0x80cdd18d
  • “无法访问内存”消息并不意味着您的程序的 %eip 去了那里。这甚至不意味着您的程序试图访问该地址!这意味着 gdb 出于某种原因想要访问下级进程的地址空间中的该地址并且不能。在行为不端的程序的 gdb 会话期间,经常会看到这种警告。你的肯定是行为不端 - 它有缓冲区溢出!尝试在 strcpy 之后使用stepi 而不是next 进行单步指令,您可能会更清楚地了解发生了什么。
  • 您可能会发现它对display/i $pc(可能还有其他一些有趣的寄存器)和stepi 通过返回序列很有用。
  • 感谢您的 cmets,我发布了答案,问题是 $ebp 的值在覆盖期间发生了变化

标签: c assembly x86 cpu-registers buffer-overflow


【解决方案1】:

好的,谢谢@Wumpus Q. Wumbley,这帮助我理解了一些事情。

执行next 会完全跳转leaveretret 是改变eip 的指令,它必须等价于pop eip。但是leave之前修改了堆栈指针espebp(特别是因为当我覆盖ebp+4时我改变了ebp中包含的值)

TLDR : 不覆盖 ebp 的值使其工作成功。

【讨论】:

  • next 不会跳过 leaveret (在不执行它们的意义上)。它只是不会在每条指令之后返回到 gdb 提示符。其目的是一直持续到当前 source 行完成。有时这需要一些指令,有时需要很多指令。 nextstepnextistepi 都有它们的用途,但 stepi 在这种情况下是最有用的,因为它不关心源代码行。当您进行缓冲区溢出攻击时,运行进程的状态与源代码级调试信息中表达的状态大相径庭。 next 感到困惑。
  • 所以这解释了问题的一半,但它没有说明为什么它首先不起作用leave 然后ret 使 ebp 指向旧的 ebp 和 esp 指向 ebp (+- 一些字节)和 eip 到 ebp+4 中的值。因此,当覆盖 ebp 中的值时,一切都会好起来的,除了“旧 ebp”会出错。但是 esp 和 eip 会很好,那为什么不起作用呢?
  • 已损坏的“旧 %ebp”将通过 leave 指令加载到真正的 %ebp 寄存器中。然后您的ret 会将您带到您在漏洞利用中选择的地址。如果需要可用的 %ebp,则该地址中的任何内容都会出现问题
  • 好的,问题就在'ret'之前。当我介入(执行ret)时,它说“无法访问地址...的内存”。所以它没有时间弹出 eip,它(gdb 或处理器?)只是做了一些检查,看看 ebp 是否是一个有效的堆栈指针,而它不是。
  • gdb 喜欢在程序每次停止时打印有关当前堆栈帧的一些信息。当由于缓冲区溢出而没有有效的堆栈帧时,可能会导致一些警告。你只需要学会忽略它们并手动打印你需要的东西。
【解决方案2】:

如果这是针对 x86(而不是 x86-64),通常的函数序言包括推入 ebp,然后为其分配 esp 的值,这会将返回地址留在堆栈上 ebp+4 .

看看你的函数的反汇编,看看第一条指令是否像这样:

pushl   %ebp
movl    %esp, %ebp

如果是这样,这就是偏移的原因。

【讨论】:

  • 是的,这是 x86,第一个指令看起来像你说的那样。那么既然确定了ebp+4应该包含RA,为什么它不起作用呢?
  • 您似乎成功地控制了eip 的值,但又出了点问题。很难说没有更多信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-09
  • 1970-01-01
  • 1970-01-01
  • 2010-11-10
  • 2021-11-30
  • 1970-01-01
相关资源
最近更新 更多