RA2红色警戒红警2辅助

2024/01/02 sec 共 23592 字,约 68 分钟
  • Content

开启日志

0x4068E0 函数是一个空函数,开发阶段应该是输出调试日志的,发布阶段函数体是空的。而它的后续有足够的空间,可以设置一个hook。

004068E0   $  C3            retn
004068E1      90            nop
004068E2      90            nop
004068E3      90            nop
004068E4      90            nop

具体代码如下:

// 打印错误信息
void printLastError(DWORD error, const char* tag = NULL) {
    char buffer[1024] = {};
    sprintf_s(buffer, sizeof(buffer), "Tag: %s, Error Code: %lu", tag, error);
    OutputDebugStringA(buffer);
}


#pragma optimize("", off)
BOOL installHook(LPVOID addr, DWORD newFunc) {
    byte buff[5];
    DWORD* offset = (DWORD*) & buff[1];
    DWORD dwWrittenSize = 0;
    DWORD dwOldProtect = 0;

    buff[0] = 0xE9;    // jmp
    *offset = newFunc - (DWORD)addr - 5;

    if (VirtualProtect(addr, 5u, PAGE_EXECUTE_READWRITE, &dwOldProtect)) {
        WriteProcessMemory(GetCurrentProcess(), addr, &buff, 5u, &dwWrittenSize);
        if (!VirtualProtect(addr, 5u, dwOldProtect, &dwOldProtect)) {
            printLastError(GetLastError(), "Failed 2!");
        }
    } else {
        printLastError(GetLastError(), "Failed 1!");
    }

    return true;    
}

void __cdecl log(const char* Format, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9) {
    if (!strstr(Format, "Theme")) {
        char buff1[1024] = {};
        char buff2[1024] = {};
        DWORD* pArgs = (DWORD*)((DWORD)&Format - 4);    //&p是参数栈的地址,&p-4是返回地址

        sprintf_s(buff1, Format, a1, a2, a3, a4, a5, a6, a7, a8, a9);
        sprintf_s(buff2, "[Ra2] %08X %s", pArgs[0], buff1);
        OutputDebugStringA(buff2);
    }
}

byte backupCode[5] = {};
bool TrainerFunctions::OpenLog() {
    OutputDebugStringA("[Ra2] OpenLog");

    void* oldFunc = (byte*)GetModuleHandleA(0) + 0x68E0; // 0x4068E0 是一个空函数,就一个retn
    memcpy(&backupCode, oldFunc, 5u);
    return installHook(oldFunc, (DWORD)&log);
}
#pragma optimize("", on)

运行并hook后,输出的日志信息:

[Ra2] OpenLog    
[Ra2] 00000000 sendto 1.0.0.0 ; 0    
[Ra2] 00000000 Frame 272, Receive packet uncompressed into 0 commmands    
[Ra2] 00000000 Theme::AI(Next song = 0)    
[Ra2] 00000000 Theme::Stop(0)    
[Ra2] 00000000 Theme::PlaySong(0) - Repeating    
[Ra2] 00000000 Theme::AI(Next song = 0)    
[Ra2] 00000000 Theme::Stop(0)    
[Ra2] 00000000 Theme::PlaySong(0) - Repeating    
[Ra2] 00000000 Crate at 96,53 contains 'reveal'
[Ra2] 00000000 Crate at 71,96 contains money
[Ra2] 00000000 Crate at 139,153 contains firepower
[Ra2] 00000000 Crate at 124,76 contains a unit
[Ra2] 00000000 Crate at 96,53 contains speed
[Ra2] 00000000 Crate at 84,167 contains veterancy(TM)
[Ra2] 00000000 Response time = 2    
[Ra2] 00000000 IPX Manager: RetryDelta = 12    
[Ra2] 00000000 MaxAhead is 24    
[Ra2] 00000000 Send_Packets - created packet with 1 commands on frame 384
[Ra2] 00000000 NumSendAck = 4    
[Ra2] 00000000 Received ACK for packet 4    
[Ra2] 00000000 Sending ACK for packet 4 to be forwarded to 00

后续可以结合日志进行分析,比较容易聚焦,提高效率。

通信数据

人机对战不会产生通信数据,人人对战才会有通信数据。

结合日志分析:

sendto 1.0.0.0 ; 0
Send_Packets - added total of 1 commands on frame 384
Frame 384, my sent = 5
Frame 384, Receive packet uncompressed into 1 commmands
Received ACK for packet 4
Sending ACK for packet 4 to be forwarded to 00
Send_Packets - created packet with 1 commands on frame 384
Send_Packets - added total of 1 commands on frame 384

找到:

007B3D4F   .  68 D0E48400   push    0084E4D0                         ;  sendto %d.%d.%d.%d ; %d\n
007B3D54   .  E8 872BC5FF   call    004068E0
007B3D59   .  8B43 10       mov     eax, dword ptr [ebx+10]
007B3D5C   .  8B7424 50     mov     esi, dword ptr [esp+50]
007B3D60   .  83C4 18       add     esp, 18
007B3D63   .  8D5424 20     lea     edx, dword ptr [esp+20]
007B3D67   .  83C0 04       add     eax, 4
007B3D6A   .  8D4B 1C       lea     ecx, dword ptr [ebx+1C]
007B3D6D   .  6A 10         push    10                               ; /ToLength = 10 (16.)
007B3D6F   .  52            push    edx                              ; |pTo
007B3D70   .  6A 00         push    0                                ; |Flags = 0
007B3D72   .  50            push    eax                              ; |DataSize
007B3D73   .  51            push    ecx                              ; |Data
007B3D74   .  56            push    esi                              ; |Socket
007B3D75   .  E8 364C0100   call    <jmp.&WSOCK32.#20>               ; \sendto

地图全开

