首页
社区
课程
招聘
[分享]绕过Hackshield的hook
发表于: 2012-5-9 01:22 19511

[分享]绕过Hackshield的hook

2012-5-9 01:22
19511
之前提到过新奇迹世界用的Hackshield,用雪村看了下它的驱动,发现做一些hook,
有ssdt hook和inline函数hook:


我想恢复这些hook,参考了360安全卫士修改nt!KiFastCallEntry函数的思路,
可以参照下这个帖子 http://bbs.pediy.com/showthread.php?t=143364&highlight=

思路就是:在nt!KiFastCallEntry中,通过ssdt计算出内核函数后,调用内核函数前,先进入我的函数,根据索引号判断是否使用通过ssdt计算出的内核函数,还是原始的内核函数。

下面的代码我只做了NtWriteVirtualMemory、NtReadVirtualMemory、NtClose和NtOpenProcess的恢复,环境是win7 32bit,nt模块为ntkrnlpa.exe。此程序只为研究,所以代码中有些硬编码,请见谅。

#include "moniprocess.h"
#include "HookKiFastCallEntry.h"

ULONG g_uHookKiFastCallEntryCr0 = 0;
ULONG g_ulHookKiFastCallEntry = 0;                                        // 将要被hook的地址
ULONG g_ulJmpBackAddr = 0;                                                        // 跳回的地址
JmpCode g_struOldValue_KiFastCallEntry;                               

ULONG g_uIndexOfNtWriteVirtualMemory = 0x18f;                // NtWriteVirtualMemory在ssdt中的索引号
ULONG g_uAddrOfNtWriteVirtualMemory = 0;                        // NtWriteVirtualMemory首地址  rva=0x26171C

ULONG g_uIndexOfNtReadVirtualMemory = 0x115;                // NtReadVirtualMemory在ssdt中的索引号
ULONG g_uAddrOfNtReadVirtualMemory = 0;                                // NtReadVirtualMemory首地址  rva=0x26182C

ULONG g_uIndexOfNtClose = 0x32;                                                // NtClose在ssdt中的索引号
ULONG g_uAddrOfNtClose = 0;                                                        // NtClose首地址  rva=0x24637A

ULONG g_uIndexOfNtOpenProcess = 0x0be;                                // NtOpenProcess在ssdt中的索引号
ULONG g_uAddrOfPsOpenProcess = 0;                                        // PsOpenProcess首地址  rva=0x277E6C

__declspec(naked) int MyNtOpenProcess() // 由于NtOpenProcess被做了inline函数hook,所以这里我自己实现了这个函数,这里是直接拷贝的反汇编代码
{
        _asm
        {
                mov    edi, edi
                push   ebp
                mov    ebp, esp
                push   ecx
                push   ecx
                mov    eax, dword ptr fs:[0x124]
                mov    al, byte ptr [eax+0x13A]
                mov    ecx, dword ptr [ebp+0x14]
                mov    edx, dword ptr [ebp+0x10]
                mov    byte ptr [ebp-0x4], al
                push   dword ptr [ebp-0x4]
                push   dword ptr [ebp-0x4]
                push   dword ptr [ebp+0x0C]
                push   dword ptr [ebp+0x8]
                mov    eax, g_uAddrOfPsOpenProcess
                call   eax
               
               
               
                //leave ==

                mov    esp, ebp
                pop    ebp

                retn   0x10
        }
}

__declspec(naked) int Jmp_KiFastCallEntry()
{
        // eax为ssdt的索引号
        // edi为ServiceTableBase地址
        // edx为得到的系统函数地址

        _asm
        {               
                //pushfd
                //pushad

                // 判断是否需要恢复

                cmp eax, g_uIndexOfNtWriteVirtualMemory
                je Goto_Set_NtWriteVirtualMemory
               
                cmp eax, g_uIndexOfNtReadVirtualMemory
                je Goto_Set_NtReadVirtualMemory

                cmp eax, g_uIndexOfNtOpenProcess
                je Goto_Set_NtOpenProcess

                cmp eax, g_uIndexOfNtClose
                je Goto_Set_NtClose

                jmp Goto_End
        }

Goto_Set_NtClose:

        _asm
        {
                mov edx, g_uAddrOfNtClose // 设置原始的内核函数地址
                jmp Goto_End
        }

Goto_Set_NtOpenProcess:

        _asm
        {
                mov edx, MyNtOpenProcess  // 设置原始的内核函数地址
                jmp Goto_End
        }

Goto_Set_NtReadVirtualMemory:

        _asm
        {
                mov edx, g_uAddrOfNtReadVirtualMemory  // 设置原始的内核函数地址
                jmp Goto_End
        }

Goto_Set_NtWriteVirtualMemory:

        _asm
        {
                mov edx, g_uAddrOfNtWriteVirtualMemory
        }

Goto_End:

        _asm
        {
                //popad
                //popfd

                sub esp, ecx
                shr ecx, 2

                jmp g_ulJmpBackAddr               
        }
}


