围绕SwapContext的一点代码

 
这次的胡乱探究原因在于看到了一个08年的帖子:

· 标 题:HOOK SwapContext 枚举隐藏进程(学习笔记4)

· 作 者:bzhkl

· 时 间:2008-12-11 12:01

· 链 接:http://bbs.pediy.com/showthread.php?t=78464

都是很老的东西了,可惜很菜才开始关注

这篇帖子讲了HOOK SwapContext 枚举隐藏进程的方法

下面是我虚拟机的WIN XP SP3  调试的代码:

/*********************************************************************

nt!KiSwapContext:

8054696c 83ec10          sub     esp,10h

8054696f 895c240c        mov     dword ptr [esp+0Ch],ebx

80546973 89742408        mov     dword ptr [esp+8],esi

80546977 897c2404        mov     dword ptr [esp+4],edi

8054697b 892c24          mov     dword ptr [esp],ebp

8054697e 648b1d1c000000  mov     ebx,dword ptr fs:[1Ch]

80546985 8bf1            mov     esi,ecx                       //自己修改处

80546987 8bbb24010000    mov     edi,dword ptr [ebx+124h]

8054698d 89b324010000    mov     dword ptr [ebx+124h],esi

80546993 8a4f58          mov     cl,byte ptr [edi+58h]

80546996 e8f5000000      call    nt!SwapContext (80546a90)     //作者修改处

8054699b 8b2c24          mov     ebp,dword ptr [esp];

8054699e 8b7c2404        mov     edi,dword ptr [esp+4]

805469a2 8b742408        mov     esi,dword ptr [esp+8]

805469a6 8b5c240c        mov     ebx,dword ptr [esp+0Ch]

805469aa 83c410          add     esp,10h

805469ad c3              ret

805469ae 8bff            mov     edi,edi

/**********************************************************************/

作者就是在 0x80546996 地址处修改的CALL  XXXXX  的  XXXXX  使之先调用自己的FAKE函数,在Fake函数里得到换进换出的线程信息,进而得到进程信息。

所以想要试试能不能绕过这种方法,顺便可以增进inline hook以及堆栈平衡的理解

于是,第一次尝试:

作者是通过4号线程(本机)的KernelStack参数得到的SwapContext 的返回地址进而修改,于是打算直接绕过这里的CALL,由于测试中修改5个字节的JMP老是不对,后面指令碎屑填充nop会被认为成这样:jmp  9090:XXXXXXXX,基础有限不知为啥??于是改为了绝对跳转,在这修改

80546985 8bf1            mov     esi,ecx 

Fake函数:

__declspec (naked) VOID Fake_Function()

{

_asm

{

mov     esi,ecx                  //2 Byte

    mov     edi,dword ptr [ebx+124h] //6 Byte

        mov     dword ptr [ebx+124h],esi //6  Byte

        mov     cl,byte ptr [edi+58h]    //3  Byte

}

_asm

{

     _emit 0x90     //CALL SwapContext

         _emit 0x90

         _emit 0x90

         _emit 0x90

_emit 0x90

_emit 0x90     //JMP  BACK

         _emit 0x90

         _emit 0x90

         _emit 0x90

         _emit 0x90  

         _emit 0x90  

         _emit 0x90  

}

}

又想到如果有人在SawpContext开头做了HOOK,不就不行了么,于是又绕过了SawpContext的开头,流程:KiSwapContext--(JMP)---Fake_Function---(CALL)--Fake_SwapContext----(JMP TO)----SwapContext+14处,继续执行---(函数返回)---Fake_Function---(JMP)---KiSwapContext

_declspec (naked) VOID Fake_SwapContext()

{

_asm//14   BYTE

{

or      cl,cl

mov     byte ptr es:[esi+2Dh],2

pushfd

lea     ecx,[ebx+540h]

}

_asm

{

_emit 0x90  //jmp          Fake_SwapContext----SwapContext+0x14

        _emit 0x90

        _emit 0x90

        _emit 0x90

        _emit 0x90  

        _emit 0x90  

        _emit 0x90  

}

}

结果,居然不行。。。

照样可以得到进程信息,当时就郁闷了,结果用WINDBG查看,发现  自己的  CALL   SwapContext 被   替换成了他的,也就是说  他得到的  KernelStack  是我的CALL  Fake_SwapContext的返回地址。。。。KernelStack被修改了。。。。

基础太烂,都不知道KernelStack这个内核栈调用的开始是干嘛的,于是又在  CALL  Fake_SwapContext  前面加了一个CALL (一个空函数) 不行。。。。改为  在后面加一个CALL  还是不行。。。检测程序都能正确定位CALL    SwapContext   地址然后替换。。。。

