前言:

感谢:易道云学院 tiger老师指导:

前提:已经做完自动保护工具。主要讲解如何解析生成的保护程序。

分析:

我们已经生成的保护程序,程序末尾首先写入了有多少段要保护的代码,后面是结构体数据,二进制数据如下

02 00 00 00:有两段要保护的代码                                                                                                 50 c7 c8 00:第一段要保护的代码首地址为 C8C750                                                                           04 00 :第一段中有4个地方需要做重定位                                                                                       52 00 : 第一段保护代码大小为 0x52                                                                                             b0 c7 c8 00 :第二段要保护代码首地址为 C8C7B0                                                                             00 00:第二段中没有需要做重定位的                                                                                                   15 00:第二段保护代码带下为  0x15

在这之后写入的是第一段需要重定位地址的相对偏移,后面是第一段要保护的代码,然后是第二段....最后写入的是源程序的大小二进制数据如下:

通过前面得到第一段有四个重定位信息

0B 00 ,25 00,36 00, 3F 00 这四个数据记录的是4个重定位数据所在地址相对于该保护代码起始地址的相对偏移。                                                                                                                                56 8B F1 ..... 5E C2 04 00 :第一段代码。                                                                                        8B 44 24 ..... 01 C2 04  00: 第二段代码。                                                                                          2B CA 22 01 :记录的源程序大小. 刚好是19057195。

思路:

通过以上分析我们大致知道了生成的保护程序的结构,通过在插件中定义函数进行解析。

定义变量:

LPVOID* _EntryCode; //存放游戏保护代码
char _myFunCode[8]{ (char)0xE8,(char)0x00,(char)0x00,(char)0x00,(char)0x00,(char)0xFF,(char)0xE0,(char)0xCC }; //定义一个构建自己函数和跳转的汇编指令

定义函数:

unsigned getAddress(int _index); //根据分发函数的值获取游戏代码地址                                     bool InitEntryCode();//解析保护代码

函数:

unsigned _stdcall GetFunctionAddress(int index)
{
      
    
        return rData->getAddress(index);
    
    
}

解析:通过我们定义的汇编会跳转到这里根据参数(push 0 ,push1 ...)计算地址并跳转到指定游戏代码执行

unsigned getAddress(int _index)
{
    unsigned result = (unsigned)this->_EntryCode[_index];
    return result;
}

解析:根据参数分发地址

bool    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))  //读取文件到_data
    {
        
        char* _dataBegin = (char*)_data;
        unsigned* _uRead = (unsigned*)(_data + fileLen - 4);//定义指针指向文件末尾-4的地方,刚好是记录的源文件大小
        fileLen = _uRead[0]; //获取源文件大小
        _uRead = (unsigned*)(_data + fileLen);//指向源文件末尾,我们保护数据的开始位置
        unsigned code_count = _uRead[0];  //获取到有多少段保护代码
        _data = _data + fileLen + sizeof(code_count);  //把指针往后移动,指向第一个结构体
        PCODEConText _conTextArrys = (PCODEConText)_data;
        _data = _data + sizeof(CODEConText) * code_count;//把指针继续往后移动,指向重定位偏移的位置
        _EntryCode = new LPVOID [code_count];
        for (int i = 0; i < code_count; i++)  //分别解析这两端保护代码
        {
        
            _EntryCode[i] = new char[_conTextArrys[i].len+2];
            char* adr = (char*)_EntryCode[i];
            adr[0] = 0x9D;
            adr[1] = 0x61;
            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* _callAdr = (unsigned*)(((char*)_EntryCode[i] +2)+ rel[x] + 1); //指向E8 后面的地址
                _callAdr[0] = _callAdr[0]-(unsigned)(((char*)_EntryCode[i] + 2) + rel[x])-5; //重定位地址值  E8 XXXX=目标地址-当前地址-5  因为制作保护程序的时候已经计算出了目标地址
            }

_data = _data + offset + _conTextArrys[i].len; //把指针移动到下一段保护代码偏移的位置
            DWORD dOled;
            VirtualProtect(_EntryCode[i], _conTextArrys[i].len+2, PAGE_EXECUTE_READWRITE, &dOled);
        }
        delete[]_dataBegin;
    }
    else return false;

//写入分发函数
    auto hMod = GetModuleHandle(NULL); //获取游戏地址
    unsigned addMod = unsigned(hMod);
    unsigned codeAdr = addMod + 0xC2EFFC;   //算出我们找到的那块内存的地址
    DWORD dOld;
    ::VirtualProtect((LPVOID)codeAdr, 8, PAGE_EXECUTE_READWRITE, &dOld); //修改内存属性
    unsigned* read = (unsigned*)codeAdr;        //定义指针指向那块内存的地址
    read[0] = (unsigned)this->_myFunCode;       //把函数写入该地址
    read = (unsigned*)(this->_myFunCode + 1);   //把指针指向call后面的地址值                  
    read[0] = (unsigned)GetFunctionAddress - 5 - (unsigned)(this->_myFunCode); //计算好地址写入
    return true;
}

解析:该函数是核心解析函数,通过读取文件依次解析出各个数据,并再循环中写入每段保护代码,并重新计算需要重定位的地址。注意要再每段代码前写入 popfd 和popad来恢复寄存器的值。

总结:

通过文件读取来读取我们保护的数据,并通过该数据把保护代码写入到插件中,当游戏执行到保护代码时会先进行寄存器数据的保存,然后跳转到我们指定的地址,进去后执行我们的分发函数,通过参数来跳转到我们插件中保护的代码,进入后首先恢复寄存器的值然后执行游戏代码。