NTSTATUS RealHookKiFastCallEntry()
{
        if( 0 != g_ulHookKiFastCallEntry )
        {
                ULONG ulMachineCode;
                ulMachineCode = GetMachineCode( g_ulHookKiFastCallEntry, Jmp_KiFastCallEntry );

                WPOFF( &g_uHookKiFastCallEntryCr0 );

                __asm
                {                         
                        // save  5字节
                        mov eax, g_ulHookKiFastCallEntry
                        mov ebx, dword ptr [ eax ]
                        mov g_struOldValue_KiFastCallEntry.dwJmpCode[0], ebx

                        mov bl, byte ptr [ eax + 4 ]
                        mov ecx, offset g_struOldValue_KiFastCallEntry
                        mov byte ptr [ ecx + 4 ], bl

                        // hook
                        mov byte ptr [ eax ], 0x0e9

                        add eax, 1
                        mov ecx, ulMachineCode
                        mov dword ptr [ eax ], ecx
                }

                WPON( &g_uHookKiFastCallEntryCr0 );

                return STATUS_SUCCESS;
        }

        g_ulHookKiFastCallEntry = 0;

        return STATUS_ACCESS_DENIED;
}

NTSTATUS HookKiFastCallEntry( IN ULONG ulFunAddr )
{
        NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;

        if( 0 == ulFunAddr )
                return ntStatus;

        g_ulHookKiFastCallEntry = ulFunAddr;
        if( 0x0e9c1e12b == *( (PDWORD)g_ulHookKiFastCallEntry ) )
        {
                ntStatus = RealHookKiFastCallEntry();
                if( !NT_SUCCESS( ntStatus ) )
                        g_ulHookKiFastCallEntry = 0;
        }

        return ntStatus;
}

VOID UnHookKiFastCallEntry()
{
        if( 0 != g_ulHookKiFastCallEntry )
        {

                WPOFF( &g_uHookKiFastCallEntryCr0 );

                __asm
                {
                        // 恢复  5字节
                        mov eax, g_ulHookKiFastCallEntry
                        mov ebx, g_struOldValue_KiFastCallEntry.dwJmpCode[0]
                        mov dword ptr [ eax ], ebx

                        mov ecx, offset g_struOldValue_KiFastCallEntry
                        mov bl, byte ptr [ ecx + 4 ]
                        mov byte ptr [ eax + 4 ], bl       
                }

                WPON( &g_uHookKiFastCallEntryCr0 );

                KeSleep( 1 );
        }

        g_ulHookKiFastCallEntry = 0;
}

BOOL GetKiFastCallEntryAddr_XP32_And_WIN732( OUT PULONG pFunAddr )
{
        BOOL bRet = FALSE;
        ULONG nModuleBase, nModuleSize;
        ULONG nCopyModuleBase = 0, nCopyModuleSize = 0;
        ULONG ulBuildNumber, ulMinorVersion, ulMajorVersion;
        ULONG ulArrayFeatures[ 16 ];
        ULONG ulOffset, ulTemp;
        UNICODE_STRING uniNtKrnlFileName;

        do
        {
                if( NULL == pFunAddr )
                        break;

                PsGetVersion( &ulMajorVersion, &ulMinorVersion, &ulBuildNumber, 0 );
                if( ulMajorVersion == 5 && ulMinorVersion == 1 ) // xp 32位
                {
                        ulOffset = 0x8053e553 - 0x8053e540;
                }
                else if( ulMajorVersion == 6 && ulMinorVersion == 1 ) // win7 32位
                {
                        ulOffset = 0x8053e554 - 0x8053e540;
                }
                else
                {
                        break;
                }

                bRet = GetModuleBaseAndSize( NameOfNT1, &nModuleBase, &nModuleSize, &uniNtKrnlFileName );
                if( !bRet )
                {
                        bRet = GetModuleBaseAndSize( NameOfNT2, &nModuleBase, &nModuleSize, &uniNtKrnlFileName );
                }

                if( !bRet )
                        break;

                bRet = FALSE;
                if( CopyModule( &uniNtKrnlFileName, &nCopyModuleBase, &nCopyModuleSize ) )
                {
                        ulArrayFeatures[0] = 0x6a04618b;
                        ulArrayFeatures[1] = 0x6a9c5223;
                        ulArrayFeatures[2] = 0x08c28302;
                        ulArrayFeatures[3] = 0x244c809d;

                        ulArrayFeatures[4] = 0x1b6a0201;
                        ulArrayFeatures[5] = 0x030435ff;
                        ulArrayFeatures[6] = 0x006affdf;
                        ulArrayFeatures[7] = 0x57565355;                       

                        ulTemp = GetUnDocApiAddr( nCopyModuleBase, nCopyModuleSize, ulArrayFeatures, 8 );
                        if( 0 != ulTemp )
                        {
                                ulTemp = ulTemp + nModuleBase - ulOffset;                       
                                if( 0 != ulTemp )
                                {
                                        *pFunAddr = ulTemp;

                                        g_uAddrOfNtWriteVirtualMemory = 0x26171C;
                                        g_uAddrOfNtReadVirtualMemory = 0x26182C;
                                        g_uAddrOfPsOpenProcess = 0x277E6C;
                                        g_uAddrOfNtClose = 0x24637A;

                                        g_uAddrOfNtWriteVirtualMemory += nModuleBase;
                                        g_uAddrOfNtReadVirtualMemory += nModuleBase;
                                        g_uAddrOfPsOpenProcess += nModuleBase;
                                        g_uAddrOfNtClose += nModuleBase;
  
                                        bRet = TRUE;
                                }
                        }
                }

                RtlFreeUnicodeString( &uniNtKrnlFileName );

        } while (0);

        if( 0 != nCopyModuleBase )
        {
                ExFreePool( (PVOID)nCopyModuleBase );
        }

        return bRet;
}

