C 功能';s的返回地址与其假定值不同,缓冲区溢出,请帮助
大家好 我试图了解缓冲区溢出是如何工作的。现在,我正在确定函数返回地址的地址,我应该更改该地址以执行缓冲区溢出攻击。我根据在互联网上读到的一个例子编写了一个简单的程序。这个程序所做的是创建一个整数指针,将函数返回地址的地址存储在堆栈中。为此,(假设我理解函数/程序变量在堆栈中的组织方式),我将8添加到缓冲区变量的地址,并将其设置为ret的值。我不会在这里做任何改变func返回地址位置中包含的地址的事情 更新:我对程序做了一些修改,所以它会打印func参数a的堆栈地址。如您所见,和缓冲区之间的距离约为8字节,因此根据堆栈布局,这可能意味着保存的FP和旧的EIP(func返回地址)介于两者之间。我说得对吗 节目如下:C 功能';s的返回地址与其假定值不同,缓冲区溢出,请帮助,c,assembly,buffer-overflow,C,Assembly,Buffer Overflow,大家好 我试图了解缓冲区溢出是如何工作的。现在,我正在确定函数返回地址的地址,我应该更改该地址以执行缓冲区溢出攻击。我根据在互联网上读到的一个例子编写了一个简单的程序。这个程序所做的是创建一个整数指针,将函数返回地址的地址存储在堆栈中。为此,(假设我理解函数/程序变量在堆栈中的组织方式),我将8添加到缓冲区变量的地址,并将其设置为ret的值。我不会在这里做任何改变func返回地址位置中包含的地址的事情 更新:我对程序做了一些修改,所以它会打印func参数a的堆栈地址。如您所见,和缓冲区之间的距离
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
放在堆栈的更高位置),因此您可能需要对值进行实验。我会做几件事:
对于以下程序
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