游玩外挂原理分析与打造 – [内存数值修改类 篇一]

  修改变量的数值→得先找到存储变量的内存地址→得先找到游戏窗口的句柄→得先找到游戏的进度。

   图片 1

   推荐阅读《数据结构》相关书籍更好的熟稔数据结构,有编程经验的就无需多说了。

  PS:转载请附带原文路径:http://www.cnblogs.com/lene-y/p/7096485.html 。

  依照什么依照推导出的路线吧?

  函数原型:

 

  • 句柄:英文HANDLE,一个整数值。数据的位置必要转移,变动将来就必要有人来记录管理变动,就似乎户籍管理一样,由此系统用句柄来记载数据地址的改观。肉眼看到的一个个文件夹,窗口,按钮,图标,应用程序可以透过句柄访问相应的目的的音信

   整数型:游戏中诸如血量、法力可能用到那连串型。

  进入正题,根据目标反向推导下须求取得怎么样音信,大家最终才能想要落成修改数值。

  lpBuffer:结构体指针,用于存放内存信息。

   文本型:比如世界喊话,人物命名,一般选用文本型保存那类数据。

 

   浮点型:带有小数点的数字,假若金币或者加害值带有小数点,那很可能是那种数据类型保存的。

  按照上面的API,先来看怎么获取第四个参数:窗体句柄,同样的kernel32.dll提供了名为OpenProcess的函数用来打开一个已存在的进度对象,并再次来到进度的句柄。

  • 对于单机游戏而言,游戏中多方面的参数(比如血、蓝、能量亦或者金币)都存储在微机的库房中,一些接近剧情进程的则加密后写入当地的自定义配置文件中;

   函数原型:

 

  我们赢获得进度的PID未来,就足以调用OpenProcess获取窗体的句柄,然后利用函数VirtualQueryEx遍历内存查找地方音讯,根据地方利用ReadProcessMemory查找具体存放的值,末了动用WriteProcessMemory把修改后的值写入该地址,那样就成功了四遍数据的修改。来看一下API的函数原型:

  • 进程:每一个应用程序/游戏启动,都会发出至少一个经过Process,在职分管理器里能够见到进度名称和进度PID。
      /// <summary>
      /// 根据进程句柄读入该进程的某个内存空间
      /// </summary>
      /// <param name="lpProcess">进程句柄</param>
      /// <param name="lpBaseAddress">内存读取的起始地址</param>
      /// <param name="lpBuffer">写入地址</param>
      /// <param name="nSize">写入字节数</param>
      /// <param name="BytesRead">实际传递的字节数</param>
      /// <returns>读取结果</returns>
      [DllImportAttribute("kernel32.dll", EntryPoint = "ReadProcessMemory")]
      public static extern bool ReadProcessMemory
      (
          IntPtr lpProcess,
          IntPtr lpBaseAddress,
          IntPtr lpBuffer,
          int nSize,
          IntPtr BytesRead
      );    

  我们上边逐个分析参数:

  重返值:函数写入lpBuffer的字节数,若是字节数等于结构体PMEMORY_BASIC_INFORMATION的深浅,表示函数执行成功。

  dwLength:上述结构体的大小。

  本章目的在于讲解外挂落成原理,未长远涉及至代码层面。希望能与对那上头感兴趣的爱人多多交换,毕竟理论是死的,套路是一向的,惟有破解经验是花多量年华和心血积累的。

  /// <summary>
  /// 查询地址空间中内存地址存储的信息
  /// </summary>
  /// <param name="hProcess">句柄</param>
  /// <param name="lpAddress">内存地址</param>
  /// <param name="lpBuffer">结构体指针</param>
  /// <param name="dwLength">结构体大小</param>
  /// <returns>写入字节数</returns>
  [DllImport("kernel32.dll")]     
      public static extern int VirtualQueryEx(
      IntPtr hProcess, 
      IntPtr lpAddress, 
      out MEMORY_BASIC_INFORMATION lpBuffer, 
      int dwLength);
  //根据进程名称获取PID
  public int GetPIDByPName(string ProcessName)
      {
          Process[] ArrayProcess = Process.GetProcessesByName(processName);
        foreach (Process pro in ArrayProcess)
        {
            return pro.Id;
        }
        return -1;
    }

  推荐阅读《统计机操作系统》相关书籍愈来愈多的刺探总结机原理。

 

  dwProcessId :进度标示符PID。

  对于经过PID各个编程语言有协调的取得格局,以C#语言为例(针对非多开客户端):

  /// <summary>
  /// 打开一个已存在的进程对象,并返回进程的句柄
  /// </summary>
  /// <param name="iAccess">渴望得到的访问权限</param>
  /// <param name="Handle">是否继承句柄</param>
  /// <param name="ProcessID">进程PID</param>
  /// <returns>进程的句柄</returns>
  [DllImportAttribute("kernel32.dll", EntryPoint = "OpenProcess")]
  public static extern IntPtr OpenProcess
  (
      int iAccess,
      bool Handle,
      int ProcessID
  );

  此函数将依照句柄读取该进度的某部内存空间,并将读取到的字节数写入到我们开拓的一块空间中,而此空间存放的难为大家苦苦找寻的“有意义的数值”。此函数的有些参数看重于上一个函数VirtualQueryEx发生的结果。

 

 

   字节型:按照分歧的编辑器,1个整形占用N个字节(N>1),一般很早以前生产的GBA游戏为了节省开销会用到那连串型。

 

    在此从前,我们来了然部分基础知识:

  lpAddress:查询的内存地址,输入参数,须求主动提供地方。但大家并不知道我们必要的数值它被寄放的地点,大家只好一个页面一个页面的估摸,直到扫描到某个页面的某块内存里面存放的新闻正是与我们需求的音讯相同或者存在必然的函数关系。其次,对于同一个数值也许出现在七个地点,比如