00481F9D  |> \0FBF56 26     movsx   edx, word ptr [esi+26]
00481FA1  |.  0FBF46 24     movsx   eax, word ptr [esi+24]
00481FA5  |.  52            push    edx
00481FA6  |.  50            push    eax
00481FA7  |.  68 10D08100   push    0081D010                         ;  ASCII "Crate at %d,%d contains 'reveal'",LF
00481FAC  |.  E8 2F49F8FF   call    004068E0                         ;  空函数
00481FB1  |.  8B4D 08       mov     ecx, dword ptr [ebp+8]
00481FB4  |.  83C4 0C       add     esp, 0C
00481FB7  |.  8B91 1C020000 mov     edx, dword ptr [ecx+21C]
00481FBD  |.  B9 E8F78700   mov     ecx, 0087F7E8
00481FC2  |.  52            push    edx
00481FC3  |.  E8 C85D0F00   call    00577D90                         ;  地图全开

2024年1月3日:已验证可行性。

// 全地图内联代码
void Map_Assemble() {
    _asm {
        pushad
        mov eax,0x00A83D4C
        mov edx,[eax]
        mov ecx,0x0087F7E8
        push edx
        mov eax,0x00577D90
        call eax
        popad                      
    }
}

雷达开启

以下汇编仅作过程分析的参考:

00508DF0  /$  C681 79570000>mov     byte ptr [ecx+5779], 0
00508DF7  |.  A1 4C3DA800   mov     eax, dword ptr [A83D4C]
00508DFC  |.  83EC 0C       sub     esp, 0C
00508DFF  |.  3BC8          cmp     ecx, eax
00508E01  |.  0F85 4D010000 jnz     00508F54
00508E07  |.  8B81 B8020000 mov     eax, dword ptr [ecx+2B8]
00508E0D  |.  53            push    ebx
00508E0E  |.  55            push    ebp
00508E0F  |.  56            push    esi
00508E10  |.  8BB1 B0020000 mov     esi, dword ptr [ecx+2B0]
00508E16  |.  57            push    edi
00508E17  |.  83FE FF       cmp     esi, -1
00508E1A  |.  C64424 10 00  mov     byte ptr [esp+10], 0
00508E1F  |.  74 0E         je      short 00508E2F
00508E21  |.  8B15 84EDA800 mov     edx, dword ptr [A8ED84]
00508E27  |.  2BD6          sub     edx, esi
00508E29  |.  3BD0          cmp     edx, eax
00508E2B  |.  7D 0A         jge     short 00508E37
00508E2D  |.  2BC2          sub     eax, edx
00508E2F  |>  85C0          test    eax, eax
00508E31  |.  0F85 F8000000 jnz     00508F2F
00508E37  |>  A1 30B2A800   mov     eax, dword ptr [A8B230]
00508E3C  |.  8A90 A4340000 mov     dl, byte ptr [eax+34A4]
00508E42  |.  84D2          test    dl, dl                           ;  雷达开启判断
00508E44  |.  0F85 E0000000 jnz     00508F2A

2024年1月4日:已验证可行性,一键开启全图和雷达,无须修改指令。

//全地图内联代码
#pragma pack(1)
void Map_Assemble() {
    _asm {
        pushad
        mov eax, 0x00A83D4C
        mov edx, [eax]
        mov ecx, 0x0087F7E8
        push edx
        mov eax,0x00577D90
        call eax
        popad
    }
}

// 雷达全开 [[0x00A8B230] + 0x34A4] = 1
void RadarOn_Assemble() {
    _asm {
        pushad
        mov eax, 0x00A8B230
        mov eax, [eax]
        mov byte ptr [eax + 0x34A4], 0x1
        popad
    }
}

// 判断游戏是否运行
 bool isGameRunning() {
     bool isRunning = false;

     __try {
         _asm {
             pushad
             mov eax, 0x00A83D4C
             mov eax, [eax]
             mov eax, 0x0087F7E8
             mov eax, [eax]
             popad
         }

         isRunning = true;
     } __except (EXCEPTION_EXECUTE_HANDLER) {
         isRunning = false;
     }
     return isRunning;
}

#pragma pack()

调用:

//地图全开
void openAllMap() {
    if (isGameRunning()) {
        Map_Assemble();
        RadarOn_Assemble();
    } else {
        ::Beep(523, 400);    // do
    }
}

其他:

  • 对 00577D90 函数下断点,创建雷达后断下来跟踪。
  • 找到地址: 0x00A83D4C 0x0087F7E8 0x00A8B230 0x34A4 之间的关系和来源,最好能从一个地址出发找到其他地址。

科技全开

参考:

科技树参考(优先以这个为准):

