如何跳过在C中执行缓冲区溢出的行

时间:2011-03-12 05:32:41

标签: c buffer-overflow cracking

我想使用x=1;跳过C中的一行,主要部分中的行bufferoverflow;但是,我不知道为什么我不能跳过从4002f4到下一个地址4002fb的地址,尽管我计算从<main+35>到{{1}的7个字节}}

我还在Debian和AMD环境中配置了randomniZation和execstack环境的选项,但我仍然得到<main+42>。这个程序有什么问题?

我用dba来调试堆栈和内存地址:

x=1;

4 个答案:

答案 0 :(得分:4)

您必须阅读Smashing the Stack for Fun and Profit文章。我正在阅读同一篇文章,并发现同样的问题,它没有跳过该指令。在IDA中进行了几个小时的调试会话后,我更改了下面的代码,它打印x = 0和b = 5.

#include <stdio.h>

void function(int a, int b) {
     int c=0;
     int* pointer;

     pointer =&c+2;
     (*pointer)+=8;
}

void main() {
  int x =0;
  function(1,2);
  x = 3;
  int b =5;
  printf("x=%d\n, b=%d\n",x,b);
  getch();
}

答案 1 :(得分:4)

为了更改function()中的回复地址以跳过x = 1中的main(),您需要两条信息。

1。堆栈帧中返回地址的位置。

我用gdb来确定这个值。我在function() break function )设置断点,执行代码到断点( run ),检索位置在当前堆栈帧( p $rbp info reg )的内存中,然后检索内存中buffer的位置(< EM> p &buffer 的)。使用检索到的值,可以确定返回地址的位置。

(使用GCC -g标志编译以包含调试符号并在64位环境中执行)

(gdb) break function
...
(gdb) run
...
(gdb) p $rbp
$1 = (void *) 0x7fffffffe270
(gdb) p &buffer
$2 = (char (*)[5]) 0x7fffffffe260
(gdb) quit

(帧指针地址+字大小) - 缓冲区地址=从本地缓冲区变量到返回地址的字节数
0x7fffffffe270 + 8) - 0x7fffffffe260 = 24

如果您无法理解调用堆栈的工作原理,那么阅读call stackfunction prologue维基百科文章可能会有所帮助。这显示了在C中制作“缓冲区溢出”示例的困难。来自buffer的24的偏移量假定了某种填充样式和编译选项。 GCC现在很乐意插入stack canaries,除非你告诉它不要。

2。要添加到返回地址以跳过x = 1

的字节数

在您的情况下,保存的指令指针将指向0x00000000004002f4<main+35>),这是函数返回后的第一条指令。要跳过赋值,您需要使保存的指令指针指向0x00000000004002fb<main+42>)。

这是7个字节的计算是正确的(0x4002fb - 0x4002fb = 7 )。

我使用gdb反汇编应用程序( disas main )并验证了我的案例计算。通过检查反汇编,可以手动解决该值。


请注意,我使用Ubuntu 10.10 64位环境来测试以下代码。

#include <stdio.h>

void function(int a, int b, int c)  
{
    char buffer[5];
    int *ret;

    ret = (int *)(buffer + 24);
    (*ret) += 7; 
}

int main()
{
     int x = 0; 
     function(1, 2, 3);
     x = 1;
     printf("x = %i \n", x);  
     return 0;  
}

输出

  

x = 0


这实际上只是改变function()的返回地址而不是实际的缓冲区溢出。在实际的缓冲区溢出中,您将溢出buffer[5]以覆盖返回地址。但是,大多数现代实现都使用诸如stack canaries之类的技术来防止这种情况。

答案 2 :(得分:2)

你在这里所做的事情似乎与传统的缓冲区溢出攻击没什么关系。缓冲区溢出攻击的整个想法是修改“函数”的返回地址。反汇编程序将显示ret指令(假设x86)从哪里获取地址。这是您需要修改为指向main+42

我假设你想在这里明确激发缓冲区溢出,通常你需要通过操纵'function'的输入来激发它。

通过声明buffer[5]你正在向错误的方向移动堆栈指针(通过查看生成的程序集来验证这一点),返回地址位于堆栈内部的某处(它被放在那里电话指令)。在x86堆栈中向下增长,即向较低的地址增长。

我会通过声明int*并将其向上移动直到我在推送返回地址的指定地址,然后将该值修改为指向main+42并让函数ret

答案 3 :(得分:1)

你不能这样做。 这是一个经典的bufferoverflow代码示例。看看用键盘输入5个然后6个字符后会发生什么。如果你去更多(16个字符应该做)你将覆盖基指针,然后函数返回地址,你会得到分段错误。你想要做的是弄清楚哪4个字符覆盖了返回地址。并使程序执行您的代码。谷歌围绕linux堆栈,内存结构。

 void ff(){
     int a=0; char b[5];
     scanf("%s",b);
     printf("b:%x a:%x\n" ,b ,&a);
     printf("b:'%s' a:%d\n" ,b ,a);
 }

 int main() {
     ff();
     return 0;
 }