Author:[CISRG]KiSSinGGer
E-mail:[email protected]
MSN:[email protected]
题目有点搞......Anti-CallStack Check and Anti-Anti-CallStack Check...(;- -)
发现最近MJ0011“基于CallStackAnti-Rootkit HOOK检测思路”和gyzy“基于栈指纹检测缓冲区溢出点思路”两篇文章有异曲同工的妙
两者都通过检测CallStack中返回地址来做文章
最近在初步学习些AntiRootkit技术这两个不得不吸引我眼球
按照MJ0011大侠逻辑,从Rootkit DetectorHook点向上检测CallStack.
但是CallStack里面都是些DWORDs,如何判断哪儿是参数,哪儿是返回地址呢?
我Goo了两把...普遍是用EBP回溯方式.
考虑大部分__stdcall形式:
mov edi edi
push ebp
mov ebp esp
...
...
我们从dword ptr [EBP]里面可以获得上个callEBP,dword ptr [EBP+4]里面获得需要检测返回地址,然后EBP = dword ptr [EBP],继续找下去.找到栈基址为止.
每次得到返回地址,判断下它是否在个合法模块中.
但是,根据gyzy大侠<编写绕过卡巴主动防御Shellcode>文启示,我们可以知道如下种方式,可使这样检测方式失效.
1.在合法系统模块里(e.g. ntoskrnl.exe),找到个'C3'(ret Opcode)字节,它指针是K.
2.使用如下方式Hook
HookedZwXxx(...)
{
//
// 些参数处理操作
//
jmp __pushrealretaddr
__trickstage:
push Arg[N]
push Arg[N-1]
...
push Arg[0]
push K
jmp ZwXxx; //原始
__pushrealretaddr:
call __trickstage
realretaddr:
//
// 另些结果处理操作
//
}
这样,在ZwXxx深处检查栈,dword ptr [EBP+4]是个处于合法模块中地址K.
我写了个如下ring3举例.
定义如下些:
__stdcall Call_C( a, b)
{
check_callstack;
a+b;
}
__stdcall Call_B( a, b)
{
Call_C(a,b);
}
__stdcall Call_A( a, b)
{
Call_B(a,b);
}
次序是A->B->C,其中C里面执行check_callstack来检测是否有非法返回地址.
void
__stdcall
check_callstack( void )
{
saved_ebp;
retaddr;
prf("Check Call Stack Methord 1:\n");
__asm
{
mov eax, dword ptr [ebp+4]
mov retaddr, eax
mov eax, dword ptr [ebp]
mov saved_ebp, eax
}
prf("retaddr = 0x%08X\n",retaddr);
while(saved_ebp < StackBase && saved_ebp > 0)
{
(saved_ebp != 0)
{
retaddr = *(*)(saved_ebp+4);
prf("retaddr = 0x%08X\n",retaddr);
saved_ebp = *(*)saved_ebp;
}
}
}
在没有Hook情况下,我们执行Call_A(1,2),得到正常返回为3.
check_callstack输出:
retaddr = 0x00401008
retaddr = 0x00401030
retaddr = 0x00401050
retaddr = 0x00401126
retaddr = 0x0040149D
retaddr = 0x7C816FD7
我们现在使用个Hooked_Call_B来在Call_A中把Call_B给Hook掉.
Hook掉Call_B做只是把返回值改成4.
__declspec( naked )
Hooked_Call_B( a, b)
{
__asm
{
push ebp
mov ebp, esp
jmp __a
__trickstage:
mov eax, b
push eax
mov eax, a
push eax
//为了方便这里使用个OD得到硬编码:P
push 0x004011AD //这个地址指向个'C3'
jmp Call_B
__a:
call __trickstage
mov eax, 4 //这里,改返回值,使得1+2结果为4.
pop ebp
ret 8
}
}
用来改写Call_A,这个在2003编译出来EXE中会导致异常
.text段没有写权限.实际测试中我用StudPE改了段属性.在内核态
话...这个修改代码段段属性问题...应该很简单把...
最新评论