Like Share Discussion Bookmark Smile

J.J. Huang   2019-12-19   Game Cheats   瀏覽次數:

遊戲輔助 | 植物大戰殭屍 (C# 打不死的植物)

工具準備

  • Cheat Engine
  • Visual Studio
  • Plants vs. Zombies

行前準備

輔助構思

  • 透過Cheat Engine抓取扣血的地址並分析
  • 使用C#呼叫Win32API進行修改

CE補充

有時你可能不知道要搜索的值的確切編號,或者它更改得太快而無法正常掃描。這就是為什麼Cheat Engine提供了幾種尋找值的方法。
無論你是否知道,這些掃描選項都可以查找任何值。
可用的選項分為兩個:“第一次掃描”選項和“下次掃描”選項。

首次掃描選項為

  • Exact Value (確切值)
  • Bigger than... (比…更大)
  • Smaller than... (比…小)
  • Value between... (之間的值…)
  • Unknown initial value (初始值未知)

下一步掃描選項是

  • Exact Value (確切值)
  • Bigger than... (比…更大)
  • Smaller than... (比…小)
  • Value between... (之間的值…)
  • Increased Value (增值)
  • Increased Value by... (價值增加…)
  • Decreased Value (價值下降)
  • Decreased Value by... (價值下降…)
  • Changed Value (變更值)
  • Unchanged Value (不變價值)
  • Same as First Scan (與第一次掃描相同)

所有這些選擇都能說明一切。Cheat Engine會記住上一次掃描中找到的值,從而使其能夠將新值與舊值進行比較並還原為上一次掃描。它還會記住“首次掃描”的值。

找尋基址

  • 開啟Plants vs. Zombies主程式
  • 稍微遊玩到可以種植牆果

  • 開啟Cheat Engine
  • 選擇Plants vs. Zombies程序

  • 等待殭屍出現
  • 種植牆果植物到最前線

  • 選擇Unknown initial value (初始值未知),首次搜尋

  • 殭屍咬到牆果
  • 再次搜尋Decreased Value (價值下降)
  • 反覆多次觀察數值變動
  • 最終找到0F7742D8 (每次都會不一樣)
  • 對該地址點擊兩下,新增至下方的作弊表內
  • 修改數值變5000,發現牆果從破損狀態恢復成完整狀態

註:搜尋的示範GIF圖檔太大,影響頁面Loading速度,固直接提供GIF檔下載點我下載

  • 0F7742D8右鍵選擇Find out what writes to this address (找出是什麼改寫了這個地址)
  • 會開啟The following opcodes write to 0F7742D8視窗

  • 回到Plants vs. Zombies
  • 讓殭屍繼續咬牆果
  • 回至Cheat Engine
  • 可見The following opcodes write to 0F7742D8視窗內多一筆資料

  • 點擊該筆資料
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
EAX=00000000
EBX=00000001
ECX=00000003
EDX=0F6EB850
ESI=0F774298
EDI=00000002
EBP=0F71DECC
ESP=0018F998
EIP=0052FCF4

Probable base pointer =0F774298

0052FCE8 - mov ecx,[ebp+04]
0052FCEB - call 0040CB10
0052FCF0 - add dword ptr [esi+40],-04
0052FCF4 - mov ecx,[esi+40]
0052FCF7 - mov [esi+000000B4],00000032
  • 這邊要知道的是做add這個指令是在哪個地址,發現是0052FCF0

  • 這邊可以判定為,當殭屍咬食牆果,這地址做的動作是加-04

  • 點擊Show disassembler

  • 代碼修改
1
2
3
4
// 修改前
add dword ptr [esi+40],-04
// 修改後
add dword ptr [esi+40],-00
  • 注意最十六進位資料變化
1
2
3
4
// 修改前
83 46 40 FC
// 修改後
83 46 40 00
  • 第四個位置由FC變成00
  • 所以要修改的地址為0052FCF3

註:修改玩代碼後,可以回到Plants vs. Zombies看殭屍咬食牆果是否數值不會動了。

編寫輔助

沿用上一章節的PZCheat project程式碼來進行修改

  • 調整PZHelper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace PZCheat
{
class PZHelper
{
#region API

//從指定內存中讀取字節集資料
[DllImportAttribute("kernel32.dll", EntryPoint = "ReadProcessMemory")]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, IntPtr lpNumberOfBytesRead);

//從指定內存中寫入字節集資料
[DllImportAttribute("kernel32.dll", EntryPoint = "WriteProcessMemory")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, int[] lpBuffer, int nSize, IntPtr lpNumberOfBytesWritten);

//打開一個已存在的進程對象,並返回進程的句柄
[DllImportAttribute("kernel32.dll", EntryPoint = "OpenProcess")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

//關閉一個內核對象。其中包括文件、文件映射、進程、線程、安全和同步對象等。
[DllImport("kernel32.dll")]
public static extern void CloseHandle(IntPtr hObject);

#endregion

#region 使用方法

//根據進程名獲取PID
public static int GetPidByProcessName(string processName)
{
Process[] arrayProcess = Process.GetProcessesByName(processName);
foreach (Process p in arrayProcess)
{
return p.Id;
}
return 0;
}

//讀取內存中的值
public static int ReadMemoryValue(int baseAddress, string processName)
{
try
{
byte[] buffer = new byte[4];
//獲取緩沖區地址
IntPtr byteAddress = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
//打開一個已存在的進程對象 0x1F0FFF 最高權限
IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPidByProcessName(processName));
//將制定內存中的值讀入緩沖區
ReadProcessMemory(hProcess, (IntPtr)baseAddress, byteAddress, 4, IntPtr.Zero);
//關閉操作
CloseHandle(hProcess);
//從非托管內存中讀取一個 32 位帶符號整數。
return Marshal.ReadInt32(byteAddress);
}
catch
{
return 0;
}
}

//將值寫入指定內存地址中
public static void WriteMemoryValue(int baseAddress, string processName, int value)
{
try
{
//打開一個已存在的進程對象 0x1F0FFF 最高權限
IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPidByProcessName(processName));
//從指定內存中寫入字節集資料
WriteProcessMemory(hProcess, (IntPtr)baseAddress, new int[] { value }, 4, IntPtr.Zero);
//關閉操作
CloseHandle(hProcess);
}
catch { }
}

#endregion
}
}
  • 開啟Form1.cs[設計]
  • 新增一個CheckBox

  • 雙擊CheckBox建立CheckedChanged事件

  • 撰寫程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private Boolean lock_blood = false;

private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (PZHelper.GetPidByProcessName(processName) == 0)
{
MessageBox.Show("遊戲沒有運行!");
return;
}

IntPtr hProcess = PZHelper.OpenProcess(0x1F0FFF, false, PZHelper.GetPidByProcessName(processName));
if (lock_blood)
{
PZHelper.WriteProcessMemory(hProcess, (IntPtr)0x0052FCF3, new int[] { 0xFC }, 1, IntPtr.Zero);
lock_blood = false;
}
else
{
PZHelper.WriteProcessMemory(hProcess, (IntPtr)0x0052FCF3, new int[] { 0x00 }, 1, IntPtr.Zero);
lock_blood = true;
}
PZHelper.CloseHandle(hProcess);
}
  • 重開Plants vs. Zombies

  • 運行測試

  • 勾選CheckBox

  • 開始遊玩遊戲,發現植物不會扣血

  • 恭喜打不死的植物的修改完成

註:如要分享.exe檔案,請到專案目錄下的Debug資料夾內,將其全部複製給別人即可。注意因為使用C#撰寫,對方的電腦要有安裝.NET Framework才可執行。


註:以上參考了
植物大戰殭屍 (Plants vs Zomebies) 遊戲簡介、下載與完整攻略
植物大战僵尸(5) 打不死的植物