最近怀旧玩老游戏《天地劫-神魔至尊传》
游戏资源和介绍:http://www.verycd.com/topics/2725382/
发现原有的patch.com是win9x时代的免CD补丁,使用的大概是subst挂载的方法虚拟CD。
在WinXP SP3 上已经不能正常无CD启动了。
作为初学OD的新手抱着试一试的心态,决定自己去掉游戏的CD启动。

1启动游戏
立刻弹出消息框“Please insert game cd 2 into drive G:\” G:\是我的光驱


2用OD加载游戏,查找“Please insert game cd 2 into drive”字串
找到字串“Please insert game cd 2 into drive %s.”

3定位引用“Please insert game cd 2 into drive %s.”的代码,将整个函数进行分析:
该函数应该是设定读取光盘部分资料路径的函数。

004129D0  /$  81EC E4000000 sub     esp, 0E4
004129D6  |.  53            push    ebx
004129D7  |.  55            push    ebp
004129D8  |.  56            push    esi
004129D9  |.  57            push    edi
函数进入

004129DA  |.  8B3D 34B04500 mov     edi, dword ptr [<&KERNEL32.GetDr>;  kernel32.GetDriveTypeA
004129E0  |.  8BD9          mov     ebx, ecx
004129E2  |.  33F6          xor     esi, esi
004129E4  |>  8D46 43       /lea     eax, dword ptr [esi+43]
004129E7  |.  8D4C24 10     |lea     ecx, dword ptr [esp+10]
004129EB  |.  50            |push    eax
004129EC  |.  68 98834600   |push    00468398                        ;  %c:\
004129F1  |.  51            |push    ecx
004129F2  |.  E8 69E50300   |call    00450F60
004129F7  |.  83C4 0C       |add     esp, 0C
004129FA  |.  8D5424 10     |lea     edx, dword ptr [esp+10]
004129FE  |.  52            |push    edx
004129FF  |.  FFD7          |call    edi
00412A01      83F8 05       cmp     eax, 5
00412A04  |.  74 27         |je      short 00412A2D
00412A06  |.  46            |inc     esi
00412A07  |.  83FE 17       |cmp     esi, 17
00412A0A  |.^ 7C D8         \jl      short 004129E4
从C:\开始,枚举形如X:\模式的盘符
并找到第一个GetDriveTypeA返回为光驱属性(eax=5)的驱动器

00412A0C  |>  8B03          mov     eax, dword ptr [ebx]
00412A0E  |.  8D53 04       lea     edx, dword ptr [ebx+4]
00412A11      6A 10         push    10                               ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00412A13      52            push    edx                              ; |Title
00412A14      68 7C834600   push    0046837C                         ; |can't find any cdrom drive.
00412A19      50            push    eax                              ; |hOwner
00412A1A      FF15 1CB14500 call    dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
00412A20  |.  5F            pop     edi
00412A21  |.  5E            pop     esi
00412A22  |.  5D            pop     ebp
00412A23  |.  32C0          xor     al, al
00412A25  |.  5B            pop     ebx
00412A26  |.  81C4 E4000000 add     esp, 0E4
00412A2C  |.  C3            retn
00412A2D  |>  83FE 17       cmp     esi, 17
00412A30  |.^ 7D DA         jge     short 00412A0C
如果找到Z:\还没找到光驱
弹出消息框"can't find any cdrom drive.",错误返回。

00412A32  |.  8D4424 10     lea     eax, dword ptr [esp+10]
00412A36  |.  8D4C24 60     lea     ecx, dword ptr [esp+60]
00412A3A  |.  50            push    eax
00412A3B  |.  68 54834600   push    00468354                         ;  please insert game cd 2 into drive %s.
00412A40  |.  51            push    ecx
00412A41  |.  E8 1AE50300   call    00450F60
00412A46  |.  8B35 1CB14500 mov     esi, dword ptr [<&USER32.Message>;  USER32.MessageBoxA
00412A4C  |.  8B2D 2CB04500 mov     ebp, dword ptr [<&KERNEL32.GetVo>;  kernel32.GetVolumeInformationA
00412A52  |.  83C4 0C       add     esp, 0C
00412A55  |.  8D7B 04       lea     edi, dword ptr [ebx+4]
设定函数入口和字符串地址到寄存器。

00412A58  |>  8B03          /mov     eax, dword ptr [ebx]
00412A5A      6A 21         |push    21
00412A5C      8D5424 64     |lea     edx, dword ptr [esp+64]
00412A60      57            |push    edi
00412A61      52            |push    edx
00412A62      50            |push    eax
00412A63      FFD6          |call    esi
弹出消息框"please insert game cd 2 into drive X:\."

00412A65      83F8 01       cmp     eax, 1
00412A68  |.  75 79         |jnz     short 00412AE3
用户取消信息框,错误返回。

00412A6A  |.  8D8C24 B40000>|lea     ecx, dword ptr [esp+B4]
00412A71  |.  6A 40         |push    40
00412A73  |.  8D5424 20     |lea     edx, dword ptr [esp+20]
00412A77  |.  51            |push    ecx
00412A78  |.  8D4424 20     |lea     eax, dword ptr [esp+20]
00412A7C  |.  52            |push    edx
00412A7D  |.  8D4C24 20     |lea     ecx, dword ptr [esp+20]
00412A81  |.  50            |push    eax
00412A82  |.  51            |push    ecx
00412A83  |.  8D5424 34     |lea     edx, dword ptr [esp+34]
00412A87  |.  6A 40         |push    40
00412A89  |.  8D4424 28     |lea     eax, dword ptr [esp+28]
00412A8D  |.  52            |push    edx
00412A8E  |.  50            |push    eax
00412A8F  |.  FFD5          |call    ebp
00412A91  |.  85C0          |test    eax, eax
00412A93  |.^ 74 C3         |je      short 00412A58
利用GetVolumeInformationA判断光驱确实插入了盘片
否则重新提示

00412A95  |.  8D4C24 20     |lea     ecx, dword ptr [esp+20]
00412A99  |.  68 48834600   |push    00468348                        ;  swordman_2
00412A9E  |.  51            |push    ecx
00412A9F  |.  E8 8C6A0400   |call    00459530
00412AA4  |.  83C4 08       |add     esp, 8
00412AA7  |.  85C0          |test    eax, eax
00412AA9  |.^ 75 AD         \jnz     short 00412A58
并且盘片的卷标为swordman_2
否则重新提示

00412AAB  |.  8B13          mov     edx, dword ptr [ebx]
00412AAD      6A 30         push    30
00412AAF      57            push    edi
00412AB0      68 00834600   push    00468300                         ;  please notice!!!\ndon't eject game cd when playing,\nor error will occur
00412AB5      52            push    edx
00412AB6      FFD6          call    esi
弹出消息框:
"please notice!!!
don't eject game cd when playing,
or error will occur"

00412AB8  |.  8D4424 10     lea     eax, dword ptr [esp+10]
00412ABC  |.  68 F4824600   push    004682F4                         ;  swordman\
00412AC1  |.  50            push    eax
00412AC2  |.  81C3 5C020000 add     ebx, 25C
00412AC8      68 F1824600   push    004682EC                         ;  %s%s
00412ACD  |.  53            push    ebx
00412ACE  |.  E8 8DE40300   call    00450F60
由于程序老旧OD没有显示使用的C库。
猜测是利用sprintf(路径字串,"%s%s","X:\","swordman\")合并字串。

00412AD3  |.  83C4 10       add     esp, 10
平衡堆栈

00412AD6  |.  B0 01         mov     al, 1
00412AD8  |.  5F            pop     edi
00412AD9  |.  5E            pop     esi
00412ADA  |.  5D            pop     ebp
00412ADB  |.  5B            pop     ebx
00412ADC  |.  81C4 E4000000 add     esp, 0E4
00412AE2  |.  C3            retn
正常返回

00412AE3  |>  8B0B          mov     ecx, dword ptr [ebx]
00412AE5  |.  6A 10         push    10
00412AE7  |.  57            push    edi
00412AE8  |.  68 D4824600   push    004682D4                         ;  can't access game cd 2.
00412AED  |.  51            push    ecx
00412AEE  |.  FFD6          call    esi
弹出消息框"can't access game cd 2."

00412AF0  |.  5F            pop     edi
00412AF1  |.  5E            pop     esi
00412AF2  |.  5D            pop     ebp
00412AF3  |.  32C0          xor     al, al
00412AF5  |.  5B            pop     ebx
00412AF6  |.  81C4 E4000000 add     esp, 0E4
00412AFC  \.  C3            retn
错误返回

4修改
首先想到跳过繁琐的光驱检查,直接改变字串“%s%s”为".\"
跳过光驱检查:直接跳过
from:
  004129E4  |>  8D46 43       /lea     eax, dword ptr [esi+43]
  004129E7  |.  8D4C24 10     |lea     ecx, dword ptr [esp+10]
to:
  004129E4     /E9 CF000000   jmp     00412AB8
  004129E9     |90            nop
  004129EA     |90            nop

改变字串“%s%s”为".\"时出现了问题,程序错误退出。如图:

经过跟踪发现,其他地方合并字串时也使用了这个“%s%s”作为模式串。
所以采取添加一个新的字串".\"在00412AC8处使用,修改如下:
在数据段空地添加字串".\":
from:
  004682EC  25 73 25 73 00 00 00 00                          %s%s....
to:
  004682EC  25 73 25 73 00 2E 5C 00                          %s%s..\.

修改成使用".\"字串合并:
from:
  00412AC8      68 F1824600   push    004682EC                         ;  %s%s
to:
  00412AC8      68 F1824600   push    004682F1                         ;  .\

5将光盘上swordman\目录下内容拷贝到游戏安装目录
成功在不放入光盘的情况下运行程序。