常州做网站哪家好,上海中风险地区有哪些,九江商城网站建设,淘宝网站建设类目前置内容#xff1a; 50.网游逆向分析与插件开发-游戏反调试功能的实现-TP、NP等反调试驱动的原理-CSDN博客 码云地址#xff08;master分支#xff09;#xff1a;https://gitee.com/dye_your_fingers/sro_-ex.git
码云版本号#xff1a;87e45c4acc2e842f147ce0e037731f…前置内容 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在文档里看它它不是给我们应用层的它本身是一个驱动层的函数首先要回顾一下它调试的逻辑调试的本质下断点的本质就是int3int3本质就是异常有了异常以后调试器会接收到异常然后就给一个处理的机会有了异常之后它是先找调试器处理完之后再找调试器第一次调试器不理它第二次就会崩这个时候利用驱动层的这个函数能够把线程设置成在调试器下设置为隐藏就是我不响应调试器就是说面对调试器的时候我就认为我是没有调试器的实际带来的后果是当这个线程一旦如果说发生不调试的话这时是附加了调试器的比如说一个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.hGameProtect* _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(Lindex:%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(Lindex:%d获取地址%x, index, result);// AfxMessageBox(txt);return 0;
}GameProtect::GameProtect()
{//AfxMessageBox(L122222);_protect this;AntiDebug();if (!InitEntryCode()) {AfxMessageBox(L程序加载失败);ExitProcess(0);}CString txt;txt.Format(L111);AfxMessageBox(txt);
}bool GameProtect::MulCheckBySempore()
{auto hMuls OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, Lsystem_seamp);if (!hMuls) {hMuls CreateSemaphore(0, 3, 3, Lsystem_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(LPVEHandl当前地址%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第二个参数是给一个0x110x11就代表把线程设置成隐匿的状态*/
typedef NTSTATUS (NTAPI* ZwSetInformationThreadPtr)(DWORD,DWORD,DWORD,DWORD);void GameProtect::AntiDebug()
{/**这个函数在ntdll..dll里这个位置真正使用时不能这样写因为这样写了之后会被人看出来最好的方式是通过启动器计算好传递过来传递过来就是悄无声息了相当于调用了一个函数但破解者不知道调用函数还可以猥琐点把它拷贝到我们的内存空间里调用。*/auto hNtdll LoadLibrary(Lntdll.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();
};