C#简易外挂制作

时间:2024-02-18 09:42:07

【外挂修改器简单介绍

游戏外挂分为很多种类型,例如本地客户端的内存修改、远程服务器的封包破解。

一般的网游由于服务器的机能限制,并不会将游戏产生的所有数据、计算都提供给服务器来承担。经常的,服务器只会将玩家人物的属性、血量、加点、金钱、装备等重要信息储存在服务器本地,计算结果和数据传递则是通过加密封包来和客户端传输。

因此网游如果封包被破解而被用户发送伪造的封包数据将造成非常严重的后果。

 

【C#本地修改器

 

如上所述,虽然封包的一般无法破解,但是利用服务器无法储存所有的信息这个特点,我们可以通过修改本地客户端的内存数据来制作一些建议的外挂,如修改坐标达到穿墙、加速的效果。

修改这类的本地数据,一般我们使用到 Cheatgine 来搜索内存特定数值。关于这个这工具网上已经有很多完善的教程,这边就不赘述了。

这边通过QQ连连看的示例来教程一般的C#的外挂制作。 

 

通过Cheatgine搜索到时间、罗盘、重列的数量、本机座位的内存基址偏移量,再绘制出界面就可以开始制作。

(CheatEngine)

 

(简易的界面UI)

 

 

这边提供一个C#的内存修改读取抽象类

  1     public abstract class Helper  //内存读写核心
2 {
3 [DllImportAttribute("kernel32.dll", EntryPoint = "ReadProcessMemory")]
4 public static extern bool ReadProcessMemory
5 (
6 IntPtr hProcess,
7 IntPtr lpBaseAddress,
8 IntPtr lpBuffer,
9 int nSize,
10 IntPtr lpNumberOfBytesRead
11 );
12
13 [DllImportAttribute("kernel32.dll", EntryPoint = "OpenProcess")]
14 public static extern IntPtr OpenProcess
15 (
16 int dwDesiredAccess,
17 bool bInheritHandle,
18 int dwProcessId
19 );
20
21 [DllImport("kernel32.dll")]
22 private static extern void CloseHandle
23 (
24 IntPtr hObject
25 );
26
27 //写内存
28 [DllImportAttribute("kernel32.dll", EntryPoint = "WriteProcessMemory")]
29 public static extern bool WriteProcessMemory
30 (
31 IntPtr hProcess,
32 IntPtr lpBaseAddress,
33 int[] lpBuffer,
34 int nSize,
35 IntPtr lpNumberOfBytesWritten
36 );
37
38 //获取窗体的进程标识ID
39 public static int GetPid(string windowTitle)
40 {
41 int rs = 0;
42 Process[] arrayProcess = Process.GetProcesses();
43 foreach (Process p in arrayProcess)
44 {
45 if (p.MainWindowTitle.IndexOf(windowTitle) != -1)
46 {
47 rs = p.Id;
48 break;
49 }
50 }
51
52 return rs;
53 }
54
55 //根据进程名获取PID
56 public static int GetPidByProcessName(string processName)
57 {
58 Process[] arrayProcess = Process.GetProcessesByName(processName);
59
60 foreach (Process p in arrayProcess)
61 {
62 return p.Id;
63 }
64 return 0;
65 }
66
67 //根据窗体标题查找窗口句柄(支持模糊匹配)
68 public static IntPtr FindWindow(string title)
69 {
70 Process[] ps = Process.GetProcesses();
71 foreach (Process p in ps)
72 {
73 if (p.MainWindowTitle.IndexOf(title) != -1)
74 {
75 return p.MainWindowHandle;
76 }
77 }
78 return IntPtr.Zero;
79 }
80
81 //读取内存中的值
82 public static int ReadMemoryValue(int baseAddress, string processName)
83 {
84 try
85 {
86 byte[] buffer = new byte[4];
87 IntPtr byteAddress = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); //获取缓冲区地址
88 IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPid(processName));
89 ReadProcessMemory(hProcess, (IntPtr)baseAddress, byteAddress, 4, IntPtr.Zero); //将制定内存中的值读入缓冲区
90 CloseHandle(hProcess);
91 return Marshal.ReadInt32(byteAddress);
92 }
93 catch
94 {
95 return 0;
96 }
97 }
98
99 //将值写入指定内存地址中
100 public static void WriteMemoryValue(int baseAddress, string processName, int value)
101 {
102 IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPid(processName)); //0x1F0FFF 最高权限
103 WriteProcessMemory(hProcess, (IntPtr)baseAddress, new int[] { value }, 4, IntPtr.Zero);
104 CloseHandle(hProcess);
105 }
106
107 }


 

 将找到的内存基址定义好

 1         //将值写入指定内存中
2 public void WriteMemory(int baseAdd, int value)
3 {
4 Helper.WriteMemoryValue(baseAdd, processName, value);
5 }
6
7 private int baseAddress = 0x00111DEC; //游戏内存基址
8 private string processName = "QQ游戏 - 连连看角色版"; //游戏进程名字
9
10 int temp = 0; int sit = 0;
11

 

 利用所提供的内存读写抽象类写入内存,并利用一个timer持续写入这个内存数值以达到锁定数值的目的。

 1         private void timer1_Tick(object sender, EventArgs e) //冻结时间
2 {
3 int address = ReadMemoryValue(baseAddress);
4 address += 0x49d8;
5
6 if (checkBox1.Checked == true)
7 {
8 timer1.Enabled = true;
9 WriteMemory(address, 700);
10 label1.Text = "已冻结";
11
12 }
13
14 if (checkBox1.Checked != true) label1.Text = "未冻结";
15 }


 

以上就是一个例子,一般的单机游戏修改器也可以用这样的方法制作完成。

当然现在有不少网游有保护盾,可以防止游戏客户端内存被修改,这类的技术一般是用驱动、内核、进程挂钩完成,可以利用XT手动解除这些保护。