魔兽3内存修改器V5 For 1.22.0.6328,以及智力修改详解

距离上一次写魔兽修改器(V4在这里)已经有超过一年半的时间了, 这个期间有不少网友来信,但是我完全没有要再写一版的意思。包括像出现在本Blog的hyp发布了他自己的修改器(这里),包括暴雪出了1.22补丁,我都没有改。直到另一位网友给我写信(他没有留言,我假设他不希望自己的名字出现在这里)声称他已经能找到所有单位的HP为止,我顿时 愤怒了 对他刮目相看! war3trainerv5.gif于是我想写一个集大成的修改器,可以模拟整个游戏界面,看到地图上的所有单位,可以点击任何想改的数据然后改掉,切换到游戏时已经改好……做一个这样的修改器好像难度也不会很大,但是我还很忙,所以就不要这么麻烦了(雾很大)。

这两天我趁glascholar同学帮我去解决电脑上没有导出并口接插件并且寄到苏州来的空档,做了这个V5修改器来针对1.22.0.6328版的Warcraft 3。为了避免与hyp同学重复,我依然没有用内存搜索的方法来做,而是坚持了我以前的游戏代码篡改的思路。但是与V4不同的是,我花了很大力气实现了只注入一次就能修改全部属性的特性。也就是说:我已经解决了单位各属性地址之间的关系。所以其他人也应该可以根据我的理论实现自己的内存搜索版的修改器。

修改器+源代码+手册打包:war3trainerv5.rar

[特性]

  • V5版修改器具有以下特性:
  • 仅适用于魔兽3 1.22.0.6328,其他版本不用试也知道不行
  • 可以修改前10个玩家的钱,并且不用注入就能修改
  • 可以修改英雄的一些属性,每个英雄只需要注入一次,其他地址可以推算
  • V5的注入对一般单位无效,这反而变成V5修改器的缺陷,而V4版是可以改一般单位的。因为唯一的一次注入放在了英雄状态栏绘制的函数里面,而V4版是每个属性单独注入一次,所以没有这个问题。如果我愿意放下自尊,不去搞什么“只注入一次”的话,就可以解决这个问题,但是这样就无法炫耀技术了,对吧?
  • 智力修改完美解决,现在不可能找不到智力的地址了
  • 新增HP、MP,及其最大值的修改

[详解智力修改]
在V2版(这里)中,我曾经给过一个傻x的修改方案,现在给出更加精确的算法。为什么智力的修改与力量、敏捷不同。这是因为后两者的代码比较集中,而且代码也比较规则。例如力量的绘制代码如下:

6F353D7D   mov ecx, [ebp+0D4h] eHeroMultiply = *(pAttribute1 + 0x35);
6F353D83   mov esi, [ebp+94h] vHeroPower = *(pAttribute1 + 0x25);
6F353D89   mov [esp+8ECh+eHeroMultiply], ecx
6F353D8D   lea ecx, [ebp+6Ch] vPowerAdd = sub_6F4634E0(pAttribute1 + 0x1B);
6F353D90   call sub_6F4634E0
6F353D95   lea edx, [esp+8ECh+eHeroMultiply]
6F353D99   push edx
6F353D9A   mov edx, eax ePowerAdd = ZipNum_Encode_NotSure(&tmpInt1, vPowerAdd);
6F353D9C   lea ecx, [esp+8F0h+tmpInt1]
6F353DA0   call ZipNum_Encode_NotSure
6F353DA5   mov edx, eax ePowerSum = ZipNum_Multiply_NotSure(&tmpInt2, ePowerAdd, &eHeroMultiply);
6F353DA7   lea ecx, [esp+8F0h+tmpInt2]
6F353DAB   call ZipNum_Multiply_NotSure
6F353DB0   mov ecx, eax vPowerSum = ZipNum_Decode_NotSure(ePowerSum);
6F353DB2   call ZipNum_Decode_NotSure
6F353DB7   add eax, esi s578_SStrPrintf(
Buffer1,
0x40u
,
"%d"
,
vHeroPower
+ vPowerSum - *AttributeBiasCopy1
);
6F353DB9   sub eax, [ebx]
6F353DBB   push eax
6F353DBC   push offset aD_0 ; "%d"
6F353DC1   lea eax, [esp+8F4h+Buffer1]
6F353DC5   push 40h ; BufferSize
6F353DC7   push eax ; Buffer
6F353DC8   call s578_SStrPrintf
6F353DCD   mov esi, [ebx]
6F353DCF   mov ecx, [esp+8FCh+GBufferCopy1] GBufferCopy2 = GBufferCopy1;
6F353DD3   add esp, 10h
6F353DD6   add esi, [ecx] sumPower = *GBufferCopy1 + *AttributeBiasCopy1;
if
( sumPower )
{
6F353DD8   jz short loc_6F353E1B
6F353DDA   test esi, esi
6F353DDC   mov eax, offset aCff00ff00_1 ; " |CFF00FF00+"     tmpString1 = " |CFF00FF00+";
6F353DE1   jg short loc_6F353DE8     if ( sumPower<= 0 )
6F353DE3   mov eax, offset aCffff0000_1 ; " |CFFFF0000" tmpString1 = " |CFFFF0000";
6F353DE8   push 40h ; MaxLength     s503_SStrNCat(Buffer1, tmpString1, 0x40u);
6F353DEA   push eax ; pSrc
6F353DEB   lea edx, [esp+8F4h+Buffer1]
6F353DEF   push edx ; pDest
6F353DF0   call s503_SStrNCat
6F353DF5   push esi     s578_SStrPrintf(Buffer2, 0x40u, "%d|R", sumPower);
6F353DF6   push offset aDR ; "%d|R"
6F353DFB   lea eax, [esp+8F4h+Buffer2]
6F353DFF   push 40h ; BufferSize
6F353E01   push eax ; Buffer
6F353E02   call s578_SStrPrintf
6F353E07   add esp, 10h     s503_SStrNCat(Buffer1, Buffer2, 0x40u);
6F353E0A   push 40h ; MaxLength
6F353E0C   lea ecx, [esp+8F0h+Buffer2]
6F353E10   push ecx ; pSrc
6F353E11   lea edx, [esp+8F4h+Buffer1]
6F353E15   push edx ; pDest
6F353E16   call s503_SStrNCat }

