游戏外挂原理解析与制作 - [内存数值修改类 篇二]

  本章旨在讲解如何利用高级语言根据变量数值寻找内存地址。涉及代码以C#为例。

  我用C#写了一个WinForm形式的Demo,界面如下:

  

  源代码:

        //血量初始值
        private int value = 1000;

        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 刷新界面:将最新的血量显示在界面
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_refresh_Click(object sender, EventArgs e)
        {
            this.label_display.Text = value.ToString();
        }

        /// <summary>
        /// 更新血量:将自定义的数值写入血量变量
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_update_Click(object sender, EventArgs e)
        {
            int iVaule = -1;
            bool ParseResult = int.TryParse(this.textBox_value.Text,out iVaule);
            if (ParseResult)
            {
                value = iVaule;
                this.label_display.Text = this.textBox_value.Text;
            }
        }
    

  很简单的一个Demo:一个名为value的变量,整数型,赋予其初始值1000;两个按钮:修改按钮点击后把文本框的数值赋值给value,并且修改标签文本=修改后value的值;另一个刷新按钮,点下后更新标签文本=value的最新值。

  

  回顾上一章节,我们讲到查询数值的内存地址需要用到两个函数VirtualQueryEx和ReadProcessMemory:

  其中VirtualQueryEx的第三个参数是一个用于接收内存信息的结构体指针,来看一下组成这个结构体的成员

        //接收内存信息的结构体
        public struct MEMORY_BASIC_INFORMATION
        {
            //区域基地址
            public int BaseAddress;
            //分配基地址
            public int AllocationBase;
            //区域被初次保留时赋予的保护属性
            public int AllocationProtect;
            //区域大小
            public int RegionSize;
            //状态
            public int State;
            //保护属性
            public int Protect;
            //类型
            public int lType;
        }

  这些注释是我从百度百科上摘抄的,更准确的解释建议查阅MSDN的API,下面贴代码的时候我也会据我的理解去解释涉及到的成员,但还是建议深入学习计算机的操作系统原理才能真正掌握这些术语与它们的意义。特地贴出这一段是我认为这是整个外挂制作过程中最重要的一个步骤。套用我们现成的模板或者利用后续我也会提到的一系列辅助工具去完成外挂的制作,是很难成长的,一些知名的游戏靠工具搜索基址千难万难,只有慢慢的去理解这些API、了解寄存器和汇编语言,才能走的更远。

  原归正传,我就直接跟着实际测试来一步一步讲解:

  1). 打开测试程序

  

  程序的名称:WinMemory_Test

  

  2). 根据上一章节通过进程名称获取PID=7956

  

  3). 还是上一章节提到的通过PID=7956获取进程句柄Handle=1072

  

  4). 通过Handle循环遍历可读写内存地址,取得字节数组。

 public void SearchAddress()
        {
            MEMORY_BASIC_INFORMATION MBInfo = new MEMORY_BASIC_INFORMATION();
            //获取结构体大小[单次读取字节数]
            int MBSize = Marshal.SizeOf(MBInfo);
            //从0x00开始查询
            StartAddress = 0x000000;
            //实际读取的字节数
            int ReadSize = 0;
            //从0开始查询,直到查询到整形的最大值2147483647
            while (StartAddress >= 0 && StartAddress <= 0x7fffffff && MBInfo.RegionSize >= 0)
            {
                //读取结果存入输出参数MBInfo
                MBSize = VirtualQueryEx(hProcess, (IntPtr)StartAddress, out MBInfo, Marshal.SizeOf(MBInfo));
                //如果实际读取到的字节数等于结构体MEMORY_BASIC_INFORMATION字节数,表示读取成功
                if (MBSize == Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION)))
                {
                    //PAGE_READWRITE:允许读写的内存区。
                    //MEM_COMMIT:已分配物理内存[要找的数值确定了,那么内存肯定提前分配了]。
                    if (MBInfo.Protect == PAGE_READWRITE && MBInfo.State == MEM_COMMIT)
                    {
                        byte[] FindArray = new byte[MBInfo.RegionSize];
                        //把读取到的字节写入上面定义的数组byData中
                        if (ReadProcessMemory(hProcess, (IntPtr)StartAddress, FindArray, MBInfo.RegionSize, out ReadSize))
                            //如果读取的字节数无误
                            if (ReadSize == MBInfo.RegionSize)
                            {
                                //处理数据[对比分析]
                                DealData(DataArray, StartAddress);
                            }
                    }
                }
                else
                {
                    break;
                }
                StartAddress += MBInfo.RegionSize;
            }

        }

  

  5). 将获取的字节数组转化整型与1000进行对比,将寻找到的所有结果保存到全局List.

