收藏 分销(赏)

过TP保护的基本方案复习课程.doc

上传人:精**** 文档编号:3867539 上传时间:2024-07-22 格式:DOC 页数:16 大小:373.50KB
下载 相关 举报
过TP保护的基本方案复习课程.doc_第1页
第1页 / 共16页
过TP保护的基本方案复习课程.doc_第2页
第2页 / 共16页
过TP保护的基本方案复习课程.doc_第3页
第3页 / 共16页
过TP保护的基本方案复习课程.doc_第4页
第4页 / 共16页
过TP保护的基本方案复习课程.doc_第5页
第5页 / 共16页
点击查看更多>>
资源描述

1、过TP保护的基本方案精品文档过TP保护分析过程【转帖】本文只为研究技术,请所有童鞋切勿使用本文之方法做下那天理难容罪恶不舍之坏事。既是研究游戏保护,那么总要有一个研究对象。本文就以TMD_TP这款游戏保护为例进行分析讲解。请勿对号入座,如有雷同之处。纯属反汇编引擎之错误,不关我的事!转载请注明出处 关键字:DNF 驱动保护鉴于最近很多同学找上门来求解这那问题,反正这东西又不是绝密档案,放在我手里大半个月了,还不如放出来让大家一起进步算了。另外都是取之看雪还之看雪罢了。索性我也就公布一个全套的方案。绝无其他意思,所以还请同道中人嘴下留情。切勿背地使坏!在正式开篇之前我要感谢看雪ID:十年寒窗 在

2、我最困惑的时候,他给予了最大的帮助!另外还有一位和我同岁的神秘人物也给予了不小的帮助,感谢你们。废话了半天,正式开始吧。tmd_TP也就是国内比较流行的游戏D_N*F的游戏保护。它在ring0层一共HOOK了几个地方和一些其他的工作。来达到保护的目的下面是简报:url=javascript:复制代码/url1. NtOpenThread /防止调试器在它体内创建线程 NtOpenProcess /防止OD等在进程列表看到它 KiAttachProcess /防止其他软件附加它 NtReadVirtualMemory /防止别人读取它的内存 NtWriteVirtualMemory /防止别人在

3、它的内存里面乱写乱画 KDCOM.dll:KdReceivePacket /这两个是COM串口的接受和发送数据 KDCOM.dll:KdSendPacket /主要用来方式别人双机调试使用了KdDisableDebugger来禁用双机调试代码: url=javascript:复制代码/url1. .text:010025F0 jz short loc_1002622 .text:010025F2 call sub_10022A4 .text:010025F7 call ds:KdDisableDebugger .text:010025FD push offset byte_10022EC .t

4、ext:01002602 push esi .text:01002603 push offset byte_10022DC .text:01002608 push edi .text:01002609 push dword_100CF24并对debugport进行了疯狂的清零操作甚至还包括EPROCESS+70+74+78等几处位置图片:1.jpg处理的手段通常都是向64端口写入FE导致计算机被重启代码: url=javascript:复制代码/url1. .text:01001665 mov al, 0FEh .text:01001667 out 64h, al ; AT Keyboard

5、controller 8042. .text:01001667 ; Resend the last transmission .text:01001669 popa .text:0100166A retn下面简单看下他关键的几个HOOK:KiAttachProcess 图片:2.jpgNtReadVirtualMemory 图片:3.jpgNtWriteVirtualMemory 图片:4.jpgNtOpenThread图片:5.jpgNtOpenProcess 图片:6.jpg引用:其中,前3个直接恢复即可。第4个有监视,直接恢复即刻重启第5个和ring3有通信,直接恢复1分钟内SX非法模块

6、 根据上面的分析,下面给出相应的解决方案1.直接恢复 第1、2、3处HOOK2.绕过4、5处HOOK3.将debugport清零的内核线程干掉4.恢复硬件断点但是要有一个先后的逻辑顺序因为内核有一个线程负责监视几个地方,必须要先干掉它。但是这个内容我写在了处理debugport清零的一起,也就是第3步。所以大家在照搬源码的时候注意代码执行次序先从简单的工作讲起,恢复1、2、3处的HOOKKiAttachProcess的处理代码: url=javascript:复制代码/url1. / / 名称: Nakd_KiAttachProcess / 功能: My_RecoveryHook_KiAtta

