czx1703 发表于 2013-8-2 15:05:22

分享一下最新过TP DebugPort清零的方法

众所周知
TP 系统全称 TenProtect,是由腾讯自主研发推出的安全系统,可以有效保护游戏不受智辅侵犯,同时具备反木马盗号功能,
能有效的防止用户游戏帐号和虚拟财产被窃取。腾讯 TP 系统主要作用为智辅检测、反盗号、反非法工作室、防非法消息。


文章写的有点赶,没有带图,代码可能也有点乱,各位将就看看吧!


首先要提出的是,我现在所做的过 TP 驱动保护只支持 32 位 XP,在所有的 32 位 XP 上都可以正常运行,
不过 Win7 的话还不行,因为里面用到了搜索特征码来定位未导出 API,而我只针对 XP 做了处理。

首先我们先分析一下TP所做的保护:
1、 NtOpenProcess 中的 Deep InLine Hook:
2、 NtOpenThread 中的 Deep InLine Hook:
3、 NtReadVirtualMemory 中的 InLine Hook:
4、 NtWriteVirtualMemory 中的 InLine Hook:
5、 KiAttachProcess和KeStackAttachProcess的 InLine Hook:
6、 NtGetContextThread 中的 InLine Hook:
7、 NtSetContextThread 中的 InLine Hook:
8 、DebugPort清零:
大概主要的函数就是以上这些了,一些小HOOK就不写了。


我相信前7个函数的处理方法在网上应该已经被人讲过一遍又一遍了,所以我直接从DebugPort清零说起。

首先我们又虚拟机进行双机调试 下游戏基址+0xbc 的访问断点
可以发现现在最新的TP 有四处清零和一处检测
他们分别是

TesSafe基址:   B13AF000
进程基址:      829FFDA0

Breakpoint 0 hit
<Unloaded_TesSafe.sys>+0x6ef1:
b1117ef1 8b4624          mov   eax,dword ptr


Breakpoint 0 hit
<Unloaded_TesSafe.sys>+0x22a2:
b11132a2 8b09            mov   ecx,dword ptr


Breakpoint 0 hit
<Unloaded_TesSafe.sys>+0xba4cc:
b11cb4cc e9a8350000      jmp   <Unloaded_TesSafe.sys>+0xbda79 (b11cea79)


