函数的返回地址与其假定值不同,缓冲区溢出,请帮忙

发布于 2024-09-06 06:49:02 字数 1580 浏览 2 评论 0原文

大家好!

我想了解缓冲区溢出是如何工作的。现在,我正在确定函数返回地址的地址,我应该更改该地址以执行缓冲区溢出攻击。我根据在互联网上阅读的示例编写了一个简单的程序。该程序的作用是创建一个整数指针来存储堆栈中函数的返回地址的地址。为此,(假设我了解函数/程序变量如何在堆栈中组织),我将 8 添加到缓冲区变量的地址并将其设置为 ret 的值。我在这里没有做任何会更改 func 返回地址位置中包含的地址的操作。

更新:我对程序进行了一些修改,因此它打印了 func 参数 a 的堆栈地址。正如您所看到的,a 和 buffer 之间的距离约为 8 个字节,因此,根据堆栈布局,这可能意味着保存的 FP 和旧 EIP(函数返回地址)位于两者之间。我说得对吗?

这是程序:

void func( int a){
    char buffer[3];

    int *ret;

    ret = buffer + 11; // this is the configuratio which made the whole program works... This now points to the address containing func's return address

    printf (" address of a is %d\n", &a);

    printf ("address of buffer is %x\n", buffer);

    printf ("address of ret is %x\n", ret);

    printf ("value of ret is %x\n", (*ret));

}

void main(){
    int num;

    num = 0;

    func(num);

    num = 1;

    printf("Num now is %d", num);
}

执行时程序的输出:

alt text http://img20. imageshack.us/img20/2034/72783404.png

如您所见,我正在打印变量 buffer 和 ret 的地址。我添加了一条附加语句,用于打印 ret 变量的值(假定是 func 返回地址的位置,因此这应该打印下一条指令的地址,该指令将在 func 从执行返回后执行)。

这是转储,显示了 func 返回后要执行的指令的假定地址。 (绿色下划线)如您所见,该值与变量 ret 中包含的打印值有很大不同。

替代文本 http://img717.imageshack.us/img717/8273/assemblecodecopy.png< /a>

我的问题是,为什么它们不同? (当然假设我所做的都是正确的)。 不然我到底做错了什么?难道我对程序运行时堆栈的理解有误?请帮助我理解这一点。我的项目将于下周到期,但我几乎还没碰过它。如果我要求太高的话,我很抱歉,我非常需要你的帮助。

Good day everyone!

I am trying to understand how buffer overflow works. Right now, I’m in the process of determining the address of a function’s return address which I’m supposed to change to perform a buffer overflow attack. I’ve written a simple program based from an example I’ve read in the internet. What this program does is it creates an integer pointer to store the address of the function's return address in the stack. To do this, (granted I understand how a function/program variables get organized in the stack), I add 8 to the buffer variable’s address and set it as the value of ret. I’m not doing anything here that would change the address contained in the location of func’s return address.

UPDATE: I've modified the program a bit, so it prints the stack address of func's parameter a. As you can see, the distance between a and buffer is about 8 bytes, so that would probably mean, based from the stack layout, that saved FP and old EIP (func return address) is in between. Am I right?

Here's the program:

void func( int a){
    char buffer[3];

    int *ret;

    ret = buffer + 11; // this is the configuratio which made the whole program works... This now points to the address containing func's return address

    printf (" address of a is %d\n", &a);

    printf ("address of buffer is %x\n", buffer);

    printf ("address of ret is %x\n", ret);

    printf ("value of ret is %x\n", (*ret));

}

void main(){
    int num;

    num = 0;

    func(num);

    num = 1;

    printf("Num now is %d", num);
}

Output of the program when gets excecuted:

alt text http://img20.imageshack.us/img20/2034/72783404.png

As you can see, I’m printing the address of the variables buffer and ret. I’ve added an additional statement printing the value of the ret variable (supposed location of func return address, so this should print the address of the next instruction which will get executed after func returns from execution).

Here is the dump which shows the supposed address of the instruction to be executed after func returns. (Underlined in green) As you can see, that value is way different from the value printed contained in the variable ret.

alt text http://img717.imageshack.us/img717/8273/assemblycodecopy.png

My question is, why are they different? (of course in the assumption that what I’ve done are all correct).
Else, what have I done wrong? Is my understanding of the program’s runtime stack wrong? Please, help me understand this. My project is due nextweek and I’ve barely touched it yet. I’m sorry if I’m being demanding, I badly need your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

深爱成瘾 2024-09-13 06:49:02

对于以下程序,

int main(int argc, char **argv) {
   int v[2];

   return 0;
}

堆栈布局基本上如下:

 
       -------------   
           arg n 
       ------------- 
         .........
       -------------   
0x1010     arg 0 
       ------------- 
0x100C  ret address
       =============
0x1008     old fp 
       -------------
0x1004     v[1]
       -------------
0x1000     v[0]
       -------------

您可以使用 v + 3 找出 main 的返回地址。

假设地址放置在堆栈的左侧, v 的地址为 0x1000 ,返回地址的地址为 (v + 3 => 0x1000 + 4 * 3 = 0x100C)

For the following program

