Jim's游戏外挂学习笔记2—适时编写个读取状态的小程序增加一下士气

作者:Jim's

支持原创,经典收藏!
这贴之前有朋友发过,东西很全面,所以整理了一下发出来,应该对新来的朋友有帮助!

[外挂学习]Jim's游戏外挂学习笔记2——适时编写个读取状态的小程序增加一下士气

游戏:天龙八部
版本:0.13.0402
系统:windows xp
工具:CE5.2+OD1.10+C# 2005
目标:编写获取分析到内存偏移地址的游戏属性的程序

按照学习笔记1中的方法继续查找到了MP,HP上限,HP上限,人物ID,人物姓名等属性,接下来编写一个简单的状态读取程序,语言用C# 2005,程序运行界面如下


项目文件布局如下


以下为各文件简单说明:
1. 内存地址配置文件AddressListConfig.xml,用来存放各级基地址,以及人物各属性的偏移地址
1<?xml version="1.0" encoding="utf-8" ?>
2<Configs>
3    <AddressList Key="Base1" Offset="0x013D2BD8" ValueType="System.Int32" ValueLength="4">
4        <AddressList Key="Base1.Base2" Offset="0x12C" ValueType="System.Int32" ValueLength="4">
5            <AddressList Key="Base1.Base2.MyPlayer" Offset="0x8" ValueType="System.Int32" ValueLength="4">
6                <Address Key="Base1.Base2.MyPlayer.UserId" Offset="0" ValueType="System.String" ValueLength="4" />
7                <Address Key="Base1.Base2.MyPlayer.Name" Offset="0x10" ValueType="System.String" ValueLength="12" />
8                <Address Key="Base1.Base2.MyPlayer.Hp" Offset="0x6B8" ValueType="System.Int32" ValueLength="4" />
9                <Address Key="Base1.Base2.MyPlayer.Mp" Offset="0x6BC" ValueType="System.Int32" ValueLength="4" />
10                <Address Key="Base1.Base2.MyPlayer.MaxHp" Offset="0x81C" ValueType="System.Int32" ValueLength="4" />
11                <Address Key="Base1.Base2.MyPlayer.MaxMp" Offset="0x820" ValueType="System.Int32" ValueLength="4" />
12            </AddressList>
13        </AddressList>
14    </AddressList>
15</Configs>
1) AddressList为嵌套的基地址
      Key为全局的读取键名,Offset为学习笔记1中查到的偏移量,ValueType属性为此地址存放的值对应.net中的数据类型,ValueLength为读取内存长度值
2) Address节点中存放的是各游戏属性对应的地址
      各属性与AddressList类似

2. 基地址类AddressListClass,对应XML中的AddressListClass节点

 


  1using System;
  2using System.Collections.Generic;
  3using System.Text;
  4using System.Collections;
  5using System.Xml;
  6
  7namespace TLPlayer
  8{
  9    public class AddressListClass : Hashtable
10    {
11        private string mKey;
12
13        public string Key
14        {
15            get { return mKey; }
16            set { mKey = value; }
17        }
18
19        private int mOffset;
20
21        public int Offset
22        {
23            get { return mOffset; }
24            set { mOffset = value; }
25        }
26
27        private Type mValueType;
28
29        public Type ValueType
30        {
31            get { return mValueType; }
32            set { mValueType = value; }
33        }
34
35        private int mValueLength;
36
37        public int ValueLength
38        {
39            get { return mValueLength; }
40            set { mValueLength = value; }
41        }
42
43        private int mValue;
44
45        public int Value
46        {
47            get { return mValue; }
48            set { mValue = value; }
49        }
50
51
52        private void AddChild(AddressListClass childAddressList)
53        {
54            this.Add(childAddressList.Key, childAddressList);
55        }
56
57        private void AddChild(AddressClass childAddress)
58        {
59            this.Add(childAddress.Key, childAddress);
60        }
61
62        //从配置文件里获取配置
63        public void LoadConfig(string fileName)
64        {
65            XmlDocument xmlDoc = new XmlDocument();
66            xmlDoc.Load(fileName);
67            XmlNode currentNode = xmlDoc.DocumentElement.SelectSingleNode(string.Format("AddressList[@Key='{0}']", this.Key));
68            this.Key = currentNode.Attributes["Key"].Value;
69            this.Offset = Convert.ToInt32(currentNode.Attributes["Offset"].Value, 16);
70            this.ValueType = Type.GetType(currentNode.Attributes["ValueType"].Value);
71            this.ValueLength = Convert.ToInt32(currentNode.Attributes["ValueLength"].Value);
72            LoadConfigFromNode(this, currentNode);
73        }
74
75        //获取某节点
76        public AddressListClass GetAddressList(string key)
77        {
78            foreach (string s in this.Keys)
79            {
80                if (s == key)
81                {
82                    return (AddressListClass)this[s];
83                }
84                else
85                {
86                    return ((AddressListClass)this[s]).GetAddressList(key);
87                }
88            }
89            return null;
90        }
91
92        //获取某叶子
93        public AddressClass GetChildAddress(string key)
94        {
95            foreach (string s in this.Keys)
96            {
97                if (s == key)
98                {
99                    return (AddressClass)this[s];
100                }
101            }
102            return null;
103        }
104
105        //递归加载所有节点
106        private void LoadConfigFromNode(AddressListClass addressList, XmlNode node)
107        {
108            foreach (XmlNode childNode in node.ChildNodes)
109            {
110                if (childNode.Name == "AddressList")
111                {
112                    AddressListClass childAddressList = new AddressListClass();
113                    childAddressList.Key = childNode.Attributes["Key"].Value;
114                    childAddressList.Offset = Convert.ToInt32(childNode.Attributes["Offset"].Value, 16);
115                    childAddressList.ValueType = Type.GetType(childNode.Attributes["ValueType"].Value);
116                    childAddressList.ValueLength = Convert.ToInt32(childNode.Attributes["ValueLength"].Value);
117                    addressList.AddChild(childAddressList);
118                    LoadConfigFromNode(childAddressList, childNode);
119                }
120                else if (childNode.Name == "Address")
121                {
122                    AddressClass childAddress = new AddressClass();
123                    childAddress.Key = childNode.Attributes["Key"].Value;
124                    childAddress.Offset = Convert.ToInt32(childNode.Attributes["Offset"].Value, 16);
125                    childAddress.ValueType = Type.GetType(childNode.Attributes["ValueType"].Value);
126                    childAddress.ValueLength = Convert.ToInt32(childNode.Attributes["ValueLength"].Value);
127                    addressList.AddChild(childAddress);
128                }
129            }
130        }
131    }
132}
133