BOOL InitKiFastCallEntry()
{
        BOOL bRet = FALSE;
        ULONG nTemp, nHookAddr, ulBuildNumber, ulMinorVersion, ulMajorVersion;       

        do
        {
                if( !GetKiFastCallEntryAddr_XP32_And_WIN732( &nTemp ) )    // 获得nt!KiFastCallEntry的地址
                        break;

                PsGetVersion( &ulMajorVersion, &ulMinorVersion, &ulBuildNumber, 0 );
                if( ulMajorVersion == 5 && ulMinorVersion == 1 ) // xp 32位
                {
                        nHookAddr = nTemp + 0x0e1;
                        g_ulJmpBackAddr = nTemp + 0x0e6;
                }
                else if( ulMajorVersion == 6 && ulMinorVersion == 1 ) // win7 32位
                {
                        nHookAddr = nTemp + 0x0e4;
                        g_ulJmpBackAddr = nTemp + 0x0e9;
                }
                else
                        break;

                if( NT_SUCCESS( HookKiFastCallEntry( nHookAddr ) ) )
                        bRet = TRUE;

        } while (0);

        return bRet;
}

通过以上的恢复,可以打开、杀掉游戏进程。

目前用od附加还是要失败,估计是NtGetContextThread之类的hook还没有恢复。

明天再搞,今天就这样了。

driver.rar

[课程]FART 脱壳王!加量不加价!FART作者讲授!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (20)
雪    币: 585
活跃值: (568)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
2
还发现一个问题,恢复了一些hook后,游戏进程在一段时间后,会自动退出。
我估计是hs会定时检查hook的有效性,如果被别人恢复了,就自动退出了。
看来还是要研究下hs的白名单,通过它的正规途径来搞才行。
2012-5-9 01:28
0
雪    币: 48
活跃值: (491)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
3
__declspec(naked) int Jmp_KiFastCallEntry()这个函数看的我蛋疼。
2012-5-9 01:49
0
雪    币: 585
活跃值: (568)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
4
怎么蛋疼了。哈哈
2012-5-9 03:16
0
雪    币: 60
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
Mark HS
2012-5-9 08:41
0
雪    币: 120
活跃值: (160)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
[QUOTE=guxinyi;1070847]之前提到过新奇迹世界用的Hackshield,用雪村看了下它的驱动,发现做一些hook,
[/QUOTE]

咋一看,以为又新出了安全工具。
2012-5-9 10:33
0
雪    币: 585
活跃值: (568)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
7
我同事称 xuetr 为 雪村,我也觉得挺好的,
2012-5-9 10:36
0
雪    币: 258
活跃值: (84)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
8
过来看一看!!!
2012-5-9 10:37
0
雪    币: 27
活跃值: (90)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
9
雪村
2012-5-9 11:13
0
雪    币: 308
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
我咋没发现什么新的技术点呢?
2012-5-9 11:18
0
雪    币: 4887
活跃值: (3127)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
喜欢这样的代码风格。
2012-5-9 17:30
0
雪    币: 2177
活跃值: (2045)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
12
现在搞游戏保护的人还真多。。
2012-5-9 18:48
0
雪    币: 585
活跃值: (568)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
13
hook除了修修改改,,还能怎么做

有什么新思路就说说,,让我学习学习。
2012-5-9 21:13
0
雪    币: 170
活跃值: (58)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
路过看下.
2012-5-9 22:00
0
雪    币: 224
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
绕过后一段时间退出,只要在过滤函数的时候把它的进程的相关调用指他HOOK的路径就可以了.
2012-5-14 23:18
0
雪    币: 1905
活跃值: (1542)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
16
正解。学习了。
2012-5-14 23:46
0
雪    币: 142
活跃值: (310)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
17
判断调用的来源是不是你的进程,不是你的进程就调用原始HOOK函数,是你的进程调用你的proc,不过HOOK恢复了还要一些操作,还有一些XUETR看不到的隐藏的操作
2012-5-15 01:21
0
雪    币: 244
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
真被雪村给忽悠了,一眼看去的就是这词,哈哈哈
2012-5-15 01:42
0
雪    币: 44
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
19
学习了。。。膜拜n
2012-5-18 23:25
0
雪    币: 230
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
请问HS如何多开
2012-5-19 10:37
0
雪    币: 2592
活跃值: (37)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
moniprocess.h  没有
2017-7-27 14:51
0
游客
登录 | 注册 方可回帖
返回
//