在某个时间间隔人物的抨击数值和防御数值等同都为1200,那么注明至少有四个地方存放了那个数目。我们要求把这么些地址全都筛选出来。

  hProcess:顾名思义,进度句柄,也就是说想要查询地址存放的音讯,首先得获得进度的句柄。

 

  但此函数只承担获取内存音信,而查询内存新闻中实际存放数值则用到另一函数ReadProcessMemory,来看一下函数原型:

  

  
 一般套路就是上述,一些防护性强大的游戏会在上述的每一步中都设置难点,等着大家去破解。

  Windows系统库的kernel32.dll库文件中含有了内存操作的API,其中VirtualQueryEx用于查询地址空间中内存地址的音信。

  dwDesiredAccess :渴望得到的拜会权限,那里默许填写PROCESS_ALL_ACCESS |
0x1F0FFF 予以负有可能同意的权位。

  /// <summary>
  /// 写入某一进程的内存区域
  /// </summary>
  /// <param name="lpProcess">进程句柄</param>
  /// <param name="lpBaseAddress">写入的内存首地址</param>
  /// <param name="lpBuffer">写入数据的指针</param>
  /// <param name="nSize">写入字节数</param>
  /// <param name="BytesWrite">实际写入字节数的指针</param>
  /// <returns>大于0代表成功</returns>
  [DllImportAttribute("kernel32.dll", EntryPoint = "WriteProcessMemory")]
  public static extern bool WriteProcessMemory
      (
          IntPtr lpProcess,
          IntPtr lpBaseAddress,
          int [] lpBuffer,
          int nSize,
          IntPtr BytesWrite
      );

  bInheritHandle :是或不是持续句柄,FALSE即可。

  到了此地,修改游戏数值的原理和套路已经很明白了,甚至脱离游戏来讲,任何的运用假诺没有对缓存中的数据举行优质的加密,都是存在很大的高风险隐患的,这一章节重视明白部分常用到的名词和API的使用。具体哪些选用代码举办调用API,以及更详细的剖析每一步的逻辑,将在下一章节讲述。

  参数就不再一一解释了,注释都有,最后一个参数默认填写Null或者IntPtr.ZeroI即可。

  • 对此页游、网游和手游,尽管服务器保存了大量的机要的参数,但鉴于客户端不可幸免的内需展开大气的计量和资源的加载,本地内存种必定存有一对的临时变量,通过判断那几个变量的变化规律和函数的破密寻到有益自身的参数,比如加害值一类,继而寻找该变量的内存地址,按照指针偏移分析获得内存基址,再升级权限行使Windows
    API把自定义数值写入该内存块,就完了了修改某项数值的操作,一般的话,只要破解了一项数值,利用规律继而破解其余数值就越是容易了。
  • 数据类型:游戏中的血量、蓝、生命值,我们将她们叫做变量,变量包括了变量名称和数据类型,那么它的名字就是”血量、生命值”等等,而它的数据类型决定了数值以何种方法存储到电脑的内存中,想要找到自己需求的变量,倘若得以确定那几个变量的数据类型或者有按照的揣摸来压缩变量的数据类型范围,那么对于火速稳定该变量是具备支持性的。以下是三种普遍的变量类型:

相关文章