自己做个游戏修改工具
lq7972
[email]bruceyu13@sina.com[/email]
5・1 放几天假,遛遛,有 Q 友拉我去浩方平台挑星际争霸(V1.1),输了 3 盘;同电脑对打,又输 3 盘― KAO
用金山游侠改没商量;在满足虚荣同时,想自个儿做个修改工具
工具软件:
星际争霸 -> 母巢之战 V1.1
金山游侠 2002
MSVC 6.0
Win2000
开始~
这里仅用联网对战中使用率高的两幅地图:The Hunters 和 Lost Temple
用金山游侠查找水晶矿(mineral),运气好的话,三两次就可能找到两个地址:0x69013C 和 0x5013??(?? 表示可能不同)。其中,0x69013C 总不会变,0x5013?? 则似乎总有变化。先看图:
从 0x501370 起是含 12 个元素的数组,均初始为 0x32(也就是50D――星际开始时每个玩家有水晶矿 50 单位);0x690130 处的 0x7CF4 是你的种族为 Terran (其他:Zerg - 0x7DB4,Protoss - 0x7C34),0x690138 为瓦斯矿(Gas),0x69013C 为水晶。
很容易想到,要使修改有效,必须确定0x5013??。前面提到,0x690138 和 0x69013C 总是玩家“当前的”瓦斯和水晶――当前的意思是这两个数值逐一累加或递减,这表现在游戏当中的玩家资源在不停地变化,变化的单位是 1。问题在于应该修改 0x501370 处那个数组中的哪一个?
The Hunters 地图,如下:
图中 Start Location 及资源的分布,如同一个钟表盘顺时针: 11:00,12:00,1:00,3:00,5:00,6:00,7:00,9:00;如果使用过 staredit (Starcraft Campaign Editor,星际战役编辑器)这一点可以很轻松地看出来
实际上,那个数组就对应着这幅地图!例如,当前玩家在 5:00 位置即图中“5”处,那么水晶资源数据的另一个存储地址是 0x501380 (第5个),而瓦斯资源数据,自然也紧跟其后即加上 0x30 = 0x5013B0。由于玩家 Start Location 总是程序 Random 给定的,所以这里的资源地址也就 Random 啦。不过这里资源的变化单位不是 1,比如,一个 Terran SCV 挖了一块水晶运回总部 (Command Center) 后,0x501380 处的水晶资源一次性增加 8 单位。
Lost Temple 地图中如下左:
要是能找到程序随机化结果多好,可:-(……先确定 Start Location,再填相应的...
还有一件事,就是游戏结束后得分表中的资源得分仍然能暴露出你修改了;那么如何克服这一点呢?请看右图。也就是从 0x5013?? 加上 2*0x30 (Gas Mined)和 加上 3*0x30(Minerals Mined)
下面就开始写自己的修改工具了~
首先用 FindWindow 函数得到窗口句柄,然后用 GetWindowThreadID 函数从窗口句柄得到这个进程的ID,接着用 OpenProcess 得到进程的读写权限,最后用 ReadProcessMemory 和 WriteProcessMemory 读写内存,...
// 这里列出功能最简单的源程序,你可加入锁定和热键的功能;实现后别忘了告诉我
// brood.c
#include <windows.h>
#include "resource.h"
#define PATCH_POSITION 0x00501370 // 补丁地址
BOOL CALLBACK _ProcDlgMain(HWND, UINT, WPARAM, LPARAM) ;
void MemPatch (HWND, UINT, ULONG, ULONG) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
DialogBoxParam (hInstance, DLG_MAIN, NULL, _ProcDlgMain, NULL) ;
}
BOOL CALLBACK _ProcDlgMain (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
BOOL isTrue ;
UINT uLock, uTop, uPos ;
ULONG dwMineral, dwGas ;
switch (message)
{
case WM_INITDIALOG :
// 输入想要的数值
SetDlgItemInt (hDlg, IDC_POS, 1, FALSE) ; // Start Location
SetDlgItemInt (hDlg, IDC_MINERAL, 400, FALSE) ; // Mineral
SetDlgItemInt (hDlg, IDC_GAS, 300, FALSE) ; // Gas
SetFocus (GetDlgItem (hDlg, IDC_MINERAL)) ;
break ;
case WM_COMMAND :
switch (LOWORD (wParam))
{
case IDOK :
uPos = GetDlgItemInt (hDlg, IDC_POS, &isTrue, FALSE) - 1 ;
dwMineral = GetDlgItemInt (hDlg, IDC_MINERAL, &isTrue, FALSE) ;
dwGas = GetDlgItemInt (hDlg, IDC_GAS, &isTrue, FALSE) ;
// 做一点限制
if (uPos < 0) uPos = 0 ;
else if (uPos > 8) uPos = 8 ;
if (dwMineral < 0) dwMineral = 50 ;
else if (dwMineral > 99999) dwMineral = 99999 ;
if (dwGas < 0) dwGas = 0 ;
else if (dwGas > 99999) dwGas = 99999 ;
MemPatch (hDlg, uPos, dwMineral, dwGas) ; // 内存修改
break ;
case IDCANCEL :
EndDialog (hDlg, 0) ;
return TRUE ;
}
break ;
}
return FALSE ;
}
// *************************************************************************
void MemPatch (HWND hDlg, UINT uPos, ULONG dwMin, ULONG dwGas)
{
BOOL bROK, bWOK ;
DWORD hProcID, dwPatched, dwWMin, dwWGas, dwWMinMined, dwWGasMined;
HWND hWnd ;
HANDLE hOK ;
hWnd = FindWindow (NULL, "Brood War") ; // 得到窗口句柄
if (!(hWnd)) MessageBox (hDlg, "Have not running", "ErrInfo", MB_OK) ;
else {
GetWindowThreadProcessId (hWnd, &hProcID) ; // 从窗口句柄得到进程ID
// 打开进程并得到读写权限
hOK = OpenProcess (PROCESS_ALL_ACCESS | PROCESS_TERMINATE |
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
FALSE, hProcID) ;
if (!(hOK)) MessageBox (hDlg, "Could not open process", "ErrInfo", MB_OK) ;
else {
bROK = ReadProcessMemory (hOK, (LPCVOID)PATCH_POSITION, (LPVOID)&dwPatched,
4, NULL) ;
if (bROK) {
// 得到资源的地址
dwWMin = PATCH_POSITION + 0x000000004 * uPos ; // Mineral 地址
dwWGas = dwWMin + 0x00000030 ; // Gas 地址
dwWMinMined = dwWGas + 0x00000030 ;
dwWGasMined = dwWMinMined + 0x00000030 ;
// 修改资源
bWOK = WriteProcessMemory (hOK, (LPVOID)dwWMin, &dwMin, 4, NULL) ;// Mineral
bWOK = WriteProcessMemory (hOK, (LPVOID)dwWGas, &dwGas, 4, NULL) ;// Gas
// 资源得分
bWOK = WriteProcessMemory (hOK, (LPVOID)dwWMinMined, &dwMin, 4, NULL) ;// Minerals Mined
bWOK = WriteProcessMemory (hOK, (LPVOID)dwWGasMined, &dwGas, 4, NULL) ;// Gas Mined
}
if (!(bWOK)) MessageBox (hDlg, "Write Error", "ErrInfo", MB_OK) ;
}
CloseHandle (hOK) ; // 关闭进程句柄
}
}
// *************************************************************************
// brood.rc
#include "afxres.h"
#include "resource.h"
DLG_MAIN DIALOGEX 0, 0, 123, 102
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION
CAPTION "星际争霸:母巢之战v1.1 资源修改器"
FONT 10, "System"
BEGIN
GROUPBOX "",IDC_STATIC,7,0,109,58
CTEXT "Start Location",IDC_STATIC,14,9,59,11,SS_CENTERIMAGE |
SS_SUNKEN,WS_EX_STATICEDGE
RTEXT "Mineral",IDC_STATIC,14,26,28,11,SS_CENTERIMAGE,
WS_EX_STATICEDGE
RTEXT "Gas",IDC_STATIC,14,42,28,11,SS_CENTERIMAGE,
WS_EX_STATICEDGE
EDITTEXT IDC_POS,77,9,32,12,ES_NUMBER
EDITTEXT IDC_MINERAL,46,26,63,12,ES_AUTOHSCROLL
EDITTEXT IDC_GAS,46,42,63,12,ES_AUTOHSCROLL
DEFPUSHBUTTON "确定",IDOK,18,82,35,14
PUSHBUTTON "取消",IDCANCEL,69,82,34,14
CTEXT " By lq7972\n [email]bruceyu13@sina.com[/email]",IDC_STATIC,7,59,109,
17,SS_SUNKEN | WS_DISABLED
END
// *************************************************************************
// resource.h
#define DLG_MAIN 101
#define IDI_MAIN 102
#define IDC_MINERAL 1000
#define IDC_GAS 1001
#define IDC_POS 1010
#define IDC_LOCK 1011
#define IDC_TOP 1012
#define IDC_HELP 1015
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
最后,这个程序我只在同电脑对挑时验证通过,5・1 当天就弄出了,直到今天才整理出来,手都麻...
难免遗漏,请大家指教~
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!