51.网游逆向分析与插件开发-游戏反调试功能的实现-设置主线程为隐藏调试破坏调试通道

前置内容:

50.网游逆向分析与插件开发-游戏反调试功能的实现-TP、NP等反调试驱动的原理-CSDN博客

码云地址(master分支):https://gitee.com/dye_your_fingers/sro_-ex.git

码云版本号:87e45c4acc2e842f147ce0e037731fc5a139e047

代码下载地址,在 SRO_EX 目录下,文件名为:SRO_Ex-设置主线程为隐藏调试破坏调试通道.zip

链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg

提取码:q9n5

--来自百度网盘超级会员V4的分享

HOOK引擎,文件名为:黑兔sdk.zip

链接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw

提取码:78h8

--来自百度网盘超级会员V4的分享

以 网游逆向分析与插件开发-代码保护壳的优化-修改随机基址为固定基址-CSDN博客 它的代码为基础进行修改

看完前置内容应该知道为何游戏厂家都要做驱动,不做驱动也确实没法搞,没有下手的机会,但天无绝人之路它还有一个口子用来做反调试,这个口子将来能不能用不知道,这个口子本身就是Windows未公开的api在文档里看它它不是给我们应用层的,它本身是一个驱动层的函数,首先要回顾一下它调试的逻辑,调试的本质下断点的本质就是int3,int3本质就是异常,有了异常以后调试器会接收到异常,然后就给一个处理的机会,有了异常之后它是先找调试器,处理完之后再找调试器,第一次调试器不理它第二次就会崩,这个时候利用驱动层的这个函数能够把线程设置成在调试器下设置为隐藏就是我不响应调试器,就是说面对调试器的时候我就认为我是没有调试器的,实际带来的后果是当这个线程一旦如果说发生不调试的话,这时是附加了调试器的,比如说一个int3的断点本质上是产生的异常,既然会产生异常,调试器又不处理,这个异常是调试器给的,但是调试器不处理,现在除了崩溃就没第二个选择了。

这种口子之类的知识没有地方去找,只能一点点的积累。

通过调用下方的AntiDebug函数(ZwSetInformationThread内核函数)就实现了隐藏线程,效果就是调试器下断点之后游戏会崩溃退出,原因就是通过 ZwSetInformationThread 函数把游戏主线程设置成对于调试器来说是隐藏状态,通俗点说就是游戏出轨了并且被调试器现场捉奸,然后调试器跟游戏离婚了,所以出现int3异常之后调试器不响应游戏,然后游戏只好自己处理异常,然后由于游戏中没有处理异常的代码,游戏又去找调试器,调试器还是不理它,然后就崩溃关闭了,然后下方的代码就破坏了调试的通道,实际使用的时候要猥琐,不能跟 AntiDebug函数里光明正大的用,说它光明正大的原因,首先 ZwSetInformationThread 常量字符串,就可以在字符串表里看出来,还有 ntdll.dll 也是一个常量在字符串表里也能看出来,对于有经验的人来说,看到 ntdll.dll 和 ZwSetInformationThread之后就能知道你在干嘛,所以说 ZwSetInformationThread 函数地址通过登录器传递进去是最好的

破解方式,把ZwSetInformationThread第二个参数设置成除了0x11其它的值

GameProtect.cpp文件的修改,修改了 GameProtect函数,新加 AntiDebug函数、ZwSetInformationThreadPtr函数指针

