jus*_*sij 15
在Windows上,将生成堆栈溢出异常.
以下Windows代码说明了这一点:
#include <stdio.h>
#include <windows.h>
void StackOverFlow()
{
CONTEXT context;
// we are interested control registers
context.ContextFlags = CONTEXT_CONTROL;
// get the details
GetThreadContext(GetCurrentThread(), &context);
// print the stack pointer
printf("Esp: %X\n", context.Esp);
// this will eventually overflow the stack
StackOverFlow();
}
DWORD ExceptionFilter(EXCEPTION_POINTERS *pointers, DWORD dwException)
{
return EXCEPTION_EXECUTE_HANDLER;
}
void main()
{
CONTEXT context;
// we are interested control registers
context.ContextFlags = CONTEXT_CONTROL;
// get the details
GetThreadContext(GetCurrentThread(), &context);
// print the stack pointer
printf("Esp: %X\n", context.Esp);
__try
{
// cause a stack overflow
StackOverFlow();
}
__except(ExceptionFilter(GetExceptionInformation(), GetExceptionCode()))
{
printf("\n****** ExceptionFilter fired ******\n");
}
}
Run Code Online (Sandbox Code Playgroud)
运行此exe时,将生成以下输出:
Esp: 12FC4C
Esp: 12F96C
Esp: 12F68C
.....
Esp: 33D8C
Esp: 33AAC
Esp: 337CC
****** ExceptionFilter fired ******
Run Code Online (Sandbox Code Playgroud)
adl*_*adl 12
在Linux上,如果代码尝试写入堆栈,则会出现分段错误.
堆栈的大小是进程之间继承的属性.如果你可以阅读或修改它在使用类似的命令壳ulimit -s(中sh,ksh,zsh)或limit stacksize(tcsh,zsh).
从程序中,可以使用读取堆栈的大小
#include <sys/resource.h>
#include <stdio.h>
struct rlimit l;
getrlimit(RLIMIT_STACK, &l);
printf("stack_size = %d\n", l.rlim_cur);
Run Code Online (Sandbox Code Playgroud)
我不知道获得可用堆栈大小的标准方法.
堆栈首先argc跟着argv环境的内容和副本,然后是你的变量.但是因为内核可以随机化堆栈起始位置,并且上面可能存在一些虚拟值argc,所以假设您在l.rlim_cur下面有可用字节是错误的&argc.
检索堆栈的确切位置的一种方法是查看文件/proc/1234/maps (1234程序的进程ID 在哪里).一旦了解了这些边界,就可以通过查看最新局部变量的地址来计算堆栈的使用量.
Kkn*_*knd 10
gcc在"不安全"函数调用中的返回地址和正常变量之间放置了一个额外的内存块,就像(在这个例子中函数是void test(){char a [10]; b [20]}:
call stack:
-----------
return address
dummy
char b[10]
char a[20]
Run Code Online (Sandbox Code Playgroud)
如果函数在指针'a'中写入36个字节,则溢出将"损坏"返回地址(可能的安全漏洞).但它也会改变'dummy'的值,即指针和返回地址之间的值,因此程序会崩溃并发出警告(你可以使用-fno-stack-protector禁用它)
在Windows上,堆栈(针对特定线程)按需增长,直到达到为此线程创建之前指定的堆栈大小.
按需增长是使用保护页面实现的,因为最初只有一个堆栈片段可用,然后是一个保护页面,当被命中时会触发异常 - 这个异常是特殊的,并由系统处理you - 处理增加了可用的堆栈空间(如果已达到限制,也会检查!)并重试读取操作.
一旦达到限制,就不再增长,导致堆栈溢出异常.当前堆栈基数和限制存储在线程环境块中,称为_NT_TIB(线程信息块).如果你有一个方便的调试器,这就是你看到的:
0:000> dt ntdll!_teb @$teb nttib.
+0x000 NtTib :
+0x000 ExceptionList : 0x0012e030 _EXCEPTION_REGISTRATION_RECORD
+0x004 StackBase : 0x00130000
+0x008 StackLimit : 0x0011e000
+0x00c SubSystemTib : (null)
+0x010 FiberData : 0x00001e00
+0x010 Version : 0x1e00
+0x014 ArbitraryUserPointer : (null)
+0x018 Self : 0x7ffdf000 _NT_TIB
Run Code Online (Sandbox Code Playgroud)
StackLimit属性将按需更新.如果检查此内存块上的属性,您将看到类似的内容:
0:000> !address 0x0011e000
00030000 : 0011e000 - 00012000
Type 00020000 MEM_PRIVATE
Protect 00000004 PAGE_READWRITE
State 00001000 MEM_COMMIT
Usage RegionUsageStack
Pid.Tid abc.560
Run Code Online (Sandbox Code Playgroud)
检查旁边的页面会显示guard属性:
0:000> !address 0x0011e000-1000
00030000 : 0011d000 - 00001000
Type 00020000 MEM_PRIVATE
Protect 00000104 PAGE_READWRITE | PAGE_GUARD
State 00001000 MEM_COMMIT
Usage RegionUsageStack
Pid.Tid abc.560
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你.
| 归档时间: |
|
| 查看次数: |
25849 次 |
| 最近记录: |