Aircraft [1]-ORCA-Intruder-入侵者战机
Aircraft [2]-HORNET-Hornet-大黄蜂
Aircraft [7]-BEAG-Black Eagle-黑鹰战机
Building [0]-GAPOWR-Allied Power Plant-盟军发电厂
Building [1]-GAREFN-Allied Ore Refinery-盟军矿厂
Building [2]-GACNST-Allied Construction Yard-盟军建造场
Building [3]-GAPILE-Allied Barracks-盟军兵营
Building [4]-GASAND-Sandbags-沙墙
Building [5]-GADEPT-Allied Service Depot-盟军维修厂
Building [6]-GATECH-Allied Battle Lab-盟军作战实验室
Building [7]-GAWEAP-Allied War Factory-盟军战车工厂
Building [8]-CALAB-Einstein's Lab-爱因斯坦实验室
Building [9]-NAPOWR-Soviet Tesla Reactor-磁能反应炉
Building [10]-NATECH-Soviet Battle Lab-苏军作战实验室
Building [11]-NAHAND-Soviet Barracks-苏军兵营
Building [12]-GAWALL-Allied Wall-盟军围墙
Building [13]-NARADR-Soviet Radar Tower-苏军雷达
Building [14]-NAWEAP-Soviet War Factory-苏军战车工厂
Building [15]-NAREFN-Soviet Ore Refinery-苏军矿厂
Building [16]-NAWALL-Soviet Wall-苏军围墙
Building [18]-NAPSIS-Psychic Sensor-心灵感应器
Building [20]-NALASR-Soviet Sentry Gun-哨戒炮
Building [21]-NASAM-Allied Patriot Missile-爱国者飞弹
Building [22]-CASYDN02-Sydney Kangaroo Burger-悉尼袋鼠堡
Building [23]-GAYARD-Allied Shipyard-盟军船厂
Building [24]-NAIRON-Soviet Iron Curtain Device-铁幕装置
Building [25]-NACNST-Soviet Construction Yard-苏军建造场
Building [26]-NADEPT-Soviet Service Depot-苏军维修厂
Building [27]-GACSPH-Allied Chrono Sphere-超时空传送仪
Building [29]-GAWEAT-Allied Weather Controller-天气控制器
Building [30]-CABHUT-Bridge repair hut-桥梁维修小屋
Building [47]-CAHOSP-Old Civilian Hospital-市民医院
Building [53]-TESLA-Soviet Tesla Coil-磁暴线圈
Building [54]-NAMISL-Soviet Nuclear Missile Silo-核弹发射井
Building [55]-ATESLA-Allied Prism Cannon-光棱塔
Building [56]-CAMACH-Tech Machine Shop-科技机器商店
Building [58]-CASYDN03-Sydney Opera House-悉尼歌剧院
Building [59]-AMMOCRAT-Ammo Crates-弹药箱
Building [61]-NAYARD-Soviet Shipyard-苏军造船厂
Building [62]-GASPYSAT-Allied SpySat Uplink-间谍卫星
Building [63]-GAGAP-Allied Gap Generator-裂缝产生器
Building [64]-GTGCAN-Allied Grand Cannon-巨炮
Building [65]-NANRCT-Soviet Nuclear Reactor-核子反应堆
Building [66]-GAPILL-Allied Pill Box-机枪碉堡
Building [67]-NAFLAK-Soviet Flak Cannon-防空炮
Building [68]-CAOUTP-Tech Outpost-科技前哨站
Building [69]-CATHOSP-Tech Hospital-科技医院
Building [70]-CAAIRP-Tech Airport-科技机场
Building [71]-CAOILD-Tech Oil Derrick-科技钻油厂
Building [72]-NACLON-Cloning Vats-复制中心
Building [73]-GAOREP-Allied Ore Processor-矿石精炼器
Building [79]-CANEWY04-Statue of Liberty-自由女神像
Building [80]-CANEWY05-ZZZ World Trade Center-世贸中心
Building [82]-CATECH01-Communications-通讯中心
Building [85]-CAWASH01-White House-白宫
Building [92]-CAMISC01-Barrels-油桶1
Building [93]-CAMISC02-Barrel-油桶2
Building [104]-CAPARS01-Paris Tower-埃菲尔铁塔
Building [105]-GAAIRC-Allied Airforce Command Headquarters-盟军空指部
Building [107]-CAFRMB-Farm Outhouse-移动式厕所
Building [135]-AMRADR-Allied American Airforce Command Headquarters-美国空指部
Building [137]-CAGARD01-Guard Shack-警卫哨
Building [143]-MAYAN-Mayan Prism Pyramid-玛雅金字塔
Building [147]-CAMEX01-Mayan Prism Pyramid-玛雅金字塔
Building [160]-CARUS03-Russain Kremlin Palace-克里姆林宫
Building [179]-CAPARS11-Paris Arc de Triumphe-巴黎凯旋门
Building [181]-CAFARM06-Lighthouse-灯塔
Building [183]-NAPSYB-Psychic Beacon-心灵信标
Building [184]-NAPSYA-Psychic Amplifier-心灵增幅器
Building [186]-CACOLO01-Air Force Academy Chapel Colorado-空军学院礼拜堂
Building [289]-CAMSC13-Derelict Tank-废弃猛犸坦克
Building [313]-CASLAB-Tech Secret Lab-秘密科技实验室
Building [320]-CATRAN03-TRANS FORTRESS-尤里要塞
Building [369]-CAPOWR-Tech Civilian Power Plant-科技电厂
Building [398]-CABUNK03-Concrete Bunker 03-科技混凝土碉堡
Building [399]-CABUNK04-Concrete Bunker 04-科技混凝土碉堡
Building [402]-YACNST-YACNST-尤里建造场
Building [403]-YAPOWR-YAPOWR-生化反应室
Building [404]-YAREFN-YAREFN-奴隶矿场
Building [405]-YABRCK-YABRCK-尤里兵营
Building [406]-YATECH-YATECH-尤里作战实验室
Building [407]-YAWEAP-YAWEAP-尤里战车工厂
Building [408]-NABNKR-NABNKR-战斗碉堡
Building [409]-YAGGUN-YAGGUN-盖特机炮
Building [410]-YAPSYT-YAPSYT-心灵控制塔
Building [411]-NATBNK-NATBNK-坦克碉堡
Building [412]-GAFWLL-GAFWLL-尤里围墙
Building [413]-YAYARD-YAYARD-尤里船坞
Infantry [0]-E1-GI-美国大兵
Infantry [1]-E2-Conscript-动员兵
Infantry [2]-SHK-Shock Trooper-磁暴步兵
Infantry [3]-ENGINEER-Engineer-工程师
Infantry [4]-JUMPJET-Rocketeer-火箭飞行兵
Infantry [5]-GHOST-SEAL-海豹部队
Infantry [6]-YURI-Yuri-尤里
Infantry [7]-IVAN-Crazy Ivan-疯狂伊文
Infantry [8]-DESO-Desolater-辐射工兵
Infantry [9]-DOG-Attack Dog-苏联警犬
Infantry [13]-CTECH-Technician-技师
Infantry [15]-CLEG-Chrono Legionnaire-超时空军团兵
Infantry [16]-SPY-Spy-间谍
Infantry [17]-CCOMAND-Chrono Commando-超时空突击队
Infantry [18]-PTROOP-Psi-Corp Trooper-尤里复制人
Infantry [19]-CIVAN-Chrono Ivan-超时空伊文
Infantry [20]-YURIPR-Yuri Prime-尤里改
Infantry [21]-SNIPE-Sniper-狙击手
Infantry [22]-COW-Animal Cow-奶牛
Infantry [23]-ALL-Animal Alligator-鳄鱼
Infantry [24]-TANY-Tanya-谭雅
Infantry [25]-FLAKT-Flak Trooper-防空步兵
Infantry [26]-TERROR-Terrorist-恐怖分子
Infantry [27]-SENGINEER-Soviet Engineer-苏军工程师
Infantry [28]-ADOG-Allied Attack Dog-盟军警犬
Infantry [29]-VLADIMIR-Vladimir-弗拉基米尔
Infantry [30]-PENTGEN-General Pentagon-五角大楼将军
Infantry [31]-PRES-President-总统
Infantry [32]-SSRV-Secret Service-秘密保镖
Infantry [43]-POLARB-Animal Polar Bear-北极熊
Infantry [44]-JOSH-Animal Monkey-猴子
Infantry [51]-CLNT-Cowboy-Westwood之星
Infantry [52]-ARND-Hero-终结者
Infantry [53]-STLN-Bodybuilder-兰博
Infantry [54]-CAML-Animal Camel-骆驼
Infantry [55]-EINS-Albert Einstein-爱因斯坦
Infantry [56]-MUMY-Evil Mummy-木乃伊
Infantry [57]-RMNV-Romanov-罗曼诺夫
Infantry [58]-LUNR-Lunar Infantry-登月飞行兵
Infantry [59]-DNOA-Animal T-Rex-暴龙
Infantry [60]-DNOB-Animal Bront-恐龙
Infantry [62]-WWLF-Werewolf-狼人
Infantry [65]-BRUTE-BRUTE-狂兽人
Unit [0]-AMCV-Allied Construction Vehicle-盟军移动基地车
Unit [1]-HARV-War Miner-武装采矿车
Unit [2]-APOC-Apocalypse-灾厄坦克
Unit [3]-HTNK-Rhino Heavy Tank-犀牛坦克
Unit [4]-SAPC-Armored Transport-野牛运输艇
Unit [9]-MTNK-Grizzly Battle Tank-灰熊坦克
Unit [10]-HORV-War Miner-武装采矿车
Unit [13]-CARRIER-Aircraft Carrier-航空母舰
Unit [14]-V3-V3 Launcher-V3导弹车
Unit [15]-ZEP-Kirov Airship-基洛夫空艇
Unit [16]-DRON-Terror Drone-恐怖机器人
Unit [17]-HTK-Flak Track-防空履带车
Unit [18]-DEST-Destroyer-驱逐舰
Unit [19]-SUB-Typhoon Attack Sub-台风攻击潜艇
Unit [20]-AEGIS-Aegis Cruiser-神盾巡洋舰
Unit [21]-LCRF-Landing Craft-旅行者运输艇
Unit [22]-DRED-Dreadnought-无畏级导弹舰
Unit [23]-SHAD-BlackHawk Transport-黑鹰直升机
Unit [24]-SQD-Giant Squid-巨型乌贼
Unit [25]-DLPH-Dolphin-海豚
Unit [26]-SMCV-Soviet Construction Vehicle-苏军移动基地车
Unit [27]-TNKD-Tank Destroyer-坦克杀手
Unit [28]-HOWI-Howitzer-西风火炮
Unit [29]-TTNK-Tesla Tank-磁暴坦克
Unit [30]-HIND-Hind Transport-飞碟
Unit [31]-LTNK-Light Tank-轻坦克
Unit [32]-CMON-Chrono Miner(noback)-超时空采矿车
Unit [33]-CMIN-Chrono Miner-超时空采矿车
Unit [34]-SREF-Prism Tank-光棱坦克
Unit [36]-HYD-Sea Scorpion-海蝎
Unit [37]-MGTK-Mirage Tank-幻影坦克
Unit [38]-FV-IFV-多功能步兵车
Unit [40]-VLAD-Vladimir's Dreadnought-弗拉基米尔指挥舰
Unit [41]-DTRUCK-Demolitions Truck-自爆卡车
Unit [52]-CRUISE-Cruise Ship-游轮
Unit [73]-YDUM-YDUM
Unit [83]-PCV-PCV-尤里移动基地车