7、chProcess的中继函数 / 参数: / 返回: / static NAKED VOID Nakd_KiAttachProcess() _asm mov edi,edi push ebp mov ebp,esp push ebx push esi mov eax,KiAttachProcessAddress /注意这个是全局变量 BYTE* add eax,7 jmp eax / / 名称: RecoveryHook_KiAttachProcess / 功能: 解除游戏保护对_KiAttachProcess函数的HOOK(DNF) / 参数: / 返回: 状态 / NTSTATUS My_

8、RecoveryHook_KiAttachProcess() BYTE *KeAttachProcessAddress = NULL; /KeAttachProcess函数地址 BYTE *p; BYTE MovEaxAddress5 = 0xB8,0,0,0,0; / BYTE JmpEax2 = 0xff,0xe0; KIRQL Irql; /特征码 BYTE Signature1 = 0x56, /p-1 Signature2 = 0x57, /p-2 Signature3 = 0x5F, /p-3 Signature4 = 0x5E, /p+5 Signature5 = 0xE8; /

9、p第一个字节 /获得KeAttachProcess地址,然后通过特征码找到 /KiAttachProcess的地址 KeAttachProcessAddress = (BYTE*)MyGetFunAddress(LKeAttachProcess); if (KeAttachProcessAddress = NULL) KdPrint(KeAttachProcess地址获取失败n); return FAILED_TO_OBTAIN_FUNCTION_ADDRESSES; /将p指向KeAttachProcess函数开始处 p = KeAttachProcessAddress; while (1)

10、 if (*(p-1) = Signature1) & (*(p-2) = Signature2) & (*(p+5) = Signature3) & (*(p+6) = Signature4) & (*p = Signature5) /定位成功后取地址 KiAttachProcessAddress = *(PULONG)(p+1)+(ULONG)(p+5); break; /推动指针 p+; /计算中继函数地址 *(ULONG *)(MovEaxAddress+1)=(ULONG)Nakd_KiAttachProcess; WPOFF(); /清除CR0 /提升IRQL中断级 Irql=Ke

11、RaiseIrqlToDpcLevel(); /写入 RtlCopyMemory(KiAttachProcessAddress,MovEaxAddress,5); RtlCopyMemory(KiAttachProcessAddress+5,JmpEax,2); /恢复Irql KeLowerIrql(Irql); WPON(); /恢复CR0 return STATUS_SUCCESS; NtReadVirtualMemory和NtWriteVirtualMemory的处理注意这里,我对他们俩开头的第2句PUSH的处理我直接写入了push 0x78563412大家可以根据自己的地址来硬编码一

12、次。或者干脆这样使用代码: url=javascript:复制代码/url1. / / 名称: My_RecoveryHook_NtReadAndWriteMemory / 功能: 解除游戏保护对NtReadVirtualMemory和 / NtWriteVirtualMemory的HOOK / 参数: / 返回: / NTSTATUS My_RecoveryHook_NtReadAndWriteMemory() BYTE Push1Ch2 = 0x6a,0x1c; /02字节 BYTE PushAdd5 = 0x68,0x12,0x34,0x56,0x78; /NtReadVirtualMe

13、mory物理机 /BYTE PushAdd25 = 0x68,0xf0,0x6f,0x4f,0x80; /NtWriteVirtualMemory物理机 KIRQL Irql; BYTE *NtReadVirtualMemoryAddress = NULL; /NtReadVirtualMemory的地址 BYTE *NtWriteVirtualMemoryAddress = NULL; /NtWriteVirtualMemory的地址 /从SSDT表中获取NtReadVirtualMemory函数地址 NtReadVirtualMemoryAddress = (BYTE*)myGetCurr

14、entAddress(0xBA); if (NtReadVirtualMemoryAddress = NULL) KdPrint(NtReadVirtualMemory函数地址获取失败! n); return FAILED_TO_OBTAIN_FUNCTION_ADDRESSES; /从SSDT表中获取NtWriteVirtualMemory函数地址 NtWriteVirtualMemoryAddress = (BYTE*)myGetCurrentAddress(0x115); if (NtWriteVirtualMemoryAddress = NULL) KdPrint(NtWriteVir

15、tualMemory函数地址获取失败! n); return FAILED_TO_OBTAIN_FUNCTION_ADDRESSES; WPOFF(); /清除CR0 /提升IRQL中断级 Irql=KeRaiseIrqlToDpcLevel(); /写入 RtlCopyMemory(NtReadVirtualMemoryAddress,Push1Ch,2); RtlCopyMemory(NtReadVirtualMemoryAddress+2,PushAdd,5); RtlCopyMemory(NtWriteVirtualMemoryAddress,Push1Ch,2); RtlCopyMe

16、mory(NtWriteVirtualMemoryAddress+2,PushAdd,5); /恢复Irql KeLowerIrql(Irql); WPON(); /恢复CR0 return STATUS_SUCCESS; 好了,下面来处理NtOpenProcess和NtOpenThread这两个函数的处理上不能太鲁莽了。手法要风骚一点细腻一点了介于篇幅的原因,我只贴出来前者的处理方法,后者雷同细微之处大家自行修改。我总不能真的给你方法又给你工具。眼看着自己变成教唆犯代码: url=javascript:复制代码/url1. /NtOpenProcess用到的全局变量为了方便堆栈平衡的处理使用

17、全局变量 PEPROCESS processEPROCESS = NULL; /保存访问者的EPROCESS ANSI_STRING p_str1,p_str2; /保存进程名称 BYTE *ObOpenObjectByPointerAddress = NULL; /ObOpenObjectByPointer的地址 BYTE *p_TpHookAddress = NULL; /TP的HOOK函数地址 BYTE *p_ReturnAddress = NULL; /返回到的地址 BYTE *p_MyHookAddress = NULL; /我们的HOOK函数在哪写入 #define DNF_EXE

18、 DNF.exe /要检索的进程名 / / 名称: Nakd_NtOpenProcess / 功能: My_RecoveryHook_NtOpenProcess的中继函数 / 参数: / 返回: / static NAKED VOID Nakd_NtOpenProcess() /获得调用者的EPROCESS processEPROCESS = IoGetCurrentProcess(); /将调用者的进程名保存到str1中 RtlInitAnsiString(&p_str1,(ULONG)processEPROCESS+0x174); /将我们要比对的进程名放入str2 RtlInitAnsi

19、String(&p_str2,DNF_EXE); if (RtlCompareString(&p_str1,&p_str2,TRUE) = 0) /说明是DNF进程访问了这里 _asm push dword ptr ebp-38h push dword ptr ebp-24h push p_ReturnAddress mov eax,p_TpHookAddress jmp eax else _asm push dword ptr ebp-38h push dword ptr ebp-24h push p_ReturnAddress mov eax,ObOpenObjectByPointerAd

20、dress jmp eax / / 名称: My_RecoveryHook_NtOpenProcess / 功能: 解除游戏保护对NtOpenProcess的HOOK / 参数: / 返回: 状态 / NTSTATUS My_RecoveryHook_NtOpenProcess() BYTE *NtOpenProcessAddress = NULL; /NtOpenProcess的地址 BYTE *p = NULL; /临时 TOP5CODE *top5code = NULL; /保存5字节内容 BYTE JmpAddress6 = 0xE9,0,0,0,0,0x90; KIRQL Irql;

21、 /获取NtOpenProcess的地址 NtOpenProcessAddress = (BYTE*)MyGetFunAddress(LNtOpenProcess); if (NtOpenProcessAddress = NULL) KdPrint(NtOpenProcess地址获取失败n); return FAILED_TO_OBTAIN_FUNCTION_ADDRESSES; /获取ObOpenObjectByPointer的地址 ObOpenObjectByPointerAddress = (BYTE*)MyGetFunAddress(LObOpenObjectByPointer); i

22、f (ObOpenObjectByPointerAddress = NULL) KdPrint(ObOpenObjectByPointer地址获取失败n); return FAILED_TO_OBTAIN_FUNCTION_ADDRESSES; /将p指向NtOpenProcess函数开始处 p = NtOpenProcessAddress; /用一个无限循环来判断给定的特征码来确定被HOOK位置 while (1) if (*(p-7) = 0x50) & (*(p-0xE) = 0x56) & (*(p+0xd) = 0x50) & (*(p+0x16) = 0x3b) & (*(p+0x

23、17) = 0xce) & (*p = 0xE8) & (*(p+5) = 0x8b) & (*(p+6) = 0xf8) KdPrint(%0X n,(ULONG)p); break; /推动指针向前走 p+; /将top5code指向 p 的当前处 /用以取出 call 地址 这5字节里面的地址 top5code = (TOP5CODE*)p; p_TpHookAddress = (BYTE*)(ULONG)p+5+top5code-address); /找到我们写入自定义函数的地址 p_MyHookAddress = p-6; /保存调用ObOpenObjectByPointer函数以后

