最近好不容易找到我最喜欢的游戏《英雄无敌3之埃拉西亚的光复》,可惜是光盘版的,要用虚拟光驱来运行,感觉不爽,网上也找不到免CD补丁,于是决定自己动手。
首先感谢这篇文章的作者
http://bbs.pediy.com/showthread.php?t=101023
是他引领我进入反汇编的大门。这篇文章的第一步,就是找到GetDriveType的调用(GetDriveType就是判断某盘符是光驱、硬盘或网络磁盘等的API函数),于是我用C32Asm,对游戏主程序Heroes3.exe进行反汇编,再查找GetDriveType,结果还真有,如下:
::005A8437:: FF15 48A05B00 CALL [5BA048] >>>: KERNEL32.DLL:GetDriveTypeA
::005A843D:: 85C0 TEST EAX,EAX
::005A843F:: 74 0A JE SHORT 005A844B \:JMPDOWN
::005A8441:: 83F8 01 CMP EAX,1
::005A8444:: 74 05 JE SHORT 005A844B \:JMPDOWN
::005A8446:: 6A 01 PUSH 1 \:BYJMP JmpBy:005A8420,
::005A8448:: 58 POP EAX
::005A8449:: 5D POP EBP
::005A844A:: C3 RETN
但是和文章中不一样啊,他在调用GetDriveTypeA之后,判断返回值是否为5(5是光驱),而我这里却是1
::005A8441:: 83F8 01 CMP EAX,1
后面的逻辑也不一样。而继续查找GetDriveType也找不到了。于是我再仔细看看上面的代码,发现“>>>: KERNEL32.DLL:GetDriveTypeA”这只是反汇编器加上的注释,真正调用的是5BA048这个地址的代码,于是又搜5BA048,结果又找到一处
::004E7B69:: 8B35 48A05B00 MOV ESI,[5BA048]
::004E7B6F:: 33ED XOR EBP,EBP
::004E7B71:: 8BF8 MOV EDI,EAX
::004E7B73:: 896C24 10 MOV [ESP+10],EBP
::004E7B77:: BB 02000000 MOV EBX,2
::004E7B7C:: BA 01000000 MOV EDX,1 \:BYJMP JmpBy:004E7BAF,
::004E7B81:: 8BCB MOV ECX,EBX
::004E7B83:: D3E2 SHL EDX,CL
::004E7B85:: 85D7 TEST EDI,EDX
::004E7B87:: 74 22 JE SHORT 004E7BAB \:JMPDOWN
::004E7B89:: 8AC3 MOV AL,BL
::004E7B8B:: 04 41 ADD AL,41
::004E7B8D:: 68 DC495E00 PUSH 5E49DC \->: A:\
::004E7B92:: A2 DC495E00 MOV [5E49DC],AL
::004E7B97:: FFD6 CALL ESI
::004E7B99:: 83F8 05 CMP EAX,5
原来它是把5BA048给了 ESI,然后在后面 CALL ESI。找到这里就可以改了,把 CMP EAX,5,也就是83F8 05改成83F8 03,汇编代码的地址是004E7B99,对应的十六进制代码地址就是000E7B99。改完之后保存运行,发现还是报告找不到光盘。我就继续参考上面那篇文章,发现他后面的逻辑又和我的对不上了,应该是两游戏的版本不同。接下来该怎么办呢?我只好硬着头皮,从CMP EAX,5接着往下看,发现有这么一段:
::004E7C8C:: BF 387D5E00 MOV EDI,5E7D38 \->: d;^kIwuL{ ::004E7C91:: F2 REPNE SCASB ::004E7C92:: AE SCASB ::004E7C93:: F7D1 NOT ECX ::004E7C95:: 49 DEC ECX ::004E7C96:: 74 1A JE SHORT 004E7CB2 \:JMPDOWN ::004E7C98:: 2892 387D5E00 SUB [EDX+5E7D38],DL \:BYJMP JmpBy:004E7CB0, ::004E7C9E:: 83C9 FF OR ECX,FFFFFFFF ::004E7CA1:: 33C0 XOR EAX,EAX ::004E7CA3:: 42 INC EDX ::004E7CA4:: BF 387D5E00 MOV EDI,5E7D38 \->: d;^kIwuL{ ::004E7CA9:: F2 REPNE SCASB ::004E7CAA:: AE SCASB ::004E7CAB:: F7D1 NOT ECX ::004E7CAD:: 49 DEC ECX ::004E7CAE:: 3BD1 CMP EDX,ECX ::004E7CB0:: 72 E6 JB SHORT 004E7C98 \:JMPUP ::004E7CB2:: 68 00800000 PUSH 8000 \:BYJMP JmpBy:004E7C96, ::004E7CB7:: 80C3 41 ADD BL,41 ::004E7CBA:: 68 387D5E00 PUSH 5E7D38 \->: d;^kIwuL{ ::004E7CBF:: 881D 387D5E00 MOV [5E7D38],BL ::004E7CC5:: E8 27960B00 CALL 005A12F1 这个5E7D38里面是什么东东,后面的代码貌似对它进行了加工(SUB [EDX+5E7D38],DL和MOV [5E7D38],BL),于是请出反汇编调试利器--Visual Studio!利用VS的F11单步调试,程序直接停在入口处(main函数对应的汇编代码),然后在004E7C8C处下断点,并且打开内存查看窗口,查看5E7D38处的内容,发现是一串奇怪的字符串“.;^kIwuL{ 接下来就好办了,只要把光盘里的文件复制到游戏根目录下、把d;^kIwuL{ 1.用虚拟光驱打开游戏光盘的ISO文件,复制heroes3文件夹到硬盘上英雄无敌的根目录下。 2.用ASCII码转换工具,把d;^kIwuL{ 3.还是VS,找到004E7C8C所对应的十六进制地址000E7C8C(原来汇编地址和十六进制地址相差0x00400000),把从000E7C8C开始,到004E7CC5为止,所有的十六进制数都改成90,即空指令NOP,这样就把解密算法去掉了。 最后保存运行一下,直接进入了,大功告成!