网上的资料(不一定准确):

[建筑类]
0=GAPOWR;盟军发电厂
1=GAREFN ;盟军矿厂
2=GAPILE ;盟军兵营
3=GAWEAP ;盟军兵工厂
4=GAAIRC ;盟军空军指挥部
5=AMRADR ;美国空军指挥部--AmericanParaDropSpecial
6=GADEPT ;盟军维修厂
7=GAYARD ;盟军船厂
8=GATECH ;盟军实验室
9=GAROBO; 控制中心 ---
10=GAOREP; 矿石精鍊器
11=GAWALL; 盟军围墙
12=GAPILL; 机枪碉堡---Vulcan2
13=NASAM ;爱国者飞弹 --RedEye2
14=GAGAP ;裂缝产生器
15=ATESLA ;光棱塔----PrismShot / PrismSupport
16=GASPYSAT; 间谍卫星
17=GACNST ;盟军建造场
18=GTGCAN ;法国巨炮  GrandCannonWeapon
19=GACSPH ;超时空传送仪 --- ChronoSphereSpecial
20=GAWEAT ;天气控制器 --- LightningStormSpecial
21=GASAND ;沙袋
22=GAGATE_A; 闸门
23=;===苏军======;
24=NAPOWR; 磁能反应炉
25=NAREFN ;苏军矿厂
26=NAHAND; 苏军兵营
27=NAWEAP; 苏军兵工厂
28=NARADR ;苏军雷达 --- SpyPlaneSpecial
29=NADEPT ;苏军维修厂
30=NAYARD ;苏军造船厂
31=NATECH ;苏军实验室
32=NANRCT ;核子反应堆 --- NukePayload
33=NAINDP ;工业工厂
34=NAWALL ;苏军围墙
35=NABNKR ;战斗碉堡
36=NALASR ;哨戒炮--Vulcan
37=NAFLAK ;防空炮--FlakWeapon
38=TESLA ;磁暴线圈 -- CoilBolt / OPCoilBolt
39=NACNST ;苏军建造厂
40=NAIRON ;铁幕 --- IronCurtainSpecial
41=NAMISL ;核弹发射井 -- NukeSpecial
42=NAPSYB ;心灵信标
43=;===尤里======;
44=YAPOWR ;生化反应炉
45=YAREFN ;奴隶矿厂
46=YABRCK ;尤里兵营
47=YAWEAP ;尤里兵工厂
48=NAPSIS ;心灵感应器 --- PsychicRevealSpecial
49=YAYARD ;尤里船厂
50=YAGRND ;部队回收厂
51=YATECH ;尤里实验室
52=GAFWLL ;尤里围墙
53=NATBNK ;坦克碉堡
54=YAGGUN ;盖特机炮
55=YAPSYT ;心灵控制塔----MultipleMindControlTower
56=NACLON ;复制中心
57=YAGNTC ;基因突变器 --- GeneticConverterSpecial
58=YAPPET ;心灵控制器 --- PsychicDominatorSpecial
59=YACNST ;尤里建造场
60=YAROCK ;不明建筑物
61=YACOMD ;尤里指挥中心
62=;===平======;
63=GASAND;沙墙
64=CAAIRP;科技机场---ParaDropSpecial
65=CAOILD;=科技钻油厂
66=CAPARS01;=艾菲尔铁塔
67=CAEAST02;=尤里雕像----PrismShot
68=CATRAN03;=尤里要塞
69=CAEAST01;=复活岛石像

