堆栈与堆溢出检测
在像linux这样的需求分页系统中,我读到的页面可能约为4k,它通过检查堆栈或堆大小是否超过给定的页面数来确保保护。当我在 for 循环中创建两个变量时
char *s = (char *) malloc(100);
char sa[100];
,我可以在出现内存错误之前编写 s[i] = 'c';
几乎 4000 次 而使用 sa[i] = 'c';
编辑:对于大于数组大小的任何内容,我会收到分段错误
或堆栈粉碎
错误。
我可以理解在第一种情况下存在页面错误,并且它发现没有更多页面被分配到堆,因此内存违规。但是在第二种情况下,gcc 会在运行时检查所有预分配的变量吗?
编辑:我在下面发布完整的代码
int main(int argc,char* argv[]){
char *s = (char *) malloc(20);
char sa[400] = {0};
int i ,count;
printf(" enter the number of chars to write: ");
scanf("%d",&count);
for (i=0;i<count;i++){
printf("%d\n",i);
sa[i] = 'a';
//s[i] = 'a';
}
free(s);
}
In a demand paged system like linux where pages maybe~4k from what I read, it ensures protection by checking if the stack or heap size exceeds the number of pages given to each. WHen I create two variables
char *s = (char *) malloc(100);
char sa[100];
In a for loop I can write s[i] = 'c';
almost 4000 times before it comes up with memory error
whereas with sa[i] = 'c';
EDIT: I get a segmentation fault
or stack smashing
error for anything greater than array size.
I can understand in the first case there is a page fault and it sees that no more pages have been allocated to heap hence a memory violation. But what happens in the second case does gcc keep a check at runtime for all the preallocated variables?.
EDIT: I am posting the entire code below
int main(int argc,char* argv[]){
char *s = (char *) malloc(20);
char sa[400] = {0};
int i ,count;
printf(" enter the number of chars to write: ");
scanf("%d",&count);
for (i=0;i<count;i++){
printf("%d\n",i);
sa[i] = 'a';
//s[i] = 'a';
}
free(s);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在许多 32 位操作系统上,堆栈向下增长。您只在数组中使用正索引,因此这取决于函数调用的嵌套深度。当您从数组中建立索引时,您将首先覆盖金丝雀。所以堆栈粉碎错误是第一个。接下来,您将开始覆盖函数参数和返回地址。如果没有金丝雀,这将导致函数返回跳转到永远不会的地方,通常会产生段错误。并非总是如此,它可能会意外地落在有效代码上,即堆栈缓冲区溢出攻击背后的逻辑。
当您继续前进时,您最终将越过堆栈顶部写入未分配的页面。然后出现段错误。在一个很少有快速发生的嵌套调用的小型测试程序中,会产生或消耗几千字节的数据。
也可以尝试使用负偏移量。这可以持续一段时间,不会造成任何意外,因为您正在写入未分配的堆栈空间。当您写入超过分配的堆栈大小(通常为兆字节)时,就会出现段错误。在 Windows 上,您将触发堆栈保护页面,生成一个异常,该异常就是为此站点命名的。
On a lot of 32-bit operating systems the stack grows downwards. You only use positive indexes into the array so it depends how deeply nested your function call is. As you index out of the array, you'll first overwrite the canary. So the stack smashing error is first. Next, you'll start overwriting the function arguments and return address. Without the canary, that will cause the function return to jump into nevernever land, usually producing a segfault. Not always, it might accidentally land on valid code, the logic behind stack buffer overflow attacks.
As you keep going, you'll eventually write past the top of the stack into unallocated pages. Segfault then. On a small test program with few nested calls that happens quickly, couple of kilobytes give or take.
Also try it with negative offsets. That can keep going for a while, not otherwise causing any mishap since you're writing into unallocated stack space. The segfault comes when you write past the allocated stack size, typically a megabyte. On Windows you'd trigger the stack guard page, generating an exception for which this site is named.