24、的返回地址 p_ReturnAddress = p+5; /将一条JMP Nakd_NtOpenProcess写入到数组中 *(ULONG *)(JmpAddress+1)=(ULONG)Nakd_NtOpenProcess - (ULONG)p_MyHookAddress+5); WPOFF(); /清除CR0 /提升IRQL中断级 Irql=KeRaiseIrqlToDpcLevel(); /写入 RtlCopyMemory(p_MyHookAddress,JmpAddress,6); /恢复Irql KeLowerIrql(Irql); WPON(); /恢复CR0 return STA

25、TUS_SUCCESS; 处理之后:图片:7.jpg简而言之其原理就是,任何人调用了NtOpenProcess的时候会先进入Nakd_NtOpenProcess函数,我们判断。如果是游戏进程访问的话,就有可能是验证之类的我们转到它自己的函数里面。让它保持与ring3层的通信。否则的话,嘿嘿接下来是第3步处理debugport清零的这块了。我想绝大多数人关心的都是这里了网络上能搜多到的办法几乎都失效了有办法的人又不肯放出来,急眼了就自己想了个土办法虽然不那么时尚。但是绝对的奏效。由于代码凌乱不堪,简单说下其原理。我们定位内核模块TxxxSxxx.sys的首地址然后根据特征码遍历整个模块找到我们需

26、要的地方,然后干掉他们。那么我们又如何能够通过人工的判断出来到底是哪里在作怪呢利用syser或Start SoftICE对EPROCESS+BC处设置断点。就可以一层一层的追溯上去了到底如何用他们,我想大家自己多花点时间在看雪和GOOGLE或者BAIDU上面是不会吃亏的。由于ZwQuerySystemInformation函数的使用非常繁琐。而且篇幅有限。所以我只给出关键代码,至于这个函数如何使用。大家可以自己在搜索引擎找“枚举内核模块”代码: url=javascript:复制代码/url1. / / 名称: MyEnumKernelModule / 功能: 枚举内核模块 / 参数: str

27、:内核模块名称 / moduleadd:该模块地址传出 / modulesie:该模块大小传出 / 返回: / NTSTATUS MyEnumKernelModule(IN CHAR* str,OUT ULONG *moduleadd,OUT ULONG *modulesie) NTSTATUS status = STATUS_SUCCESS; ULONG n = 0; ULONG i = 0; PSYSTEM_MODULE_INFORMATION_ENTRY module = NULL; PVOID pbuftmp = NULL; ANSI_STRING ModuleName1,Module

28、Name2; BOOLEAN tlgstst= FALSE; /如果找到了指定模块则设置为TRUE /利用11号功能枚举内核模块 status = ZwQuerySystemInformation(11, &n, 0, &n); /申请内存 pbuftmp = ExAllocatePool(NonPagedPool, n); /再次执行,将枚举结果放到指定的内存区域 status = ZwQuerySystemInformation(11, pbuftmp, n, NULL); module = (PSYSTEM_MODULE_INFORMATION_ENTRY)(PULONG )pbuftm

29、p + 1 ); /初始化字符串 RtlInitAnsiString(&ModuleName1,str); / n = *(PULONG)pbuftmp ); for ( i = 0; i n; i+ ) RtlInitAnsiString(&ModuleName2,&module.ImageName); /DbgPrint(%dt0x%08X 0x%08X %sn,module.LoadOrderIndex,module.Base,module.Size,module.ImageName); if (RtlCompareString(&ModuleName1,&ModuleName2,TRU

30、E) = 0) DbgPrint(MyEnumKernelModule:%s:%0X n,ModuleName2.Buffer,module.Base); *moduleadd = module.Base; *modulesie = module.Size; tlgstst = TRUE; break; ExFreePool(pbuftmp); if tlgstst = FALSE) return FAILED_TO_OBTAIN_FUNCTION_ADDRESSES; return status; / / 名称: My_Recovery_Debugport / 功能: 恢复游戏对debugp