[步兵类代码]
0=E1;美国大兵
1=E2;苏联动员兵
2=SHK;磁爆步兵
3=ENGINEER;盟军工程师
4=JUMPJET;火箭飞行兵
5=GHOST;海豹部队
6=YURI;尤里
7=IVAN;疯狂伊万
8=DESO;生化步兵
9=DOG;苏联军犬
10=CIV1;平民1
11=CIV2;平民2
12=CIV3;平民3
13=CTECH;技师
14=WEEDGUY;防IE挂载(没用)
15=CLEG;超时空兵团
16=SPY;间谍
17=CCOMAND;超时空突击队
18=PTROOP;伞兵
19=CIVAN;超时空伊万
20=YURIPR;尤里改
21=SNIPE;狙击手
22=COW;奶牛
23=ALL ;鳄鱼
24=TANY;谭雅
25=FLAKT;防空步兵
26=TERROR;恐怖分子
27=SENGINEER;苏联工程师
28=ADOG;盟军军犬
29=VLADIMIR;VLADIMIR
30=PENTGEN;PENTGEN
31=PRES;总统
32=SSRV;终级保镖
33=CIVA;德克萨斯平民A
34=CIVB;德克萨斯平民B
35=CIVC;德克萨斯平民C
36=CIVBBP;棒员运动员
37=CIVBFM;海滩肥男
38=CIVBF;海滩女
39=CIVBTM;海滩瘦男
40=CIVSFM;雪中肥男
41=CIVSF;雪中肥女
42=CIVSTM;雪中瘦男
43=POLARB;北极熊
44=JOSH;猴子
45=YENGINEER;尤里工程师
46=GGI;重装大兵
47=INIT;尤里新兵
48=BORIS;鲍裏斯
49=BRUTE;狂兽人
50=VIRUS;病毒狙击手
51=CLNT;快枪手
52=ARND;终结者
53=STLN;蓝波
54=CAML;骆驼
55=EINS;爱因斯坦
56=MUMY;木乃伊
57=RMNV;洛马诺夫总理
58=LUNR;登月火箭兵
59=DNOA;暴龙
60=DNOB;暴龙
61=SLAV;奴隶矿工
62=WWLF;(木乃伊)
63=YDOG;尤里军犬
64=YADOG;尤里军犬
65=CIVFM;海滩肥女

[战车类代码]
0=AMCV;盟军移动基地车
1=HARV;尤里奴隶采矿车
2=APOC;天启坦克
3=HTNK;犀牛坦克
4=SAPC;装甲运输船
5=CAR;汽车
6=BUS;校车
7=WINI;wini
8=PICK;小货车
9=MTNK;灰熊坦克
10=HORV;武装采矿车
11=TRUCKA;货车A
12=TRUCKB;货车B
13=CARRIER;航空母舰
14=V3;V3火箭车
15=ZEP;基洛夫空艇
16=DRON;恐怖机器人
17=HTK;防空履带车
18=DEST;驱逐舰
19=SUB;飓风级战舰
20=AEGIS;宙斯盾战舰
21=LCRF;盟军运输船
22=DRED;无畏级战舰
23=SHAD;夜鹰直升机
24=SQD;乌贼
25=DLPH;海豚
26=SMCV;苏联移动机基车
27=TNKD;坦克杀手
28=HOWI;榴弹炮
29=TTNK;磁爆坦克
30=LTNK;轻坦克
31=CMON;超时空采矿车(不回)
32=CMIN;超时空采矿车
33=SREF;光棱坦克
34=XCOMET;位置标定器
35=HYD;海蝎
36=MGTK;幻影坦克
37=FV;多功能步兵车
38=VLAD;维拉迪摩指挥舰
39=DTRUCK;自爆卡车
40=PROPA;宣传车
41=CONA;挖掘机
42=COP;cop
43=EUROC;欧洲汽车
44=LIMO;豪华轿车
45=STANG;小轿车
46=SUVB;小汽车A
47=SUVW;小汽车B
48=TAXI;出租车
49=PTRUCK;货车C
50=CRUISE;巡游船
51=TUG;拖船
52=CDEST;海岸巡逻船
53=YHVR;尤里气垫船
54=PCV;尤里机动基地车
55=SMIN;尤里奴隶矿厂
56=SMON;超时空采矿车
57=YCAB;黄色计程车
58=YTNK;盖特炮坦克
59=BFRT;战斗要塞
60=TELE;磁电坦克
61=CAOS;神经突袭车
62=DDBX;巴士
63=BCAB;黑色计程车
64=BSUB;雷鸣潜艇
65=SCHP;武装直升机
66=JEEP;卡车
67=MIND;精神控制车
68=DISK;镭射幽浮
69=UTNK;激光坦克
70=ROBO;遥控坦克
71=SCHD;武装直升机
72=DOLY;摄影车
73=CBLC;电车
74=FTRK;救火车
75=AMBU;救护车
76=CIVP;民航机
77=V3V3;V3火箭车
78=TURCKB;货车B