public void DealData(byte[] DataArray, int StartAddress)
        {
            byte[] intBuff = new byte[4];

            for (int i = 0; i < DataArray.Length - 4; i++)
            {
                Array.Copy(DataArray, i, intBuff, 0, 4);
                int num = BitConverter.ToInt32(intBuff, 0);
                if (num == 1000)
                {
                    AddressList.Add(StartAddress + i);
                }
            }
        }

  看一下结果:

  

  至此,Demo中整形数值等于1000的地址已经全部被我们找到了,下一章节讲解如何定位我们所要查找的那个“1000”以及修改其值。

  PS:转载请附带原文路径:http://www.cnblogs.com/lene-y/p/7107526.html ,我已委托“维权骑士”为我的文章进行维权行动。

  欢迎关注微信公众号[游戏外挂原理解析与制作],对本文有不理解的地方或者不同的观点可以给我留言,一定回复。

       

时间: 2024-10-19 13:53:58

游戏外挂原理解析与制作 - [内存数值修改类 篇二]的相关文章

游戏外挂原理解析与制作 - [内存数值修改类 篇一]

本章旨在讲解外挂实现原理,未深入涉及至代码层面.希望能与对这方面感兴趣的朋友多多交流,毕竟理论是死的,套路是固定的,只有破解经验是花大量时间和心血积累的. 对于单机游戏而言,游戏中绝大部分的参数(比如血.蓝.能量亦或是金币)都存储在计算机的堆栈中,一些类似剧情进度的则加密后写入本地的自定义配置文件中: 对于页游.网游和手游,虽然服务器保存了大量的重要的参数,但由于客户端不可避免的需要进行大量的计算和资源的加载,本地内存种必定存有部分的临时变量,通过判断这些变量的变化规律和函数的破密寻到利于自身的

游戏外挂原理解析与制作 - [内存数值修改类 篇四]

前三篇的博文结合了C#的Demo对内存数据修改一类的挂剖析了原理,利用C#语言调用Windows API,我们其实已经写出了一个简单的内存扫描工具,但是它存在一些缺陷,比如说只能所搜索单一类型数值(整型),只能搜索确定的数值,比如1000.2000,而不能进行模糊搜索,比如搜索某个值变小了,或者在某某区间内变化了等. 我一直认为语言只是一种工具,只要能够达到修改数值的目的,用什么语言都可以,甚至可以配合着多种语言和工具来完成一项数值的修改.其实实际中通常都是这样,因为每种语言有自己的优势,比如C

Android&quot;挂逼&quot;修炼之行---防自动抢红包外挂原理解析

一.前言 春节过年发个红包本来就是为了讨个喜庆,朋友亲戚之间的关系交流,但是现在随着技术变革,抢红包插件越来越多,导致现在不太愿意发红包了,特别是在一个多人群里,潜水的非常多,但是丢个红包瞬间就没了,感觉真的很不爽呀,然后造成的现象就是你用插件,我也用,结果抢红包就变得没有意思了.在这里我还是觉得尽量不要用这些所谓的抢红包插件.多读些书多好呀! 二.自动抢红包插件分析 本文就来应对那些自动抢红包插件功能的防护功能,我们知道现在自动抢红包主要有着三种方式: 第一种:利用辅助功能和通知栏消息拦截来做

垃圾收集器与内存分配策略之篇二:垃圾收集器

