ACCESS戏外挂原理分析及做 – [内存数值修改类 篇一]

  本章旨在讲解外挂实现原理,未深入涉及到代码层面。希望会及针对立即方面感兴趣之爱人多交流,毕竟理论是可怜的,套路是定点的,只有破解经验是消费大量时间和心血积累的。

  • 对单机游戏而言,游戏被多方面之参数(比如血、蓝、能量也或者金币)都存储在电脑的库中,一些像样剧情快的虽然加密后形容副当地的自定义配置文件被;

  • 对页游、网游和手游,虽然服务器保存了大气底要害的参数,但出于客户端不可避免的需开展大气底盘算和资源的加载,本地内存种必定存来有的临时变量,通过判断这些变量的变化规律和函数的破密寻到便民己之参数,比如伤害值一近似,继而寻找该变量的内存地址,根据指针偏移分析得到内存基址,再提升权限行使Windows
    API把从定义数值写副该内存块,就完事了修改某项数值的操作,一般的话,只要破解了一如既往宗数值,利用规律继而破解其他数值便愈容易了。

  
 一般套路就是上述,一些防护性强大的游戏会在上述的各级一样步着还安难题,等着咱去破解。

 

    在此之前,我们来打探部分基础知识:

  • 数据类型:游戏受的血量、蓝、生命值,我们用她们叫变量,变量包含了变量名称以及数据类型,那么它的讳就是是”血量、生命值”等等,而其的数据类型决定了累累值为何种方法囤到电脑的内存中,想使找到自己要之变量,如果得以规定这个变量的数据类型或者来因的度来压缩变量的数据类型范围,那么对速稳定该变量是持有帮助性的。以下是几乎种普遍的变量类型:

   整数型:游戏被遵循血量、法力可能为此到这种类型。

   字节型:根据不同的编辑器,1独整形占用N个字节(N>1),一般大早前生产的GBA游戏为了节约开支会为此到这种类型。

   浮点型:带有小数点之数字,如果金币或者伤害值带有小数点,那好可能是这种多少列保存之。

   文本型:比如世界喊话,人物命名,一般采取文本型保存这仿佛数据。

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

 

  • 进程:每一个应用程序/游戏启动,都见面有至少一个历程Process,在职责管理器里可看来进程名称与过程PID。

   ACCESS 1

 

  • 句柄:英文HANDLE,一个整数值。数据的地方需要转移,变动后就是得有人来记录管理变动,就象是户籍管理一样,因此系统就此句柄来记载数据地址的反。肉眼看底一个个文件夹,窗口,按钮,图标,应用程序能够由此句柄访问相应的对象的音讯

  推荐阅读《计算机操作系统》相关书籍更多的摸底计算机原理。

  

  进入正题,根据目的反向推导下需要取得怎样消息,我们最终才会想使贯彻修改数值。

  修改变量的数值→得事先找到存储变量的内存地址→得预找到游戏窗口的语句柄→得事先找到打的过程。

  根据什么依据推导出底不二法门也?

 

  Windows系统库的kernel32.dll库文件中蕴藏了内存操作的API,其中VirtualQueryEx用来查询地址空间中内存地址的消息。

   函数原型:

  /// <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);

  我们下逐个分析参数:

  hProcess:顾名思义,进程句柄,也就是说想如果询问地址存放的信息,首先得得进程的句柄。

  lpAddress:查询的内存地址,输入参数,需要积极提供地方。但咱并不知道我们需要的数值它于寄放的地点,我们只能一个页面一个页面的猜测,直到扫描到某个页面的某块内存里面存的消息正是与我们得之信息相同或者在必然的函数关系。其次,对于与一个数值或出现于差不多个地方,比如
在某个时刻间隔人物之抨击数值与防御数值等与都也1200,那么证明至少发生三三两两只地方存放了之数据。我们用把这些地方都筛选出。

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

  dwLength:上述结构体的轻重。

  返回值:函数写副lpBuffer的字节数,如果字节数等于结构体PMEMORY_BASIC_INFORMATION的分寸,表示函数执行成功。

 

  但以此函数只当取内存信息,而查询内存信息遭到现实存放数值则据此到其他一样套数ReadProcessMemory,来拘禁一下函数原型:

      /// <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
      );    

 

  此函数将依据句柄读博该过程的某某内存空间,并以读取到的字节数写副到我们开发的如出一辙片空间受到,而这空间存放的正是我们苦苦寻找的“有义的数值”。此函数的一对参数依赖让上一个函数VirtualQueryEx产生的结果。

 

  根据地方的API,先来拘禁怎么抱第一只参数:窗体句柄,同样的kernel32.dll供了名吧OpenProcess的函数用来开辟一个都是的长河对象,并返回过程的句柄。

  函数原型:

  /// <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
  );

  dwDesiredAccess :渴望获得的顾权限,这里默认填写PROCESS_ALL_ACCESS |
0x1F0FFF 授予所有或允许的权。

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

  dwProcessId :进程标示符PID。

 

  对于经过PID各种编程语言有协调的得到方式,以C#语言为例(针对非多开客户端):

  //根据进程名称获取PID
  public int GetPIDByPName(string ProcessName)
      {
          Process[] ArrayProcess = Process.GetProcessesByName(processName);
        foreach (Process pro in ArrayProcess)
        {
            return pro.Id;
        }
        return -1;
    }

  我们沾到过程的PID以后,就足以调用OpenProcess获取窗体的句柄,然后采用函数VirtualQueryEx遍历内存查找地方信息,根据地点以ReadProcessMemory查找具体存放的值,最后用WriteProcessMemory把修改后底价值写副该地址,这样即便做到了同等软数据的改动。来拘禁一下API的函数原型:

  /// <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
      );

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

  到了这边,修改游戏数值的原理和套路已经非常懂了,甚至脱离游戏来讲,任何的运如果无针对性缓存中的多少开展良好的加密,都是在好挺之高风险隐患的,这无异段节着重了解部分常用到的名词和API的应用。具体什么采取代码进行调用API,以及更详尽的剖析每一样步之逻辑,将在生同样回节讲述。

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

相关文章