关于Win7 x64下过TP保护(应用层)(转)
非常感谢大家那么支持我上一篇教程。
Win10 快出了,所以我打算尽快把应用层的部分说完。
调试对象:DXF
调试工具:CE、OD、PCHunter、Windbg
调试先言:TP的应用层保护做得比较多,包括对调试器的检测,比如CE工具会被DXF报非法。有的保护还是内核与应用层交替保护。
应用层:
1、TP让调试器卡死(内核互动)
现象: <ignore_js_op>
如图,TP会检测调试器让调试器暂停运行,实际上就是暂停了调试器所有的线程而已。
这个保护是今年7月份新出的,所以我这里重点分析下,我刚开始调试的时候就发现OD会莫名其妙地卡死。
打开PCHunter发现OD的进程线程全部被暂停了。
开始我认为是TP调用了SuspendThread(函数:暂停指定线程)来让调试器卡死的。
于是我就打开Windbg附加并在这个函数上下断点,发现没有断下来。
然后我认为是调用了接口函数NtSuspendThread(函数:暂停指定线程<内核接口>)
但是还是没有断下。所以排除了DXF在Ring3调用了暂停线程让OD卡死。
于是我思考了一下,打开虚拟机,简单过了双机调试保护(一段时间后还是会蓝屏),在DXF启动之后,
在Windbg输入!process OD的进程ID 来查看线程的调用堆载,我发现了很有意思的东西。
SuspendCount被置为了1,再看看调用堆载。
原来TP在Ring0中调用了KiSuspendThread来暂停OD的线程啊。怪不得断不下来。
于是我在KiSuspendThread头部下断点,发现当OD打开的时候会断下,
这个是它的函数开头
0: kd> u KiSuspendThread
nt!KiSuspendThread:
fffff800`03e6cc60 48895c2408 mov qword ptr [rsp+8],rbx
fffff800`03e6cc65 4889742410 mov qword ptr [rsp+10h],rsi
fffff800`03e6cc6a 57 push rdi
fffff800`03e6cc6b 4883ec30 sub rsp,30h
fffff800`03e6cc6f 8364245800 and dword ptr [rsp+58h],0
fffff800`03e6cc74 65488b1c2588010000 mov rbx,qword ptr gs:[188h]
fffff800`03e6cc7d 4885db test rbx,rbx
它还保留着用__stdcall的调用约定,在64位下一般都是__fastcall
通过对参数的分析,我发现这个函数的第一个参数也就是rbx,里面存的是线程对象。
我在网上也没有找到相关的信息,于是我自己在头部改成了ret。
之后运行OD就不会卡死了。
继续深究,原来TP创建了一个内核回调,就是CreateProcess的回调,
自己可以打开PCHunter查看。
当发现是OD的进程被创建时,就会调用这个函数让进程暂停。
哦,原来是这样,那我们有什么办法解决它呢?怎么才能让调试器正常运行呢?
方案:1、自己恢复调试器的进程(推荐) 2、删除内核回调(驱动推荐)3、Hook KiSuspendThread 绕过(稍难)
在这里我推荐第一种,因为我们是要在应用层下操作。
方法很简单,当我们打开OD工具时,打开PCHunter选择OD的进程,右键恢复进程运行即可。
也可以自己做一个工具,恢复OD的进程,但是你要确保自己的程序不会进入黑名单。
至此,我们的调试器能正常打开了。
2、函数钩子(Hook)
这个保护不能说是新鲜了的吧,在应用层里很多游戏都这么干。
其实就是把一些重要的调试函数进行钩子,导致程序崩溃或者无法调试。
我们打开PCHunter,来到如图的位置,选择DXF的进程->右键选择扫描。
<ignore_js_op>
现在你只需要坐下等大约5分钟吧,好像有一千多个钩子(笑),要有耐心。
看到图中3个钩子了吗,它就是我们要说的。
我这里来说明下这3个函数的用途。
DbgUiRemoteBreakin:远程中断,附加调试器时调试器会发送信息让进程走这里。
KiUserExceptionDispatcher:UEF异常处理函数,梦老大讲解过的,这个我们不能随便恢复,干脆不用管它
因为DXF自己制造异常自己处理。
LdrInitalizeThunk:映像文件链入口,当DLL载入时会经过这里,如果我们不恢复它将无法注入DLL。
这3个钩子有两个是我们必须恢复的,就是一和三。
第三个比较好处理,PCHunter中已经给出了函数原来的机器码。我们之间用PCHunter恢复也可以自己写个程序恢复
但是第一个就不好了,我们必须用程序自己来恢复,因为:
<ignore_js_op>
红线部分是需要重定位的,机器每次开机都会不同,我们可以通过获取自己程序的这个位置的代码来恢复。
具体怎么恢复这里就不说了,我会贴出代码给大家。
那么2个Hook搞定后我们就要来解决崩溃问题了。
3、异常崩溃
大家可以发现OD附加DXF后运行,游戏会莫名其妙地崩溃,你可能会认为OD被DXF检测到了,其实它是个通用
的反调试的手法。
自己给自己制造异常,自己处理,如果OD抢着处理这个异常,反而会使进程崩溃。
这个就是它异常崩溃的原理。
其实是一个线程在自发异常的,怎么把它揪出来呢?
打开Windbg,附加DXF,运行,可以发现一段时间后,Windbg断下
如图所示:
<ignore_js_op>
线程ID:F08 发送了一个内存访问异常(0x80000002)它故意让Windbg断下。
它需要试探是否有调试器,于是我们就找到它了,把f08换成十进制发现是
3848的线程发送异常的,在PCHunter中可以看到,如图所示,它是由ntdll.dll发送的。
唯一的办法就是结束这个线程,右键->结束线程,搞定,OD附加DXF不会崩溃了。
但是你得自己做个程序来找到这条线程然后来结束掉,可以通过搜索线程入口特征码的方式来
找到它。
那么现在,我们调试DXF再也没有问题了。但是CE工具开启久了也会被提示非法,怎么办?
4、检测非法工具
也许大家非常想要知道怎么办。
它检测非法工具的原理是:
使用ReadProcessMemory(函数:读取进程内存)搜索进程特征码,找到属于非法工具的特征码后游戏消失,提示非法重启。
若想解决它,我们有以下方案:
1、删除工具中的特征码 2、在内核中拦截NtReadVirtualMemory或KeStackAttachProcess来绕过搜索
3、找到搜索的线程,结束该线程。
其实我发现第3种是一劳永逸,所以我在这里说下第三种方法。
打开PCHunter找到如下几条线程。选择后同时右键结束,OK,CE再也不会非法了。
<ignore_js_op>
这几条线程都是TenSLX.dll模块里的,其实这个方法在腾Xun游戏里面通用。
别问我是怎么知道的,其实我是一个个试过的(笑)。
5、关于CRC代码自校验
通过上面的说明,大家应该可以总结一个结论
在应用层中游戏若想保护自己都是采用走线程或Hook方式。
所以大家可以自己找到CRC代码自校验的线程吧?结束掉,OK,可以下软件断点(int 3)了。
结束语:
别以为这样就能在DXF里为所欲为了,还有三方检测等着你呢!
这些还需要靠大家自己多去练习,总结规律,其实你会发现,
再难的保护还都是这样子的了(笑)......
附赠代码(部分):
- void CAnitTP_AppDlg::OnBnClickedButtonAnit()
- {
- DWORD pid = GetProcessIdByProcName(TEXT("DNF.exe"));
- if (pid==0)
- {
- MessageBox(TEXT("对不起,没有找到指定游戏进程.(DNF.exe)"), TEXT("操作失败"), MB_OK | MB_ICONERROR);
- return;
- }
- const BYTE code[8] = {0x90,0x90,0x90,0x90,0x90,0x55,0x8b,0xec};
- const BYTE code2[13] = { 0xC3, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 ,0xE9};
- DWORD trds[521];
- int trdcount=0;
- trdcount=GetProcessThreadId(pid, trds);
- LPVOID pEntryPoint=NULL;
- BYTE buf[13];
- HANDLE hThread;
- for (int i = 0; i < trdcount;i++)
- {
- pEntryPoint=GetThreadEntryPointById(trds[i]);
- ReadProcessMemoryEx(pid, pEntryPoint, buf, 8);
- TCHAR ModuleName[256];
- GetProcessThreadModuleNameByTid(pid, trds[i], ModuleName);
- if (memcmp(buf, code, 8) == 0 || lstrcmp(ModuleName, L"TenSLX.dll")==0)
- {
- hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, trds[i]);
- if (!hThread)continue;
- TerminateThread(hThread,0);
- CloseHandle(hThread);
- }
- ReadProcessMemoryEx(pid, (LPVOID)((int)pEntryPoint - 0xc), buf, 13);
- if (memcmp(buf, code2, 13) == 0)
- {
- hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, trds[i]);
- if (!hThread)continue;
- SuspendThread(hThread);
- CloseHandle(hThread);
- }
- }
- byte code3[7] = { 0x6A, 0x08, 0x68, 0x00, 0x00, 0x00, 0x00 };
- LPVOID pDbgUiRemoteBreakin = (LPVOID)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "DbgUiRemoteBreakin"); //调试用
- memcpy(&code3[3], (LPVOID)((int)pDbgUiRemoteBreakin + 3), 4);
- WriteProcessMemoryEx(pid, pDbgUiRemoteBreakin, code3, 7);
- byte code4[6] = { 0x8b, 0xff, 0x55, 0x8b, 0xec, 0xff };
- LPVOID pLdrInitializeThunk = (LPVOID)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "LdrInitializeThunk"); //DLL注入用
- WriteProcessMemoryEx(pid, pLdrInitializeThunk, code4, 6);
- MessageBox(TEXT("操作完毕,开始调试吧!"),TEXT("OK"),MB_OK|MB_ICONINFORMATION);
- }
复制代码
功能函数头文件:
- #ifndef HANSHU
- #define HANSHU
- #include <TlHelp32.h>
- #include <psapi.h>
- #pragma comment(lib,"psapi.lib")
- typedef enum _THREADINFOCLASS {
- ThreadBasicInformation,
- ThreadTimes,
- ThreadPriority,
- ThreadBasePriority,
- ThreadAffinityMask,
- ThreadImpersonationToken,
- ThreadDescriptorTableEntry,
- ThreadEnableAlignmentFaultFixup,
- ThreadEventPair_Reusable,
- ThreadQuerySetWin32StartAddress,
- ThreadZeroTlsCell,
- ThreadPerformanceCount,
- ThreadAmILastThread,
- ThreadIdealProcessor,
- ThreadPriorityBoost,
- ThreadSetTlsArrayAddress,
- ThreadIsIoPending,
- ThreadHideFromDebugger,
- ThreadBreakOnTermination,
- MaxThreadInfoClass
- } THREADINFOCLASS;
- typedef struct _CLIENT_ID {
- HANDLE UniqueProcess;
- HANDLE UniqueThread;
- } CLIENT_ID;
- typedef CLIENT_ID *PCLIENT_ID;
- typedef struct _THREAD_BASIC_INFORMATION { // Information Class 0
- LONG ExitStatus;
- PVOID TebBaseAddress;
- CLIENT_ID ClientId;
- LONG AffinityMask;
- LONG Priority;
- LONG BasePriority;
- } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;
- typedef LONG (__stdcall *fZwQueryInformationThread) (
- IN HANDLE ThreadHandle,
- IN THREADINFOCLASS ThreadInformationClass,
- OUT PVOID ThreadInformation,
- IN ULONG ThreadInformationLength,
- OUT PULONG ReturnLength OPTIONAL
- );
- fZwQueryInformationThread ZwQueryInformationThread;
- DWORD GetProcessPidByWndName(LPCTSTR szWndName)
- {
- HWND hWnd = FindWindow(NULL,szWndName);
- if (IsWindow(hWnd))
- {
- DWORD pid;
- GetWindowThreadProcessId(hWnd,&pid);
- return pid;
- }
- return 0;
- }
- DWORD GetProcessIdByProcName(LPCTSTR szProcName)
- {
- HANDLE hSnapshot= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
- PROCESSENTRY32 pro;
- pro.dwSize=sizeof(pro);
- BOOL bMore=Process32First(hSnapshot,&pro);
- while (bMore)
- {
- if (lstrcmp(szProcName,pro.szExeFile)==0)
- {
- CloseHandle(hSnapshot);
- return pro.th32ProcessID;
- }
- bMore=Process32Next(hSnapshot,&pro);
- }
- CloseHandle(hSnapshot);
- return 0;
- }
- BOOL ReadProcessMemoryEx(DWORD pid,LPVOID addr,LPVOID buffer,DWORD size)
- {
- HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
- if (hProcess==0)
- {
- return FALSE;
- }
- BOOL bResult=ReadProcessMemory(hProcess,addr,buffer,size,NULL);
- CloseHandle(hProcess);
- return bResult;
- }
- BOOL WriteProcessMemoryEx(DWORD pid,LPVOID addr,LPVOID buffer,DWORD size)
- {
- HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
- if (hProcess==0)
- {
- return FALSE;
- }
- BOOL bResult=WriteProcessMemory(hProcess,addr,buffer,size,NULL);
- CloseHandle(hProcess);
- return bResult;
- }
- int GetProcessThreadId(DWORD pid,DWORD *trds)
- {
- HANDLE hSnapshot= CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,pid);
- if (hSnapshot==INVALID_HANDLE_VALUE)
- return 0;
- THREADENTRY32 trd;
- trd.dwSize=sizeof(trd);
- BOOL bMore=Thread32First(hSnapshot,&trd);
- int i=0;
- while (bMore)
- {
- if (trd.th32OwnerProcessID==pid)
- {
- trds[i]=trd.th32ThreadID;
- i++;
- }
- bMore=Thread32Next(hSnapshot,&trd);
- }
- CloseHandle(hSnapshot);
- return i;
- }
- LPVOID GetThreadEntryPointById(DWORD tid)
- {
- HANDLE hThread=OpenThread(THREAD_ALL_ACCESS,FALSE,tid);
- if (hThread==0)
- {
- return NULL;
- }
- LPVOID Addr=NULL;
- ZwQueryInformationThread=(fZwQueryInformationThread)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")),"ZwQueryInformationThread");
- ZwQueryInformationThread(hThread,ThreadQuerySetWin32StartAddress,&Addr,4,NULL);
- CloseHandle(hThread);
- return Addr;
- }
- BOOL GetProcessThreadModuleNameByTid(DWORD pid, DWORD tid, LPWSTR pszModuleName)
- {
- HANDLE hProcess = NULL;
- LPVOID pStart = NULL;
- TCHAR tmpStr[256];
- hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
- if (!hProcess)return FALSE;
- pStart = GetThreadEntryPointById(tid);
- if (!pStart) return FALSE;
- GetMappedFileName(hProcess, pStart, tmpStr, 256);
- for (int i = lstrlen(tmpStr); i >0; i--)
- {
- if (tmpStr[i]== '\\')
- {
- lstrcpy(pszModuleName, &tmpStr[i+1]);
- break;
- }
- }
- CloseHandle(hProcess);
- return TRUE;
- }
- void TerminateThreadEx(DWORD tid,DWORD exitcode=0)
- {
- HANDLE hThread=OpenThread(THREAD_ALL_ACCESS,FALSE,tid);
- if (hThread!=NULL)
- {
- TerminateThread(hThread,exitcode);
- CloseHandle(hThread);
- }
- }
- BOOL EnableDebugPrivilege()
- {
- HANDLE token;
- //提升权限
- if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&token))
- {
- return FALSE;
- }
- TOKEN_PRIVILEGES tkp;
- tkp.PrivilegeCount = 1;
- ::LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tkp.Privileges[0].Luid);
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- if(!AdjustTokenPrivileges(token,FALSE,&tkp,sizeof(tkp),NULL,NULL))
- {
- return FALSE;
- }
- CloseHandle(token);
- return TRUE;
- }
- #endif
复制代码
jpg改rar
关于Win7 x64下过TP保护(应用层)(转)的更多相关文章
- [转载] 关于Win7 x64下过TP保护的一些思路,内核层过保护,驱动过保护
首先特别感谢梦老大,本人一直没搞懂异常处理机制,看了他的教程之后终于明白了.在他的教程里我学到了不少东西.第一次在论坛发帖,就说说Win7 x64位下怎么过TP保护.如果有讲错的地方,还望指出.说不定 ...
- Win7 x64下进程保护与文件保护(ObRegisterCallbacks)
进程保护部分参考 http://bbs.pediy.com/showthread.php?t=168023 进程保护,在任务管理器不能结束进程 #ifndef CXX_PROTECTPROCESSX6 ...
- Oracle学习笔记1:win7 x64下安装Oracle10g
oracle 10g在win7x64下的安装: 第一次直接双击setup,出错了…… 可能是兼容性的问题,所以试着 右击setup-->属性-->兼容性-->勾上"以兼容模 ...
- WIN7 X64 下 VS2008升级补丁 (显示隐藏按钮)
原文地址:http://blog.sina.com.cn/s/blog_57b5da120100gk7l.html 更新列表: 2010年3月26日:增加对日文版的支持. 2010年3月3日:更新代码 ...
- pcl 1.8 + VS 2010 在win7 x64下的配置
https://blog.csdn.net/zhangping560/article/details/53978011 版权声明:(转载请注明作者和出处:http://blog.csdn.net/zh ...
- WIN7 x64下java 8的环境变量配置
Oracle官网下载JDK进行安装:我下载的是Java 8 JDK,地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-do ...
- X64下MmIsAddressValid的逆向及内存寻址解析
标 题: [原创]X64下MmIsAddressValid的逆向及内存寻址解析 作 者: 普通朋友 时 间: 2015-10-21,20:03:52 链 接: http://bbs.pediy.com ...
- 如何在Win7 x64上的配置32位的PostgreSQL ODBC数据源
在Win7 x64下安装最新版的PostgreSQL 9.x 后,从其官网下载最新的 ODBC驱动,分为普通的32位和64位版本,正常安装后,从已安装软件列表里可以看到两个版本的驱动都已经正确显示出来 ...
- x64下进程保护HOOK
目录 x64(32)下的进程保护回调. 一丶进程保护线程保护 1.简介以及原理 1.2 代码 1.3注意的问题 二丶丶回调函数写法 2.1 遇到的问题. 2.2 回调代码 x64(32)下的进程保护回 ...
随机推荐
- ocr 识别 github 源码
参考 [1] https://github.com/eragonruan/text-detection-ctpn [2] https://github.com/senlinuc/caffe_ocr [ ...
- AutoFac文档2(转载)
目录 开始 Registering components 控制范围和生命周期 用模块结构化Autofac xml配置 与.net集成 深入理解Autofac 指导 关于 词汇表 Registering ...
- 区别getElementByID,getElementsByName,getElementsByTagName
以人来举例说明,人有能标识身份的身份证,有姓名,有类别(大人.小孩.老人)等. 1. ID 是一个人的身份证号码,是唯一的.所以通过getElementById获取的是指定的一个人. 2. Name ...
- atitit.判断时间重叠方法总结 java c++ c#.net js php
atitit.判断时间重叠方法总结 java c++ c#.net js php 1. 判断时间重叠具体流程思路 1 2. 重叠算法 实际上就是日期集合跟个时间集合的的交集(乘法算法) 1 3. 代 ...
- Ubuntu环境下使用npm安装node模块时报错的处理方法
错误信息: npm ERR : node: not found : npm ERR! not ok code 0 解决方案: sudo apt-get install nodejs-legacy 也可 ...
- 李洪强iOS开发之苹果企业开发者账号申请流程
李洪强iOS开发之苹果企业开发者账号申请流程 一. 开发者账号类型选择 邓白氏码 DUNS number,是Data Universal Numbering System的缩写,是一个独一无二的9位数 ...
- Centos 挂载NTFS格式的USB硬盘
公司的一台服务器本身硬盘容量较小,要加一块2T的硬盘,用来做samba服务器,以下是挂载硬盘的主要记录: 这是服务器不认NTFS格式的情况:mount: unknown filesystem type ...
- 小贝_redis 高级应用-事务
redis高级应用-事务 一.redis的事务 二.redis实现事务 三.redis事务问题 一.redis的事务 事务提供了一种"将多个命令打包,然后一次性.按顺序地运行"的机 ...
- json datatable互转(真正能用的-原创)
网上有不少的转换类 可是不全 或者有错误 我现在贴一个 js 和C# 互转代码 希望能帮到需要的童鞋 首先C#转成 json /// <summary> /// DataT ...
- IOS让返回按钮显示自定义标题而不是上个ViewController的title
在开发IOS的时候发现当从一个ViewController跳转到另一个ViewController时,被跳转到的那个ViewController的返回按钮总是显示的是上个ViewController的 ...