首页
社区
课程
招聘
[旧帖] [原创]最新过TX驱动保护,恢复debugport相关函数 0.00雪花
2010-8-10 23:07 6758

[旧帖] [原创]最新过TX驱动保护,恢复debugport相关函数 0.00雪花

2010-8-10 23:07
6758
研究驱动有一个多月了,准备实践一下,拿DNF的TX驱动开刀,说干就干,刚开始心里没底,在看雪论坛找了很多相关的帖子,但是好象都比较早,直接拿来用是不行,但是我觉得思路绝对是对的,只有摸着石头过河,先把我的方法贴出来请各位大牛指教,在最后随便请教一下其他问题..

我过TX驱动是为了能用windbg调试DNF,我把他分成几个部分来做:
1.恢复OpenProcess, OpenThread,ReadVirtualMemory,WriteVirtualMemory
2.修改读写DebugPort的相关API
3.修复AttachProcess
步骤应该和以前是一样,但是方法变了.

我做一个TX驱动保护恢复工具(由于要时不时的看看ssdt和对比反汇编索性做在一起了,后面有下载地址),在工具启动的时候(打开游戏之前)做一些数据初始化和收集工作,并在进入游戏之后在点恢复键做真正的恢复工作.
首先是工具启动做的事情:
1.        ReadVirtualMemory,WriteVirtualMemory这两个函数现在没有保护,在工具启动的时候复制前16个字节保存:
ULONG AddrRead = (ULONG)KeServiceDescriptorTable->pSSDTBase + 0xBA * 4;
ULONG AddrWrite = (ULONG)KeServiceDescriptorTable->pSSDTBase + 0x115 * 4;
//记录NtReadVirtualMemory/NtWriteVirtualMemory 前16 字节
OrgRead[0] = *(PULONG)(*(PULONG)AddrRead);
OrgRead[1] = *(PULONG)(*(PULONG)AddrRead + 4);
OrgRead[2] = *(PULONG)(*(PULONG)AddrRead + 8);
OrgRead[3] = *(PULONG)(*(PULONG)AddrRead + 12);
OrgWrite[0] = *(PULONG)(*(PULONG)AddrWrite);
OrgWrite[1] = *(PULONG)(*(PULONG)AddrWrite + 4);
OrgWrite[2] = *(PULONG)(*(PULONG)AddrWrite + 8);
OrgWrite[3] = *(PULONG)(*(PULONG)AddrWrite + 12);

