写在前面:
这篇文章写了很久了,我自己都忘了,最近想把以前搞过的乱七八糟的东西整理下,就翻了出来,这只是一部份,剩下的由于当时太懒一直没写下去。近期抽空把剩下的完结掉,同时再写点关于MH的东西,权当毕业年的一次整理。
2012-11-14 凌晨
标题: 【原创】关于 Dota-rd模式的阵容计算
作者: Flicker317
时间: 2011-05-24
【文章标题】: 关于 Dota -rd模式的阵容计算
【作者邮箱】: flicker317@163.com
【作者主页】: http://hi.baidu.com/new/flicker317
【作者QQ号】: 1623223345
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
转载请注明出处!!
--------------------------------------------------------------------------------
一些资料的链接:
http://bbs.pediy.com/showthread.php?t=125424 //-roll的过程
http://hi.baidu.com/suwuhao/blog/item/607d78111b1260dcf7039eb2.html //锁定阵容
------------------------------------------------------------------------------
我们知道魔兽是通过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 > 3BF8 cmp edi,eax 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 > 2BC7 sub eax,edi 01BC40C1 . 83C0 01 add eax,0x1 01BC40C4 . 8BF0 mov esi,eax 01BC40C6 > 8B0D 30E22D02 mov ecx,dwordptr ds:[0x22DE230] 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 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 esp,0x8 0182217C \. 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的返回值确定(这句话表达的…好吧…)。
载入地图的过程下次在接着讲…
我自己写的计算器: