[外挂学习]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(0x0010true, 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[i] * 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人物各属性的
 

posted on 2007-04-21 23:56  Jim Zhang  阅读(6848)  评论(12编辑  收藏  举报

导航