#include "pch.h"
#include "GameProtect.h"GameProtect* _protect;
extern int client;unsigned _stdcall GetFunctionAddress(int index) {//CString txt;//txt.Format(L"接收到:%d", index);//AfxMessageBox(txt);return _protect->GetAddress(index);
}unsigned GameProtect::GetAddress(int index)
{//CString txt;unsigned result = (unsigned)this->_EntryCode[index];//txt.Format(L"index:%d获取地址:%x", index, result);// AfxMessageBox(txt);return result;
}unsigned GameProtect::GetAddressHide(unsigned _eip)
{//CString txt;for (int i = 0; i < _HideCount; i++){if (_HideCode[i].Start == _eip) {return (unsigned)_EntryCode[_HideCode[i].Index];}}//txt.Format(L"index:%d获取地址:%x", index, result);// AfxMessageBox(txt);return 0;
}GameProtect::GameProtect()
{//AfxMessageBox(L"122222");_protect = this;AntiDebug();if (!InitEntryCode()) {AfxMessageBox(L"程序加载失败!");ExitProcess(0);}CString txt;txt.Format(L"111");AfxMessageBox(txt);
}bool GameProtect::MulCheckBySempore()
{auto hMuls = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, L"system_seamp");if (!hMuls) {hMuls = CreateSemaphore(0, 3, 3, L"system_seamp");}if (WaitForSingleObject(hMuls, 0) == WAIT_TIMEOUT) return true;return false;
}void GameProtect::CheckMult()
{if (MulCheckBySempore()) {AfxMessageBox(L"当前客户端启动已经超过最大数量");ExitProcess(0);}
}LONG _stdcall PVEHandl(PEXCEPTION_POINTERS val) {if (val->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) {unsigned _eip = val->ContextRecord->Eip;unsigned _eipReal = _protect->GetAddressHide(_eip);/*	CString txt;txt.Format(L"PVEHandl当前地址:%X", _eipReal);AfxMessageBox(txt);*/if (_eipReal) {val->ContextRecord->Eip = _eipReal;return EXCEPTION_CONTINUE_EXECUTION; // 继续执行}else return EXCEPTION_CONTINUE_SEARCH;}return EXCEPTION_CONTINUE_SEARCH;
}bool GameProtect::InitEntryCode()
{TCHAR FileModule[0x100];GetModuleFileName(NULL, FileModule, 0x100);auto hFile = CreateFile(FileModule, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE) {return false;}DWORD dRead;DWORD filelen = GetFileSize(hFile, &dRead);char* _data = new char[filelen];if (ReadFile(hFile, _data, filelen, &dRead, NULL)) {char* _dataBegin = _data;unsigned* _uRead = (unsigned*)(_data + filelen - 4);for (int i = 0; i < filelen - _uRead[0]-4; i++) // 解密数据{_data[_uRead[0] + i] = _data[_uRead[0] + i] ^ 0x23;}//unsigned* _uRead = (unsigned*)_data[filelen - 4];filelen = _uRead[0];// 真实的文件大小_uRead = (unsigned*)(_data + filelen);unsigned code_count = _uRead[0];_data = _data + filelen + sizeof(code_count);PCODEContext _ContextArrys = (PCODEContext)_data;for (int i = 0; i < code_count; i++){if (_ContextArrys[i].hide) {_HideCount++;}}if (_HideCount > 0) {AddVectoredExceptionHandler(1, PVEHandl);_HideCode = new HIDE_CODE[_HideCount];_HideCount = 0;}_data = _data + sizeof(CODEContext) * code_count;_EntryCode = new LPVOID[code_count];for (int i = 0; i < code_count; i++){char* _tmpByte = new char[_ContextArrys[i].len + 2];_EntryCode[i] = _tmpByte;_tmpByte[0] = 0x9D;_tmpByte[1] = 0x61;/*CString txt;txt.Format(L"当前地址:%X", _EntryCode[i]);AfxMessageBox(txt);*/unsigned offset = sizeof(_ContextArrys[i].r_count) * _ContextArrys[i].r_count;memcpy((char*)_EntryCode[i] + 2, _data + offset, _ContextArrys[i].len);unsigned short* rel = (unsigned short*)_data;for (int x = 0; x < _ContextArrys[i].r_count; x++){unsigned* _callAddr = (unsigned*)((char*)_EntryCode[i] + rel[x] + 1 + 2);_callAddr[0] = _callAddr[0] - (unsigned)_callAddr - 4;// AfxMessageBox(L"这里代码存在问题,后面改");}_data = _data + offset + _ContextArrys[i].len;DWORD dOld;VirtualProtect(_EntryCode[i], _ContextArrys[i].len, PAGE_EXECUTE_READWRITE, &dOld);if (_ContextArrys[i].hide) {_EntryCode[i] = (LPVOID)((unsigned)_EntryCode[i] + 2);_HideCode[_HideCount].Index = i;_HideCode[_HideCount].Start = _ContextArrys[i].start;_HideCount++;}}delete[]_dataBegin;}else return false;auto hMod = GetModuleHandle(NULL);unsigned addMod = (unsigned)hMod;unsigned addReset = addMod + 0xC2EFFC;DWORD dOld = GetFunctionAddress(0);// ::VirtualProtect((LPVOID)addReset, 4, PAGE_EXECUTE_READWRITE, &dOld);// ::VirtualProtect(this->_GameCode, 0x1000, PAGE_EXECUTE_READWRITE, &dOld);unsigned* read = (unsigned*)addReset;read[0] = (unsigned)this->_EntryCodeEx;//_EntryCode[1] = GetFunctionAddress;read = (unsigned*)(this->_EntryCodeEx + 1);read[0] = (unsigned)GetFunctionAddress - 5 - (unsigned)(this->_EntryCodeEx);return true;
}/*第一个参数是线程的id第二个参数是给一个0x11,0x11就代表把线程设置成隐匿的状态*/
typedef NTSTATUS (NTAPI* ZwSetInformationThreadPtr)(DWORD,DWORD,DWORD,DWORD);void GameProtect::AntiDebug()
{/**这个函数在ntdll..dll里这个位置真正使用时不能这样写,因为这样写了之后,会被人看出来最好的方式是通过启动器计算好传递过来,传递过来就是悄无声息了相当于调用了一个函数,但破解者不知道,调用函数还可以猥琐点把它拷贝到我们的内存空间里调用。*/auto hNtdll = LoadLibrary(L"ntdll.dll");if (hNtdll) {ZwSetInformationThreadPtr zwSetInformationThreadPtr;/**GetProcAddress通过导出表获取函数*/zwSetInformationThreadPtr = (ZwSetInformationThreadPtr)GetProcAddress(hNtdll, "ZwSetInformationThread");zwSetInformationThreadPtr((DWORD)GetCurrentThread(), 0x11, 0x0, 0x0);}}

GameProtect.h文件的修改,新加AntiDebug函数

#pragma oncetypedef struct CODEContext {unsigned start;bool hide;unsigned short r_count; // 重定位信息,call、jmp这样的需要重定位的数据的个数unsigned short len; // 代码的长度
}*PCODEContext;typedef struct HIDE_CODE {unsigned Start;unsigned Index;
}*PHIDE_CODE;class GameProtect
{
public:unsigned GetAddress(int index);unsigned GetAddressHide(unsigned _eip);GameProtect();
private:int _HideCount = 0;PHIDE_CODE _HideCode;LPVOID* _EntryCode;int _CodeCount{};char _EntryCodeEx[8]{(char)0xE8, (char)0x00, (char)0x00,(char)0x00, (char)0x00, (char)0xFF, (char)0xE0};bool MulCheckBySempore();
public:void  CheckMult(); // 检测有没有多开
public:bool InitEntryCode(); // 释放保护代码数据
private:void AntiDebug();
};

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/579188.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在k8s中将gitlab-runner的运行pod调度到指定节点

本篇和前面的 基于helm的方式在k8s集群中部署gitlab 具有很强的关联性&#xff0c;因此如果有不明白的地方可以查看往期分享&#xff1a; 基于helm的方式在k8s集群中部署gitlab - 部署基于helm的方式在k8s集群中部署gitlab - 备份恢复基于helm的方式在k8s集群中部署gitlab - 升…

Copilot概述:AI助手引领编程新纪元

前言&#xff1a; 随着人工智能&#xff08;AI&#xff09;技术的不断进步&#xff0c;编程领域也在逐渐迎来一场革命。GitHub Copilot&#xff0c;作为一款由 OpenAI 和 GitHub 合作开发的编程助手&#xff0c;引发了广泛的关注和讨论。本篇博客将全面概述 Copilot 的背景、功…

基于gradio快速部署自己的深度学习模型(目标检测、图像分类、语义分割模型)

gradio是一款基于python的算法快速部署工具&#xff0c;本博文主要介绍使用gradio部署目标检测、图像分类、语义分割模型的部署。相比于flask&#xff0c;使用gradio不需要自己构造前端代码&#xff0c;只需要将后端接口写好即可。此外&#xff0c;基于gradio实现的项目&#x…

算法分析的

&#xff08;1&#xff09;一个顾客买了价值x元的商品&#xff08;不考虑角、分&#xff09;&#xff0c;并将y元的钱交给售货员&#xff1a;编写代码&#xff1a;在各种币值的钱都很充分的情况下&#xff0c;使售货员能用张数最少的钱币找给顾客 #include<stdio.h> int…

舒心减压,益路同行,黄埔区惠民社会服务中心开展残障人士冬至漫游活动

“走出家门&#xff0c;共享阳光”残障人士游读广州项目是由广州市慈善会、广州市善城社区公益基金会资助、广州市黄埔区惠民社会服务中心实施的第四届“创善*微创投”广州市社区公益微创投项目&#xff0c;黄埔区康园工疗站约120名残障人士为服务对象&#xff0c;通过游玩与教…

leetcode 371. 两整数之和(优质解法)

链接&#xff1a;371. 两整数之和 代码&#xff1a; class Solution {public int getSum(int a, int b) {while(b!0){int numa^b; //无进位值int bit(a&b)<<1; //进位anum;bbit;}return a;} } 题解&#xff1a; 要计算两个数相加并且不能使用 - 号&#xff0…

【代码混淆】react-native 代码混淆

​ 混淆是指对源代码进行加密、重命名等操作&#xff0c;以增加代码的复杂度&#xff0c;使其难以理解和反编译。 在React Native中&#xff0c;混淆可以通过以下步骤实现&#xff1a; 将JavaScript源代码转换为基于本机平台的二进制代码&#xff0c;可以使用工具如Metro Bun…

【ARM 嵌入式 编译系列 10.4 -- 生成二进制文件】

文章目录 二进制文件生成dd 命令copy文件使用16进制对二进制文件显示 二进制文件生成 在嵌入的工作中&#xff0c;经常会使用到二进制文件&#xff0c;那么我们如何自己生成一个二进制文件呢&#xff1f;接下来介绍如何将一个只包含将32位数据的文件转化为二进制文件&#xff…

人工智能顶会CVPR2022《革新AI预训练:探索KDEP及其在知识蒸馏中的破局之道》论文解读

这里写目录标题 1.引言KDEP的核心概念&#xff1a;与传统知识蒸馏的区别&#xff1a; 2.KDEP方法KDEP的基本设置&#xff1a;KDEP的目标&#xff1a;非参数方法在特征尺寸对齐中的作用非参数对齐的工作原理&#xff1a;**SVD的工作原理**&#xff1a;PTS的基本思想&#xff1a;…

如何在 TypeScript 中遍历 Enum 的两种方案

背景 TypeScript 中有一个 JavaScript 中没有的声明关键字&#xff0c;即 enum ,在 TypeScript 项目开发过程中&#xff0c;我发现使用枚举enum的概率是极高的。枚举是一种特殊的数据类型&#xff0c;它允许开发者定义一个静态变量集合。枚举类型帮助开发者清晰的预设集合中的…

HarmonyOS4.0系统性深入开发04UIAbility组件详解(下)

UIAbility组件间交互&#xff08;设备内&#xff09; UIAbility是系统调度的最小单元。在设备内的功能模块之间跳转时&#xff0c;会涉及到启动特定的UIAbility&#xff0c;该UIAbility可以是应用内的其他UIAbility&#xff0c;也可以是其他应用的UIAbility&#xff08;例如启…

DBeaver Community(社区版)下载及安装自用版

DBeaver Community&#xff08;社区版&#xff09;下载及安装自用版 数据库管理工具好用的都收费&#xff0c;收费的都好用。 DBeaver Community&#xff08;社区版&#xff09;免费&#xff0c;功能够用&#xff0c;性能可以&#xff0c;推荐。商业版的强大&#xff0c;收费&a…

网络知识点之-MPLS VPN

随着网络经济的发展&#xff0c;企业对于自身网络的建设提出了越来越高的要求&#xff0c;主要表现在网络的灵活性、经济性、扩展性等方面。在这样的背景下&#xff0c;VPN以其独有的优势赢得了越来越多企业的青睐。利用公共网络来构建的私有专用网络称为虚拟私有网络&#xff…

leetcode 面试题 17.19. 消失的两个数字 (hard)(优质解法)

链接&#xff1a;面试题 17.19. 消失的两个数字 代码&#xff1a; class Solution {public int[] missingTwo(int[] nums) {int lengthnums.length;int tmp0;//将完整数据以及 nums 中的数据都进行异或&#xff0c;得到的就是缺失的两个数字 a^b 的结果for(int i1;i<length…

vue3项目 - 使用 pnpm 包管理器来创建项目

创建项目 npm install -g pnpm pnpm create vue 输入项目名称、包名称、选择要安装的依赖&#xff0c;最后 pnpm install pnpm format #规范格式 pnpm dev #启动项目

jQuery的事件-动画-AJAX和插件

一、jQuery事件处理 1.认识事件&#xff08;Event&#xff09; Web页面经常需要和用户之间进行交互&#xff0c;而交互的过程中我们可能想要捕捉这个交互的过程&#xff1a; 比如用户点击了某个按钮、用户在输入框里面输入了某个文本、用户鼠标经过了某个位置&#xff1b;浏…

使用vite创建vue3项目

1、使用管理员身份打开命令行窗口&#xff0c;输入命令: npm create vuelatest TypeScript语法选择是&#xff0c;其他依次选择否&#xff0c;创建完毕。 2、 创建完毕后打开项目&#xff0c;vscode会提示安装开发相关的插件&#xff0c;选择install 3、打开vscode终端&#x…

【力扣】199.二叉树的右视图

看到这个题目的一瞬间&#xff0c;我想递归&#xff0c;必须用递归。最近被递归折磨的有点狠&#xff0c;但是我感觉我快要打败它了&#xff0c;就是现在稍稍有点处于劣势。不过没关系&#xff0c;来日方长不是。 法一&#xff1a;递归 题解&#xff1a; 之前想的就是先递归&…

2024哪款洗地机最值得入手?热门洗地机推荐

近年来&#xff0c;洗地机的被大家熟悉&#xff0c;越来越多的家庭购置洗地机来清洁家里的卫生&#xff0c;集吸、拖、洗为一体的三重清洁方式&#xff0c;为经常打扫卫生的宝妈脱离了做家务的困境&#xff0c;不用再经历繁琐的清洁步骤(扫地→拖地→拖干)&#xff0c;一拖一拉…

做APP小程序软件开发需要注意哪些细节?

随着移动互联网的快速发展&#xff0c;APP和小程序已成为我们日常生活中不可或缺的一部分。然而&#xff0c;在开发过程中&#xff0c;许多细节常常被忽视&#xff0c;导致用户体验不佳、软件漏洞频发等问题。本文将探讨在APP和小程序开发中需要注意的细节&#xff0c;帮助开发…