五.垃圾收集器 如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现.由于java虚拟机规范对垃圾收集器实现没有任何的规范因此不同的厂商,不同的版本的虚拟机所提供的垃圾收集器都有可能会有很大的区别,并且一般都会提供参数供用户根据自己的应用特点和要求组合出各个年代所使用的收集器. 虚拟机中所包含的垃圾收集器如下图: 连线代代表他们可以组合使用.下面分别对以上垃圾收集器进行说明: 01)Serial 是历史悠久的收集器,在垃圾回收期间或中断用户线程,是一个单线程的收集器,在进行垃圾

你不得不知道的-垃圾回收机制及析构函数原理解析

前言 当学习到Web API中摸索原理时,对于其中有关垃圾回收只是有点印象并未深入去了解其原理并且对索引器用的也很少,所以利用放假期间好好回顾下已经忘记或者遗漏的知识,温故而知新大概就是这道理吧,虽然园子中关于这两者的文章也是多不胜数,但笔者也有自己独特的见解. 垃圾回收机制 引言 我们知道.NET Framework中的对象是创建在托管堆中的,但是像C.C++等其他底层语言中的对象是创建在非托管堆中的,所以在这类语言中就会出现编程人员忘记去释放已经没有用的对象,同时编程人员也可能会去试图访问已

游戏外挂制作原理

外挂现在大体上来讲分为三种,分别是模拟按键,WPE封包和内存挂.比如模拟键盘的,鼠标的,这种就叫做按键模拟,也叫脚本精灵:还有修改数据包的,这种就叫做WPE封包外挂,这种外挂相对而言比较稳定,但是对于技术要求难度也比较高,因为修改WPE封包,你需要知道和了解加密解密算法等等一系列的知识:还有最后一种就是修改本地内存的,这种相对而言比较常见,市场上面比较常见的也是这种游戏外挂,相对而言技术要求也不是太高,资料也比较齐全,比较大众:但好像没有修改服务器内存的哦,呵呵.其实修改服务器也是有办法的,只是

【转载】游戏外挂的编写原理和思路

原文:游戏外挂的编写原理和思路 游戏外挂的编写原理(一) 一. 前言 所谓游戏外挂,其实是一种游戏外辅程序,它可以协助玩家自动产生游戏动作.修改游戏网络数据包以及修改游戏内存数据等,以实现玩家用最少的时间和金钱去完成功力升级和过关斩将.虽然,现在对游戏外挂程序的“合法”身份众说纷纭,在这里我不想对此发表任何个人意见,让时间去说明一切吧. 不管游戏外挂程序是不是“合法”身份,但是它却是具有一定的技术含量的,在这些小小程序中使用了许多高端技术,如拦截Sock技术.拦截API技术.模拟键盘与鼠标技术.

初级游戏外挂编程详解 windows运行原理+游戏辅助编程 游戏外挂编程

详解游戏辅助编程 [目录] 1-什么是Windows API 2-Windows进程 3-Windows 的内存的运行原理 4-windows 中句柄的概念 5-Windows的变量类型 6-辅助实现的原理 7-编程实现游戏辅助 8-怎样查找内存地址 9-总结 准备软件:VC,CheatEngineer5.5 学习这部分内容,你必须要掌握C语言的基础知识,非常基础的语法就行了.这篇文章的内容适合刚开始接触编程的人,高手请飘过. [1]什么是windows API Windows API 中文翻译

内存型游戏外挂讲解

一,要想做好外挂,那么必不可少的就是要找到游戏基址和偏移,首先讲解一下游戏基址和偏移的找法:这里我们使用CE来找寻基址和偏移我们先来找寻游戏生命基址 首先选择游戏进程,选择好后,数值类型选择"字节",扫描类型选择"精确数值".然后在数值框中输入当前生命,点"新的扫描"按扭.扫描完成后,把人物挂一次,改变一下生命,然后再在数据框中输入现在的生命,点"再次扫描",直到找到生命动态地址为止. 这里我们找到了,我们的生命动态地址为02