Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 功能';s的返回地址与其假定值不同,缓冲区溢出,请帮助_C_Assembly_Buffer Overflow - Fatal编程技术网

C 功能';s的返回地址与其假定值不同,缓冲区溢出,请帮助

C 功能';s的返回地址与其假定值不同,缓冲区溢出,请帮助,c,assembly,buffer-overflow,C,Assembly,Buffer Overflow,大家好 我试图了解缓冲区溢出是如何工作的。现在,我正在确定函数返回地址的地址,我应该更改该地址以执行缓冲区溢出攻击。我根据在互联网上读到的一个例子编写了一个简单的程序。这个程序所做的是创建一个整数指针,将函数返回地址的地址存储在堆栈中。为此,(假设我理解函数/程序变量在堆栈中的组织方式),我将8添加到缓冲区变量的地址,并将其设置为ret的值。我不会在这里做任何改变func返回地址位置中包含的地址的事情 更新:我对程序做了一些修改,所以它会打印func参数a的堆栈地址。如您所见,和缓冲区之间的距离

大家好

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

更新:我对程序做了一些修改,所以它会打印func参数a的堆栈地址。如您所见,和缓冲区之间的距离约为8字节,因此根据堆栈布局,这可能意味着保存的FP和旧的EIP(func返回地址)介于两者之间。我说得对吗

节目如下:

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);
}
超出时程序的输出:

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

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

我的问题是,为什么它们不同?(当然,假设我所做的一切都是正确的)。
否则,我做错了什么?我对程序运行时堆栈的理解是否错误?请帮我理解这一点。我的项目下个星期就要交了,我几乎还没碰过。很抱歉,如果我有要求,我非常需要您的帮助。

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

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

  • 将缓冲区更改为4字节
  • 用不同的偏移量进行实验。我有一种感觉,你可能需要查找12个字节,甚至16个字节才能找到你的回信地址

  • 对于以下程序

    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] ------------- 0 4 bytes (for char, assuming 4bytes alignment) 4 4 bytes (for whatever, maybe argument) 8 4 bytes (return address) ------------- 精氨酸 ------------- ......... ------------- 0x1010 arg 0 ------------- 0x100C ret地址 ============= 0x1008旧fp ------------- 0x1004 v[1] ------------- 0x1000 v[0] ------------- 您可以使用v+3查找main的返回地址


    假设地址放在堆栈左侧,v有地址0x1000,return address有地址(v+3=>0x1000+4*3=0x100C)

    当然,除非将指针传递给原始num,否则无法修改原始num;所以在主函数中,num首先是0,然后是1,func永远不会真正修改它。func中(
    &a
    )的地址是参数的本地副本(按值)的地址,在大多数情况下可能是堆栈上的地址。ret会指出什么?你有一个3字符的缓冲区,你得到的地址超过它;你必须考虑它现在是垃圾的指针,即使你可能指向一些“有趣”,根据局部变量是如何“组织”在内存中的。所以你不能100%确定它确实指向了回信地址。您假设以下情况:

    ------------- arg n ------------- ......... ------------- 0x1010 arg 0 ------------- 0x100C ret address ============= 0x1008 old fp ------------- 0x1004 v[1] ------------- 0x1000 v[0] ------------- 0 4 bytes (for char, assuming 4bytes alignment) 4 4 bytes (for whatever, maybe argument) 8 4 bytes (return address) 0 4字节(对于字符,假设4字节对齐) 4字节(无论什么,可能是参数) 8 4字节(返回地址) 这要视情况而定。这取决于架构;这取决于编译器如何“翻译”函数的代码。让我们想象一下x86。以下是一种合理的功能实现方法

    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 func: 推动ebp;保存一些注册表。。。 推动eax;还是普莎? 电动汽车 推0;对于字符a[3] mov-eax,ebp 添加eax,4-4 + 8 推动eax;对于int*ret ; -4(ebp)给出了一个 ; -8(ebp)给出int*ret ; 所以ebp-4是指向a的指针,我们 ; 加上8,获得ebp+4,哪些分数 ; 要保存ebp。。。错过ret ptr ; (其他代码…) 电除尘器 pop-eax;还是用波帕? 流行ebp ret
    如果保存的regs更多呢?如果char a[4]和int*ret的顺序被交换怎么办?你怎么知道?你不能假设任何事情,除非你自己直接在asm中编写代码,在这种情况下你可以准确地控制发生了什么。否则,一个可以正常工作的C代码会碰巧工作…

    请在您的帖子中包含您实际代码的文本(不仅仅是屏幕截图)。对不起,这里有所有内容。您的堆栈看起来是这样的:因此堆栈上的返回地址比第一个局部变量的地址高8字节。我猜声明一个int并在地址中加上8将检索到确切的返回地址。我已经解决了这个问题。事实证明,我的输出(printf)的糟糕格式实际上是造成我混乱的原因。是的,据我所知,调用func时堆栈的布局应该是这样的,从较高的mem地址到较低的mem地址,| nums value | ret | sfp(ebp)| buffer |,因此堆栈中buffer和ret之间的距离,“应该像8,”奥特约翰-但你不是8