[飞机类代码]
0=APACHE;阿帕奇
1=ORCA;入侵者战机
2=HORNET;大黄蜂
3=V3ROCKET;V3火箭
4=ASW;舰载反潜机
5=DMISL;无畏级导弹
6=PDPLANE;运输机
7=BEAG;黑鹰战机
8=BPLN;米格战机(鲍里斯的飞机)
9=SPYP;侦察机
10=CMISL;雷鸣导弹
void _openTechOne(int objType, int index) {
    _asm {
        pushad
        mov ecx, 0x0087F7E8
        push index
        push objType
        mov eax, 0x006A6300
        call eax
        popad
    }
}

void _openTechAll(int objType, int count) {
    _asm {
        pushad
        xor esi, esi
    label:
        push esi
        push objType            // 0x7是建筑;0x10(也可能是0xF)是步兵;0x28是车船;0x1F=武器
        mov ecx, 0x0087F7E8
        mov eax, 0x006A6300
        call eax
        inc esi
        cmp esi, count            // 可以填一个编号上限值,参考上述ini
        jle label
        popad
    }
}

// 科技全开
void OpenTech() {
    //_openTechAll(7, 69);                // 建筑全开
    //_openTechAll(0x10, 30);            // 步兵全开
    //_openTechAll(0x28, 40);            // 坦克全开

    _openTechOne(0x28, 0);        // 盟军基地车
    _openTechOne(0x28, 26);    // 苏军基地车
    //_openTechOne(0x28, 54);            // 尤里基地车

    _openTechOne(0x28, 2);        // 天启
    _openTechOne(0x28, 14);    // V3
    //_openTechOne(0x28, 15);    // 基洛夫
    _openTechOne(0x28, 16);    // 恐怖机器人(蜘蛛)
    _openTechOne(0x28, 27);    // 坦克杀手
    _openTechOne(0x28, 34);    // 光棱坦克
    _openTechOne(0x28, 36);    // 幻影
    _openTechOne(0x28, 37);    // 多功能
}

科技开启后游戏主程序会自动恢复,防止恢复的简单做法是跳过恢复,将如下指令修改为jmp

006AA788  |. /0F85 DA020000 |jnz     006AAA68        ;; 测试有效

或者,用CE使用如下注入代码:

[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,64)
label(returnhere)
label(originalcode)
label(exit)
newmem: //this is allocated memory, you have read,write,execute access
//place your code here
jmp 004F7B96
originalcode:
mov ecx,[00A8B238]
exit:
jmp returnhere
"{proc}"+F7B6C:
jmp newmem
nop
returnhere:
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"{proc}"+F7B6C:
mov ecx,[00A8B238]
//Alt: db 8B 0D 38 B2 A8 00

写了一个防科技全开恢复的补丁(在项目MatchBin中编译),这个工具是通用的,需配置patch.ini文件:

[main]
tag=ra2
path=D:\Ra2Game412\gamemd-spawn.exe

运行后输出如下日志代表成功:

tag: ra2
path: D:\Ra2Game412\gamemd-spawn.exe
Done! time used: 0.132713 ms

补丁的主要功能代码为:

void PEFilePatcher::PatchRa2(const wchar_t* inFilePath) {
 PEFilePatcher patcher(inFilePath);
 const uint8_t newValue[] = { 0xE9, 0xDB, 0x02, 0x00, 0x00, 0x90 };
 patcher.patch(0x006AA788, newValue, sizeof(newValue));
}

心灵探测

判断是否有选中单位(选中的单位数量大于零),然后判断单位是否是建筑物类型(通过对象虚函数表),然后对单位的某个属性字段做修改(具体看代码),心灵探测的字段为一个word类型,因此最大的有符号正数是0x7FFF。使用时,要选中一下建筑。

这个代码可能会出现内存访问读写异常,须加上异常处理机制。

// 开启心灵探测
void OpenPsychicDetection() {
	__try {
		_asm {
			pushad
			mov eax, 0x00A8ECC8
			mov eax, [eax]					//选中单位的数量
			cmp eax, 0						//是否有选中单位
			je exit1
			mov eax, 0x00A8ECBC
			mov eax, [eax]
			mov eax, [eax]					// +0
			mov eax, [eax]					// +0
			cmp eax, 0x007E3EBC				// Building vt
			jnz exit1
			mov eax, 0x00A8ECBC
			mov eax, [eax]
			mov eax, [eax]					// +0
			mov eax, [eax + 0x520]			// +0x520
			mov word ptr[eax + 0x170C], 0x7FFF	// 0x170C PsychicDetectionRadius
		exit1:
			popad
		}
	} __except (EXCEPTION_EXECUTE_HANDLER) {
	}
}

无限信标

联网对战的时候最多只能放置三个信标,当超过三个时需要把多余的删除掉才能放置新的信标,这样就会造成一个麻烦:战况激烈的时候,想放置信标的时候放置不了,还需要在地图上删除一个信标才能继续放置。

004FC1C6: sub_431410(dword_89C3B0, *(_DWORD *)(dword_A83D4C + 0x30));