恢复OpenProcess(OpenThread是一样的,只是跳转的地址需要重新计算):
OpenProcess只修改了一处call ObOpenObjectByPointer, 直接用原始的地址去恢复直接蓝屏,修改call ObOpenObjectByPointer前的push代码跳转到自制代码也是蓝屏,甚至原本想修改e9的跳转地址再跳回来也是蓝屏,后来我把心一横,直接修改了OpenProcess的前两个push指令改成一个一个jmp,跳到我的自制代码,自制代码的结构是前16个字节做好堆栈直接jmp到一个写好的C函数,C函数的作用的是比较是否DNF.exe进程在调用OpenProcess,这里要先说一下在工具初始化的时候我分配了整个OpenProcess两倍加16个字节的代码数组也就是0x285*2+16,初始化的时候我已经复制了一份原始的OpenProcess到数组里面,然后在游戏运行的时候又复制了一份已经被HOOK了的OpenProcess代码在里面,所以C函数的作用是如果是DNF.exe的进程则进第二份被HOOK了的代码,否则进原始的代码:
UCHAR MyThreadRoot[ThreadLength*2+16], MyProcessRoot[ProcessLength*2+16];
// 游戏加载前,保存一次原始的函数代码
BufferCode(MyThreadRoot+16, (ULONG)OldThread, ThreadLength);
BufferCode(MyProcessRoot+16, (ULONG)OldProcess, ProcessLength);
// 游戏加载后,保存一次被HOOK了的函数代码
BufferCode(MyThreadRoot + ThreadLength + 16, (ULONG)OldThread, ThreadLength);
BufferCode(MyProcessRoot + ProcessLength + 16, (ULONG)OldProcess, ProcessLength);
// 修改OpenProcess前几个字节跳到自己的MyOpenProcess
ProcessCode[0] = *((BYTE*)OldProcess+0);
ProcessCode[1] = *((BYTE*)OldProcess+1);
ProcessCode[2] = *((BYTE*)OldProcess+2);
ProcessCode[3] = *((BYTE*)OldProcess+3);
ProcessCode[4] = *((BYTE*)OldProcess+4);
ProcessCode[5] = *((BYTE*)OldProcess+5);
addr1 = (ULONG)(UCHAR*)(MyProcessRoot) - (ULONG)OldProcess - 5;
*(BYTE*)((ULONG)OldProcess)        = 0xe9;
*((BYTE*)((ULONG)OldProcess)+1) = *(BYTE*)(&addr1);
*((BYTE*)((ULONG)OldProcess)+2) = *((BYTE*)(&addr1)+1);
*((BYTE*)((ULONG)OldProcess)+3) = *((BYTE*)(&addr1)+2);
*((BYTE*)((ULONG)OldProcess)+4) = *((BYTE*)(&addr1)+3);
*((BYTE*)((ULONG)OldProcess)+5) = 0x90;
// 下面是上面跳转到的自制代码
// 这里相当于前面提到的代码数组的前16个字节,需要再跳到C函数进行上面提到的那个判断然后在选// 择跳到原始代码还是被HOOK了的代码
addr1 = (ULONG)IsDNFprocess - (ULONG)MyProcessRoot - 5;
*(BYTE*)((ULONG)MyProcessRoot) = 0xe8;
*((BYTE*)((ULONG)MyProcessRoot)+1) = *(BYTE*)(&addr1);
*((BYTE*)((ULONG)MyProcessRoot)+2) = *((BYTE*)(&addr1)+1);
*((BYTE*)((ULONG)MyProcessRoot)+3) = *((BYTE*)(&addr1)+2);
*((BYTE*)((ULONG)MyProcessRoot)+4) = *((BYTE*)(&addr1)+3);
addr1 = (ULONG)(MyProcessRoot + ProcessLength + 16) - (ULONG)(UCHAR*)(MyProcessRoot + 7) - 6;
*((BYTE*)((ULONG)MyProcessRoot)+5) = 0x85;
*((BYTE*)((ULONG)MyProcessRoot)+6) = 0xc0;
*((BYTE*)((ULONG)MyProcessRoot)+7) = 0x0f;
*((BYTE*)((ULONG)MyProcessRoot)+8) = 0x84;
*((BYTE*)((ULONG)MyProcessRoot)+9) = *(BYTE*)(&addr1);
*((BYTE*)((ULONG)MyProcessRoot)+10) = *((BYTE*)(&addr1)+1);
*((BYTE*)((ULONG)MyProcessRoot)+11) = *((BYTE*)(&addr1)+2);
*((BYTE*)((ULONG)MyProcessRoot)+12) = *((BYTE*)(&addr1)+3);
// 下面是那个判断是否是DNF.exe进程的C函数
int IsDNFprocess() {
        char Name[16];
        if(GetProcessName(Name)) {
                if (strcmp(Name,"DNF.exe")) {
                        dprintf("不是指定进程在调用!\n");
                        return 1;
                }
                else {

                        dprintf("是指定进程在调用!\n");
                        return 0;
                }
        }
        else {
                dprintf("未获取到进程名!\n");
                return 2;
        }
}
// 下面是上面IsDNFprocess函数调用到的几个函数
ULONG GetProcessNameOffset() {
        int i=0;
        PEPROCESS curproc;
        DWORD procNameOffset;
        curproc = PsGetCurrentProcess();
        for(; i< 4096; i++) {
                if( !strncmp( "System", (PCHAR) curproc + i, strlen("System") )) {               
                        procNameOffset = i;
                        return procNameOffset;
                }
        }
        return 0;
}
BOOL GetProcessName( PCHAR theName ) {
        PEPROCESS       curproc;
        char            *nameptr;
        ULONG           i;
        KIRQL           oldirql;
        if( g_ProcessNameOffset ) {
                curproc = PsGetCurrentProcess();
                nameptr   = (PCHAR) curproc + g_ProcessNameOffset;
                strncpy( theName, nameptr, 16 );
                theName[15] = '\0'; /**//* NULL at end */
                return TRUE;
        }
        return FALSE;
}
还有一个重要的处理是将被HOOK了OpenProcess中call ObOpenObjectByPointer地址提取出来重新计算代码数组第二段的call ObOpenObjectByPointer(因为e8是相对地址所以要再计算一次..)

