微软的C\C++编译器总是非常的弱智,不但随便乱插运行时函数,还随便加进乱七八糟的引用,导致程序难以通用。例如__chkstk函数,只要你使用8120字节以上的局部变量,他就会偷偷调用(CALL)该函数, 例如
int Data[8192];
int *P=(int*)&Data;
for(int I=0;I<8192;I++,P++)
{
*P=(int)I;
}
ALIGN DWORD
chkstk PROC USES EBX EDX ESI EDI mov eax,esp
mov ecx,32
@@:
sub esp, 1000H
test BYTE PTR[esp],0
loop @B
mov esp,eax
ret chkstk
于是就可以访问了.
但我们的问题有三:
1:随便乱CALL导致代码不可整体搬移.
2:在内核即使探测也没用,内核堆栈只有8KB,探测也不会提交,更不会增大.
3:偷偷摸摸乱增加引用增加了调试难度. 如果我们真的需要增大堆栈,那么在用户态,我们完全可以ZwAllocateVirtualMemory分配10-20MB,在内核态我们可以用ExAllocatePoolWithTag分配几MB,然后 mov esp,xxxxxxxx.
int Data[8192];
int *P=(int*)&Data;
for(int I=0;I<8192;I++,P++)
{
*P=(int)I;
}
反汇编结果,在进行for循环之前,他会隐藏调用__chkstk。该函数 汇编伪代码如下:
ALIGN DWORD
chkstk PROC USES EBX EDX ESI EDI mov eax,esp
mov ecx,32
@@:
sub esp, 1000H
test BYTE PTR[esp],0
loop @B
mov esp,eax
ret chkstk
ENDP
于是就可以访问了.
但我们的问题有三:
1:随便乱CALL导致代码不可整体搬移.
2:在内核即使探测也没用,内核堆栈只有8KB,探测也不会提交,更不会增大.
3:偷偷摸摸乱增加引用增加了调试难度. 如果我们真的需要增大堆栈,那么在用户态,我们完全可以ZwAllocateVirtualMemory分配10-20MB,在内核态我们可以用ExAllocatePoolWithTag分配几MB,然后 mov esp,xxxxxxxx.
因此这种鸡肋的功能没有必要留在程序里.但是翻遍MSDN,没有找到取消的办法,最后在编译器参数里(项目->属性->配置属性->C/C++->命令行->其他选项),找到某个参数,说明如下:
/Gs 设置堆栈检查字节数. 我们使用/Gs8192设置堆栈检查字节为8MB,经测试,对 __chkstk的调用没有了,成功达到我们的目的.