AdjWang / RA2YurisRevengeTrainer

红色警戒2 尤里的复仇v1.001 内存修改器
85 stars 8 forks source link

【建议】如意宝箱 #30

Open bigsinger opened 2 months ago

bigsinger commented 2 months ago

箱子目前是随机效果,可以实现一个如意宝箱的效果,就是想来啥来啥。这个目前在单机版已经实现了,可以用,代码如下:

// 所有捡箱子的效果:金钱
void 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)) {
            OutputDebugString("Failed 2!");
        }
    } else {
        OutputDebugString("Failed 1!");
    }
}

其他捡箱子效果可以参考这个来设计。这样当缺钱的时候,就按下按键让所有捡箱子效果是金钱,当需要升级部队时按下某个按键让捡箱子效果都是升级,以此类推……

另:这个功能在联网对战中会卡死,不知道啥原因,有知道的吗?

AdjWang commented 1 month ago

联网模式改 text 段会有两个问题,一个是被反作弊扫描到;另一个是产生平行世界,除非把所有人的同时都改了。

bigsinger commented 1 month ago

联网模式改 text 段会有两个问题,一个是被反作弊扫描到;另一个是产生平行世界,除非把所有人的同时都改了。

如果在内存中找到存放箱子列表的地址呢?然后修改箱子数据的属性,是不是就可以实现?

参考这个文章:红色警戒2-尤里复仇之自动全图捡箱子,里面提到「所有箱子坐标」,应该能找到箱子的列表。 image

bigsinger commented 1 month ago

从下面的代码可以看出,esi应该是箱子对象相关,动态调试时给拦截下来看一下:

00481DE0  |.  FF2495 C43348>jmp     dword ptr [edx*4+4833C4]
00481DE7  |>  0FBF46 26     movsx   eax, word ptr [esi+26]
00481DEB  |.  0FBF4E 24     movsx   ecx, word ptr [esi+24]
00481DEF  |.  50            push    eax
00481DF0  |.  51            push    ecx
00481DF1  |.  68 80D08100   push    0081D080                         ;  crate at %d,%d contains poison gas\n
00481DF6  |.  E8 E54AF8FF   call    004068E0

如下地址不确定是否跟箱子数据有关,动态调试的时候看下:

00481A28  |.  8B0D 843DA800 mov     ecx, dword ptr [A83D84]

00481A3F  |.  8B15 38B2A800 mov     edx, dword ptr [A8B238]

00481A95  |.  A1 48E78900   mov     eax, dword ptr [89E748]

00481D5B  |.  8A83 C0EC8900 mov     al, byte ptr [ebx+89ECC0]
AdjWang commented 1 month ago

联机有数据一致性要求,本地数据修改必须直接或者间接发送给所有玩家,保持多人游戏状态同步。自动捡箱子功能会把对单位的操作也发给别的玩家,没有不一致问题。对箱子内容的修改无法发送给别的玩家,会导致多客户端数据不一致,俗称平行世界…… 就拿你之前提的几个建议来举例,改 GUI,放大小地图不需要主动同步,配置进攻策略,工程师自动抢修,自动维修,巨炮有顺序攻击,巨炮自动转向都需要主动同步,有些同步可能调了接口引擎就自动发了数据,接口上面看不到但是网络数据上有。

bigsinger commented 2 weeks ago

倒也不是不可行,要看修改的时机。

猜想:

可以在触碰箱子的时候,修改箱子的处理效果函数,例如修改为升级效果,之后的逻辑不动,则发送数据到服务端的逻辑仍然是通的。 也即修改的操作在发送数据之前应该是可行的。

@AdjWang

bigsinger commented 2 weeks ago

看下这块代码,动态调试下看看时机和箱子属性。

