zoukankan      html  css  js  c++  java
  • c#做外挂 step by step(转)

    做外挂我也是现学的。可以说写的这个教程是现学现卖,希望对用C#的外挂爱好者能有点帮助。
    本教程中有一些以"废话"字样标注的内容,赶时间的可以直接越过。

    第一课:C#使用WINDOW API和对内存的操作。
    这一课是些简单的东西,了解的可以直接越过。考虑到大多数使用c#的人都是做网站的,可能没有机会接触这些,所以我在这里做一下粗略的介绍。

    step 1:认识WINAPI

    windows系统里提供了很多的函数,我们如果做外挂的话,就需要用到其中的函数(以下简称API)。(废话:这些API被封装在系统路径下的DLL文件里。事实上,我们不用关心它在哪,我们只要知道怎么用就可以了,)用起来很简单,格式如下:
    public partial class Form1 : Form
    {
    [DllImport("kernel32.dll")]          \
    public static extern int ReadProcessMemory( |
    int hProcess,               |
    int lpBaseAddress,             |
    int lpBuffer,                >代码段1
    int nSize,                 |
    int lpNumberOfBytesWritten         |
    );                      /
    ...
    public Form1()
    {
    InitializeComponent();
    ReadProcessMemory(processhandle,... >代码2
    ...
    }
    ...
    }
    代码段1就是引用api的代码。我们引用的函数,是做外挂时最常用的函数,从它的名字就可以看的出来它的作用---读取进程内存。(废话:从代码里,我们很容易看的出来,这个函数被封装在了kernel32.dll这个文件里。)引用之后,我们就可以在自己的代码中使用这个函数了(如代码2)。
    (废话:WINDOWS还提供很多的API,如果你有兴趣了解的话,可以到网上搜WINAPI手册。想深入了解的话,可以看MSDN。)

    step 2:读写内存
    下面我来说一下,如何使用上一步引用的那个API读取游戏的数据。先来看看参数:
    public static extern int ReadProcessMemory(
    int hProcess, //进程,如果你是做外挂的话,它代表你要挂的那个游戏。
    int lpBaseAddress, //你要读取的内存地址
    int lpBuffer, //从上面那个参数地址里读出来的东西(调用这个函数的就是为了它)
    int nSize, //长度,上一个参数,类型是int,那个长度应该用4
    int lpNumberOfBytesWritten //用0就行了,想知道它是干嘛的,自己去MSND吧
    关于第一个参数hProcess如何获取,我过会再说。假设它已经搞定了,那么这个函数,我们需要关心的只有lpBaseAddress和lpBuffer,既读的地址,和读出来的值。(废话:对了,这个函数貌似还有个返回值,我们这里用不到它。如果你有兴趣了解,MSDN)读出来的值out int lpBuffer我们在引用API的时候声明为int型了,但是,我们要从内存里读的值不一定总是int。我们可以多次引用这个API,第3个参数分别用不同的类型。
    下面,我们结合实际,来写一段读取诛仙人物HP的代码。首先,我们需要知道人物HP的地址,(废话:如何知道这个地址,用CE还是IE,你自己搞定吧。)我是用IE在这里http://www.ghoffice.com/bbs/read.php?tid-35908-fpage-2.html找到的,它这里是这样写的:
    人物基址:[[&H12F830]+&H28]=base
    生命:[base+&H254]
    (注:&H表示16进制,在C#里我们用0x表示)
    一对[]表示读一次地址。也就是说123表示值123,而[123]就表示从地址123读出来的值。几对[],就要用几次ReadProcessMemory,我们来写下代码:
    int Base;
    int hp;
    ReadProcessMemory(process, 0x12F830, Base;, 4, 0);//相当于Base=[&H12F830]
    ReadProcessMemory(process, Base+0x28, Base;, 4, 0);//相当于Base=[Base+&H28]
    //读出了人物基址base
    ReadProcessMemory(process, Base+0x254, hp;, 4, 0);//相当于hp=[base+&H254]
    //读出了hp
    怎么样,很简单吧。
    我们读HP只用了3行ReadProcessMemory。有的时候,读某个值可能需要很多对[],就要写N行ReadProcessMemory,这样写起来就很麻烦,看起来也很晕。下面我们来写个函数,让读内存的过程看起来和[]表示法差不多。
    //为了看起来好看,函数的名字最好短些,所以我们用r,表示read
    public static int r(int add)
    {
    int r;
    try
    {
    ReadProcessMemory(process, add, r, 4, 0);
    return r;
    }
    catch (Exception ex)
    {
    return -1;
    }
    }
    这个函数很简单,不用我多说了吧。
    有了这个函数,上面的读取HP的代码,我们就可以写成这样了:
    int Base;
    int hp;
    Base=r(r(0x12F830)+0x28);
    //读出了人物基址base
    hp=r(base+&H254);
    //读出了hp
    看起来清晰多了吧。

    下面我来说下读取字符串,首先引用API:
    [DllImport("kernel32.dll")]
    public static extern int ReadProcessMemory(
    int hProcess,
    int lpBaseAddress,
    byte[] lpBuffer,
    int nSize,
    int lpNumberOfBytesRead
    );
    然后和上面一样,写一个读字符串的方法。
    public static string rString(IntPtr process, uint add)
    {
    string[] r;
    string temp;
    byte[] b = new byte[256];
    try
    {
    API.ReadProcessMemory(process, (IntPtr)add, b, 256, (IntPtr)0);
    //读出的byte[]要按Unicode编码为字符串
    temp = System.Text.Encoding.Unicode.GetString(b);
    //截取第一段字符串
    r = temp.Split('\0');
    return r[0];
    }
    catch (Exception ex)
    {
    return "error";
    }
    }
    这个函数和上面那个函数差不多,多的东西注释里已经写了,也很简单,不必我废话了。
    下面,我们来读人物的名字。还是刚才那个帖子里得到的,人物名字偏移如下:
    人物角色名:[[base+3a4]+0]
    代码如下:
    string name;
    name=rString(r(basse + 0x3a4)+0x0);//+0x0可以去掉
    读其他类型的数据和读INT的雷同,我就不废话了,大家自己搞定吧。

    现在万事俱备,就差这个process了,下面我来说下,如果获得游戏的进程句柄(废话:进程句柄:一个用来表示某进程的整形值。推广到一般,**句柄,就是表示某**的整形值)。
    分两步,第一步:
    System.Diagnostics.Process[] GamesProcess
    = System.Diagnostics.Process.GetProcessesByName("elementclient");
    这一步用的是.NET本身的方法,System.Diagnostics.Process是.NET里的进程类,GetProcessesByName静态方法是通过进程的名字获得进程数组。这行语句执行之后,所有游戏进程就放在了GamesProcess里面。如果你想做多开挂的话,可以通过数组GamesProcess的下标,来确定你要挂的游戏。
    第二步:
    int ProcessID=GamesProcess[0].Id;
    int process = OpenProcess(0x1F0FFF, 0, ProcessID);
    第1行是获得进程ID,就是任务管理器里看到的PID。第2行就是获得进程句柄。OpenProcess也是一个系统API,也是在kernel32.dll里。他的3个参数和返回值都声明为INT就OK了。如何引用请看step 1。大家应该可以看出来怎么用,第3个参数是进程ID,返回的就是进程句柄(废话:1,2参数做何用,想知道的自己看MSDN。懒人直接用示例里的参数就行了。以后此类废话不再多说了)。

    看到这里,大家可以试着写一个读取人物资料的小东西试试了。当然,前提是你要知道资料的地址。
    写内存:
    (废话:修改游戏数据,对于写现在的网游外挂来说,意义不是很大。因为重要数据的处理都是在服务端进行的,改了也没用。人们使用写内存,通常是改游戏的代码,以实现一些特殊功能,比如诛仙里的穿墙,无限跳等。要想知道如何改,需要反汇编分析经验。就不是我们这些菜鸟能及的了,呵呵)
    WriteProcessMemory(process, (IntPtr)add, bytes, (UInt32)bytes.Length, 0);
    写进程内存函数。这个API的各参数和ReadProcessMemory是一一对应的。大家自己声明,用用看吧。喜欢的话,也可以向上面一样自己写个函数,以简化写内存的代码。在下一课,我们要用这个函数来向游戏里写代码。

  • 相关阅读:
    【翻译】让你的网站飞起来
    理解ASP.NET MVC中的模型绑定
    【转载】创建定制ASP.NET MVC视图引擎
    修改STM32主频
    Cortex系列ARM核心及体系结构介绍
    递归
    NFD模拟兴趣包的转发
    NX 笔记
    MicroPython 8266 配置
    Python JSON操作
  • 原文地址:https://www.cnblogs.com/grantvip/p/1302464.html
Copyright © 2011-2022 走看看