callstack:伪造返回地址绕过CallStack检测以及检测伪造返回地址的实战笔记

来源:安全焦点

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改了段属性.在内核态
话...这个修改代码段段属性问题...应该很简单把...





  • 篇文章: 谈VBS在Hacking中作用的 2

  • 篇文章: 简简单单清除肉鸡上日志文件
  • Tags:  伪造ip callstack.dump .netcallstack callstack

    延伸阅读

    最新评论

    发表评论