游戏插件开发之防插件剥离的简单保护壳工具设计(利用反汇编引擎实现自动化代码保护)下相关推荐

  1. 游戏插件开发之防插件剥离的简单保护壳工具设计(利用反汇编引擎实现自动化代码保护)上

    前言: 感谢:易道云学院 tiger老师指导: 前提:需要导入小蜜蜂反汇编引擎,不会的可以回复问,这里不做介绍,MFC页面的搭建也不做详细介绍.因为任务量太大本贴只写代码保护工具的制作,后续解析在下个 ...

  2. Unity游戏Mod/插件制作教程05 - 插件实例2: 简单功能实现

    这一次的教程进行一个小小的功能实现,完整的制作一个插件.以Mirror这个游戏为例,插件的目标是当玩家按下空格时,有一定概率为玩家增加金钱,或者扣除玩家金钱.概率.增加的金钱.扣除的金钱都由配置文件决 ...

  3. FastAdmin插件开发辅助增强插件

    本人开发的FastAdmin插件开发辅助增强插件 不改变官方的开发习惯,但更丝滑,尽最大的努力生成你想要的代码 非常重要 非常重要 非常重要 写在最前面是为了不要漏了,导致插件没有正常工作. 编写代码 ...

  4. idea插件开发--服务-翻译插件

    gitee地址:https://gitee.com/jyq_18792721831/studyplugin.git idea插件开发入门 idea插件开发–配置 idea插件开发–服务-翻译插件 id ...

  5. 游戏开发之U3D插件EasyTouch5.x使用

               游戏开发之U3D插件EasyTouch5.x使用 本篇只讲EasyTouch5.x的使用,不讲源码.本来想把EasyTouch5.x的使用手册翻译一遍,想来也是没那个时间. 第一 ...

  6. 游戏客户端内存防修改浅析

    游戏客户端内存防修改浅析 但凡现在有点人气的游戏都可能被hack,而且网上有很多方便的工具可以使用,单就手机端还讲,最常见的内存修改器有八门神器.烧饼修改器.最近针对这两种内存修改器做了些防护处理,简 ...

  7. 科技计算机玩游戏,迷你世界:插件科技新玩法,一招造出计算机,在游戏内玩游戏...

    文/陌瑾 引言:陌瑾出品,争做精品! 游戏加入高科技"插件包"玩法 迷你世界在最近在游戏内新加入了一个插件库的玩法,它相对于之前的另两种游戏道具"微缩道具模型和地形编辑器 ...

  8. 【Chrome浏览器插件开发】浏览器插件运行机制03之实战使用Vue.js 3 + Vite 2开发出简易的浏览器插件(含源码)

    文章目录 知识点: 一.使用 vite 创建项目 1.1 环境搭建 1.2 安装vite工具 1.3 创建vite项目 1.4 进入项目并安装依赖 1.5 修改端口 1.6 运行项目 二.创建项目资源 ...

  9. 前端自动化工具 grunt 插件 uglify 的简单使用(一)

    Grunt 的简介: Grunt 是一套前端自动化工具,是一个基于 node.js 的命令行工具,它一般用于: 1.压缩文件: 2.合并文件: 3.简单的语法检测: 4.监听文件变动: 5.less ...

最新文章

  1. Maya游戏角色绑定入门学习教程 Game Character Rigging for Beginners in Maya
  2. python语言使用什么语句实现上下文管理协议_Python 技巧探究:上下文管理器和with语句...
  3. freemarker写入word【未完,待续】
  4. 服务器不显示内存条,服务器主机检测不到内存条
  5. 第十届蓝桥杯省赛JavaC组真题——详细答案对照(完整版-包含打扫机器人的视频全过程讲解与编码内容对照)
  6. codeforces-1201 C Maximum Median
  7. 我又来学ElasticSearch了。。。
  8. Atitit.判断汉字的编码 regedit 注册表里面的reg_sz
  9. querydsl动态 sql_SpringDataJPA学习记录(四)--使用QueryDSL
  10. 英雄联盟显示服务器属于高限制,玩英雄联盟出现超出频率限制,该怎么处理?
  11. 批量重命名图片去掉烦人的括号
  12. GPIB编程控件指令
  13. maps-api-v3_利用Google Maps API发挥创意
  14. qgc地面站飞行模式
  15. PDF限制编辑怎么解决
  16. machine learning 四要素
  17. scrapy框架连接MongoDB数据库
  18. c语言编程:vc++6.0入门教程及习题_百度文库,C语言编程:vc++6.0入门教程及习题.doc...
  19. 架构系列之标准Web系统的架构分层
  20. 一战封神!“中国飞人”苏炳添跑出9秒83到底有多牛?

热门文章

  1. 用SAX优化读excel文件的内存消耗
  2. 微信开发者工具出现catch sdkSubPackage: sclEngine error: TypeError: Cannot redefine property:
  3. DC-DC开关电源电感选型指南
  4. 5G反开3D-MIMO之负荷均衡优化
  5. 倒车喇叭语音ic芯片
  6. EVC创建DLL及调用的基本方法
  7. 16.深度解密十六:解密投放百度竞价广告效果提升的问题讲解
  8. 阿里云是什么,与亚马逊的云服务相比较,处于什么位置?
  9. 单片机节日彩灯实训报告_单片机(节日彩灯控制).doc
  10. linux rm 文件找回_linux下执行rm -rf命令后如何恢复