首页
社区
课程
招聘
自己做个游戏修改工具
发表于: 2004-6-2 16:52 6599

自己做个游戏修改工具

2004-6-2 16:52
6599
自己做个游戏修改工具

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 当天就弄出了,直到今天才整理出来,手都麻...

难免遗漏,请大家指教~

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 6
支持
分享
最新回复 (7)
雪    币: 271
活跃值: (226)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
2
图好像搞不上去,上一个包吧;全在中间了:D 点击下载:附件!
2004-6-2 17:03
0
雪    币: 319
活跃值: (1076)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
3
和破解有关么,对游戏也没什么兴趣,不过偶尔会打打反恐,嘿嘿。。。浩方里的aqtata就是我。。。
2004-6-2 18:43
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
4
你这样真的可以修改网游?对方没有验证么?
2004-6-2 20:23
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
不懂~内存是动态的怎么办?
2004-12-5 15:39
0
雪    币: 161
活跃值: (231)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
最初由 shihao 发布
不懂~内存是动态的怎么办?

如果是动态的申请内存,那么游戏中必然有一个静态变量保存这个申请到的内存的首地址。找到这个地址就行了。
2004-12-5 15:43
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
明白,但具体怎么找?求教!
2004-12-5 15:47
0
雪    币: 161
活跃值: (231)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
没有人能走过同一条河流,我也不能教你找每一个不同的程序的方法。但有一点,你可以通过在申请内存的函数上下断点。然后跟踪申请来的内存保存地址就OK了。
2004-12-5 15:58
0
游客
登录 | 注册 方可回帖
返回
//