该类的属性为XML文件中对应的节点属性,多出来的Value属性是用来临时存放该地址对应的内存值的,主要方法是LoadConfig方法,从XML中读取各属性和关系

3. AddressClass类,类似AddressListClass类,作用是存放AddressClass节点的配置,即各游戏属性所在地址的配置,该类只有属性没有方法

4. MemoryClass类,内存数据读取用到的类,是核心类,代码如下


1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Diagnostics;
5using System.Runtime.InteropServices;
6
7namespace TLPlayer
8{
9    public class MemoryClass
10    {
11        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
12        public static extern int OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
13
14        [DllImport("kernel32.dll", SetLastError = true)]
15        static extern int CloseHandle(int hProcess);
16
17        [DllImport("kernel32.dll", SetLastError = true)]
18        static extern int ReadProcessMemory(int hProcess, IntPtr lpBaseAddress, [In, Out] byte[] lpBuffer, int nSize, ref int lpNumberOfBytesWritten);
19
20        private int hProcess;
21
22        private byte[] buffer;
23
24        private int lpNumberOfBytesWritten = 0;
25
26        public void Init()
27        {
28            Process[] ps = Process.GetProcessesByName("game");
29            if (ps.Length == 0)
30            {
31                throw new Exception("游戏未打开!");
32            }
33            Process p = ps[0];
34
35            hProcess = OpenProcess(0x0010, true, p.Id);
36            if (hProcess <= 0)
37            {
38                throw new Exception("进程打开失败!");
39            }
40        }
41
42        public void Dispose()
43        {
44            if(hProcess> 0)
45                CloseHandle(hProcess);
46        }
47
48        public int ReadInt(int address,int length)
49        {
50            if (length > 4)
51                length = 4;
52            if(length < 1)
53                length = 4;
54            buffer = new byte[length];
55            int r = ReadProcessMemory(hProcess, (IntPtr)address, buffer, length, ref lpNumberOfBytesWritten);
56            if (r == 0)
57            {
58                throw new Exception("读取内存错误!");
59            }
60            r = 0;
61            for (int i = 0; i < length; i++)
62            {
63                r += buffer * ComputeExp(256, i);
64            }
65            return r;
66        }
67
68        public string ReadString(int address, int length)
69        {
70            buffer = new byte[length];
71            int r = ReadProcessMemory(hProcess, (IntPtr)address, buffer, length, ref lpNumberOfBytesWritten);
72            if (r == 0)
73            {
74                throw new Exception("读取内存错误!");
75            }
76            return Encoding.GetEncoding("gb2312").GetString(buffer);
77        }
78
79        private int ComputeExp(int i, int j)
80        {
81            int r = 1;
82            for (int o = 0; o < j; o++)
83            {
84                r *= i;
85            }
86            return r;
87        }
88    }
89}
90
该类中读取内存数据的原理是先用OpenProcess打开游戏进程,再用ReadProcessMemory方法去读,最后CloseHandle方法释放资源,进程操作使用.net framework的Process类

