c - 离开函数时重写ret地址

标签 c buffer-overflow

我正在尝试重写函数 foo() 中的 ret 地址,以在离开函数 foo() 后跳过第一条指令。我正在关注《Smash stack for fun orprofit》和 Jon Erickson 的《Hacking》。这是我想跳过“b = 2;”的简单代码指令,所以b中应该存储值1。

在gcc中编译,设置:-fno-stack-protector -z execstack -g
我还关闭了 ASLR。

#include <stdio.h>
int foo() {
    int c = 0;
    int *ptr;
    ptr = (int*) 0x00007fffffffdf38;
    // Second instruction after leaving from foo(). I also tried to skip all instructions before call printf function.
    *ptr = 0x0000000000400577; 
    return 0;
}

int main()
{
    int b = 1;
    foo();
    b = 2;
    printf("b = %d\n", b);      
    return 0;
}

该程序的输出是:“b = 2”。

我如何假设 RET 指令存储在何处:

(gdb) disass main
...
0x000000000040056b <+20>:   call   0x40052d <foo>
0x0000000000400570 <+25>:   mov    DWORD PTR [rbp-0x4],0x2
0x0000000000400577 <+32>:   mov    eax,DWORD PTR [rbp-0x4]
0x000000000040057a <+35>:   mov    esi,eax
...
(gdb) break 4       // set breakpoint 1 in function foo before int *ptr;
(gdb) break 7       // set breakpoint 2 in function foo after rewriting RET for checking
(gdb) run
(gdb) x/8x &c       // "x/8x $esp" doesn't work, it says: "Cannot access memory at address 0xffffffffffffdf30", so I'm looking into memory from &c
0x7fffffffdf2c: 0x00000000  0xffffdf50  0x00007fff  0x00400570
0x7fffffffdf3c: 0x00000000  0xffffe030  0x00007fff  0x00000000
// simple math tell me, it should be:
(gdb) x/8xb 0x7fffffffdf38
0x7fffffffdf38: 0x70    0x05    0x40    0x00    0x00    0x00    0x00    0x00

这就是我找到RET地址的方法,它位于0x7fffffffdf38。我将下一条指令的地址放置到这个地方 - 0x0000000000400577。 然而,即使RET被成功重写,计算机仍然没有跳过指令b = 2。 我检查了一下,确认是否真的替换了RET地址:

(gdb) c
(gdb) x/8xb 0x7fffffffdf38
0x7fffffffdf38: 0x77    0x05    0x40    0x00    0x00    0x00    0x00    0x00

所以 RET 地址确实被重写了,但是当程序从函数 foo() 离开时,它跳转到原始地址 0x0000000000400570 我想跳过...

应该很简单,找到ret地址存放的地方,然后把其他地址放到这个地方。我究竟做错了什么? 感谢您的每一个回答。

为了指定查询,我添加了反汇编函数:

Dump of assembler code for function foo:
0x000000000040052d <+0>:    push   rbp
0x000000000040052e <+1>:    mov    rbp,rsp
0x0000000000400531 <+4>:    mov    DWORD PTR [rbp-0x4],0x0
0x0000000000400538 <+11>:   movabs rax,0x7fffffffdf38
0x0000000000400542 <+21>:   mov    QWORD PTR [rbp-0x10],rax
0x0000000000400546 <+25>:   mov    rax,QWORD PTR [rbp-0x10]
0x000000000040054a <+29>:   mov    DWORD PTR [rax],0x400577
0x0000000000400550 <+35>:   mov    eax,0x0
0x0000000000400555 <+40>:   pop    rbp
0x0000000000400556 <+41>:   ret    
End of assembler dump.
(gdb) disass main
Dump of assembler code for function main:
0x0000000000400557 <+0>:    push   rbp
0x0000000000400558 <+1>:    mov    rbp,rsp
0x000000000040055b <+4>:    sub    rsp,0x10
0x000000000040055f <+8>:    mov    DWORD PTR [rbp-0x4],0x1
0x0000000000400566 <+15>:   mov    eax,0x0
0x000000000040056b <+20>:   call   0x40052d <foo>
0x0000000000400570 <+25>:   mov    DWORD PTR [rbp-0x4],0x2
0x0000000000400577 <+32>:   mov    eax,DWORD PTR [rbp-0x4]
0x000000000040057a <+35>:   mov    esi,eax
0x000000000040057c <+37>:   mov    edi,0x400624
0x0000000000400581 <+42>:   mov    eax,0x0
0x0000000000400586 <+47>:   call   0x400410 <printf@plt>
0x000000000040058b <+52>:   mov    eax,0x0
0x0000000000400590 <+57>:   leave  
0x0000000000400591 <+58>:   ret    

最佳答案

当我在 gdb 调试器中运行它时,它可以工作。那么代码写好了,问题就解决了。问题出在其他地方......

关于c - 离开函数时重写ret地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27213625/

相关文章:

c - 为什么 valgrind 不检测数组中的多余元素

c - 使用 .* 宽度说明符调用 sprintf 时出现奇怪的警告

c - 防止结构中的字符指针溢出

c - 两个同时发送会锁定两个程序

c - 简单数组索引失败

c - 位域未在字节边界对齐的结构的大小

c - 微 Controller C 代码的单元测试模式

c - 使用结构数组与结构指针数组的优缺点是什么?

c - 我怎样才能找到这段代码中的漏洞?