00481A00  /$  55            push    ebp
00481A01  |.  8BEC          mov     ebp, esp
00481A03  |.  83E4 F8       and     esp, FFFFFFF8
00481A06  |.  81EC 7C010000 sub     esp, 17C
00481A0C  |.  53            push    ebx
00481A0D  |.  56            push    esi
00481A0E  |.  57            push    edi
00481A0F  |.  8B7D 08       mov     edi, dword ptr [ebp+8]
00481A12  |.  85FF          test    edi, edi
00481A14  |.  8BF1          mov     esi, ecx
00481A16  |.  0F84 6D190000 je      00483389
00481A1C  |.  8B46 44       mov     eax, dword ptr [esi+44]
00481A1F  |.  83F8 FF       cmp     eax, -1
00481A22  |.  0F84 61190000 je      00483389
00481A28  |.  8B0D 843DA800 mov     ecx, dword ptr [A83D84]
00481A2E  |.  8B1481        mov     edx, dword ptr [ecx+eax*4]
00481A31  |.  8A9A AA020000 mov     bl, byte ptr [edx+2AA]
00481A37  |.  84DB          test    bl, bl
00481A39  |.  0F84 4A190000 je      00483389
00481A3F  |.  8B15 38B2A800 mov     edx, dword ptr [A8B238]
00481A45  |.  C64424 13 00  mov     byte ptr [esp+13], 0
00481A4A  |.  85D2          test    edx, edx
00481A4C  |.  C74424 14 000>mov     dword ptr [esp+14], 0
00481A54  |.  74 17         je      short 00481A6D
00481A56  |.  8B97 1C020000 mov     edx, dword ptr [edi+21C]
00481A5C  |.  8B52 34       mov     edx, dword ptr [edx+34]
00481A5F  |.  8A9A A6010000 mov     bl, byte ptr [edx+1A6]
00481A65  |.  84DB          test    bl, bl
00481A67  |.  0F85 1C190000 jnz     00483389
00481A6D  |>  8B0481        mov     eax, dword ptr [ecx+eax*4]
00481A70  |.  8A88 AB020000 mov     cl, byte ptr [eax+2AB]
00481A76  |.  84C9          test    cl, cl
00481A78  |.  74 4E         je      short 00481AC8
00481A7A  |.  8B47 34       mov     eax, dword ptr [edi+34]
00481A7D  |.  85C0          test    eax, eax
00481A7F  |.  74 3A         je      short 00481ABB
00481A81  |.  0FBF4E 26     movsx   ecx, word ptr [esi+26]
00481A85  |.  0FBF56 24     movsx   edx, word ptr [esi+24]
00481A89  |.  51            push    ecx
00481A8A  |.  52            push    edx
00481A8B  |.  68 A4D08100   push    0081D0A4                         ;  springing trigger on crate at %d,%d\n
00481A90  |.  E8 4B4EF8FF   call    004068E0
AdjWang commented 1 week ago

从箱子生成到单位拾取箱子过程中,只有对单位的移动指令会发送给服务器,其他的都是计算出来的。发送到服务器的内容有限,事件类型定义在 https://github.com/Phobos-developers/YRpp/blob/phobos-dev/GeneralDefinitions.h#L1370。 具体到这个例子,假如两个人在线上,双方的游戏配置共同的随机数种子,时钟就是游戏从开始时候累计的帧数,"在第1000帧随机生成升级箱子"这个事件是计算出来的,因为随机数和帧数计算结果一致,所以不发送网络数据双方也是同步的。 只有玩家输入的操作,比如建造、移动单位、攻击这些无法通过随机数和时钟计算得到的事件,才会发到服务器上。

bigsinger commented 1 week ago

@AdjWang 那就比较困惑了:

  1. 不会出现同步问题吗?这个机制相当于是玩家各自捡自己客户端随机生成的箱子,如何做到数据同步的?
  2. 如果某个客户端进行欺骗操作:生成一个箱子呢?
  3. 单位拾取箱子是服务器来计算的?根据玩家的单位距离箱子的远近和碰撞来计算是谁拾取了箱子?然后分发数据给所有客户端?
bigsinger commented 1 week ago

我大概理解下: 所有玩家拥有所有地图和所有单位的所有数据,各自客户端各自计算自己的,因为数据和算法一致,所以结果也是一致的,不会出现同步问题。

有点类似区块链的思想,每个客户端都在计算,都有全量数据。

如果按照这个思路的话,似乎如意宝箱就很难实现了,但是似乎强制修改数据有实现的可能,修改后锁死并同步出去,有机会可以将所有玩家的数据给刷回去。

AdjWang commented 1 week ago

我大概理解下: 所有玩家拥有所有地图和所有单位的所有数据,各自客户端各自计算自己的,因为数据和算法一致,所以结果也是一致的,不会出现同步问题。

有点类似区块链的思想,每个客户端都在计算,都有全量数据。

如果按照这个思路的话,似乎如意宝箱就很难实现了,但是似乎强制修改数据有实现的可能,修改后锁死并同步出去,有机会可以将所有玩家的数据给刷回去。

是这样的。

  1. 只要随机数种子一样,调用随机数函数的结果序列就是一样的。
  2. 单个客户端自行改变箱子数据会导致多客户端数据不一致。
  3. 单位拾取箱子是客户端计算的。客户端先生成箱子,之后玩家在客户端发起单位移动事件(MEGAMISSION),移动事件发送服务器并广播到所有客户端,然后所有客户端的单位接收移动事件,前往箱子位置拾取箱子。