ACCESS打闹外挂原理分析和制造 – [内存数值修改类 篇一]

  本章旨在讲解外挂实现原理,未深入涉及到代码层面。希望能与对当下上头感兴趣的爱侣多交流,毕竟理论是深的,套路是固定的,只有破解经验是消费大量时日和心血积累的。

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

  • 于页游、网游和手游,虽然服务器保存了大量之要的参数,但出于客户端不可避免的待进行大气之计和资源的加载,本地内存种必定存来一部分的临时变量,通过判断这些变量的变化规律和函数的破密寻到福利己之参数,比如伤害值一类,继而寻找该变量的内存地址,根据指针偏移分析得到内存基址,再升格权限行使Windows
    API把打定义数值写副该内存块,就完成了改某项数值的操作,一般的话,只要破解了一致项数值,利用规律继而破解其他数值便越便于了。

  
 一般套路就是上述,一些防护性强大的游戏会在上述的诸一样步着都装难题,等正在咱错过破解。

 

    在此之前,我们来打听一些基础知识:

  • 数据类型:游戏中之血量、蓝、生命值,我们将她们称之为变量,变量包含了变量名称与数据类型,那么她的名就是”血量、生命值”等等,而它的数据类型决定了数价为何种措施囤到计算机的内存中,想只要找到自己需要的变量,如果得以确定此变量的数据类型或者有依据的想来压缩变量的数据类型范围,那么对迅速稳定该变量是独具帮助性的。以下是几种植普遍的变量类型:

   整数型:游戏受本血量、法力可能因此到这种类型。

   字节型:根据不同之编辑器,1单整形占用N个字节(N>1),一般很早前生产的GBA游戏为了省去出会就此到这种类型。

   浮点型:带有小数点的数字,如果金币或者伤害值带有小数点,那不行可能是这种数量类保存的。

   文本型:比如世界喊话,人物命名,一般以文本型保存这好像数据。

   推荐阅读《数据结构》相关书籍更好的习数据结构,有编程经验的尽管不要多说了。

 

  • 进程:每一个应用程序/游戏启动,都见面发生至少一个过程Process,在任务管理器里好看进程名称以及经过PID。

   

 

  • 句柄:英文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 。

相关文章