接下来是恢复DebugPort:
还是老办法将nt!_eprocess+0xbc转移到其他地址,我尝试了0x70,0x74,我发现经常被修改,如果将DebugPort对象地址保存到里面被修改之后再由nt!PsGetProcessDebugPort返回出来直接蓝屏,我用的0x78这个地址好象没怎么被修改.
找DebugPort相关是函数我是直接KD调试虚拟机,然后先设置硬件写断点,然后在虚拟机里面随便调试一个进程,ba w4 nt!_eprocess+0xdc,找出所有修改了这个地址的API,然后再找读的,读和写是一个方法.
找到之后我整理了一下有如下几个(我看到有人找的和我找的很多不一样,我百思不得其解,这也是我最后要请教的问题):
// 自己跟踪出来的地址(下面用的0x74我已经换成了0x78)

1        nt!DbgkpSetProcessDebugObject+0x6a                                8063a930
8063a98e 8b450c          mov     eax,dword ptr [ebp+0Ch]
8063a991 8b4d14          mov     ecx,dword ptr [ebp+14h]
8063a994 8987bc000000    mov     dword ptr [edi+0BCh],eax
Change:         898774000000                         {0x89,0x87,0x74,0x00,0x00,0x00}

2        nt!DbgkCopyProcessDebugPort+0xf
        80639993 8b4508          mov     eax,dword ptr [ebp+8]
80639996 83a0bc00000000  and     dword ptr [eax+0BCh],0


1        nt!DbgkpSetProcessDebugObject+0x5c                                8063a930
        8063a980 c645ff01        mov     byte ptr [ebp-1],1
8063a984 ffd6            call            esi
8063a986 399fbc000000    cmp     dword ptr [edi+0BCh],ebx
Change:         399f74000000                        {0x39,0x9f,0x74,0x00,0x00,0x00}

2        nt!DbgkpMarkProcessPeb+0x48                                        806398fa
        80639937 897dfc          mov     dword ptr [ebp-4],edi
8063993a 33c0            xor     eax,eax
8063993c 39bebc000000    cmp     dword ptr [esi+0BCh],edi
Change:        39be74000000                        {0x39,0xbe,0x74,0x00,0x00,0x00}       

3        nt!DbgkCreateThread+0x12b                                                8063b08c
        8063b1b1 399ebc000000    cmp     dword ptr [esi+0BCh],ebx
        Change:         399e74000000                        {0x39,0x9e,0x74,0x00,0x00,0x00}

4        nt!DbgkpQueueMessage+0x81:                                        80639bec
        80639c64 8b4508          mov     eax,dword ptr [ebp+8]
80639c67 8b80bc000000    mov     eax,dword ptr [eax+0BCh]
Change:        8b8074000000                        {0x8b,0x80,0x74,0x00,0x00,0x00}

5        nt!PsGetProcessDebugPort+0xe                                        8052874c
8052874f 8bec            mov     ebp,esp
80528751 8b4508          mov     eax,dword ptr [ebp+8]
80528754 8b80bc000000    mov     eax,dword ptr [eax+0BCh]
Change:        8b8074000000                        {0x8b,0x80,0x74,0x00,0x00,0x00}

6        nt!DbgkForwardException+0x44                                        8063aee0
        8063af1e 8b81bc000000    mov     eax,dword ptr [ecx+0BCh]
        Change:         8b8174000000                        {0x8b,0x81,0x74,0x00,0x00,0x00}

7        nt!PspExitThread+0x28c                                                        805c938a
        805c9606 7408            je      nt!PspExitThread+0x286 (805c9610)
805c9608 8b4de0          mov     ecx,dword ptr [ebp-20h]
805c960b e862a5f5ff      call    nt!ObfDereferenceObject (80523b72)
805c9610 399fbc000000    cmp     dword ptr [edi+0BCh],ebx
Change:        399f74000000                                {0x39,0x9f,0x74,0x00,0x00,0x00}

8        nt!DbgkExitThread+0x26                                                8063b42a
        8063b441 f6804802000004  test    byte ptr [eax+248h],4
8063b448 7551            jne     nt!DbgkExitThread+0x71 (8063b49b)
8063b44a 8b89bc000000    mov     ecx,dword ptr [ecx+0BCh]
Change:        8b8974000000                        {0x8b,0x89,0x74,0x00,0x00,0x00}

9        nt!KiDispatchException+0x18d                                        804fd94e
        804fdacc 64a124010000    mov     eax,dword ptr fs:[00000124h]
804fdad2 8b4044          mov     eax,dword ptr [eax+44h]
804fdad5 39b8bc000000    cmp     dword ptr [eax+0BCh],edi
Change:        39b874000000                        {0x39,0xb8,0x74,0x00,0x00,0x00}

10        nt!DbgkpCloseObject+0x3e:
        8063a7bd 8b5d08          mov     ebx,dword ptr [ebp+8]
8063a7c0 81c3bc000000    add     ebx,0BCh
        Change:        81c374000000                                {0x81,0xc3,0x74,0x00,0x00,0x00}

然后是修改相关API,我没有一个一个找特征码我怕漏了,我直接计算了KernelBase和KernelSize比如0x804d8000, 0x1f000000,我就在这区间里面直接替换。比如第10个API nt!DbgkpCloseObject我直接搜索区间里面所有的81c3bc000000替换为81c378000000,其他同理.

最后是恢复KiAttachProcess
我查看的时候这里没有特殊的保护,所以我在工具初始化的时候保存了原始地址,然后直接恢复了该地址.

工具的下载地址(目前xp下能用):

bk_ssdtview.rar

结果是:我已经能用windbg附加DNF,但是还是收不到调试消息,我查看了debugport已经成功转移到了eprocess+0x78并且未被清,所有的API也已经使用了该地址,但是windbg还是显示挂起30秒那个提示,请各位给点提示!
随便请那位大哥给个邀请码,感谢!

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

上传的附件:
收藏
点赞6
打赏
分享
最新回复 (23)
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jerrynpc 2010-8-11 01:16
2
0
很好很强大 mark学习。
雪    币: 216
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
擦肩er過 2010-8-11 02:45
3
0
XP SP3 蓝屏2次    额   

本人纯属 菜菜鸟  只想用下工具调试下DNF 玩玩 结果 ...............
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
manmancong 2010-8-11 03:52
4
0
菜鸟,完全看不懂....................
雪    币: 73
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
私仇之路 2010-8-11 09:02
5
0
不了解,帮顶。
雪    币: 74
活跃值: (27)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
bluehook 1 2010-8-11 09:35
6
0
最好在虚拟机上用,虚拟机我装的DEEP XP。。
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bincheng 2010-8-11 16:33
7
0
来这里看看好像还是非常可疑的,招商
雪    币: 72
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ConanAI 2010-8-11 18:54
8
0
Mark!!!
雪    币: 177
活跃值: (278)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
天堂猪 2010-8-11 21:03
9
0
楼主试试kdcom.dll/kd1394.dll/kdusb.dll-------->KdSendPacket/KdReceivePacket。
还有KdDebuggerEnabled/KdDisableDebugger
雪    币: 2174
活跃值: (961)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Crakme 2010-8-13 23:27
10
0
楼主这么牛X
开帖就是精华
膜拜
雪    币: 74
活跃值: (27)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
bluehook 1 2010-8-14 10:26
11
0
谢谢天堂猪,虽然还没试,但是启发很大!
雪    币: 221
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
xionw 2010-9-15 17:30
12
0
好像你的DEBUGPORT没有找齐。。
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
华hua华 2011-1-11 05:57
13
0
学习中.............
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小八路 2011-7-25 23:56
14
0
还没学会,拜读了
雪    币: 105
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
才情岁月 2011-7-26 08:49
15
0
谢谢楼主,学习了!
雪    币: 3989
活跃值: (2401)
能力值: ( LV10,RANK:165 )
在线值:
发帖
回帖
粉丝
DMemory 3 2011-7-26 15:04
16
0
支持楼主,分享一下原码就更好了~哈!
雪    币: 24
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lovehejiao 2011-8-22 17:21
17
0
我是一个新手。看不懂啊
雪    币: 17
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
amggking 2011-8-22 19:49
18
0
写的好啊 可惜本人小菜一个 看不懂 恳求说详细些
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
更新 2012-2-24 21:46
19
0
多谢指导啊,很好的文章
雪    币: 110
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sjm 2015-10-17 18:00
20
0
这方法不可行是因为tp修改debugport并不用api函数,而是自己写,直接对偏移写。
听说改写内核wrk修改偏移bc可以骗过,因为tp 写入bc 并不是debugport
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lypkingcn 2015-10-20 21:03
21
0
拜读驱动
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lzhs 2015-10-25 17:18
22
0
122179779
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lzhs 2015-10-25 17:20
23
0
我用xt工具无法检测到保护程序 这是为什么
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
圣运律师 2015-10-26 10:21
24
0
游客
登录 | 注册 方可回帖
返回