首页
社区
课程
招聘
[原创]解决TP最新版双机调试实例下篇---AGP论坛视频培训课件
发表于: 2013-11-12 21:34 14253

[原创]解决TP最新版双机调试实例下篇---AGP论坛视频培训课件

2013-11-12 21:34
14253

一共有两篇

1篇:TP对双机调试干扰的原理与分析
2篇:解决TP双机调试实战

首先要理解双机调试的几个常识(有点类似初中上学时候,我们要做一道关于三角形的证明题,那么数学老师是不是要先交你几个定理:勾股定理,两点之间直线最短,同角或等角的补角相等 等等),那么现在你要解决双机调试,肯定也要知道双机调试的几个定理(常识):
我们获取知识的来源:
1:就是我告诉你们(别人告诉你们也好。)
2:从自己的实战经验总结(实战出真理。)
3:从书本上得到的知识。

1:KdReceivePacket和KdSendPacket的两个串口函数, 用于接收和发送串口数据
被调试的系统--》KdSendPacket发送数据到串口--》VM虚拟机串口转接到windbg
==》KdSendPacket发送数据到串口,然后被调试的系统KdReceivePacket接收数据

2:不能调用KdDisableDebugger禁止内核调式,否则windbg将无法调式。
NTSTATUS KdDisableDebugger(void)
{
  int v0; // ecx@7
  char v2; // [sp+1h] [bp-1h]@1

  v2 = KfRaiseIrql(2);
  KdpPortLock();
  if ( !KdDisableCount )
  {
    if ( !(_BYTE)KdDebuggerEnabled || (KdPreviouslyEnabled = 1, KdPitchDebugger) )
      KdPreviouslyEnabled = 0;
    if ( (_BYTE)KdDebuggerEnabled )
    {
      KdpSuspendAllBreakpoints();
      KiDebugRoutine = (int)KdpStub;
      LOBYTE(KdDebuggerEnabled) = 0;
    }
  }
  ++KdDisableCount;
  KdpPortUnlock();
  LOBYTE(v0) = v2;
  return KfLowerIrql(v0);
}
//禁止双机调试
KiDebugRoutine = (int)KdpStub;
LOBYTE(KdDebuggerEnabled) = 0;

3:双机调试的时候,那么 [KiDebugRoutine]必须指向KdpTrap(正常启动的系统KiDebugRoutine为KdpStub,在Boot.ini里加上/DEBUG启动的系统的KiDebugRoutine为KdpTrap),为了证明这点,我们现在来看虚拟机:

在正常系统下:
lkd> dd KiDebugRoutine //全局变量指向804f7c86 !KdpStub
80553f84  804f7c86 00000000 7c92e4a8 7c92e45c
80553f94  7c92e440 7c92e430 0002625a 00000000
80553fa4  00000000 00000000 00000000 00000000
80553fb4  00000000 00000000 00000000 00000000
80553fc4  00000000 00000000 00000000 00000000
80553fd4  00000000 00000000 00000000 80502b9c
80553fe4  00000000 0000011c 80503010 bf999e80
80553ff4  00000000 0000029b bf99ab90 00000000
lkd> u 804f7c86
nt!KdpStub:
804f7c86 8bff            mov     edi,edi
804f7c88 55              push    ebp
804f7c89 8bec            mov     ebp,esp
804f7c8b 8b4510          mov     eax,dword ptr [ebp+10h]
804f7c8e 813803000080    cmp     dword ptr [eax],80000003h
804f7c94 7525            jne     nt!KdpStub+0x35 (804f7cbb)
804f7c96 83781000        cmp     dword ptr [eax+10h],0
804f7c9a 761f            jbe     nt!KdpStub+0x35 (804f7cbb)

在双机环境下:
kd> dd KiDebugRoutine
80553f84  80661a86 00000000 7c92e4a8 7c92e45c
80553f94  7c92e440 7c92e430 0002625a 00000000
80553fa4  00000000 00000000 00000000 00000000
80553fb4  00000000 00000000 00000000 00000000
80553fc4  00000000 00000000 00000000 00000000
80553fd4  00000000 00000000 00000000 80502b9c
80553fe4  00000000 0000011c 80503010 bf999e80
80553ff4  00000000 0000029b bf99ab90 00000000
kd> u 80661a86
nt!KdpTrap:
80661a86 8bff            mov     edi,edi
80661a88 55              push    ebp
80661a89 8bec            mov     ebp,esp
80661a8b 51              push    ecx
80661a8c 51              push    ecx
80661a8d 8b4510          mov     eax,dword ptr [ebp+10h]
80661a90 813803000080    cmp     dword ptr [eax],80000003h
80661a96 56              push    esi

内核调试器加载,则KiDebugRoutine(KdpTrap)可以处理int 0x3异常(看windbg断下之后是不是 int 0x3):
nt!RtlpBreakWithStatusInstruction:
80528bec cc              int     3

异常处理到这里被正常返回。处理方法是将当前的处理器状态(比如各寄存器等重要信息)发送KdSendPacket(定理1要用到的函数)  给通过串口相连的主机上的内核调试器,并一直在等待内核调试器的回应,系统这时在KdpTrap里调用一个Kd函数KdpSendWaitContinue循环等待KdReceivePacket来自串口的数据(内核调试器和被调试系统通过串口联系),直到内核调试器下达继续执行的命令g,,让系统继续执行,系统可以正常从int 0x3后面一条指令执行。

我大概画了个图给大家理解:

通过图片我们大概知道流程,那么反双机调试只需要把[KiDebugRoutine]修改为KdpStub,又达到了反双机的目的。
推荐大家看两篇文章:http://www.xfocus.net/articles/200412/761.html
http://www.xfocus.net/articles/200412/765.html

一节课我们是无法阐述内核调试原理的,但是我们只要满足上面的三个条件,那么windbg就可以双机调试。那么我们来分析TP。大家都还记得前面我教大家怎么分析游戏保护对系统做的手脚,如果大家对那一节课还没吃透,建议再回去看看。

现在我们以现有的工具gmer来静态分析TP(至于动态分析,我们要到下一节课才会学到。)

为什么不用xuetr,因为人怕出名猪怕壮,xuetr已经进入了tp的黑名单。

总结:
1:两个串口发送函数已经被tp hook。
2:肯定会调用KdDisableDebugger来禁止内核调试
3:TP会强行的把KiDebugRoutine全局变量修改为KdpStub

PS:请期待下篇,下篇讲提供可用的BIN。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 5
支持
分享
最新回复 (13)
雪    币: 160
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark,总结的还不错。
2013-11-12 21:45
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
谢谢分享,前排占个座
2013-11-12 21:46
0
雪    币: 10
活跃值: (231)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
双基友 又发好东西了
2013-11-12 21:49
0
雪    币: 47
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
前来围观~~~~~~~~~~~~~~
2013-11-12 23:19
0
雪    币: 796
活跃值: (370)
能力值: ( LV9,RANK:380 )
在线值:
发帖
回帖
粉丝
6
首先要理解双机调试的几个常识(有点类似初中上学时候,我们要做一道关于三角形的证明题,那么数学老师是不是要先交你几个定理:勾股定理,两点之间直线最短,同角或等角的补角相等 等等),那么现在你要解决双机调试,肯定也要知道双机调试的几个定理(常识):
我们获取知识的来源:
1:就是我告诉你们(别人告诉你们也好。)
2:从自己的实战经验总结(实战出真理。)
3:从书本上得到的知识。

1:KdReceivePacket和KdSendPacket的两个串口函数, 用于接收和发送串口数据
被调试的系统--》KdSendPacket发送数据到串口--》VM虚拟机串口转接到windbg
==》KdSendPacket发送数据到串口,然后被调试的系统KdReceivePacket接收数据

2:不能调用KdDisableDebugger禁止内核调式,否则windbg将无法调式。
NTSTATUS KdDisableDebugger(void)
{
  int v0; // ecx@7
  char v2; // [sp+1h] [bp-1h]@1

  v2 = KfRaiseIrql(2);
  KdpPortLock();
  if ( !KdDisableCount )
  {
    if ( !(_BYTE)KdDebuggerEnabled || (KdPreviouslyEnabled = 1, KdPitchDebugger) )
      KdPreviouslyEnabled = 0;
    if ( (_BYTE)KdDebuggerEnabled )
    {
      KdpSuspendAllBreakpoints();
      KiDebugRoutine = (int)KdpStub;
      LOBYTE(KdDebuggerEnabled) = 0;
    }
  }
  ++KdDisableCount;
  KdpPortUnlock();
  LOBYTE(v0) = v2;
  return KfLowerIrql(v0);
}
//禁止双机调试
KiDebugRoutine = (int)KdpStub;
LOBYTE(KdDebuggerEnabled) = 0;

3:双机调试的时候,那么 [KiDebugRoutine]必须指向KdpTrap(正常启动的系统KiDebugRoutine为KdpStub,在Boot.ini里加上/DEBUG启动的系统的KiDebugRoutine为KdpTrap),为了证明这点,我们现在来看虚拟机:

在正常系统下:
lkd> dd KiDebugRoutine //全局变量指向804f7c86 !KdpStub
80553f84  804f7c86 00000000 7c92e4a8 7c92e45c
80553f94  7c92e440 7c92e430 0002625a 00000000
80553fa4  00000000 00000000 00000000 00000000
80553fb4  00000000 00000000 00000000 00000000
80553fc4  00000000 00000000 00000000 00000000
80553fd4  00000000 00000000 00000000 80502b9c
80553fe4  00000000 0000011c 80503010 bf999e80
80553ff4  00000000 0000029b bf99ab90 00000000
lkd> u 804f7c86
nt!KdpStub:
804f7c86 8bff            mov     edi,edi
804f7c88 55              push    ebp
804f7c89 8bec            mov     ebp,esp
804f7c8b 8b4510          mov     eax,dword ptr [ebp+10h]
804f7c8e 813803000080    cmp     dword ptr [eax],80000003h
804f7c94 7525            jne     nt!KdpStub+0x35 (804f7cbb)
804f7c96 83781000        cmp     dword ptr [eax+10h],0
804f7c9a 761f            jbe     nt!KdpStub+0x35 (804f7cbb)

在双机环境下:
kd> dd KiDebugRoutine
80553f84  80661a86 00000000 7c92e4a8 7c92e45c
80553f94  7c92e440 7c92e430 0002625a 00000000
80553fa4  00000000 00000000 00000000 00000000
80553fb4  00000000 00000000 00000000 00000000
80553fc4  00000000 00000000 00000000 00000000
80553fd4  00000000 00000000 00000000 80502b9c
80553fe4  00000000 0000011c 80503010 bf999e80
80553ff4  00000000 0000029b bf99ab90 00000000
kd> u 80661a86
nt!KdpTrap:
80661a86 8bff            mov     edi,edi
80661a88 55              push    ebp
80661a89 8bec            mov     ebp,esp
80661a8b 51              push    ecx
80661a8c 51              push    ecx
80661a8d 8b4510          mov     eax,dword ptr [ebp+10h]
80661a90 813803000080    cmp     dword ptr [eax],80000003h
80661a96 56              push    esi

内核调试器加载,则KiDebugRoutine(KdpTrap)可以处理int 0x3异常(看windbg断下之后是不是 int 0x3):
nt!RtlpBreakWithStatusInstruction:
80528bec cc              int     3

异常处理到这里被正常返回。处理方法是将当前的处理器状态(比如各寄存器等重要信息)发送KdSendPacket(定理1要用到的函数)  给通过串口相连的主机上的内核调试器,并一直在等待内核调试器的回应,系统这时在KdpTrap里调用一个Kd函数KdpSendWaitContinue循环等待KdReceivePacket来自串口的数据(内核调试器和被调试系统通过串口联系),直到内核调试器下达继续执行的命令g,,让系统继续执行,系统可以正常从int 0x3后面一条指令执行。

我大概画了个图给大家理解:

通过图片我们大概知道流程,那么反双机调试只需要把[KiDebugRoutine]修改为KdpStub,又达到了反双机的目的。
推荐大家看两篇文章:http://www.xfocus.net/articles/200412/761.html
http://www.xfocus.net/articles/200412/765.html

一节课我们是无法阐述内核调试原理的,但是我们只要满足上面的三个条件,那么windbg就可以双机调试。那么我们来分析TP。大家都还记得前面我教大家怎么分析游戏保护对系统做的手脚,如果大家对那一节课还没吃透,建议再回去看看。

现在我们以现有的工具gmer来静态分析TP(至于动态分析,我们要到下一节课才会学到。)

为什么不用xuetr,因为人怕出名猪怕壮,xuetr已经进入了tp的黑名单。

1:两个串口发送函数已经被tp hook。
2:肯定会调用KdDisableDebugger来禁止内核调试
3:TP会强行的把KiDebugRoutine全局变量修改为KdpStub

TP反双机调试的原理分析。

1:已经处理定理1
2:我们在KdDisableDebugger函数写入ret
KiDebugRoutine = (int)KdpStub;
LOBYTE(KdDebuggerEnabled) = 0; //你就要想到,这里也是为0

如果tp的一条线程执行KdDisableDebugger,那么我们在HookKdDisableDebugger里面的[ebp+4]就是tp这条线程调用这个函数之后的下一个地址。

[ebp+4] 就是要执行的下一个地址,也就是函数返回地址。

无限调用
0 KdDisableDebugger() Call B1532008
0 KdDisableDebugger() Call B1532008
0 KdDisableDebugger() Call B1532008
0 KdDisableDebugger() Call B1532008
0 KdDisableDebugger() Call B1532008
0 KdDisableDebugger() Call B1532008
0 KdDisableDebugger() Call B1532008
0 KdDisableDebugger() Call B1532008
0 KdDisableDebugger() Call B1532008

kd> u B1532000 l 30
TesSafe+0x7000:
b1532000 b101            mov     cl,1
b1532002 85ff            test    edi,edi
b1532004 7404            je      TesSafe+0x700a (b153200a)
b1532006 ffd7            call    edi //edi KdDisableDebugger
b1532008 eb24            jmp     TesSafe+0x702e (b153202e) //[ebp+4]
b153200a 803d6ee253b100  cmp     byte ptr [TesSafe+0x1326e (b153e26e)],0
b1532011 751b            jne     TesSafe+0x702e (b153202e)
b1532013 6812010000      push    112h
b1532018 68e64d6e43      push    436E4DE6h
b153201d 6873426e57      push    576E4273h
b1532022 e865caffff      call    TesSafe+0x3a8c (b152ea8c)
b1532027 c6056ee253b101  mov     byte ptr [TesSafe+0x1326e (b153e26e)],1
b153202e 803e00          cmp     byte ptr [esi],0 //这是一条判断语句
//LOBYTE(KdDebuggerEnabled) = 0; //你就要想到,这里也是为0
//他这里的 esi 是不是 KdDebuggerEnabled???

kd> bp b153202e
kd> g
Breakpoint 1 hit
TesSafe+0x702e:
b153202e 803e00          cmp     byte ptr [esi],0
kd> r esi
esi=8054d541
kd> u 8054d541
nt!KdDebuggerEnabled:
8054d541 0100            add     dword ptr [eax],eax
8054d543 0001            add     byte ptr [ecx],al
8054d545 0000            add     byte ptr [eax],al
8054d547 003f            add     byte ptr [edi],bh
8054d549 ff              ???
8054d54a ff              ???
8054d54b ff00            inc     dword ptr [eax]
//果然证实了我们的猜想。
我们把b153202e 803e00          cmp     byte ptr [esi],0
修改为 b153202e 803e01          cmp     byte ptr [esi],1
之后,就等于pass了这条线程,那么又出现了下一条

b1532031 75b0            jne     TesSafe+0x6fe3 (b1531fe3)
b1532033 5f              pop     edi
b1532034 5e              pop     esi
b1532035 c3              ret

0 KdDisableDebugger() Call B1532124

kd> u B1532124 l 30
TesSafe+0x7124:
                        Call edi //调用禁止内核调式的函数
b1532124 eb24            jmp     TesSafe+0x714a (b153214a)
b1532126 803d72e253b100  cmp     byte ptr [TesSafe+0x13272 (b153e272)],0
b153212d 751b            jne     TesSafe+0x714a (b153214a)
b153212f 6882010000      push    182h
b1532134 68e64d6e43      push    436E4DE6h
b1532139 6873426e57      push    576E4273h
b153213e e849c9ffff      call    TesSafe+0x3a8c (b152ea8c)
b1532143 c60572e253b101  mov     byte ptr [TesSafe+0x13272 (b153e272)],1
b153214a 8b0d64e253b1    mov     ecx,dword ptr [TesSafe+0x13264 (b153e264)]
b1532150 85c9            test    ecx,ecx
b1532152 740f            je      TesSafe+0x7163 (b1532163)
b1532154 a168e253b1      mov     eax,dword ptr [TesSafe+0x13268 (b153e268)]
b1532159 85c0            test    eax,eax
b153215b 7406            je      TesSafe+0x7163 (b1532163)
b153215d 3901            cmp     dword ptr [ecx],eax
b153215f 7402            je      TesSafe+0x7163 (b1532163)
b1532161 8901            mov     dword ptr [ecx],eax
b1532163 c3              ret

b1532161 8901            mov     dword ptr [ecx],eax //eax == KdpStub

是不是似曾相识?

KiDebugRoutine = (int)KdpStub;

Eax是从b1532154 a168e253b1      mov     eax,dword ptr [TesSafe+0x13268 (b153e268)]

kd> dd b153e268
b153e268  804f7c86 00000100 00000000 00000000
b153e278  00000000 00000000 00000000 00000000
b153e288  00000000 00000000 00000000 00000000
kd> u 804f7c86
nt!KdpStub:
804f7c86 8bff            mov     edi,edi
804f7c88 55              push    ebp
804f7c89 8bec            mov     ebp,esp
804f7c8b 8b4510          mov     eax,dword ptr [ebp+10h]
804f7c8e 813803000080    cmp     dword ptr [eax],80000003h
804f7c94 7525            jne     nt!KdpStub+0x35 (804f7cbb)
804f7c96 83781000        cmp     dword ptr [eax+10h],0
804f7c9a 761f            jbe     nt!KdpStub+0x35 (804f7cbb)

Ecx是从这里来的
b153214a 8b0d64e253b1    mov     ecx,dword ptr [TesSafe+0x13264 (b153e264)]
b1532150 85c9            test    ecx,ecx

kd> dd b153e264
b153e264  80553f84 804f7c86 00000100 00000000
b153e274  00000000 00000000 00000000 00000000
b153e284  00000000 00000000 00000000 00000000
b153e294  00000000 00000000 00000000 00000000
b153e2a4  00000000 00000000 00000000 00000000
b153e2b4  00000000 00000000 00000000 00000000
b153e2c4  00000000 89c34830 00000000 00000000
b153e2d4  00000000 00001c38 00001c38 00001c38
kd> u 80553f84
nt!KiDebugRoutine:
80553f84 861a            xchg    bl,byte ptr [edx]
80553f86 66800000        add     byte ptr [eax],0
80553f8a 0000            add     byte ptr [eax],al

正好验证了我们的猜想:

KiDebugRoutine = (int)KdpStub;
b1532161 8901            mov     dword ptr [ecx],eax //eax == KdpStub

TP强行的把KiDebugRoutine 这个全局变量指向KdpStub

1:修改b153202e 803e00          cmp     byte ptr [esi],0
2:b1532161 8901            mov     dword ptr [ecx],eax //eax == KdpStub
我们可以inlinehook KdpStub 在头部直接跳到 KdpTrap 函数
或者我们可以通过搜索特征码,

b1532124 eb24            jmp     TesSafe+0x714a (b153214a)
b1532126 803d72e253b100  cmp     byte ptr [TesSafe+0x13272 (b153e272)],0
b153212d 751b            jne     TesSafe+0x714a (b153214a)
b153212f 6882010000      push    182h
b1532134 68e64d6e43      push    436E4DE6h
b1532139 6873426e57      push    576E4273h

以b1532124为开始地址,搜索特征码 ,那样我们就可以直接定位到TP的两个变量

b1532154 a168e253b1      mov     eax,dword ptr [TesSafe+0x13268 (b153e268)]

ULONG_PTR ul_tp_check = 0xb153e268;

*(ULONG_PTR*)ul_tp_check = KdpTrap;

现在我们用windbg手工。

相信大家懂得原理之后,写代码只是一个苦力活了。

为了避免TX追杀,bin就不放了,你可以通过购买AGP视频教程:http://www.antigameprotect.com/thread-2860-1-1.html
来获得更多的内核安全,游戏安全,反游戏安全的驱动知识。
上传的附件:
2013-11-13 04:20
0
雪    币: 163
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
貌似是广告?
修改了Tp,crc校验没过呀?
还有KdReceivePacket和KdSendPacket的两个串口函数,怎么处理呀?
AGP像是//想钱想疯了!!!!!!!!!
2013-11-13 06:51
0
雪    币: 4560
活跃值: (1007)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
严重同意一楼鞋童
2013-11-13 08:35
0
雪    币: 236
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
讲得很明白.
2013-11-13 08:49
0
雪    币: 53
活跃值: (734)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
bp和ba tessafe模块会直接重启的。。解决不了这个重启的问题,就过不了CRC。。CRC过不了双机无意义。
2013-11-13 09:18
0
雪    币: 1841
活跃值: (4070)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
静下心来看看wrk 代码,看看 软件调试 还搞不定,说明你不是这块料,趁早放弃。

这帮做挂的人,太浮躁...
C语言都搞不明白,就去搞驱动,也就造就了一批靠视频,过保护软件赚钱的人......
2013-11-13 11:00
0
雪    币: 110
活跃值: (34)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
12
自己造个轮子装上去替换掉系统的……
2013-11-13 11:56
0
雪    币: 90
活跃值: (51)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
干任何事情基础不扎实、想成功亦是枉然;比如自己最擅长的事、难道就没有基础吗
2013-11-13 18:18
0
雪    币: 239
活跃值: (133)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
14
有没其他保护的。双机调试。TP讲太多了。
2013-11-15 18:52
0
游客
登录 | 注册 方可回帖
返回
//