写在前面:
这篇文章写了很久了,我自己都忘了,最近想把以前搞过的乱七八糟的东西整理下,就翻了出来,这只是一部份,剩下的由于当时太懒一直没写下去。近期抽空把剩下的完结掉,同时再写点关于MH的东西,权当毕业年的一次整理。
2012-11-14 凌晨
标题: 【原创】关于 Dota-rd模式的阵容计算
作者: Flicker317
时间: 2011-05-24
【文章标题】: 关于 Dota -rd模式的阵容计算
【作者邮箱】: flicker317@163.com
【作者主页】:
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
转载请注明出处!!
一些资料的链接:
//-roll的过程
//锁定阵容
--
我们知道魔兽是通过GetRandomInt函数生成伪随机数的,而rd模式生成的英雄也应该是由该函数确定。
魔兽版本: 1.24e 地图: 6.72
启动魔兽,开始游戏后在GetRandomInt 入口下断,输入-rd可以发现war3被断了下来。
01BC40A0 . 8B4424 08 mov eax,dword ptr ss:【esp+0x8】 ;断在此处
01BC40A4 . 57 push edi
01BC40A5 . 8B7C24 08 mov edi,dword ptr ss:【esp+0x8】
01BC40A9 . 3BF8 cmp edi,eax
01BC40AB . 75 04 jnz short Game.01BC40B1
01BC40AD . 8BC7 mov eax,edi
01BC40AF . 5F pop edi
01BC40B0 . C3 retn
01BC40B1
01BC40B3 . 56 push esi
01BC40B4 . 7E 09 jle short Game.01BC40BF
01BC40B6 . 8BF7 mov esi,edi
01BC40B8 . 2BF0 sub esi,eax
01BC40BA . 83C6 01 add esi,0x1
01BC40BD . EB 07 jmp short Game.01BC40C6
01BC40BF
01BC40C1 . 83C0 01 add eax,0x1
01BC40C4 . 8BF0 mov esi,eax
01BC40C6
01BC40CC . E8 FFDFC5FF call Game.018220D0 ;更新
{
018220D0 /$ 83EC 08 sub esp,0x8
018220D3 |. 8B01 mov eax,dword ptrds:【ecx】
018220D5 |. 53 push ebx
018220D6 |. 8B59 04 mov ebx,dword ptrds:【ecx+0x4】
018220D9 |. 55 push ebp
018220DA |. 56 push esi
018220DB |. 8BF3 mov esi,ebx
018220DD |. 8BD3 mov edx,ebx
018220DF |. 0FB6EF movzx ebp,bh
018220E2 |. C1EB 10 shr ebx,0x10
018220E5 |. C1EA 18 shr edx,0x18
018220E8 |. 81E3 FF000000 and ebx,0xFF
018220EE |. 83EB 0C sub ebx,0xC
018220F1 |. 83EA 04 sub edx,0x4
018220F4 |. 81E6 FF000000 and esi,0xFF
018220FA |. 85D2 test edx,edx
018220FC |. 57 push edi
018220FD |. 8BFB mov edi,ebx
018220FF |. 895C24 10 mov dword ptrss:【esp+0x10】,ebx
01822103 |. 7D06 jge short Game.0182210B
01822105 |. 81C2 BC000000 add edx,0xBC
0182210B |> 83ED 18 sub ebp,0x18
0182210E |. 85FF test edi,edi
01822110 |. 7D0A jge short Game.0182211C
01822112 |. 81C7 D4000000 add edi,0xD4
01822118 |. 897C24 10 mov dword ptrss:【esp+0x10】,edi
0182211C |> 8B9A A8571702 mov ebx,dword ptr ds:【edx+0x21757A8】
01822122 |. 83EE 1C sub esi,0x1C
01822125 |. 85ED test ebp,ebp
01822127 |. 7D06 jge short Game.0182212F
01822129 |. 81C5 EC000000 add ebp,0xEC
0182212F |> 8BBF A8571702 mov edi,dword ptr ds:【edi+0x21757A8】
01822135 |. D1C3 rol ebx,1
01822137 |. 85F6 test esi,esi
01822139 |. 895C24 14 mov dword ptrss:【esp+0x14】,ebx
0182213D |. 7D06 jge short Game.01822145
0182213F |. 81C6 F4000000 add esi,0xF4
01822145 |> 8B9D A8571702 mov ebx,dword ptr ss:【ebp+0x21757A8】
0182214B |. C1C3 03 rol ebx,0x3
0182214E |. C1E2 08 shl edx,0x8
01822151 |. 0B5424 10 //代码效果参考:http://www.zidongmutanji.com/zsjx/105589.html
or edx,dword ptrss:【esp+0x10】01822155 |. C1C7 02 rol edi,0x2
01822158 |. 33DF xor ebx,edi
0182215A |. 339E A8571702 xor ebx,dword ptr ds:【esi+0x21757A8】
01822160 |. C1E2 08 shl edx,0x8
01822163 |. 335C2414 xor ebx,dword ptr ss:【esp+0x14】
01822167 |. 0BD5 or edx,ebp
01822169 |. 03C3 add eax,ebx
0182216B |. 5F pop edi
0182216C |. C1E2 08 shl edx,0x8
0182216F |. 0BD6 or edx,esi
01822171 |. 5E pop esi
01822172 |. 5D pop ebp
01822173 |. 8951 04 mov dword ptrds:【ecx+0x4】,edx
01822176 |. 8901 mov dword ptrds:【ecx】,eax
01822178 |. 5B pop ebx
01822179 |. 83C4 08 add //代码效果参考:http://www.zidongmutanji.com/bxxx/385884.html
esp,0x80182217C . C3 retn
}
01BC40D1 . F7E6 mul esi
01BC40D3 . B1 20 mov cl,0x20
01BC40D5 . E8 96DE4200 call Game.01FF1F70
01BC40DA . 5E pop esi
01BC40DB . 03C7 add eax,edi
01BC40DD . 5F pop edi
01BC40DE . C3 retn
Hook下GetRandomInt(int ,int)函数,让它输出形参和返回值。重新开始游戏,输入-rd后,得到如下数据
Eax Edi Ret Count
2 1 2
68 36 5B ;1
2 1 2
68 36 49 ;2
2 1 1
35 1 1A ;3
2 1 1
35 1 1A
2 1 1
35 1 29 ;4
2 1 2
68 36 5B
2 1 2
68 36 41 ;5
2 1 2
68 36 40 ;6
2 1 1
35 1 31 ;7
2 1 1
35 1 24 ;8
2 1 1
35 1 34 ;9
2 1 1
35 1 15 ;10
2 1 1
35 1 3 ;11
2 1 1
35 1 13 ;12
2 1 2
68 36 44 ;13
2 1 1
35 1 4 ;14
2 1 2
68 36 64 ;15
2 1 1
35 1 25 ;16
2 1 2
68 36 5E ;17
2 1 2
68 36 63 ;18
2 1 2
68 36 62 ;19
2 1 2
68 36 55 ;20
0x68=104 //6.72的英雄总数
阵容如下:
于是我们猜测获得一个Hero的过程
while(...){ //获取20个互不相同的idHero
int nRet = GetRandomInt(2,1);
if(nRet == 1)
idHero = GetRandomInt(0x68,0x36);
else if(nRet==2)
idHero = GetRandomInt(0x35,0x01);
}
那我们就验证下是否是这样,进入ap模式,然后输入-random后,在GetRandomInt 入口处下断,war3被断了下来,记录第一次的形参和返回值。
第一次
EAX EDI RET
2 1 1
那么根据上面我们的分析,下次EAX、EDI应该分别为0x35、0x01,让war3跑起来,war3在GetRandomInt处再次被断下,跟下去发现和我们的分析一样,EAX、EDI分别为0x35、0x01,我们修改它的返回值,改成0x5B(我们分析-rd模式下得到的第一个iHero),得到Hero地狱领主,和-rd模式下的第一个英雄一样(我们知道-rd模式下的英雄是从一点钟方位开始计算的),就证明了我们的分析是正确的,那我们就确定了0x5B是地狱领主的ID。
这是-rd模式的分析,-rdsp过程和这差不多,我就不在做演示了。
那GetRandomInt又是怎么确定随机数的呢?
关键就是callGame.018220D0 的过程了,里面的2个变量作为中间数,不断生成随机数并更新。
这2个变量的初始值在载入地图时由因游戏玩家更新调用GetTickCount的返回值确定(这句话表达的…好吧…)。
载入地图的过程下次在接着讲…
我自己写的计算器: