Like Share Discussion Bookmark Smile

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

遊戲輔助 | 小朋友下樓梯 (C# 無限血量)

工具準備

  • Cheat Engine
  • Visual Studio

行前準備

輔助構思

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

找尋基址

  • 開啟down.exe程式

  • 開啟Cheat Engine
  • 選擇down.exe程序 (00000C50-NS-SHAFT)

  • 回到down.exe
  • 並開啟一場新遊戲,並馬上按下暫停
  • 回到Cheat Engine
  • 新的搜尋12 (滿血量為12格)

  • 回到down.exe
  • 讓血量扣血,然後快速再次暫停
  • 其血量格數為7

  • 回至Cheat Engine
  • 再次搜尋7
  • 僅剩下一個地址0064CD48 (每次都會不一樣)

  • 對該地址點擊兩下,新增至下方的作弊表內

  • 0064CD48右鍵選擇Find out what writes to this address (找出是什麼改寫了這個地址)

  • 會開啟The following opcodes write to 0064CD48視窗

  • 回到down.exe
  • 讓血量扣血
  • 其血量格數為3
  • 回至Cheat Engine
  • 找尋The following opcodes write to 0064CD48視窗內為sub的動作

註:sub是組合語言的減的動作

  • 點擊該筆資料
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
EAX=00000000
EBX=00000000
ECX=0064BBD8
EDX=0008E3C8
ESI=00401C96
EDI=00000000
EBP=0018FD64
ESP=0018FD4C
EIP=00406319

Probable base pointer =0064BBD8

0040630B - shl eax,05
0040630E - mov ecx,[ebp+08]
00406311 - sub dword ptr [eax+ecx+00001170],05
00406319 - mov eax,[ebp-0C]
0040631C - shl eax,05
  • 這邊要知道的是做sub這個指令是在哪個地址,發現是00406311
  • 這邊可以判定為,當我碰到上方尖刺的時候,扣血是這地址做的動作


  • 開啟x32dbg,並開啟down.exe

  • 反匯編視窗中按下Ctrl + G輸入00406311,會跳轉到00406311位址

  • 對其位址00406311點選在資料視窗中跟隨(F)-> 選定的地址(S)

  • 在最下面的資料視窗會看到00406311的十六進位資料為83 AC 08 70

  • 00406311 | 83AC08 70110000 05 | sub dword ptr ds:[eax+ecx+1170],5 |按下空白鍵

  • 將指令修改為add dword ptr ds:[eax+ecx*1+0x1170], 0x5,按下確定

  • 修改後如下

    1
    2
    3
    4
    //修改前
    00406311 | 83AC08 70110000 05 | sub dword ptr ds:[eax+ecx+1170],5 |
    //修改後
    00406311 | 838408 70110000 05 | add dword ptr ds:[eax+ecx+1170],5 |
  • 注意最下面的資料視窗會看到00406311的十六進位資料為83 84 08 70

  • AC變成84

注意:變動的位置是第二個位置,所以需要修改的位置為00406312

  • F9執行程式
  • 開啟一場新遊戲,開始遊玩
  • 發現都不會因為扣血導致遊戲結束

註:如果有興趣,可以開啟Cheat Engine,去監控血量數值,會發現血量一直在向上加;這就是sub改成add的效果。

編寫輔助

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

  • 調整DownHelper
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
83
84
85
86
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace DownCheat
{
class DownHelper
{
#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 add_blood = false;

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

IntPtr hProcess = DownHelper.OpenProcess(0x1F0FFF, false, DownHelper.GetPidByProcessName(processName));
if (add_blood)
{
DownHelper.WriteProcessMemory(hProcess, (IntPtr)0x00406312, new int[] { 0xAC }, 1, IntPtr.Zero);
add_blood = false;
}
else
{
DownHelper.WriteProcessMemory(hProcess, (IntPtr)0x00406312, new int[] { 0x84 }, 1, IntPtr.Zero);
add_blood = true;
}
DownHelper.CloseHandle(hProcess);
}
  • 關閉x32dbg

  • 關閉所有down.exe

  • 開啟新的down.exe

  • 運行測試

  • 勾選CheckBox

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

  • 恭喜無限血量的修改完成

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


註:以上參考了
小朋友下樓梯輔助程式
Download Games