gpt4 book ai didi

c - 将参数传递给通过缓冲区溢出到达的函数

转载 作者:行者123 更新时间:2023-11-30 17:43:43 26 4
gpt4 key购买 nike

我编写了这个简单的 main,并使用标志 -fno-stack-protector 进行编译。

#include <stdio.h>
int pos;
char c = 0;

void
bof(unsigned int i)
{
fprintf(stderr, "BOF %u\n", i);
}

void
foo()
{
unsigned char buf[3];
while(c != 'X') {
scanf(" %c", &c);
buf[pos++] = c;
}
}

int
main() {
fprintf(stderr, "%p\n", bof);
foo();
return 0;
}

我试图将 0 传递给 bof 函数的输入变量,并确保我用零包围了 bof 函数的地址。(请注意,我使用 ubuntu 12.04 v. 64 位):

perl -e '打印“\x00”x24。 “\xa4\x05\x40\x00\x00\x00\x00\x00”。 “\x00”x8 。 “X”'

问题是使用此缓冲区执行程序时打印的结果不为零(甚至不是常数),但是当我尝试调试程序时:perl -e '打印“\x00”x24 。 “\xa4\x05\x40\x00\x00\x00\x00\x00”。 “\x00”x8 。 “X”' > 文件

(gdb) b 19
Breakpoint 4 at 0x40061b: file main.c, line 19.
(gdb) r < file
The program being debugged has been started already.

Start it from the beginning? (y or n) y
Starting program: /home/badnack/Documents/Code/stuff/bof/bof < file
0x4005a4

Breakpoint 4, foo () at main.c:19
19 }
(gdb) l
14 unsigned char buf[3];
15 while(c != 'X') {
16 scanf(" %c", &c);
17 buf[pos++] = c;
18 }
19 }
20
21 int
22 main() {
23 fprintf(stderr, "%p\n", bof);
(gdb) l
24 foo();
25 return 0;
26 }
(gdb) disass
Dump of assembler code for function foo:
0x00000000004005d0 <+0>: push %rbp
0x00000000004005d1 <+1>: mov %rsp,%rbp
0x00000000004005d4 <+4>: sub $0x10,%rsp
0x00000000004005d8 <+8>: jmp 0x400610 <foo+64>
0x00000000004005da <+10>: mov $0x400755,%eax
0x00000000004005df <+15>: mov $0x601040,%esi
0x00000000004005e4 <+20>: mov %rax,%rdi
0x00000000004005e7 <+23>: mov $0x0,%eax
0x00000000004005ec <+28>: callq 0x4004b0 <__isoc99_scanf@plt>
0x00000000004005f1 <+33>: mov 0x200a4d(%rip),%eax # 0x601044 <pos>
0x00000000004005f7 <+39>: movzbl 0x200a42(%rip),%edx # 0x601040 <c>
0x00000000004005fe <+46>: mov %edx,%ecx
0x0000000000400600 <+48>: movslq %eax,%rdx
0x0000000000400603 <+51>: mov %cl,-0x10(%rbp,%rdx,1)
0x0000000000400607 <+55>: add $0x1,%eax
0x000000000040060a <+58>: mov %eax,0x200a34(%rip) # 0x601044 <pos>
0x0000000000400610 <+64>: movzbl 0x200a29(%rip),%eax # 0x601040 <c>
0x0000000000400617 <+71>: cmp $0x58,%al
0x0000000000400619 <+73>: jne 0x4005da <foo+10>
=> 0x000000000040061b <+75>: leaveq
0x000000000040061c <+76>: retq
End of assembler dump.
(gdb) ni
0x000000000040061c 19 }
(gdb) x/10xg $rsp
0x7fffffffe278: 0x00000000004005a4 0x0000000000000000
0x7fffffffe288: 0x00007ffff7a3b758 0x0000000000000000
0x7fffffffe298: 0x00007fffffffe368 0x0000000100000000
0x7fffffffe2a8: 0x000000000040061d 0x0000000000000000
0x7fffffffe2b8: 0xbc2b8a4223791ede 0x00000000004004c0
(gdb) n
bof (i=0) at main.c:7
7 {
(gdb) x/10xg $rsp
0x7fffffffe280: 0x0000000000000000 0x00007ffff7a3b758
0x7fffffffe290: 0x0000000000000000 0x00007fffffffe368
0x7fffffffe2a0: 0x0000000100000000 0x000000000040061d
0x7fffffffe2b0: 0x0000000000000000 0xbc2b8a4223791ede
0x7fffffffe2c0: 0x00000000004004c0 0x00007fffffffe360
(gdb) n
8 fprintf(stderr, "BOF %u\n", i);
(gdb) n
BOF 4158473024
9 }
(gdb) x/10xg $rsp
0x7fffffffe268: 0x0000000000000000 0xf7dd434000000000
0x7fffffffe278: 0x0000000000000000 0x0000000000000000
0x7fffffffe288: 0x00007ffff7a3b758 0x0000000000000000
0x7fffffffe298: 0x00007fffffffe368 0x0000000100000000
0x7fffffffe2a8: 0x000000000040061d 0x0000000000000000
(gdb)

i 变量似乎收到了正确的值,但随后打印了另一个值(这正是 0xf7dd434000000000 的十进制表示形式。发生了什么事?为什么这个内存单元之前也不存在?

最佳答案

要准确了解发生了什么,我们必须查看函数 bof 的汇编代码。无论如何,您的方法中的一个疏忽是您没有将参数值写入堆栈; 8 字节返回地址“\xa4\x05\x40\x00\x00\x00\x00\x00”由 foo 中的 retq 从堆栈中弹出 - 我们从之前的差异看出这一点

0x7fffffffe278: 0x00000000004005a4  0x0000000000000000
0x7fffffffe288: 0x00007ffff7a3b758

以及retq之后

0x7fffffffe280: 0x0000000000000000  0x00007ffff7a3b758

(现在在 bof 中)。 “\x00”x8 现在取代了 bof 的返回地址,如果 bofcallq 定期调用,该地址将被插入堆栈顶部.

此外,使用的调用约定似乎是 System V Application Binary Interface ,其中函数 bof 的第一个(仅在本例中)参数在寄存器 %rdi 中传递,而不是在堆栈上传递。

关于c - 将参数传递给通过缓冲区溢出到达的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20182175/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com