首页
社区
课程
招聘
[讨论]堆栈不平衡居然没有出错?
发表于: 2008-4-26 17:16 5520

[讨论]堆栈不平衡居然没有出错?

2008-4-26 17:16
5520
以前不懂汇编的时候,要做一个APIHook,借鉴了一个叫Hookyou的APIhook部分关键代码。
它的原理就是在call过去的API函数头7个字节生成一个jmp far跳到自己的代码这里,处理完后恢复这7个字节,再call回去,ret后重新修改这7个字节再ret。
7个字节中最后两个好像是段基址,它是用以下代码读取的:
WORD wCS = 0;
_asm
{
        push ax
        push cs
        pop ax                ;应该是pop eax吧?
        mov wCS, ax
        pop ax
}
当时比较菜,根本没看懂在干什么,只是依样画葫芦,结果程序运行很正常,API也Hook成功了。
但是今天看来,这段程序WIN32下,堆栈明显不平衡,测试了一下,结果也确实如此。如果在自己的程序里加上这段,发现函数返回后,立即报栈出错。
可是为什么调用了这段代码的dll却没有事呢?

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 207
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
没有发现不平衡呀,两个push,两个pop,哪里不平衡了?
pop    ax
也很正确,它要获取的是上一条指令push cs的值,cs是一个字的长度,用ax就可以了,你不会是在用的时候改为eax了吧!!!!这样就是出栈了一个双字,连上面一条指令push ax的值都读出来了,还怎么平衡?那样的话pop  ax这条就破坏堆栈了。
2008-4-26 18:55
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
可是我调试的时候发现push cs的时候esp减小了4个啊,所以才说是堆栈不平衡,要不你去试试……
2008-4-26 20:36
0
雪    币: 207
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
我没有办法试,如果是那样的话,你再把它上面的和下面的代码也发一些上来吧,结合上下文看看,是不是有什么伎俩!最好是发全汇编的,像OD里显示的或者其他的。

说了楼主不要骂噶,我有点不相信你说的,从未听说过,期待看看,或者程序小的话,附件上来看看如何?
2008-4-27 00:20
0
雪    币: 207
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
[QUOTE='UD]Arthas;446081']我没有办法试,如果是那样的话,你再把它上面的和下面的代码也发一些上来吧,结合上下文看看,是不是有什么伎俩!最好是发全汇编的,像OD里显示的或者其他的。

说了楼主不要骂噶,我有点不相信你说的,从未听说过,期待看看,或者程序小的话,附件上来看看如何?[/QUOTE]

我在OD中自己试了一下确实是和楼主所说的存在不平衡的情况,push cs时压入栈的是32位的 我以前从来不知道,压栈时会多压入16位的0,扩充成一个32位的数,最后堆栈中两个pop只弹出了push cs的值,而第一个push ax的值依然还在,造成堆栈有一个字的偏移,呵呵。
我想这个要结合上下文看看
我也期待高手来回答!!!!
2008-4-27 00:45
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
void MakeJMPCode(LPBYTE lpJMPCode, LPVOID lpCodePoint)
{
	BYTE temp;
	WORD wHiWord = HIWORD(lpCodePoint);
	WORD wLoWord = LOWORD(lpCodePoint);
	WORD wCS;

	_asm						// 取當前選擇符﹒
	{
		push ax;
		push cs;
		pop  ax;
		mov  wCS, ax;
		pop  ax;
	};
	
	lpJMPCode[0] = 0xea;		// 填入 JMP 指令的機器碼﹒

	temp = LOBYTE(wLoWord);		// -------------------------
	lpJMPCode[1] = temp;
	temp = HIBYTE(wLoWord);
	lpJMPCode[2] = temp;		// 填入地址﹒在內存中的順序為;
	temp = LOBYTE(wHiWord);		// Point: 0x1234
	lpJMPCode[3] = temp;		// 內存: 4321
	temp = HIBYTE(wHiWord);
	lpJMPCode[4] = temp;		// -------------------------
	
	temp = LOBYTE(wCS);			// 填入選擇符﹒
	lpJMPCode[5] = temp;
	temp = HIBYTE(wCS);
	lpJMPCode[6] = temp;

	return;
}

反汇编后太长了,这段代码代码也就这么回事,看不出有什么伎俩在里面。

原代码在附件里,我断点测试过,确实是不平衡。
上传的附件:
2008-4-28 09:30
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
自己顶一下……
2008-4-28 16:08
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
8
堆栈不平衡只是有可能会引起崩溃,但是不一定就得崩溃

不知道从哪个版本的VC开始,会在函数头生成HASH,然后再函数尾再次HASH,前后不等便抛异常
2008-4-28 21:05
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
9
看起来是不平衡没错.
二个 pop ax 抵掉一个 CS , 所以还有一个 ax 没出来. 此时ESP是 Word 对齐(不是DWord对齐)
但是在最后他 mov esp,ebp 还原了Stack框. 也就没影响了.
不过..这明显是一个 Bug