智力的代码在6F0DA9D0,内存位置不完全相同,感兴趣可以去看,本质上还是一样的。下面的步骤供修改器使用。但是我要说,如果只注入一次的话,最难改的不是智力,而是移动速度的话,你相信吗?这件事情详见附件里面的手册。这里讲智力。

第1步:搞到英雄的基址,可以在6F353D25拿到ESI,并且解开(即所谓解引用,或者寻址),并且做如下定义:
ESI记为ThisUnit
○ [ThisUnit + 1E4] 记为 UnitAttributes(这里用不到,改别的东西要用)
○ [ThisUnit + 1EC] 记为 HeroAttributes

这个1EC是怎么来的呢?
参考的代码:6F353D00
即:int __thiscall DrawHeroProperty(int *GameContext, int **Attributes, int *AttributeBias, unsigned int *GBuffer)

6F353D51 mov ebp, [eax + 1ECh] pAttribute = Attributes[0x7B]; // 7B * 4 = 1EC
…… …… ……
6F353EDE mov ecx, ebp vIntellect = getHeroIntellect_NotSure(pAttribute);
6F353EE0 call 6F0DA9D0

第2步:获得智力的游戏全局索引,定义:
○ [HeroAttributes + 7C + 2 * 4] 记为 Index1
○ [HeroAttributes + 7C + 3 * 4] 记为 ReferenceNumber1

参考的代码:6F0DA9D0
即:int __fastcall getHeroIntellect_NotSure(int* pAttribute)

6F0DA9DE lea ecx, [esi + 7Ch] vHeroIntellect = sub_6F4634E0(pAttribute + 0x1F);
// 1F * 4 = 7C
6F0DA9E1 call 6F4634E0

参考的代码:6F4634E0
即:int __fastcall sub_6F4634E0(int *base)

6F4634E0 mov edx, [ecx + 0Ch] return *(_DWORD *)(
getValueFromGame
(*(base + 2), *(base + 3))
+ 0x78
);
6F4634E3 mov ecx, [ecx + 8]
6F4634E6 call 6F03F180
6F4634EB mov eax, [eax + 78h]
6F4634EE retn

第3步:使用所谓<算法1>(6F4634E0),获得智力的地址。

