• 游戏外挂编程二之C/C++内联汇编代码和DLL


    合肥程序员群:49313181。    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入)
    Q  Q:408365330     E-Mail:egojit@qq.com

    上一节我讲解了CE的使用,这一节我讲解一下windows下C/C++的在以后外挂编程中会用到的知识,内联汇编和C++MFC的DLL编写。这两个基本知识都是以后外挂中都会用到的,但是不一定是现在的高级语言编写者都会的知识。我虽然第一个语言是C但是我还是以C#发家的(毕业后一直主打的还是.NET平台的C#开发)。

    1.C/C++中内联汇编代码:新建一个windows 控制台项目代码如下

    #include "stdafx.h"
    
    extern int add(int a,int b);//方法声明
    int main(int argc, _TCHAR* argv[])
    {
        int re;
        re=add(1,3);//调用add方法
        printf("%d",re);
        scanf_s("%d",&re);//纯粹为了停顿查看控制台输出的结果
        return 0;
    }
    
    int add(int a,int b){
    
        _asm{//汇编代码块
        mov eax,a
        add eax,b
        mov b,eax
        
        }
        return b;
    }

    很容易看到在被调用的add方法中嵌入了汇编代码。不难看出运行结果为4。以下是图和真相

     通过这个简单的内联汇编我相信大家都熟悉了C/C++中嵌入汇编代码的方式,主要上就是放在_asm{}中。当然这其中的代码和真正的汇编还是有点区别的。让我们来看一下反汇编后的代码:

    extern int add(int a,int b);//方法声明
    int main(int argc, _TCHAR* argv[])
    {
    00143A30  push        ebp  
    00143A31  mov         ebp,esp  
    00143A33  sub         esp,0D0h  
    00143A39  push        ebx  
    00143A3A  push        esi  
    00143A3B  push        edi  
    00143A3C  lea         edi,[ebp-0D0h]  
    00143A42  mov         ecx,34h  
    00143A47  mov         eax,0CCCCCCCCh  
    00143A4C  rep stos    dword ptr es:[edi]  
    00143A4E  mov         eax,dword ptr ds:[0014800Ch]  
    00143A53  xor         eax,ebp  
    00143A55  mov         dword ptr [ebp-4],eax  
        int re;
        re=add(1,3);//调用add方法
    00143A58  push        3  
    00143A5A  push        1  
    00143A5C  call        add (01411D6h)  
    00143A61  add         esp,8  
    00143A64  mov         dword ptr [re],eax  
        printf("%d",re);
    00143A67  mov         esi,esp  
    00143A69  mov         eax,dword ptr [re]  
    00143A6C  push        eax  
    00143A6D  push        1458A8h  
    00143A72  call        dword ptr ds:[1492BCh]  
    00143A78  add         esp,8  
    00143A7B  cmp         esi,esp  
    00143A7D  call        __RTC_CheckEsp (01411E0h)  
        scanf_s("%d",&re);//纯粹为了停顿查看控制台输出的结果
    00143A82  mov         esi,esp  
    00143A84  lea         eax,[re]  
    00143A87  push        eax  
    00143A88  push        1458A8h  
    00143A8D  call        dword ptr ds:[1492B8h]  
    00143A93  add         esp,8  
    00143A96  cmp         esi,esp  
    00143A98  call        __RTC_CheckEsp (01411E0h)  
        return 0;
    00143A9D  xor         eax,eax  
    }

    这是main函数反汇编过来的。下面我们看看add函数的反汇编代码:

    int add(int a,int b){
    001417A0  push        ebp  
    001417A1  mov         ebp,esp  
    001417A3  sub         esp,0C0h  
    001417A9  push        ebx  
    001417AA  push        esi  
    001417AB  push        edi  
    001417AC  lea         edi,[ebp-0C0h]  
    001417B2  mov         ecx,30h  
    001417B7  mov         eax,0CCCCCCCCh  
    001417BC  rep stos    dword ptr es:[edi]  
    
        _asm{//汇编代码块
        mov eax,a
    001417BE  mov         eax,dword ptr [a]  
        add eax,b
    001417C1  add         eax,dword ptr [b]  
        mov b,eax
    001417C4  mov         dword ptr [b],eax  
        
        }
        return b;
    001417C7  mov         eax,dword ptr [b]  
    }

    从中可以看出C中内联汇编和汇编指令还是有点区别的。在main主函数中call add这个就是调用add函数,再往call add前面看,大家可以看到被调用的add参数被从右到左的放到堆栈中去了(汇编基础知识)。至于add函数的返回值就放到通用寄存器eax中。汇编中函数放回值都是放到eax中,add函数中有这样一行汇编mov eax,dword ptr [b]。其中 call add后面有add esp,8这个是为了保持堆栈平衡。这是高级语言中我们不需要关注的东西,其它的就不多说了。更多的还是自己去掌握汇编吧,毕竟汇编知识还是比较丰富的,三言两语讲不清。这里我只是让大家能看懂大致的脉络。在外挂编程中我们很多时候是通过内联汇编去call游戏线程中的某个方法,例如我们call补金疮药或者魔药的过程,可以实现自动喝药。这是基本的外挂过程。

    2.C++MFC DLL的编写:从其他语言过来可能不知道C++写DLL。C++DLL有很多种方式去写。这里我就介绍MFC DLL。它最容易上手。DLL的用处是什么呢??其它用处我就不说了,只说在外挂中什么作用。在外挂中我们需要进程注入。前面讲过,每个程序都有一个自己私有的4G进程空间(32位系统,0x00000000~0x7FFFFFFF空间属于应用程序的空间,高地址空间是属于操作系统的),起到保护进程的作用。那么我们怎么控制另个一程序呢??这时候我们就要想到将我们的代码放到被控制的进程空间中去,可是正常情况下,在一个程序中正常情况下是访问不到另一个程序进程空间的。这时候我们可以用进程注入的方式将我们的DLL注入到游戏进程空间中去。我比较常用的两种方式其一是通过WriteProcessMemory的方式直接写进去,另一种方式是通过钩子的形式注入。这两种注入方式在后面的章节中再做介绍。开始去写一个DLL在项目解决方案上面添加项目(我用的是vs2012).然后选择C++,在选择MFC,选择MFC DLL.在源文件后面添加一个add方法;

    int add(int a,int b){
        return a+b;
    }

    然后一步非常重要需要暴露出来。在def文件中放入这个函数名称

    def中的代码是:

    ; MFCLibrary1.def : 声明 DLL 的模块参数。
    
    LIBRARY
    
    EXPORTS
        ; 此处可以是显式导出
        add

    这样就将add函数暴露到了DLL外面。这样在exe中就可以调用了;

    exe程序中的调用代码如下:

    // ASMTest.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #pragma comment(lib,"MFCLibrary1.lib")
    
    extern int add(int a,int b);
    
    int main(int argc, _TCHAR* argv[])
    {
        int re=3;
        re=add(1,3);//调用add方法
        printf("%d",re);
        scanf_s("%d",&re);//纯粹为了停顿查看控制台输出的结果
        return 0;
    }
    
    //int add(int a,int b){
    //
    //    _asm{//汇编代码块
    //    mov eax,a
    //    add eax,b
    //    mov b,eax
    //    
    //    }
    //    return b;
    //}
    #pragma comment(lib,"MFCLibrary1.lib")这是其中一种调用方式。别忘了声明extern int add(int a,int b);否则找不到add方法。
    这样,实现了一个DLL和对DLL的调用。为后面注入DLL做好铺垫。

    版权:归博客园和Egojit所有,转载请标明出处。
  • 相关阅读:
    阿里云POLARDB荣膺2019中国数据库年度最佳创新产品
    实时大数据开发难、运维难、应用难?来,一站解决!
    阿里云应用实时监控 ARMS 再升级,支持 Prometheus 开源生态
    一线实践 | 借助混沌工程工具 ChaosBlade 构建高可用的分布式系统
    使用DataX同步MaxCompute数据到TableStore(原OTS)优化指南
    Twitter 宣布抛弃 Mesos,全面转向Kubernetes
    阿里云Kubernetes服务上使用Tekton完成应用发布初体验
    Knative Tracing 介绍
    不断被取代的传统职业:快速发展的智能交互
    bzoj1433: [ZJOI2009]假期的宿舍
  • 原文地址:https://www.cnblogs.com/egojit/p/3135607.html
Copyright © 2020-2023  润新知