初学破解,水平不是很高,想找一些既简单自己又感兴趣的东西来做. 前几天在看雪上看见有人讨论war3中随机数相关的东西,但是不是特别全,我按照他们的思路在我的机器上研究了几天,成功的弄清了war3的随机数机制,发上来分享一下,技术含量不是特别高,如果能获得邀请码就最好不过了^_^.
先说环境,我用的是war3 1.24e,dota版本也是最新的6.69c. 玩过dota的都知道,输入-roll命令,会在1-100之间roll出一个随机数,其实dota地图是直接调用war3的获取随机数函数来实现这件事情的.这个函数叫GetRandomInit(int a,int b),a和b分别是下限和上限,在game.dll中,加载到内存中后地址为0x6f3b40a0.种子地址存放在0x6FACE230处.
以下是反汇编出的二进制代码.
6F3B40A0 8B4424 08 mov eax, dword ptr [esp+8] //b,上限
6F3B40A4 57 push edi
6F3B40A5 8B7C24 08 mov edi, dword ptr [esp+8] //a,下限
6F3B40A9 3BF8 cmp edi, eax
6F3B40AB 75 04 jnz short 6F3B40B1//如果上下限相等,则直接返回
6F3B40AD 8BC7 mov eax, edi
6F3B40AF 5F pop edi
6F3B40B0 C3 retn
6F3B40B1 3BF8 cmp edi, eax
6F3B40B3 56 push esi
6F3B40B4 7E 09 jle short 6F3B40BF //if ( a <= b ) range = b-a
6F3B40B6 8BF7 mov esi, edi //if ( a > b ) range = a-b
6F3B40B8 2BF0 sub esi, eax
6F3B40BA 83C6 01 add esi, 1
6F3B40BD EB 07 jmp short 6F3B40C6
6F3B40BF 2BC7 sub eax, edi
6F3B40C1 83C0 01 add eax, 1
6F3B40C4 8BF0 mov esi, eax
6F3B40C6 8B0D 30E2AC6F mov ecx, dword ptr [6FACE230] //取种子地址
6F3B40CC E8 FFDFC5FF call 6F0120D0 //调用随机计算函数
6F3B40D1 F7E6 mul esi
6F3B40D3 B1 20 mov cl, 20
6F3B40D5 E8 96DE4200 call 6F7E1F70 //进行一些简单的移位处理
6F3B40DA 5E pop esi
6F3B40DB 03C7 add eax, edi //将结果放在eax中返回
6F3B40DD 5F pop edi
6F3B40DE C3 retn
可以看出进来后,对上下限进行一个简单的比较,如果相等直接返回,如果不相等,计算出差值为range,然后调用6F0120D0处的函数,根据种子(地址存放在ecx中)和range计算出一个随机数,最后调用6F7E1F70处的函数进行一些简单的处理后返回.我们只需要关注6F0120D0处的函数,里面有一些重要的信息.
6F0120D0 83EC 08 sub esp, 8
6F0120D3 8B01 mov eax, dword ptr [ecx] //取种子
6F0120D5 53 push ebx
6F0120D6 8B59 04 mov ebx, dword ptr [ecx+4] //取种子
6F0120D9 55 push ebp
6F0120DA 56 push esi
6F0120DB 8BF3 mov esi, ebx
6F0120DD 8BD3 mov edx, ebx
6F0120DF 0FB6EF movzx ebp, bh
6F0120E2 C1EB 10 shr ebx, 10
6F0120E5 C1EA 18 shr edx, 18
6F0120E8 81E3 FF000000 and ebx, 0FF
6F0120EE 83EB 0C sub ebx, 0C
6F0120F1 83EA 04 sub edx, 4
6F0120F4 81E6 FF000000 and esi, 0FF
6F0120FA 85D2 test edx, edx
6F0120FC 57 push edi
6F0120FD 8BFB mov edi, ebx
6F0120FF 895C24 10 mov dword ptr [esp+10], ebx
6F012103 7D 06 jge short 6F01210B
6F012105 81C2 BC000000 add edx, 0BC
6F01210B 83ED 18 sub ebp, 18
6F01210E 85FF test edi, edi
6F012110 7D 0A jge short 6F01211C
6F012112 81C7 D4000000 add edi, 0D4
6F012118 897C24 10 mov dword ptr [esp+10], edi
6F01211C 8B9A A857966F mov ebx, dword ptr [edx+6F9657A8]
6F012122 83EE 1C sub esi, 1C
6F012125 85ED test ebp, ebp
6F012127 7D 06 jge short 6F01212F
6F012129 81C5 EC000000 add ebp, 0EC
6F01212F 8BBF A857966F mov edi, dword ptr [edi+6F9657A8]
6F012135 D1C3 rol ebx, 1
6F012137 85F6 test esi, esi
6F012139 895C24 14 mov dword ptr [esp+14], ebx
6F01213D 7D 06 jge short 6F012145
6F01213F 81C6 F4000000 add esi, 0F4
6F012145 8B9D A857966F mov ebx, dword ptr [ebp+6F9657A8]
6F01214B C1C3 03 rol ebx, 3
6F01214E C1E2 08 shl edx, 8
6F012151 0B5424 10 or edx, dword ptr [esp+10]
6F012155 C1C7 02 rol edi, 2
6F012158 33DF xor ebx, edi
6F01215A 339E A857966F xor ebx, dword ptr [esi+6F9657A8]
6F012160 C1E2 08 shl edx, 8
6F012163 335C24 14 xor ebx, dword ptr [esp+14]
6F012167 0BD5 or edx, ebp
6F012169 03C3 add eax, ebx
6F01216B 5F pop edi
6F01216C C1E2 08 shl edx, 8
6F01216F 0BD6 or edx, esi
6F012171 5E pop esi
6F012172 5D pop ebp
6F012173 8951 04 mov dword ptr [ecx+4], edx //更新种子
6F012176 8901 mov dword ptr [ecx], eax //更新种子
6F012178 5B pop ebx
6F012179 83C4 08 add esp, 8
6F01217C C3 retn
重点需要关心的是以下几句代码,每次调用该函数之后都会导致种子更新.
6F0120D3 8B01 mov eax, dword ptr [ecx] //取种子
6F0120D6 8B59 04 mov ebx, dword ptr [ecx+4] //取种子
6F012173 8951 04 mov dword ptr [ecx+4], edx //更新种子
6F012176 8901 mov dword ptr [ecx], eax //更新种子
至于其他的计算过程,应该比较好理解.至此,我们已经可以动手写一个获取随机数的小程序了.用远程线程注入的方法,把一段代码注入到war3中,先保存种子,调用GetRandomInit(1,100)若干次,获取随机数后将种子写回. 然后你在dota里输入-roll,就可以看到出来的数与你获得的随机数完全一致.
获取随机数的代码用内联汇编可以写成:
for(int i=0;i<100;i++)
{
__asm
{
MOV EAX,0x64 //上限100
PUSH EAX
MOV EAX,0x1 //下限1
PUSH EAX
MOV EAX,0x6f3b40a0
CALL EAX //调用GetRandomInit
MOV temp,EAX //将结果保存到temp变量,然后可以将temp值写入文件
POP EAX
POP EAX //平衡调用堆栈
}
fout<<dec<<temp<<endl;
}
接下来就可以使用远程线程注入方法,将相关代码注入到war3进程中执行即可.附件里是我已经实现的程序,把两个dll拷贝到能找到的目录,推荐C:\WINDOWS\system32下. 首先打开war3,创建游戏进入dota,游戏开始后先暂停(这是因为游戏创建过程中和出兵后都要用到大量的随机数,为了避免干扰,先暂停以便进行试验),然后运行附件中的程序test1.exe,在d:盘根目录下会看到一个test.txt文件,打开,然后返回war3,输入命令-roll,对比一下,可以发现roll出来的数都在刚才的文件中.另外,既然能获得随机数,那么也能控制随机数,一个最简单的想法是直接改写种子.我尝试了直接把种子改成0.同样,在游戏刚开始时暂停,运行test2.exe,返回游戏输入-rd,你会看到随机出来的阵容无论多少次都是一样的,应该有影魔,屠夫和火枪.
简单的破解至此结束,望高人指正.之前已经有牛人做出来了,不过他在自己空间里没有说的很明白,我就尝试着把这件事给做完了,虽然不记得名字了,还是要向他表示感谢.就这样吧.