步3.1:[6FAA4178] 记为 ThisGame
步3.2:[ThisGame + C 记为 ThisGameMemory
步3.3:[ThisGameMemory + Index1 * 8 + 4] 记为 Address1
步3.4:[Address1 + 18] 应当等于ReferenceNumber1,不相等游戏会异常(访问地址0),所以做修改器不用考虑这里
步3.5:Address1 + 78 作为地址,里面是智力

参考的代码:6F03F180
即:int __fastcall getValueFromGame(unsigned int nIndex, int ReferenceNumber)

…… …… result = *(_DWORD *)
(
*(_DWORD *)(dword_6FAA4178 + 0xC)
+ 8 * nIndex + 4
) &
(
(*(_DWORD *)
(*(_DWORD *)
(*(_DWORD *)(dword_6FAA4178 + 0xC)
+ 8 * nIndex + 4
)
+ 24
) != ReferenceNumber)
- 1
);
6F03F1DA mov eax, [esi + 0Ch]
6F03F1DD mov ecx, [eax + ecx * 8 + 4]
6F03F1E1 xor eax, eax
6F03F1E3 cmp [ecx + 18h], edx
6F03F1E6 pop edi
6F03F1E7 setnz al
6F03F1EA pop esi
6F03F1EB sub eax, 1
6F03F1EE and eax, ecx
6F03F1F0 retn return result;

需要特别指出的是,还有一个所谓<算法2>(6F468A20)也很重要,改移动速度要用到,详见我的手册。

[后记]
这两天我在game.dll、Storm.dll阅读了超过万行汇编。在这里严重感谢Hex-Rays这款插件,虽然有的时候也会越帮越忙,但是如果没有她,我肯定无法在短时间内完成这样的工作量。

有鉴于我此刻已经厌倦修改魔兽,所以这一回,应该不会再出V6了吧!

相关日志

Comments 13

  1. zx.longinus wrote:

    看来不玩魔兽的我明显比较高明……

    tc,你为什么会玩魔兽呢,GalGame 已经放弃了?

    Reply

    Posted 09 十 2008 at 21:21
  2. [tc]天驰 wrote:

    谁放弃啦!!
    呃……不对。
    谁要玩啊!!
    好像也不对。。。

    算了,反正你懂了。

    Reply

    Posted 10 十 2008 at 11:43
  3. zx.longinus wrote:

    我明白了,你是傲娇属性的。

    离子注入机到底是什么?

    Reply

    Posted 10 十 2008 at 16:04
  4. [tc]天驰 wrote:

    怎么把半导体的事情搞到这篇来了……无视,反正只不过是用来取代热扩散技术的。

    你很久不在你的Blog上骄蛮掀桌了,有必要去找个事端……

    Reply

    Posted 10 十 2008 at 23:46
  5. mazong1123 wrote:

    ..........

    Reply

    Posted 11 十 2008 at 11:45
  6. zx.longinus wrote:

    我什么时候掀桌了?不要造谣破坏我光辉的形象。

    Reply

    Posted 11 十 2008 at 11:57
  7. hyp wrote:

    很好很牛B 小生自叹不如(先评论下在下来来看看)
    果然新的发现让你产生了更大的动力去做这个 嘿嘿
    其实建议你可以把两种方法组合在一起变成一个强大的修改器,顺便加上MH的功能就可以美名其曰 魔兽修改器
    而且我觉得可以修改英雄的技能是一个很美妙的功能,希望你也能加上去,按照你的功力我相信你能找到存放单位ID的地方 找到以后加上去 这样子方便索引

    Reply

    Posted 12 十 2008 at 2:24
  8. hyp wrote:

    话说你发份给我吧 hyp1989@sina.com
    我是教育网下载那个有点困难
    谢谢啦

    Reply

    Posted 12 十 2008 at 2:28
  9. hyp wrote:

    困啊 睡觉去 果真下不了 最后说几句
    tmpString1 = " |CFF00FF00+"; 这个里面的|CFF00FF00 在魔兽里面是搞字体颜色的 无聊的话你可以加入修改某某颜色的功能
    然后就是在Storm.dll里面有你需要的东西?

    Reply

    Posted 12 十 2008 at 2:37
  10. [tc]天驰 wrote:

    To mazong1123:
    好简短,你想说什么?

    To longinus:
    说你掀桌是在丰富你的形象,不是诋毁。

    To hyp:
    邮件已发。

    恩…加上技能修改果然会比较有用。
    Storm.dll是功能函数,比如大整数的运算、UTF-8版的字符串、Battle.net相关等等。

    Reply

    Posted 12 十 2008 at 12:09
  11. zx.longinus wrote:

    额……
    我究竟是什么形象。

    Reply

    Posted 12 十 2008 at 13:31
  12. mazong1123 wrote:

    看到你每天这么悠闲我极度不爽~~~
    很久没听到晚上熄灯后那句话了~
    "xxx,大便~"

    Reply

    Posted 14 十 2008 at 22:01
  13. [tc]天驰 wrote:

    谁悠闲啦~现在正被逼得紧呢。

    Reply

    mazong1123 reply on 十一月 16th, 2008 16:38:

    没看出来~

    Reply

    Posted 15 十 2008 at 18:27

Post a Comment

Your email is never published nor shared. Required fields are marked *

下面是页面统计代码,当作没看见就行了