31、ort的清零操作 / 参数: / 返回: / NTSTATUS My_Recovery_Debugport() NTSTATUS stats; BYTE *sd1 = NULL,*sd2 = NULL,*pd = NULL; ULONG ModuleSize,ModuleAddress,i,number = 0; BYTE *p; KIRQL Irql; BYTE C3902 = 0xc3,0x90; /获取指定的内核模块地址和字节数 stats = MyEnumKernelModule(?c:windowssystem32tessafe.sys,&ModuleAddress,&ModuleS

32、ize); if (stats = FAILED_TO_OBTAIN_FUNCTION_ADDRESSES) return FAILED_TO_OBTAIN_FUNCTION_ADDRESSES; KdPrint(Address:%0X Sie:%d n,ModuleAddress,ModuleSize); /特征码 /* sd1特征 p-1:18 p-2:87 p-3:DB p-4:33 p-5:07 p-6:03 p :33 p+1:C0 p+7:3B p+8:D8 sd2特征 p-1:07 p-2:87 p-3:c0 p-4:33 p+14:89 p+15:1c p+16:38 */ /

33、将P指向内核模块开始处 p = (BYTE*)ModuleAddress + 20; for (i = 0; i = 3) KdPrint(特征 %d -退出n,number); break; /首先干掉监视函数 while (1) if (*(pd-1) = 0xcc) & (*(pd-2) = 0xcc) KdPrint(pd首地址:%0X n,(ULONG)pd); WPOFF(); /清除CR0 /提升IRQL中断级 Irql=KeRaiseIrqlToDpcLevel(); /写入 RtlCopyMemory(pd,C390,2); /恢复Irql KeLowerIrql(Irql)

34、; WPON(); /恢复CR0 break; pd-; /干掉2个SD while (1) if (*(sd1-1) = 0xcc) & (*(sd1-2) = 0xcc) KdPrint(sd1首地址:%0X n,(ULONG)sd1); WPOFF(); /清除CR0 /提升IRQL中断级 Irql=KeRaiseIrqlToDpcLevel(); /写入 RtlCopyMemory(sd1,C390,2); /恢复Irql KeLowerIrql(Irql); WPON(); /恢复CR0 break; sd1-; while (1) if (*(sd2-1) = 0xcc) & (*

35、(sd2-2) = 0xcc) KdPrint(sd2首地址:%0X n,(ULONG)sd2); WPOFF(); /清除CR0 /提升IRQL中断级 Irql=KeRaiseIrqlToDpcLevel(); /写入 RtlCopyMemory(sd2,C390,2); /恢复Irql KeLowerIrql(Irql); WPON(); /恢复CR0 break; sd2-; return STATUS_SUCCESS; 图片:8.jpg最后,处理一下硬件断点就可以了这里我们使用到了SSDT HOOK分别HOOK了 SSDT 表中索引为 0xD5和0x55的函数。由于这里比较简单我想10

36、个人有9个人懂得SSDT HOOK的。所以直接给出源码,不做原理分析了代码: url=javascript:复制代码/url1. /处理硬件断点时 ULONG uNtSetContextThreadAddress; ULONG uNtGetContextThreadAddress; ULONG TenNtSetContextThread, TenNtGetContextThread; / / 名称: _MyNtGetThreadContext / 功能: 两个SSDT HOOK伪造函数的中继函数 / 参数: / 返回: / static NAKED NTSTATUS Nakd_NtGetThr

37、eadContext(HANDLE hThread, PCONTEXT pContext) _asm jmp dword ptrTenNtGetContextThread static NAKED NTSTATUS Nakd_NtSetThreadContext(HANDLE hThread, PCONTEXT pContext) _asm jmp dword ptrTenNtSetContextThread / / 名称: MyNtGetThreadContext & MyNtSetThreadContext / 功能: NtGetThreadContext与NtSetThreadConte

38、xt函数被SSDT HOOK的伪造函数 / 参数: / 返回: / NTSTATUS MyNtGetThreadContext(HANDLE hThread, PCONTEXT pContext) if ( _stricmp(const char*)PsGetProcessImageFileName(PsGetCurrentProcess(),DNF_EXE) ) return Nakd_NtGetThreadContext(hThread, pContext); return STATUS_UNSUCCESSFUL; NTSTATUS MyNtSetThreadContext(HANDLE hThread, PCONTEXT pContext) if ( _stricmp(const char*)PsGetProcessImageFileName(PsGetCurrentProcess(),DNF_EXE) ) return Nakd_NtSetThreadContext(hThread, pContext); /DbgPrint(Dr7:%08Xn, pContext-Dr7); if ( pContext-Dr7 = 0x101 ) return Na

展开阅读全文
相似文档                                   自信AI助手自信AI助手
猜你喜欢                                   自信AI导航自信AI导航
搜索标签

当前位置:首页 > 教育专区 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2024 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服