int main(int argc, char **argv) {
   int v[2];

   return 0;
}

The stack layout is basically the following:

 
       -------------   
           arg n 
       ------------- 
         .........
       -------------   
0x1010     arg 0 
       ------------- 
0x100C  ret address
       =============
0x1008     old fp 
       -------------
0x1004     v[1]
       -------------
0x1000     v[0]
       -------------

You can find out main's return address using v + 3.

Assuming the addresses placed on the left side of the stack, v has address 0x1000 , return adress has the address (v + 3 => 0x1000 + 4 * 3 = 0x100C)

美人如玉 2024-09-13 06:49:02

首先,请注意缓冲区的地址是奇数 0xbffffd51,然后向其添加 8 以获得 0xbffffd59。如果堆栈上的返回地址未与四字节地址对齐,我会感到非常惊讶。

根据编译器的不同,堆栈帧的具体布局方式可能会有所不同(例如,即使 buffer 位于源代码中的第一个位置,编译器也可能会将 ret 放在更高的位置)堆栈),因此您可能需要试验您的值。我会做几件事:

  1. 将缓冲区更改为 4 个字节。
  2. 尝试不同的偏移量。我有一种感觉,您可能需要向上查找 12 个字节甚至 16 个字节才能找到您的返回地址。

First off, notice that the address of buffer is an odd number 0xbffffd51 and then you add 8 to it to get 0xbffffd59. I would be quite surprised if the return address on the stack was not aligned to a four byte address.

Depending on the compiler, exactly how the stack frame is layed out could vary (for example, even though buffer is first in the source code, the compiler could put ret higher in the stack), so you may need to experiment with your values. I would do a couple of things:

  1. Change buffer to be 4 bytes.
  2. Experiment with different offsets. I have a feeling that you may need to look 12 bytes or even 16 bytes up to find your return address.
最后的乘客 2024-09-13 06:49:02

当然,你不能修改原来的num,除非你将指针传递给它;所以在 main 中,num 首先是 0,然后是 1,并且它从未被 func 真正修改过。 func 中 a (&a) 的地址是参数的本地副本(按值)的地址,在大多数情况下可能是堆栈上的地址。 ret 指向什么?你有一个 3 个字符的缓冲区,你可以得到超出它的地址;您现在必须将其视为指向垃圾的指针,即使根据局部变量在内存中的“组织”方式,您可能指向一些“有趣”的东西。所以你不能100%确定它确实指向返回地址。您假设如下:

0  4 bytes (for char, assuming 4bytes alignment)
4  4 bytes (for whatever, maybe argument)
8  4 bytes (return address)

这取决于情况。这取决于架构;这取决于编译器如何“翻译”函数的代码。让我们想象一下x86。以下是执行 func 的合理方法

func:
  push ebp  ; save some regs...
  push eax  ; or with pusha?
  mov ebp, esp
  push 0   ; for char a[3]
  mov eax, ebp
  add eax, 4  ; -4 + 8
  push eax ; for int *ret
  ; -4(ebp) gives a
  ; -8(ebp) gives int *ret
  ; so ebp-4 is the pointer to a, we
  ; add 8, to obtain ebp+4, which points
  ; to saved ebp... missing the ret ptr
  ; (other code...)
  mov esp, ebp
  pop eax ; or with popa?
  pop ebp
  ret

,如果保存的寄存器较多怎么办?如果 char a[4] 和 int *ret 的顺序互换怎么办?你怎么知道?你不能假设任何事情,除非你自己直接在 asm 中编写代码,在这种情况下你可以准确控制发生的事情。否则,一个可以做你想做的事情的 C 代码会偶然起作用......

Of course, you can't modify the original num unless you pass the pointer to it; so in the main, num first is 0, then it is 1, and it is never really modified by the func. Address of a (&a) in func is the address of the local copy (by value) of the argument, likely an address on the stack in most cases. And what would ret point to? You have a 3 char buffer, and you get the address beyond it; you must consider it now a pointer to garbage, even though likely your pointing to something "interesting", according to how local variables are "organized" in memory. So you can't be 100% sure it points to the return address indeed. You're assuming the following:

0  4 bytes (for char, assuming 4bytes alignment)
4  4 bytes (for whatever, maybe argument)
8  4 bytes (return address)

And it depends. It depends on the architecture; it depends on how the compiler "translate" the code of the function. Let us imagine x86. The following is a reasonable way of doing func

func:
  push ebp  ; save some regs...
  push eax  ; or with pusha?
  mov ebp, esp
  push 0   ; for char a[3]
  mov eax, ebp
  add eax, 4  ; -4 + 8
  push eax ; for int *ret
  ; -4(ebp) gives a
  ; -8(ebp) gives int *ret
  ; so ebp-4 is the pointer to a, we
  ; add 8, to obtain ebp+4, which points
  ; to saved ebp... missing the ret ptr
  ; (other code...)
  mov esp, ebp
  pop eax ; or with popa?
  pop ebp
  ret

and what if the saved regs are more? what if the order of char a[4] and int *ret is swapped? How do you can know? You can't assume anything, unless, you write the code yourself directly in asm, in this case you can controll exactly what's happening. Otherwise, a working C code to do what you want would work by chance...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文