只要模拟调用即可,汇编代码:

// 清除信标:一次批量清除玩家自己的3个信标
// 004FC1C6: sub_431410(dword_89C3B0, *(_DWORD *)(dword_A83D4C + 0x30));
void ClearBeacons() {
    _asm {
        pushad
        mov     eax, 0x00A83D4C
        mov     eax, [eax]
        mov     eax, [eax + 0x30]
        push    eax
        mov     ecx, 0x0089C3B0
        mov eax, 0x00431410
        call eax
        popad
    }
}

自动维修

#include "windows.h"
#include "Utils.h"
#include "Config.h"
#include "Ra2Helper.h"
#include <EventClass.h>
#include <HouseClass.h>


#pragma pack(1)

// YRpp 函数重载有问题,这里再写一遍
void MakeEventClass(EventClass* eventClass, int houseIndex, EventType eventType, int id, int rtti) {
	int typeId = static_cast<int>(eventType);
	__asm {
		pushad
		push rtti
		push id
		push typeId
		push houseIndex
		mov ecx, eventClass
		mov eax, 0x004C65E0
		call eax
		popad
	}
}

#pragma pack()

// .text:004AC0D8
void RepairNextBuilding() {
	int count = 0;
	for (int i = 0; i < HouseClass::CurrentPlayer->Buildings.Count; i++) {
		BuildingClass* building = HouseClass::CurrentPlayer->Buildings.GetItem(i);
		if (!building->IsBeingRepaired && building->Health < building->GetType()->Strength) {
			//if (building->Health / building->GetType()->Strength < 0.7f) {
			EventClass repairEvent(0, 0);
			MakeEventClass(&repairEvent, HouseClass::CurrentPlayer->ArrayIndex, EventType::Repair,
				static_cast<int>(building->UniqueID), static_cast<int>(AbstractType::Abstract));
			EventClass::AddEvent(repairEvent);
			
			if ((++count) >= Config::GetAutoRepairCount()) {
				break;
			}
		}
	}
}

// 开启自动修理功能
void AutoRepair() {
	Utils::Log("Auto Repairing");
	RepairNextBuilding();
}

如意宝箱

参考:

分析思路:

  1. OD导入,分析字符串,相关联的字符串释义如下:

    veterancy          # 老兵
    veteran          # 老兵
    base healing    # 加血
    

    找到如下的信息:

    00481EA3   push    0081D058                          crate at %d,%d contains tiberium\n
    00481F77   push    0081D034                          crate at %d,%d contains 'shroud'\n
    00481FA7   push    0081D010                          crate at %d,%d contains 'reveal'\n
    0048204B   push    0081CFF0                          crate at %d,%d contains a unit\n
    0048246F   push    0081CFD0                          crate at %d,%d contains money\n
    0048256F   push    0081CFAC                          crate at %d,%d contains explosives\n
    00482728   push    0081CF8C                          crate at %d,%d contains napalm\n
    0048284A   push    0081CF60                          crate at %d,%d contains cloaking device\n
    0048297C   push    0081CF38                          crate at %d,%d contains veterancy(tm)\n
    00482B99   push    0081CF10                          crate at %d,%d contains base healing\n
    00482CAB   push    0081CEF0                          crate at %d,%d contains icbm\n
    00482D60   push    0081CED0                          crate at %d,%d contains armor\n
    00482EB6   mov     ecx, 0081CEB8                     eva_unitarmorupgraded
    00482F40   push    0081CE98                          crate at %d,%d contains speed\n
    004830A5   mov     ecx, 0081CE80                     eva_unitspeedupgraded
    0048312F   push    0081CE5C                          crate at %d,%d contains firepower\n
    

    veterancy为例,定位到相关汇编代码:

    00482972  |> \0FBF46 26     movsx   eax, word ptr [esi+26]
    00482976  |.  0FBF4E 24     movsx   ecx, word ptr [esi+24]
    0048297A  |.  50            push    eax
    0048297B  |.  51            push    ecx
    0048297C  |.  68 38CF8100   push    0081CF38                         ;  crate at %d,%d contains veterancy(tm)\n
    00482981  |.  E8 5A3FF8FF   call    004068E0
    

    00482972表明这个从其他地方跳转过来的,找到跳转源头:

    00481DE0  |.  FF2495 C43348>jmp     dword ptr [edx*4+4833C4]
    
  2. 分析地址 4833C4 ,是一个跳转表:

    004833C4  00482463    ; crate at %d,%d contains money\n
    004833C8  00482041    ; crate at %d,%d contains a unit\n
    004833CC  00482B8F    ; crate at %d,%d contains base healing\n
    004833D0  00482840    ; crate at %d,%d contains cloaking device\n
    004833D4  00482565    ; crate at %d,%d contains explosives\n
    004833D8  0048271E    ; crate at %d,%d contains napalm\n
    004833DC  004832F5    ; ???
    004833E0  00481F6D    ; crate at %d,%d contains 'shroud'\n
    004833E4  00481F9D    ; crate at %d,%d contains 'reveal'\n
    004833E8  00482D56    ; crate at %d,%d contains armor\n
    004833EC  00482F36    ; crate at %d,%d contains speed\n
    004833F0  00483125    ; crate at %d,%d contains firepower\n
    004833F4  00482CA1    ; crate at %d,%d contains icbm\n
    004833F8  004832F5     ; ???
    004833FC  00482972    ; crate at %d,%d contains veterancy(tm)\n
    00483400  004832F5     ; ???
    00483404  00481DE7    ; crate at %d,%d contains poison gas\n
    00483408  00481E99    ; crate at %d,%d contains tiberium\n
    0048340C  90909090    ; nop
    

    一共有0x12个地址((0048340C - 004833C4) / 4),逐一在反汇编窗口中跟随查看地址,并对应一下功能。

