设为首页
收藏本站
本站论坛
   
3
3
   
  文章列表      

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[img][/img]<?xml version="1.0" encoding="UTF-8" ?> 2[img][/img]<Configs> 3[img][/img] <AddressList Key="Base1" Offset="0x013D2BD8" ValueType="System.Int32" ValueLength="4"> 4[img][/img]        <AddressList Key="Base1.Base2" Offset="0x12C" ValueType="System.Int32" ValueLength="4"> 5[img][/img]          <AddressList Key="Base1.Base2.MyPlayer" Offset="0x8" ValueType="System.Int32" ValueLength="4"> 6[img][/img]             <Address Key="Base1.Base2.MyPlayer.UserId" Offset="0" ValueType="System.String" ValueLength="4" /> 7[img][/img]             <Address Key="Base1.Base2.MyPlayer.Name" Offset="0x10" ValueType="System.String" ValueLength="12" /> 8[img][/img]             <Address Key="Base1.Base2.MyPlayer.Hp" Offset="0x6B8" ValueType="System.Int32" ValueLength="4" /> 9[img][/img]             <Address Key="Base1.Base2.MyPlayer.Mp" Offset="0x6BC" ValueType="System.Int32" ValueLength="4" />10[img][/img]             <Address Key="Base1.Base2.MyPlayer.MaxHp" Offset="0x81C" ValueType="System.Int32" ValueLength="4" />11[img][/img]             <Address Key="Base1.Base2.MyPlayer.MaxMp" Offset="0x820" ValueType="System.Int32" ValueLength="4" />12[img][/img]          </AddressList>13[img][/img]        </AddressList>14[img][/img] </AddressList>15[img][/img]</Configs>
1) AddressList为嵌套的基地址
   Key为全局的读取键名,Offset为学习笔记1中查到的偏移量,ValueType属性为此地址存放的值对应.net中的数据类型,ValueLength为读取内存长度值
2) Address节点中存放的是各游戏属性对应的地址
   各属性与AddressList类似
2. 基地址类AddressListClass,对应XML中的AddressListClass节点


   1[img][/img]using System;
   2[img][/img]using System.Collections.Generic;
   3[img][/img]using System.Text;
   4[img][/img]using System.Collections;
   5[img][/img]using System.Xml;
   6[img][/img]
   7[img][/img]namespace 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 }132screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif');}" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>}133[img][/img]

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

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

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

1[img][/img]using System;
2[img][/img]using System.Collections.Generic;
3[img][/img]using System.Text;
4[img][/img]using System.Diagnostics;
5[img][/img]using System.Runtime.InteropServices;
6[img][/img]
7[img][/img]namespace 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 }89screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif');}" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>}90[img][/img]
该类中读取内存数据的原理是先用OpenProcess打开游戏进程,再用ReadProcessMemory方法去读,最后CloseHandle方法释放资源,进程操作使用.net framework的Process类

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

   1[img][/img]using System;
   2[img][/img]using System.Collections.Generic;
   3[img][/img]using System.Text;
   4[img][/img]using System.ComponentModel;
   5[img][/img]
   6[img][/img]namespace 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 }125screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif');}" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>}126[img][/img]
该类各属性对应游戏里人物的属性,演示程序只设置几个已找到内存偏移地址的属性
实例化时关联上相关的AddressListClass类以便后面获取各属性当前地址,进而获取各地址对应的值
主要方法只有一个是LoadFromMemory,从当前内存中加载该类的各属性,原理是用各属性对应的Key值去配置里搜索到偏移地址,然后通过3级偏移地址得到各属性的值

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

1[img][/img]using System;
2[img][/img]using System.Collections.Generic;
3[img][/img]using System.ComponentModel;
4[img][/img]using System.Data;
5[img][/img]using System.Drawing;
6[img][/img]using System.Text;
7[img][/img]using System.Windows.Forms;
8[img][/img]
9[img][/img]namespace 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 }47screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open('http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif');}" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>}
没什么好说的,依次调用各类的相关方法就好
其中pg是个PropertyGrid对象,button1是用来手动reload人物各属性的

> >
 
 
   
 
网上赚钱申请指南
 

友情链接
个人主页
 
 
 
 

wel come to . 欢迎光临
宇宙浪仔