查看SwapContext的具体实现发现,有这么一处:

80546ae0 fa              cli

80546ae1 896728          mov     dword ptr [edi+28h],esp

这里将栈指针存储到了线程的KernelStack,怪不得老能被他正确定位。。

于是,第二次尝试

在原有第一次基础上,在SwapContext函数的

80546ada 8a4e2c          mov     cl,byte ptr [esi+2Ch]    //这里跳走

80546add 884b50          mov     byte ptr [ebx+50h],cl

80546ae0 fa              cli

80546ae1 896728          mov     dword ptr [edi+28h],esp

80546ae4 8b4618          mov     eax,dword ptr [esi+18h]   //跳回这里

80546ae7 8b4e1c          mov     ecx,dword ptr [esi+1Ch]

跳转到自己的函数,修改esp的值,当时想就只是修改了线程的KernelStack的值,之后又恢复了esp的值,继续执行SwapContext后边的指令( mov     eax,dword ptr [esi+18h]   //跳回这里),应该可以吧...结果蓝的不成样子,完全不知道什么错误

还发现

u  KiSwapContext

得到的结果完全不同于原始的,第一条指令就不同。。我就纳闷了,KiSwapContext函数怎么会被改掉????

于是,第三次尝试

还是第一次这个流程

    流程:KiSwapContext--(JMP)---Fake_Function---(CALL)--Fake_SwapContext----(JMP TO)----SwapContext+14处,继续执行---(函数返回)---Fake_Function---(JMP)---KiSwapContext

    但是会在Fake_Function开始即判断接下来自己的   CALL  Fake_SwapContext有没有被修改,如果没有,继续走这个流程,如果被修改了,则跳回

80546996 e8f5000000      call    nt!SwapContext (80546a90)    

继续执行,不走这个流程了,心想这样应该可以了吧。。。。

经过测试成功!

修改如下:

#include <ntddk.h>

#define LOCKEDCODE code_seg()

ULONG RealSwapContextOffset;

ULONG FixAddr;//函数KiSwapContext修改处的地址

ULONG SwapContextAddr;

ULONG NextAddr;//KiSwapContext  CALL 处的下一条指令地址

ULONG GoBackAddr;

ULONG CallAddr;//CALL Fake_Swap处的地址

extern KIRQL Irql;

extern ULONG g_uCr0;

ULONG NewCallOffset;//CALL新的偏移

PETHREAD Thread;

VOID Fake_SwapContext();

VOID Fake_Stack();

BYTE Call_To_SwapContext[5]={0xE8,0,0,0,0};

BYTE Jmp_To_KiSwapContext[7] = {0xEA, 0, 0, 0, 0, 0x08, 0x00 };

BYTE Jmp_To_SwapContext[7] = {0xEA, 0, 0, 0, 0, 0x08, 0x00 };

BYTE JNZ_JMP[6]={0x0f,0x85, 0, 0, 0, 0};BYTE EditCode[8]={0xEA,0,0,0,0,0x08,0x00,0x90};

BYTE EditCode1[1]={0x90};

NTKERNELAPI

NTSTATUS

PsLookupThreadByThreadId (

    IN PVOID        UniqueThreadId,

    OUT PETHREAD    *Thread

);

ULONG GetRealSwapContextOffset()

{

ULONG status;

ULONG Off; status=PsLookupThreadByThreadId((PVOID)8, &(PETHREAD)Thread);//win xp sp3

DbgPrint("Thread地址:%x\n",Thread);

if(NT_SUCCESS(status))

{

if(MmIsAddressValid(Thread))

{

NextAddr = *(PULONG)((ULONG)Thread+0x028 );

}

if(MmIsAddressValid(NextAddr+8))

{

_asm

{

push eax

mov eax,NextAddr

add eax,8

mov eax,[eax]

mov NextAddr,eax;

pop eax

}

DbgPrint("NextAddr:%x\n",NextAddr);

}

}

else

{

return 0;

}

_asm

{

mov eax,NextAddr

    sub eax,5

mov FixAddr,eax

mov edx,[eax+1]

push edx

pop Off

}

DbgPrint("FixAddr:%x\n",FixAddr);

DbgPrint("偏移:%x\n",Off);

SwapContextAddr=Off+NextAddr;

DbgPrint("SwapContext地址:%x\n",SwapContextAddr);

return Off;

}

__declspec (naked) VOID Fake_Function()

{

_asm

{

mov     esi,ecx                  //2 BYTE

    mov     edi,dword ptr [ebx+124h] //6 BYTE

        mov     dword ptr [ebx+124h],esi //6 BYTE

        mov     cl,byte ptr [edi+58h]    //3 BYTE

}//17 BYTE   对抗内核栈Patch

_asm

{

push ebx                         //1 BYTE

mov ebx,Fake_Function            //5 BYTE

add ebx,55                       //3 BYTE

mov ebx,[ebx]                    //2 BYTE

mov CallAddr,ebx                 //6 BYTE

pop ebx                          //1 BYTE

}//38

_asm

{

push eax                              //1 BYTE

mov eax,CallAddr                      //5 BYTE

cmp eax,NewCallOffset                 //6 BYTE

pop eax                               //1 BYTE

}//48

_asm

{

_emit 0x90  // 这个填充 jnz   //跳转到?KiSwapContext

        _emit 0x90

        _emit 0x90

        _emit 0x90

        _emit 0x90  //绝对地址

        _emit 0x90  

}//54

_asm

{

_emit 0x90  // 这个填充CALL   e8 xxxxxxxx 

        _emit 0x90

        _emit 0x90

        _emit 0x90

_emit 0x90

_emit 0x90  // 这个填充 jmp   //跳转到  KiSwapContext

        _emit 0x90

        _emit 0x90

        _emit 0x90

        _emit 0x90  //绝对地址

        _emit 0x90  

        _emit 0x90

}

}

VOID StartHookKiSwapContext()

{

ULONG uAttr;

ULONG uTemp,uTemp1;

ULONG NewCallOffset1;

RealSwapContextOffset=GetRealSwapContextOffset();

uTemp=(ULONG*)((BYTE*)Fake_Function+54);

NewCallOffset=(ULONG)Fake_SwapContext-uTemp-5;//Fake_Function----Fake_SwapContext

NewCallOffset1=(ULONG*)((BYTE*)SwapContextAddr+14);

DbgPrint("uTemp:%x\n",uTemp);

DbgPrint("NewCallOffset1:%x\n",NewCallOffset1);

DbgPrint("NewCallOffset:%x\n",NewCallOffset);

_asm

    {

        push eax;

        mov eax, cr0;

        mov uAttr, eax;

        and eax, 0FFFEFFFFh;

        mov cr0, eax;

        pop eax;

        cli

    }

    g_uCr0 = uAttr;

    //提升IRQL中断级

    //Irql=KeRaiseIrqlToDpcLevel();

*(ULONG*)(EditCode+1)=(ULONG*)Fake_Function;// KiSwapContext----Fake_Function

*((ULONG*)(Call_To_SwapContext + 1)) =NewCallOffset;//填充CALL指令

*((ULONG*)(Jmp_To_KiSwapContext + 1)) = (ULONG)((BYTE*)FixAddr+5);//填充JMP

*((ULONG*)(Jmp_To_SwapContext + 1)) = NewCallOffset1;

CallAddr=*(ULONG*)((BYTE*)Fake_Function+55);   //CALL   Fake_SwapContext    *(PULONG)CallAddr==(PULONG)Fake_SwapContext

*((ULONG*)(JNZ_JMP + 2)) = (ULONG)((BYTE*)FixAddr-1)-(ULONG)(((BYTE*)Fake_Function+48))-5;

RtlCopyMemory((BYTE*)Fake_Function+ 48,JNZ_JMP,6);

RtlCopyMemory((BYTE*)Fake_Function+ 54,Call_To_SwapContext,5); //Fake_Function----Fake_SwapContext     

RtlCopyMemory((BYTE*)Fake_SwapContext+14,Jmp_To_SwapContext,7);//Fake_SwapContext----SwapContext+0x14

RtlCopyMemory((BYTE*)Fake_Function+ 59,Jmp_To_KiSwapContext,7);//Fake_Function----KiSwapContext  

RtlCopyMemory((BYTE*)FixAddr-17,EditCode,8);//KiSwapContext----Fake_Function

//_asm int 3

    //KeLowerIrql(Irql);

    _asm

    {

        sti

        push eax;

        mov eax, g_uCr0;

        mov cr0, eax;

        pop eax;

    }

}

_declspec (naked) VOID Fake_SwapContext()

{

_asm//14   BYTE

{

or      cl,cl

mov     byte ptr es:[esi+2Dh],2

pushfd

lea     ecx,[ebx+540h]

}

_asm

{

    _emit 0x90  // 这个填充 jmp          Fake_SwapContext----SwapContext+0x14

        _emit 0x90

        _emit 0x90

        _emit 0x90

        _emit 0x90  

        _emit 0x90  

        _emit 0x90  

}

}

调用StartHookKiSwapContext即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值