实现思路:

  1. 对地址4833C4起始的0x12个四字节内容统一修改为想要的功能地址表。例如想要金钱效果,当按下热键时全部修改为0x00482463,然后再去捡箱子,则无论是什么箱子都会执行的是捡到金钱的效果。

  2. 类推,可以设计一个主要的热键功能:

    金钱    00482463
    加血    00482B8F
    经验    00482972
    防御    00482D56
    火力    00483125
    速度    00482F36
    

实现代码:

// 所有捡箱子效果:金钱
void TrainerFunctions::SetBoxAllMoney() {
    const LPVOID MethodTableAddr = (LPVOID)0x004833C4;
    const size_t MethodTableCount = 0x12;
    const SIZE_T MethodTableSize = MethodTableCount * sizeof(DWORD);
    const DWORD JumpToAddr = 0x00482463;    // 捡到的是金钱的跳转地址

    // 修改代码保护属性
    DWORD dwOldProtect = 0;
    if (VirtualProtect(MethodTableAddr, MethodTableSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)) {

        DWORD* p = (DWORD*)MethodTableAddr;
        for (size_t i = 0; i < MethodTableCount; i++) {
            *(p + i) = JumpToAddr;
        }

        // 恢复代码保护属性
        if (!VirtualProtect(MethodTableAddr, MethodTableSize, dwOldProtect, &dwOldProtect)) {
            printLastError(GetLastError(), "Failed 2!");
        }
    } else {
        printLastError(GetLastError(), "Failed 1!");
    }
}

验证效果:

  1. 单机玩有效果,但是联网对战不行,会卡,可能是触发了什么机制。

如何使用

编译项目 Ra2Tool ,使用任意注入工具把 Ra2Dll.dll 模块注入到游戏进程即可(RATrainer 用不到)。

如果使用HookLoader工具,可以参考如下使用步骤:

【使用说明】 1、运行exe 2、进入游戏之后按下快捷键【ALT + H】即可,一定要进入游戏,保险起见是在出现基地之后,其他场景没测试过。

【作者有话】 全图功能我认为对级别低的玩家比较有帮助,对级别高的玩家帮助没有那么大。其他影响游戏平衡的变态功能全部删除了,只保留了全图这个功能,不然就没有可玩性了。

内存地址

  • 0x00A83D4C :玩家。 [0x00A83D4C] + 0x30 是玩家ID。
  • 0x00A8022C :
  • 0x00A8ECBC : 选中的单位有关。[0x00A8ECBC]是选中单位的数组地址。如果要遍历选择的单位,则结合个数,每次取一个四字节,就是具体单位对象的地址。
  • 0x00A8ECC8 : 选中单位的数量,也即:0x00A8ECBC + 0x0C
  • 0x6C : 单位血量。
  • 0x150 :等级。无星是0,三星是:0x40000000。
  • 0x21C :单位归属。
  • 0x584 : 疑似速度。
  • 0x007E3EBC:建筑物的虚函数表地址,可以通过虚函数表是否是该值来判断对象是否是建筑物。

单机功能

可以参考:AdjWang/RA2YurisRevengeTrainer: 红色警戒2 尤里的复仇v1.001 内存修改器 ,主要是单机版可用的功能,联网对战中很多功能不可用,主要是借鉴参考。

  • 游戏速度:0x00A8EB60 地址的内容是速度(4字节)。

  • 金钱:[0x00A83D4C] + 0x30C 地址的内容是金钱(4字节)。

  • 快速建造:[0x00A83D4C] + 0x5378 地址起始的连续 5 个四字节内容是速度,修改为15可以实现快速建造。

  • 删除选中的单位:

    __asm {
        pushad
        mov eax,0x00A8ECC8
        mov eax,[eax]    //选中单位数量
        cmp eax,0        //是否选中单位
        je exit1
      
        mov eax,0x00A8ECBC
        mov eax,[eax]
        mov ecx,[eax]
        mov eax,[ecx]
        add eax,0xF8
        mov ebx,[eax]
        call ebx
      
        exit1:
        popad
    }
    
  • 选中单位归属为我:

    __asm
    {
        pushad
            mov eax,0x00A8ECC8    //选中单位数量
            mov eax,[eax]
            cmp eax,0            //是否选中单位
            je exit1
            push 0                //
            mov ebx,0x00A83D4C
            mov eax,[ebx]
            push eax
            mov ebx,0x00A8ECBC
            mov eax,[ebx]
            mov ecx,[eax]
            mov ebx,[ecx]
            add ebx,0x3D4
            mov ebx,[ebx]
            call ebx
            exit1:
        popad
    }
    
  • 选中单位升级:

    __asm
    {
        pushad
            mov eax,0x00A8ECBC
            mov ebx,[eax]        //选中单位首地址
            mov eax,0
      
            process:
        mov ecx,0x00A8ECC8
            cmp eax,[ecx]        //选中单位数量为零判断
            jge brek            //>=跳转
            mov ecx,[ebx+eax*4]    //当前单位地址
            mov edx,0x40000000    //三星的数值
            add ecx,0x150
            mov [ecx],edx        //修改单位经验
            add eax,1
            jmp process
      
            brek:
        popad
    }
    

无限金钱

void GiveMeMoney() {
	_asm {
		pushad
		mov eax, 0x00A83D4C
		mov eax, [eax]
		mov dword ptr[eax + 0x30C], 0x7FFFFFFF
		popad
	}
}

高级玩法

  1. 使用 Phobos-developers/YRpp 作为SDK。例如坦克单位的上述内存地址偏移,可以通过头文件 FootClass 及其父类层层查看对应偏移的字段说明,能对应的上 ,其他属性可以通过源码来判断其偏移地址。在编写工具的时候,开发阶段可以直接使用这些头文件,获取到的地址关联到对应的对象,就可以直接使用了,不需要自己计算地址的硬编码了,很是方便。
  2. 使用 CnCNet 搭建联网对战平台。这个有兴趣的可以玩玩,也可以参考其源码学习如何打补丁的。

参考

文档信息

Search

    Table of Contents