Breakpoint 0 hit
<Unloaded_TesSafe.sys>+0xbb0f2:
b11cc0f2 e9c5f1ffff      jmp   <Unloaded_TesSafe.sys>+0xba2bc (b11cb2bc

一处检测: TesSafe.sys +0x4082

在处理清零之前我们要先处理掉检测,不然要是直接把清零函数ret掉了,检测函数发现后就会重启我们的电脑。
我们要先通过IDA的逆向找出清零函数和检测函数的首地址

第一处清零首地址:TesSafe+0x6ea8;
第二处清零首地址:TesSafe+0x222e;

以下是两处VM的清零代码的地址:

第三处清零:TesSafe+0xbb0f0;
第四处清零:TesSafe+0xba4ca;

CRC检测首地址:TesSafe+0x4082;

知道这些信息后我们就开始写代码过了他吧!



代码:
void HandleDebugZero(ULONG uImageBase) //主要清零处理函数
{
                ULONG uAddr_1=uImageBase + 0x4082;//清零CRC检测首地址

ULONG uAddr_2=uImageBase + 0x6ea8;//清零处1首地址
ULONG uAddr_3=uImageBase + 0x2228;//清零处2首地址

GetDnfEprocessAddr(uImageBase);   //取得DNF 进程基址
         //这个进程基址在处理第三和第四处清零的时候用到

         if(uImageBase==0)
{
    return;
}

DisableWP();   //清除CR0

*(PUSHORT)uAddr_1=0xc3;
               //由于这个检测函数没压入参数,所以直接ret
         
   
//0x6ea8 //第一处清零首地址,也是直接ret
         *(PUCHAR)(uAddr_2)=0xc3;

//0x2228 //第二处清零首地址,还是直接ret
*(PUCHAR)(uAddr_3)=0xc3;


EnableWP();//恢复CR0


                g_uDebugPortOffset=g_uDebugPortOffset+0xbc;
                //取到清零位置的地址

HandleDebugPortPop(true,uImageBase);//处理第三处清零
HandleDebugPortPush(true,uImageBase);//处理第四处清零
}
打字打到手都累了,下面就不加那么清楚的注释了,各位自己看下吧

void HandleDebugPortPop(BOOLEAN bHook,ULONG uImageBase)
{
if(bHook)
{
    //hook pop
    if(uImageBase==0)
    {
      return ;
    }
    g_uDebugPortPopHookAddr=uImageBase+0xbb0f0;//pop hook地址

    g_uDebugPortPopRetAddr=uImageBase+0xba2bc;//pop retn 地址

    if(g_uDebugPortPopHookAddr==0)
    {
      return;
    }
    RtlCopyMemory((PVOID)g_szBackupDebugPortPop,
                (PVOID)g_uDebugPortPopHookAddr,
                     5);//保存hook地址,用于恢复
   
    InLineHookEngine(g_uDebugPortPopHookAddr,(int)FuckDebugPortPop);
    //__asm int 3
}
else
{
    if(g_uDebugPortPopHookAddr==0)
    {
      return;
    }
    // 最好判断下 TP是否 已经卸载
    int TesSafe=GetTesSafeBassAddr();
    if(TesSafe!=0)
    {
    //KIRQL Irql=KeRaiseIrqlToDpcLevel();
    DisableWP();
      RtlCopyMemory((PVOID)g_uDebugPortPopHookAddr,
                (PVOID)g_szBackupDebugPortPop,
                     5);//保存hook地址,用于恢复
    EnableWP();
    }
}

}


void HandleDebugPortPush(BOOLEAN bHook,ULONG uImageBase)
{
if(bHook)
{
    //hook pop
    if(uImageBase==0)
    {
      return ;
    }
    g_uDebugPortPushHookAddr=uImageBase+0xba4ca;//push hook地址

    g_uDebugPortPushRetAddr=uImageBase+0xba2bc;//push retn 地址

    if(g_uDebugPortPushHookAddr==0)
    {
      return;
    }
    RtlCopyMemory((PVOID)g_szBackupDebugPortPush,
                (PVOID)g_uDebugPortPushHookAddr,
                     5);//保存hook地址,用于恢复
   
    InLineHookEngine(g_uDebugPortPushHookAddr,(int)FuckDebugPortPush);
    //__asm int 3
}
else
{
    if(g_uDebugPortPushHookAddr==0)
    {
      return;
    }
    // 最好判断下 TP是否 已经卸载
    int TesSafe=GetTesSafeBassAddr();
    if(TesSafe!=0)
    {
    //KIRQL Irql=KeRaiseIrqlToDpcLevel();
    DisableWP();
                              RtlCopyMemory((PVOID)g_uDebugPortPushHookAddr,
                (PVOID)g_szBackupDebugPortPush,
                     5);//保存hook地址,用于恢复
    EnableWP();
    }
}

}

__declspec(naked)void FuckDebugPortPop()
{
//DbgPrint("Pop");
__asm
{
    pushfd
    cmp edx,g_uDebugPortOffset //判断入栈的参数是否是清零位置的地址
    jnz POPLABLE
    popfd
    add esp,0x4
    jmp g_uDebugPortPopRetAddr
POPLABLE:
    popfd
    pop dword ptr
    jmp g_uDebugPortPopRetAddr

}

}

__declspec(naked)void FuckDebugPortPush()
{
//DbgPrint("Push");
__asm
{
    pushfd
    cmp edx,g_uDebugPortOffset//判断入栈的参数是否是清零位置的地址

    jnz PUSHLABLE
    popfd
    push 0
    jmp g_uDebugPortPushRetAddr
PUSHLABLE:
    popfd
    push dword ptr
    jmp g_uDebugPortPushRetAddr
}

}

最后提一点以下这两个函数要在驱动卸载的时候加到Unload函数中
HandleDebugPortPop(false,0);
HandleDebugPortPush(false,0);

最后在自己的机子成功过了TP后,CE 可以读写内存,OD可以附加。

wsheini 发表于 2013-8-2 18:20:55

你的驱动能给我用用不

andy03 发表于 2013-8-2 18:58:59

这也算最新的。。。。我4个月前编的跟这个一模一样,你说新不新
页: [1]
查看完整版本: 分享一下最新过TP DebugPort清零的方法