10001AB0  /$ 55             push ebp
10001AB1  |. 8BEC           mov ebp,esp
10001AB3  |. 83EC 50        sub esp,50
10001AB6  |. 53             push ebx
10001AB7  |. 56             push esi
10001AB8  |. 57             push edi
10001AB9  |. 8B45 0C        mov eax,dword ptr ss:[ebp+C]
10001ABC  |. C1E8 10        shr eax,10
10001ABF  |. 25 FFFF0000    and eax,0FFFF
10001AC4  |. 66:8945 F8     mov word ptr ss:[ebp-8],ax
10001AC8  |. 66:8B4D 0C     mov cx,word ptr ss:[ebp+C]
10001ACC  |. 66:894D F4     mov word ptr ss:[ebp-C],cx
10001AD0  |. 66:50          push ax        ;有 66, 推入 Word
10001AD2  |. 0E             push cs        ;没 66, 在这里是推入 DWord
10001AD3  |. 66:58          pop ax        ;有 66, 取出 Word
10001AD5  |. 66:8945 F0     mov word ptr ss:[ebp-10],ax
10001AD9  |. 66:58          pop ax        ;有 66, 取出 Word
10001ADB  |. 8B55 08        mov edx,dword ptr ss:[ebp+8]  ;
10001ADE  |. C602 EA        mov byte ptr ds:[edx],0EA
10001AE1  |. 8A45 F4        mov al,byte ptr ss:[ebp-C]
10001AE4  |. 8845 FC        mov byte ptr ss:[ebp-4],al
10001AE7  |. 8B4D 08        mov ecx,dword ptr ss:[ebp+8]
10001AEA  |. 8A55 FC        mov dl,byte ptr ss:[ebp-4]
10001AED  |. 8851 01        mov byte ptr ds:[ecx+1],dl
10001AF0  |. 8B45 F4        mov eax,dword ptr ss:[ebp-C]
10001AF3  |. 25 FFFF0000    and eax,0FFFF
10001AF8  |. C1F8 08        sar eax,8
10001AFB  |. 25 FF000000    and eax,0FF
10001B00  |. 8845 FC        mov byte ptr ss:[ebp-4],al
10001B03  |. 8B4D 08        mov ecx,dword ptr ss:[ebp+8]
10001B06  |. 8A55 FC        mov dl,byte ptr ss:[ebp-4]
10001B09  |. 8851 02        mov byte ptr ds:[ecx+2],dl
10001B0C  |. 8A45 F8        mov al,byte ptr ss:[ebp-8]
10001B0F  |. 8845 FC        mov byte ptr ss:[ebp-4],al
10001B12  |. 8B4D 08        mov ecx,dword ptr ss:[ebp+8]
10001B15  |. 8A55 FC        mov dl,byte ptr ss:[ebp-4]
10001B18  |. 8851 03        mov byte ptr ds:[ecx+3],dl
10001B1B  |. 8B45 F8        mov eax,dword ptr ss:[ebp-8]
10001B1E  |. 25 FFFF0000    and eax,0FFFF
10001B23  |. C1F8 08        sar eax,8
10001B26  |. 25 FF000000    and eax,0FF
10001B2B  |. 8845 FC        mov byte ptr ss:[ebp-4],al
10001B2E  |. 8B4D 08        mov ecx,dword ptr ss:[ebp+8]
10001B31  |. 8A55 FC        mov dl,byte ptr ss:[ebp-4]
10001B34  |. 8851 04        mov byte ptr ds:[ecx+4],dl
10001B37  |. 8A45 F0        mov al,byte ptr ss:[ebp-10]
10001B3A  |. 8845 FC        mov byte ptr ss:[ebp-4],al
10001B3D  |. 8B4D 08        mov ecx,dword ptr ss:[ebp+8]
10001B40  |. 8A55 FC        mov dl,byte ptr ss:[ebp-4]
10001B43  |. 8851 05        mov byte ptr ds:[ecx+5],dl
10001B46  |. 8B45 F0        mov eax,dword ptr ss:[ebp-10]
10001B49  |. 25 FFFF0000    and eax,0FFFF
10001B4E  |. C1F8 08        sar eax,8
10001B51  |. 25 FF000000    and eax,0FF
10001B56  |. 8845 FC        mov byte ptr ss:[ebp-4],al
10001B59  |. 8B4D 08        mov ecx,dword ptr ss:[ebp+8]
10001B5C  |. 8A55 FC        mov dl,byte ptr ss:[ebp-4]
10001B5F  |. 8851 06        mov byte ptr ds:[ecx+6],dl
10001B62  |. 5F             pop edi
10001B63  |. 5E             pop esi
10001B64  |. 5B             pop ebx
10001B65  |. 8BE5           mov esp,ebp
10001B67  |. 5D             pop ebp
10001B68  \. C2 0800        retn 8
2008-4-29 01:06
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
原来是最后有一次mov esp, ebp……
我测试的时候把那个函数拷贝到自己的项目里面,用DEBUG编译,结果就出错了,还以为是ret的时候堆栈位置不对导致的,也没有细看。
听LS一说,又去看了一下,发现原来是最后一句mov esp,ebp之前多了三句话:
00411AE0  add         esp,0F0h
00411AE6  cmp         ebp,esp
00411AE8  call        @ILT+935(__RTC_CheckEsp) (4113ACh)
这个检测主动抛的异常,差不多就是8L说的那种。
现在终于明白了,谢谢各位了……
2008-4-29 09:42
0
游客
登录 | 注册 方可回帖
返回
//