• 给网游写一个挂吧(三) – 启动外挂下


    前面的文章给网游写一个挂吧 启动外挂上介绍了输入法注入的方法,本文解释第二种方法。

    有的游戏限制比较多,可能会将输入法注入也禁用掉……这个时候就需要另想方法了。其实我们的目的很简单,就是要让不知道我们挂存在的游戏,在某个时刻将挂作为游戏的一个组件加载进来。输入法注入是操作系统强制塞给游戏的,当然游戏有权利选择不要。那么我们可以用暴力解决,强制游戏加载外挂:

    1.         比如利用缓冲区溢出漏洞(参考文章 如何利用缓冲区溢出的程序错误来运行黑客程序 如何利用缓冲区溢出的程序错误来运行黑客程序(续))。

    2.         还有就是在游戏每次都会执行的函数上挂个钩子 ,但是一般的Windows钩子都会被游戏禁用掉……而本文的方法是Hook DirectX EndScene函数,即游戏在绘图结束后调用的函数,而且游戏会在一秒内经常调用这个函数,简直就是把它当消息队列使!

     

    WOW – 使用DirectX EndScene注入技术

    这个方法可以用在WOW 3.3.5.13930上,现在已经不行了,有兴趣的朋友可以自己搭一个3.3.5.13930的私服试试。据说有很多方法可以注入(DirectX EndScene函数在d3d9.dll文件中):

    1、 在游戏文件夹里放一个d3d9.dll,因为Windows是先搜索游戏的工作目录再查找system32文件夹的,所以会加载到自定义的d3d9.dll

    2、 直接在游戏启动前把system32文件夹中的d3d9.dll换成自己的。

    3、 使用IDA直接获取EndScene的地址,并且在游戏启动后,修改这个地址的汇编码,使其先调用我们的函数,再由我们的函数将控制权交还给真实的EndScene程序。

    4、 在外挂里启动游戏,启动时先将游戏进程暂停,执行一系列Hook操作:

    a)         Hook LoadLibrary以便在游戏加载d3d9.dll的时候;

    b)         Hook d3d9.dll里的Direct3DCreate9函数,

    c)         再通过Hook过的Direct3DCreate9函数获取D3D9的指针,

    d)         D3D9指针处Hook D3D9->CreateDevice函数,以获取指向设备的指针Device

    e)         再从Device指针处Hook Device->EndScene函数。

    5、 Windows操作系统里创建一个自己的Device

    6、 或者就是使用SetWindowsHookEx API安装一个系统级别的Hook,然后我们的外挂就会被加载进每一个进程!参考文档:http://www.woodmann.com/forum/archive/index.php/t-11023.htm

    这里我只用过第4种方法,因此本文也只介绍第4种方法,这里我们用到EasyHook这个库,这个库允许我们使用C#代码Hook系统APIEasyHook的用法很简单:

    1、 在包含Hook函数的托管DLL里,创建一个类,实现了EasyHook.IEntryPoint这个接口。

    2、 在类的构造函数里建立与宿主进程的连接。

    3、 然后在IEntryPoint.Run函数里,注册你的Hook,下面是以CreateFile这个系统API为例:

     1、    public void Run(RemoteHooking.IContext InContext, String InChannelName)

    2、    {
    3、       CreateFileHook = LocalHook.Create(
    4、           LocalHook.GetProcAddress("kernel32.dll""CreateFileW"),
    5、           new DCreateFile(CreateFile_Hooked),
    6、           this);
    7、    
    8、       CreateFileHook.ThreadACL.SetExclusiveACL(new Int32[] {0});
    9、    }

    在第5行里,那个DCreateFile就是CreateFileC#中的委托表现方式,因为是通过函数指针的方式执行的,因此会声明成一个委托。

    4、 最后在外挂里,使用下面的代码注册Hook

    1、 static void Main(string[] args)
    2、 {
    3、     Config.Register(
    4、     "A FileMon like demo application.",
    5、     "FileMon.exe",
    6、     "FileMonInject.dll");
    7、 
    8、     RemoteHooking.IpcCreateServer<FileMonInterface>(
    9、         ref ChannelName, WellKnownObjectMode.SingleCall);
    10、 
    11、    RemoteHooking.Inject(
    12、        Int32.Parse(args[0]),
    13、        "FileMonInject.dll",
    14、        "FileMonInject.dll",
    15、        ChannelName);

    16、 } 


    5、 代码里,还有一个关键的地方,就是Hook后获取的指针是一个COM接口,即拿到的是一个虚函数表,因此在Hook EndScene方法的时候,就是把这个COM接口的EndScene的虚函数指针换成我们自己的,如下表的接口定义和替换方法:

    1、    public unsafe class D3D9
    2、    {
    3、        [StructLayout(LayoutKind.Sequential, Pack = 4)]
    4、        public struct IDirect3DDevice9
    5、        {
    6、            public IntPtr** VFTable;
    7、        }
    8、    }
    9、    public IDirect3DDevice9(D3D9.IDirect3D9* InNativeIDirect3D9, 
    10、    D3D9.IDirect3DDevice9* InNativeIDirect3DDevice9)
    11、    {
    12、    NativeIDirect3D9 = InNativeIDirect3D9;
    13、    NativeIDirect3DDevice9 = InNativeIDirect3DDevice9;

    14、    OverrideFunctions();
    15、    }

    16、    public D3D9.IDirect3D9* NativeIDirect3D9 
    17、    { 
    18、    getprivate set
    19、    }

    20、    public D3D9.IDirect3DDevice9* NativeIDirect3DDevice9 
    21、    {
    22、    getprivate set
    23、    }

    24、    private void OverrideFunctions()
    25、    {
    26、    OriginalEndScene = NativeIDirect3DDevice9->VFTable[0][42];

    27、    RealEndScene =
    28、    (DelegateEndScene)Marshal.GetDelegateForFunctionPointer(
    29、    OriginalEndScene, typeof (DelegateEndScene));

    30、    MyEndScene = EndScene;
    31、    IntPtr PointerToMyEndScene = Marshal.GetFunctionPointerForDelegate(MyEndScene);

    32、    NativeIDirect3DDevice9->VFTable[0][42] = PointerToMyEndScene;
    33、    }

    34、    public uint EndScene(D3D9.IDirect3DDevice9 Device)
    35、    {
    36、    // 防止多线程访问
    37、    lock (LuaInterface.dataLock)
    38、    {
    39、    // 先做我们自己的事情,然后再将控制权转移给真正的EndScene函数

    40、    return RealEndScene(Device);
    41、    }

    42、    } 


    比如在第37 – 41行,就是在EndScene调用的时候,先做我们的事情,然后再把控制权交给真正的EndScene。而第26行,EndScene函数IDirect3DDevice9的第42个函数,因为在第3行,代码已经将IDirect3DDevice9接口(实际就是一个虚函数表)当成一个普通的C/C++结构体处理而且是32位机上的结构体(如果要支持64位改一下就可以了),而第6行代码,就是把这个虚函数表当作一个普通的数组处理。不过据说在DirectX10里已经把EndScene去掉了……

    这种方式,网上已经有完整的源代码,请在此下载(这个代码跟本文讲解使用的代码是不同的,因此有兴趣的朋友可以自行研究下面的代码):

    https://github.com/spazzarama/Direct3DHook

    EasyHook的使用方式和详细原理,请参考文档:

    http://www.codeproject.com/Articles/27637/EasyHook-The-reinvention-of-Windows-API-hooking 

    最后如果大家对调试技术感兴趣的话,可以考虑购买我的新书: 应用程序调试技术,这套视频除了讲解调试的技巧外,还尽量完整地讲解了周边用到的技术,这是因为调试技术要好的话,需要基础功和背景知识扎实才行。
     

    未完待续…… 

  • 相关阅读:
    Oracle 表空间查询
    FlaskAppBuilder 中文文档 markdown格式
    Springboot + Stomp + React 实现通过前后端通信
    Jmeter自动生成UUID
    Jmeter响应断言中,中文匹配失败问题解决
    IOS使用纯代码布局替换掉默认的storyboard
    MySQL在Windows上创建服务和删除服务
    IOS15上纯代码布局之导航控制器的导航条为透明的问题
    PHP编译FTP扩展
    ansible处理一些逻辑请求思路
  • 原文地址:https://www.cnblogs.com/killmyday/p/2553855.html
Copyright © 2020-2023  润新知