5. 游戏人物类PlayerClass,该类用于存储游戏人物的各属性值


  1using System;
  2using System.Collections.Generic;
  3using System.Text;
  4using System.ComponentModel;
  5
  6namespace TLPlayer
  7{
  8    public class PlayerClass
  9    {
10        private MemoryClass memory = null;
11        private AddressListClass[] addressLists = null;
12        private AddressListClass addressList = null;
13
14        //游戏中人物ID
15        private string mUserId;
16
17        [CategoryAttribute("ID Settings"), DescriptionAttribute("人物ID")]
18        public string UserId
19        {
20            get { return mUserId; }
21            set { mUserId = value; }
22        }
23
24        //游戏中人物姓名
25        private string mName;
26
27        [CategoryAttribute("ID Settings"), DescriptionAttribute("人物名")]
28        public string Name
29        {
30            get { return mName; }
31            set { mName = value; }
32        }
33
34        //HP
35        private int mHp;
36
37        [CategoryAttribute("ID Settings"), DescriptionAttribute("生命")]
38        public int Hp
39        {
40            get { return mHp; }
41            set { mHp = value; }
42        }
43
44        //MP
45        private int mMp;
46
47        [CategoryAttribute("ID Settings"), DescriptionAttribute("内力")]
48        public int Mp
49        {
50            get { return mMp; }
51            set { mMp = value; }
52        }
53
54        //HP上限
55        private int mMaxHp;
56
57        public int MaxHp
58        {
59            get { return mMaxHp; }
60            set { mMaxHp = value; }
61        }
62
63        //MP上限
64        private int mMaxMp;
65
66        public int MaxMp
67        {
68            get { return mMaxMp; }
69            set { mMaxMp = value; }
70        }
71
72        public PlayerClass(AddressListClass rootAddressList, MemoryClass memory)
73        {
74            this.memory = memory;
75            addressLists = new AddressListClass[3];
76            addressLists[0] = rootAddressList;
77            addressLists[1] = rootAddressList.GetAddressList("Base1.Base2");
78            addressLists[2] = addressLists[1].GetAddressList("Base1.Base2.MyPlayer");
79            addressList = addressLists[2];
80            if (addressList == null)
81            {
82                throw new Exception("没有Player的地址配置!");
83            }
84        }
85
86        public void LoadFromMemory()
87        {
88            if (memory == null)
89                return;
90
91            addressLists[0].Value = memory.ReadInt(addressLists[0].Offset, 4);
92            addressLists[1].Value = memory.ReadInt(addressLists[0].Value + addressLists[1].Offset, 4);
93            addressLists[2].Value = memory.ReadInt(addressLists[1].Value + addressLists[2].Offset, 4);
94
95            foreach (object o in addressList.Values)
96            {
97                if (o is AddressClass)
98                {
99                    AddressClass a = (AddressClass)o;
100                    switch (a.Key)
101                    {
102                        case "Base1.Base2.MyPlayer.UserId":
103                            this.UserId = memory.ReadInt(addressList.Value + a.Offset, a.ValueLength).ToString("X");
104                            break;
105                        case "Base1.Base2.MyPlayer.Name":
106                            this.Name = memory.ReadString(addressList.Value + a.Offset, a.ValueLength);
107                            break;
108                        case "Base1.Base2.MyPlayer.Hp":
109                            this.Hp = memory.ReadInt(addressList.Value + a.Offset, a.ValueLength);
110                            break;
111                        case "Base1.Base2.MyPlayer.Mp":
112                            this.Mp = memory.ReadInt(addressList.Value + a.Offset, a.ValueLength);
113                            break;
114                        case "Base1.Base2.MyPlayer.MaxHp":
115                            this.MaxHp = memory.ReadInt(addressList.Value + a.Offset, a.ValueLength);
116                            break;
117                        case "Base1.Base2.MyPlayer.MaxMp":
118                            this.MaxMp = memory.ReadInt(addressList.Value + a.Offset, a.ValueLength);
119                            break;
120                    }
121                }
122            }
123        }
124    }
125}
126
该类各属性对应游戏里人物的属性,演示程序只设置几个已找到内存偏移地址的属性
实例化时关联上相关的AddressListClass类以便后面获取各属性当前地址,进而获取各地址对应的值
主要方法只有一个是LoadFromMemory,从当前内存中加载该类的各属性,原理是用各属性对应的Key值去配置里搜索到偏移地址,然后通过3级偏移地址得到各属性的值

6. 主程序Form1中调用代码如下


1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Data;
5using System.Drawing;
6using System.Text;
7using System.Windows.Forms;
8
9namespace TLPlayer
10{
11    public partial class Form1 : Form
12    {
13        private MemoryClass memory;
14        private AddressListClass addressList;
15        private PlayerClass player;
16
17        public Form1()
18        {
19            InitializeComponent();
20        }
21
22        private void Form1_Load(object sender, EventArgs e)
23        {
24            addressList = new AddressListClass();
25            addressList.Key = "Base1";
26            addressList.LoadConfig(Application.StartupPath + "//AddressListConfig.xml");
27
28            memory = new MemoryClass();
29            memory.Init();
30
31            player = new PlayerClass(addressList, memory);
32
33            pg.SelectedObject = player;
34        }
35
36        private void button1_Click(object sender, EventArgs e)
37        {
38            player.LoadFromMemory();
39            pg.Refresh();
40        }
41
42        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
43        {
44            memory.Dispose();
45        }
46    }
47}
没什么好说的,依次调用各类的相关方法就好
其中pg是个PropertyGrid对象,button1是用来手动reload人物各属性的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值