【文章标题】: 幻世录I免CD补丁制作
【文章作者】: 晓欣
【作者邮箱】: qwerty789@tom.com
【软件名称】: 幻世录I
【下载地址】: 自己搜索下载
【加壳方式】: 无壳
【编写语言】: Microsoft Visual C++ 5.0
【使用工具】: PEiD+ZeroAdd+OD+LordPE
【操作平台】: XP SP2
【软件介绍】: 幻世录I,经典游戏,不用再介绍了
【作者声明】: 看雪注册两年多,但当时注册只是为了下载一个附件(汗!).直到半年前真正开始学习加密与解密,用幻世录I这个经典游戏作为练习,作此文.只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  说明:游戏版本光盘装好是1.05版,打上官方1.06补丁.所以文中地址可能根据具体版本有所不同.选这个游戏是因为把桌面设置为16色,再带参数-window就可以直接在窗口模式下运行,给调试带来很大方便.
  另外,由于发贴数太小,还没有上传权限,所以修改好的EXE文件就不上传了,有需要直接PM找我要吧.
  闲话少说,进入正文.
  不放光盘直接开始游戏,会出现对话框,显示cd-rom not found!!!
  用OD加载,搜索上述字符串,找到两处:
  第一处:
  0042F785    396C24 10                 CMP     DWORD PTR SS:[ESP+10],EBP
  0042F789    EB 13                     JMP     SHORT hsl2.0042F79E
  0042F78B    68 14924700               PUSH    hsl2.00479214                           ; cd-rom not found !!!
  0042F790    E8 EBA30200               CALL    hsl2.00459B80
  0042F795    83C4 04                   ADD     ESP,4
  
  第二处:
  0042F7FE    83F8 FF                   CMP     EAX,-1
  0042F801    75 13                     JNZ     SHORT hsl2.0042F816
  0042F803    68 14924700               PUSH    hsl2.00479214                           ; cd-rom not found !!!
  0042F808    E8 73A30200               CALL    hsl2.00459B80
  0042F80D    83C4 04                   ADD     ESP,4
  0042F810    5F                        POP     EDI
  
  不知道从哪一处跳出来的,两处都下断,运行,结果停在42F803处,上面42F801处正好有个条件转移指令,直接改成
  
  0042F801   /EB 13                     JMP     SHORT hsl2.0042F816
  
  保存,运行,可以直接进入游戏了!!
  
  不过这不是本文目的.由于没有了光盘,所以游戏没有音乐了,所以最主要的任务是恢复游戏的音乐.不知道音乐是用什么函数放出来的,用LordPE查看输入表,发现了输入表里面有WINMM.DLL和mciSendCommandA函数,所以播放音乐的函数应该就是它了!
  
  首先简要介绍一下这个函数,这个函数使用不同的参数来实现不同的功能,主要包括:
  打开音频设备,用mciSendCommand(0,MCI_OPEN,MCI_OPEN_TYPE,(LPMCI_OPEN_PARMS) lpOpen),其中lpOpen的第三个成员为MCI_DEVTYPE_CD_AUDIO时打开CD音轨,为MCI_DEVTYPE_WAVEFORM_AUDIO时打开波形文件(WAV,MP3等),此时lpOpen的第四个成员指向波形文件的路径,返回的设备ID保存在lpOpen的第二个成员中.
  获取文件或音轨长度,用mciSendCommand(ID,MCI_STATUS,MCI_STATUS_ITEM,(LPMCI_STATUS_PARMS) lpStatus),其中lpStatus的第三个成员应设置为MCI_STATUS_LENGTH,如果是CD音轨,其第四个成员应设置为音轨号,返回的长度保存在lpStatus的第二个成员中.
  设置时间格式,主要用于CD音轨,用mciSendCommand(ID,MCI_SET,MCI_SET_TIME_FORMAT,(LPMCI_SET_PARMS) lpSet)
  播放,用mciSendCommand(ID,MCI_PLAY,MCI_FROM | MCI_TO,(LPMCI_PLAY_PARMS ) lpPlay),lpPlay的第二,三个成员分别为播放的起点,终点.
  停止,用mciSendCommand(ID,MCI_STOP,0,0)
  暂停,用mciSendCommand(ID,MCI_PAUSE,0,0)
  恢复,用mciSendCommand(ID,MCI_RESUME,0,0)
  关闭音频设备,用mciSendCommand(ID,MCI_CLOSE,0,0)
  
  要想让不用光盘的游戏播放音乐,就需要找到实现音乐播放的函数,改为调用本地音频文件.把光盘上的音轨用抓轨工具保存成MP3,从track02.mp3到track19.mp3共18首.单轨是从1开始编号的,第一个音轨是数据,所以实际音乐只有18首,但是用mciSendCommand函数会读到19首,这点要注意一下.把抓下来的mp3保存在游戏目录的mp3文件夹下备用.
  
  在mciSendCommandA上面下API断点,运行后被断下,堆栈中显示:
  0012FEDC   00458ED7  返回到 hsl2.00458ED7
  0012FEE0   00000000  ID
  0012FEE4   00000803  MCI_OPEN
  0012FEE8   00002000  MCI_OPEN_TYPE
  0012FEEC   004CA340  hsl2.004CA340
  运行到用户代码,显示这段代码如下,从458E90开始:
  
  00458E90    53                        PUSH    EBX
  00458E91    56                        PUSH    ESI
  00458E92    57                        PUSH    EDI
  00458E93    E8 A8FFFFFF               CALL    hsl2.00458E40                           ; 未搞清什么意思
  00458E98    8B1D 1CB44C00             MOV     EBX,DWORD PTR DS:[<&WINMM.mciSendComman>; WINMM.mciSendCommandA
  00458E9E    68 40A34C00               PUSH    hsl2.004CA340
  00458EA3    B9 64000000               MOV     ECX,64
  00458EA8    83C8 FF                   OR      EAX,FFFFFFFF
  00458EAB    BF 60A34C00               MOV     EDI,hsl2.004CA360
  00458EB0    33F6                      XOR     ESI,ESI
  00458EB2    68 00200000               PUSH    2000                                    ; MCI_OPEN_TYPE
  00458EB7    68 03080000               PUSH    803                                     ; MCI_OPEN
  00458EBC    F3:AB                     REP     STOS DWORD PTR ES:[EDI]                 ; 把从4CA360处开始的100个DWORD数据改为FFFFFFFF
  00458EBE    56                        PUSH    ESI
  00458EBF    8935 40A34C00             MOV     DWORD PTR DS:[4CA340],ESI               ; lpOpen的地址
  00458EC5    C705 48A34C00 40A64700    MOV     DWORD PTR DS:[4CA348],hsl2.0047A640     ; MCI_DEVTYPE_CD_AUDIO,字符串"cdaudio"
  00458ECF    8935 4CA34C00             MOV     DWORD PTR DS:[4CA34C],ESI
  00458ED5    FFD3                      CALL    EBX                                     ; 打开设备
  00458ED7    85C0                      TEST    EAX,EAX                                 ; 成功返回0
  00458ED9    0F85 10010000             JNZ     hsl2.00458FEF
  00458EDF    A1 44A34C00               MOV     EAX,DWORD PTR DS:[4CA344]               ; 设备ID
  00458EE4    55                        PUSH    EBP
  00458EE5    68 B0A14C00               PUSH    hsl2.004CA1B0                           ; lpStatus
  00458EEA    68 02010000               PUSH    102                                     ; MCI_STATUS_ITEM | MCI_WAIT
  00458EEF    68 14080000               PUSH    814                                     ; MCI_STATUS
  00458EF4    50                        PUSH    EAX                                     ; ID
  00458EF5    A3 28A64700               MOV     DWORD PTR DS:[47A628],EAX               ; 设备ID放在47A628处
  00458EFA    8935 B0A14C00             MOV     DWORD PTR DS:[4CA1B0],ESI
  00458F00    C705 B8A14C00 03000000    MOV     DWORD PTR DS:[4CA1B8],3                 ; MCI_STATUS_NUMBER_OF_TRACKS
  00458F0A    FFD3                      CALL    EBX                                     ; 取得音轨数
  00458F0C    85C0                      TEST    EAX,EAX
  00458F0E    0F85 C0000000             JNZ     hsl2.00458FD4
  00458F14    A1 B4A14C00               MOV     EAX,DWORD PTR DS:[4CA1B4]               ; 音轨数放在4C5358
  00458F19    83F8 64                   CMP     EAX,64                                  ; 如果大于100,只取前100个
  00458F1C    A3 58534C00               MOV     DWORD PTR DS:[4C5358],EAX
  00458F21    7E 0A                     JLE     SHORT hsl2.00458F2D
  00458F23    C705 58534C00 64000000    MOV     DWORD PTR DS:[4C5358],64
  00458F2D    A1 28A64700               MOV     EAX,DWORD PTR DS:[47A628]
  00458F32    68 20A34C00               PUSH    hsl2.004CA320                           ; lpStatus
  00458F37    68 02040000               PUSH    402                                     ; MCI_SET_TIME_FORMAT | MCI_WAIT
  00458F3C    68 0D080000               PUSH    80D                                     ; MCI_SET
  00458F41    50                        PUSH    EAX
  00458F42    C705 24A34C00 0A000000    MOV     DWORD PTR DS:[4CA324],0A                ; MCI_FORMAT_TMSF,单轨,分,秒,帧
  00458F4C    FFD3                      CALL    EBX                                     ; 设置时间格式
  00458F4E    8B0D 58534C00             MOV     ECX,DWORD PTR DS:[4C5358]               ; 音轨数
  00458F54    33C0                      XOR     EAX,EAX
  00458F56    3BCE                      CMP     ECX,ESI                                 ; ESI初始值为0
  00458F58    7E 7A                     JLE     SHORT hsl2.00458FD4
  00458F5A    BF 60A34C00               MOV     EDI,hsl2.004CA360                       ; 放100个FFFFFFFF的地方
  00458F5F    BD 01000000               MOV     EBP,1
  00458F64    8B0D 28A64700             MOV     ECX,DWORD PTR DS:[47A628]               ; ID
  00458F6A    68 B0A14C00               PUSH    hsl2.004CA1B0                           ; lpStatus
  00458F6F    68 12010000               PUSH    112                                     ; MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT
  00458F74    8D70 01                   LEA     ESI,DWORD PTR DS:[EAX+1]                ; ESI+1
  00458F77    68 14080000               PUSH    814                                     ; MCI_STATUS
  00458F7C    51                        PUSH    ECX
  00458F7D    892D B8A14C00             MOV     DWORD PTR DS:[4CA1B8],EBP               ; EBP=1,MCI_STATUS_LENGTH
  00458F83    8935 BCA14C00             MOV     DWORD PTR DS:[4CA1BC],ESI               ; 当前TRACK,从1开始
  00458F89    FFD3                      CALL    EBX                                     ; 取TRACK长度
  00458F8B    85C0                      TEST    EAX,EAX
  00458F8D    75 2E                     JNZ     SHORT hsl2.00458FBD
  00458F8F    A1 B4A14C00               MOV     EAX,DWORD PTR DS:[4CA1B4]               ; 取出长度,转换为毫秒,放在100个FFFFFFFF的地方
  00458F94    33D2                      XOR     EDX,EDX
  00458F96    25 FFFF0000               AND     EAX,0FFFF
  00458F9B    8AD4                      MOV     DL,AH
  00458F9D    25 FF000000               AND     EAX,0FF
  00458FA2    8D0440                    LEA     EAX,DWORD PTR DS:[EAX+EAX*2]
  00458FA5    8D0480                    LEA     EAX,DWORD PTR DS:[EAX+EAX*4]
  00458FA8    C1E0 02                   SHL     EAX,2
  00458FAB    03C2                      ADD     EAX,EDX
  00458FAD    8D0480                    LEA     EAX,DWORD PTR DS:[EAX+EAX*4]
  00458FB0    8D0480                    LEA     EAX,DWORD PTR DS:[EAX+EAX*4]
  00458FB3    8D0C80                    LEA     ECX,DWORD PTR DS:[EAX+EAX*4]
  00458FB6    C1E1 03                   SHL     ECX,3
  00458FB9    890F                      MOV     DWORD PTR DS:[EDI],ECX
  00458FBB    EB 06                     JMP     SHORT hsl2.00458FC3
  00458FBD    C707 00000000             MOV     DWORD PTR DS:[EDI],0
  00458FC3    8B0D 58534C00             MOV     ECX,DWORD PTR DS:[4C5358]
  00458FC9    8BC6                      MOV     EAX,ESI
  00458FCB    83C7 04                   ADD     EDI,4
  00458FCE    3BC1                      CMP     EAX,ECX
  00458FD0  ^ 7C 92                     JL      SHORT hsl2.00458F64
  00458FD2    33F6                      XOR     ESI,ESI
  00458FD4    8B15 28A64700             MOV     EDX,DWORD PTR DS:[47A628]
  00458FDA    68 D4A14C00               PUSH    hsl2.004CA1D4                           ; lpStop
  00458FDF    56                        PUSH    ESI
  00458FE0    68 08080000               PUSH    808                                     ; MCI_STOP
  00458FE5    52                        PUSH    EDX
  00458FE6    8935 D4A14C00             MOV     DWORD PTR DS:[4CA1D4],ESI
  00458FEC    FFD3                      CALL    EBX                                     ; 关闭
  00458FEE    5D                        POP     EBP
  00458FEF    5F                        POP     EDI
  00458FF0    5E                        POP     ESI
  00458FF1    5B                        POP     EBX
  00458FF2    C3                        RETN
  
  根据上面分析,这段代码主要作用是初始化CD音频,取得各个音轨的长度,放在4CA360开始的一段空间中.把上面打开设备,关闭设备和取得文件长度的函数分别替换即可.
  为了后面修改方便,先用ZeroAdd增加一个节,大小为2000(H),用LordPE查看内存范围从4CE000~4D0000,把4CE000处改为字符串waveaudio,把4CE010处改为mp3\track??.mp3,从458E90处改为如下代码:
  
  00458E90    60                        PUSHAD
  00458E91    E8 AAFFFFFF               CALL    hsl2.00458E40
  00458E96    8B1D 1CB44C00             MOV     EBX,DWORD PTR DS:[<&WINMM.mciSendComman>; WINMM.mciSendCommandA
  00458E9C    B9 64000000               MOV     ECX,64
  00458EA1    83C8 FF                   OR      EAX,FFFFFFFF
  00458EA4    BF 60A34C00               MOV     EDI,hsl2.004CA360
  00458EA9    33F6                      XOR     ESI,ESI
  00458EAB    F3:AB                     REP     STOS DWORD PTR ES:[EDI]                 ; 初始化成FFFFFFFF
  00458EAD    BF 60A34C00               MOV     EDI,hsl2.004CA360
  00458EB2    B9 13000000               MOV     ECX,13
  00458EB7    890D 58534C00             MOV     DWORD PTR DS:[4C5358],ECX               ; MP3数量
  00458EBD    BA 02000000               MOV     EDX,2                                   ; 从TRACK02.MP3开始
  00458EC2    3BCA                      CMP     ECX,EDX
  00458EC4    0F8C 27010000             JL      hsl2.00458FF1
  00458ECA    51                        PUSH    ECX
  00458ECB    52                        PUSH    EDX
  00458ECC    E8 4F510700               CALL    hsl2.004CE020
  00458ED1    68 40A34C00               PUSH    hsl2.004CA340
  00458ED6    68 0A020000               PUSH    20A
  00458EDB    68 03080000               PUSH    803                                     ; MCI_OPEN
  00458EE0    56                        PUSH    ESI
  00458EE1    8935 40A34C00             MOV     DWORD PTR DS:[4CA340],ESI
  00458EE7    C705 48A34C00 00E04C00    MOV     DWORD PTR DS:[4CA348],hsl2.004CE000     ; MCI_DEVTYPE_WAVEFORM_AUDIO,字符串"waveaudio"
  00458EF1    C705 4CA34C00 10E04C00    MOV     DWORD PTR DS:[4CA34C],hsl2.004CE010     ; ASCII "mp3\track19.mp3"
  00458EFB    FFD3                      CALL    EBX                                     ; 打开设备
  00458EFD    85C0                      TEST    EAX,EAX
  00458EFF    0F85 E6000000             JNZ     hsl2.00458FEB
  00458F05    A1 44A34C00               MOV     EAX,DWORD PTR DS:[4CA344]
  00458F0A    68 B0A14C00               PUSH    hsl2.004CA1B0
  00458F0F    68 00010000               PUSH    100
  00458F14    68 14080000               PUSH    814
  00458F19    50                        PUSH    EAX
  00458F1A    8935 B0A14C00             MOV     DWORD PTR DS:[4CA1B0],ESI
  00458F20    A3 B8A14C00               MOV     DWORD PTR DS:[4CA1B8],EAX
  00458F25    FFD3                      CALL    EBX                                     ; 取得长度
  00458F27    85C0                      TEST    EAX,EAX
  00458F29    0F85 BC000000             JNZ     hsl2.00458FEB
  00458F2F    83C7 04                   ADD     EDI,4
  00458F32    A1 B4A14C00               MOV     EAX,DWORD PTR DS:[4CA1B4]               ; 保存
  00458F37    8907                      MOV     DWORD PTR DS:[EDI],EAX
  00458F39    A1 44A34C00               MOV     EAX,DWORD PTR DS:[4CA344]
  00458F3E    A3 28A64700               MOV     DWORD PTR DS:[47A628],EAX
  00458F43    68 D4A14C00               PUSH    hsl2.004CA1D4
  00458F48    56                        PUSH    ESI
  00458F49    68 04080000               PUSH    804
  00458F4E    50                        PUSH    EAX
  00458F4F    FFD3                      CALL    EBX                                     ; 关闭
  00458F51    A3 28A64700               MOV     DWORD PTR DS:[47A628],EAX
  00458F56    5A                        POP     EDX
  00458F57    59                        POP     ECX
  00458F58    42                        INC     EDX                                     ; 打开下一首
  00458F59  ^ E9 64FFFFFF               JMP     hsl2.00458EC2
  
  
  00458FF1    61                        POPAD
  00458FF2    C3                        RETN
  
  
  4CE020处是根据当前音乐的号码取得文件路径的代码,用了一个笨办法,直接比较EDX值然后改写对应内存,后来看了一下这个程序中已经有wsprintfA这个输入函数了,所以可以直接利用这个函数写出来,不过已经写好就就懒得再改了....
  
  004CE020    60                        PUSHAD
  004CE021    4A                        DEC     EDX
  004CE022    75 0A                     JNZ     SHORT hsl2.004CE02E
  004CE024    BB 31300000               MOV     EBX,3031
  004CE029    E9 E7000000               JMP     hsl2.004CE115
  004CE02E    4A                        DEC     EDX
  004CE02F    75 0A                     JNZ     SHORT hsl2.004CE03B
  004CE031    BB 32300000               MOV     EBX,3032
  004CE036    E9 DA000000               JMP     hsl2.004CE115
  004CE03B    4A                        DEC     EDX
  004CE03C    75 0A                     JNZ     SHORT hsl2.004CE048
  004CE03E    BB 33300000               MOV     EBX,3033
  004CE043    E9 CD000000               JMP     hsl2.004CE115
  004CE048    4A                        DEC     EDX
  004CE049    75 0A                     JNZ     SHORT hsl2.004CE055
  004CE04B    BB 34300000               MOV     EBX,3034
  004CE050    E9 C0000000               JMP     hsl2.004CE115
  004CE055    4A                        DEC     EDX
  004CE056    75 0A                     JNZ     SHORT hsl2.004CE062
  004CE058    BB 35300000               MOV     EBX,3035
  004CE05D    E9 B3000000               JMP     hsl2.004CE115
  004CE062    4A                        DEC     EDX
  004CE063    75 0A                     JNZ     SHORT hsl2.004CE06F
  004CE065    BB 36300000               MOV     EBX,3036
  004CE06A    E9 A6000000               JMP     hsl2.004CE115
  004CE06F    4A                        DEC     EDX
  004CE070    75 0A                     JNZ     SHORT hsl2.004CE07C
  004CE072    BB 37300000               MOV     EBX,3037
  004CE077    E9 99000000               JMP     hsl2.004CE115
  004CE07C    4A                        DEC     EDX
  004CE07D    75 0A                     JNZ     SHORT hsl2.004CE089
  004CE07F    BB 38300000               MOV     EBX,3038
  004CE084    E9 8C000000               JMP     hsl2.004CE115
  004CE089    4A                        DEC     EDX
  004CE08A    75 0A                     JNZ     SHORT hsl2.004CE096
  004CE08C    BB 39300000               MOV     EBX,3039
  004CE091    E9 7F000000               JMP     hsl2.004CE115
  004CE096    4A                        DEC     EDX
  004CE097    75 07                     JNZ     SHORT hsl2.004CE0A0
  004CE099    BB 30310000               MOV     EBX,3130
  004CE09E    EB 75                     JMP     SHORT hsl2.004CE115
  004CE0A0    4A                        DEC     EDX
  004CE0A1    75 07                     JNZ     SHORT hsl2.004CE0AA
  004CE0A3    BB 31310000               MOV     EBX,3131
  004CE0A8    EB 6B                     JMP     SHORT hsl2.004CE115
  004CE0AA    4A                        DEC     EDX
  004CE0AB    75 07                     JNZ     SHORT hsl2.004CE0B4
  004CE0AD    BB 32310000               MOV     EBX,3132
  004CE0B2    EB 61                     JMP     SHORT hsl2.004CE115
  004CE0B4    4A                        DEC     EDX
  004CE0B5    75 07                     JNZ     SHORT hsl2.004CE0BE
  004CE0B7    BB 33310000               MOV     EBX,3133
  004CE0BC    EB 57                     JMP     SHORT hsl2.004CE115
  004CE0BE    4A                        DEC     EDX
  004CE0BF    75 07                     JNZ     SHORT hsl2.004CE0C8
  004CE0C1    BB 34310000               MOV     EBX,3134
  004CE0C6    EB 4D                     JMP     SHORT hsl2.004CE115
  004CE0C8    4A                        DEC     EDX
  004CE0C9    75 07                     JNZ     SHORT hsl2.004CE0D2
  004CE0CB    BB 35310000               MOV     EBX,3135
  004CE0D0    EB 43                     JMP     SHORT hsl2.004CE115
  004CE0D2    4A                        DEC     EDX
  004CE0D3    75 07                     JNZ     SHORT hsl2.004CE0DC
  004CE0D5    BB 36310000               MOV     EBX,3136
  004CE0DA    EB 39                     JMP     SHORT hsl2.004CE115
  004CE0DC    4A                        DEC     EDX
  004CE0DD    75 07                     JNZ     SHORT hsl2.004CE0E6
  004CE0DF    BB 37310000               MOV     EBX,3137
  004CE0E4    EB 2F                     JMP     SHORT hsl2.004CE115
  004CE0E6    4A                        DEC     EDX
  004CE0E7    75 07                     JNZ     SHORT hsl2.004CE0F0
  004CE0E9    BB 38310000               MOV     EBX,3138
  004CE0EE    EB 25                     JMP     SHORT hsl2.004CE115
  004CE0F0    4A                        DEC     EDX
  004CE0F1    75 07                     JNZ     SHORT hsl2.004CE0FA
  004CE0F3    BB 39310000               MOV     EBX,3139
  004CE0F8    EB 1B                     JMP     SHORT hsl2.004CE115
  004CE0FA    BB 32300000               MOV     EBX,3032
  004CE0FF    EB 14                     JMP     SHORT hsl2.004CE115
  
  004CE115    883D 19E04C00             MOV     BYTE PTR DS:[4CE019],BH
  004CE11B    881D 1AE04C00             MOV     BYTE PTR DS:[4CE01A],BL
  004CE121    61                        POPAD
  004CE122    C3                        RETN
  
  到这里,初始化的工作基本完成了,但是还不能出声音,还需要找到对应调用播放CD的地方.
  找到mciSendCommandA函数上下条件断点,[ESP+8]==806,即开始播放时下断,中断之后堆栈中显示
  
  0012FEC4   00458C4F  返回到 hsl2.00458C4F 来自 WINMM.mciSendCommandA
  0012FEC8   00000000  ID
  0012FECC   00000806  MCI_OPEN
  0012FED0   0000000C  MCI_TO | MCI_FROM
  0012FED4   004CA500  hsl2.004CA500
  
  回到程序中,发现这段代码从458C00开始:
  
  00458C00    8B15 28A64700             MOV     EDX,DWORD PTR DS:[47A628]               ; 设备ID
  00458C06    56                        PUSH    ESI
  00458C07    8B7424 08                 MOV     ESI,DWORD PTR SS:[ESP+8]
  00458C0B    83FA FF                   CMP     EDX,-1                                  ; 如果设备ID是-1,则直接返回
  00458C0E    57                        PUSH    EDI
  00458C0F    74 5E                     JE      SHORT hsl2.00458C6F
  00458C11    8B3D 58534C00             MOV     EDI,DWORD PTR DS:[4C5358]               ; 音乐数量
  00458C17    8D46 01                   LEA     EAX,DWORD PTR DS:[ESI+1]
  00458C1A    3BC7                      CMP     EAX,EDI
  00458C1C    C705 00A54C00 00000000    MOV     DWORD PTR DS:[4CA500],0                 ; lpPlay
  00458C26    8935 04A54C00             MOV     DWORD PTR DS:[4CA504],ESI               ; 播放开始位置
  00458C2C    A3 08A54C00               MOV     DWORD PTR DS:[4CA508],EAX               ; 播放结束位置
  00458C31    B9 0C000000               MOV     ECX,0C                                  ; MCI_TO | MCI_FROM
  00458C36    7E 05                     JLE     SHORT hsl2.00458C3D
  00458C38    B9 04000000               MOV     ECX,4
  00458C3D    68 00A54C00               PUSH    hsl2.004CA500
  00458C42    51                        PUSH    ECX
  00458C43    68 06080000               PUSH    806                                     ; MCI_PLAY
  00458C48    52                        PUSH    EDX
  00458C49    FF15 1CB44C00             CALL    DWORD PTR DS:[<&WINMM.mciSendCommandA>] ; WINMM.mciSendCommandA
  00458C4F    85C0                      TEST    EAX,EAX
  00458C51    75 16                     JNZ     SHORT hsl2.00458C69
  00458C53    56                        PUSH    ESI
  00458C54    C705 5C534C00 01000000    MOV     DWORD PTR DS:[4C535C],1
  00458C5E    E8 BD010000               CALL    hsl2.00458E20
  00458C63    83C4 04                   ADD     ESP,4
  00458C66    5F                        POP     EDI
  00458C67    5E                        POP     ESI
  00458C68    C3                        RETN
  00458C69    83C8 FF                   OR      EAX,FFFFFFFF
  00458C6C    5F                        POP     EDI
  00458C6D    5E                        POP     ESI
  00458C6E    C3                        RETN
  00458C6F    56                        PUSH    ESI
  00458C70    E8 AB010000               CALL    hsl2.00458E20
  00458C75    83C4 04                   ADD     ESP,4
  00458C78    5F                        POP     EDI
  00458C79    5E                        POP     ESI
  00458C7A    C3                        RETN
  
  上面在458C00处取设备ID,由于原来是从光盘播放,所以只需要在前面初始化时打开一次即可,改成MP3之后需要播放之前先把已经打开的设备关闭,再重新打开设备.在4CE200处输入播放MP3的程序段:
  
  004CE200    60                        PUSHAD
  004CE201    A1 28A64700               MOV     EAX,DWORD PTR DS:[47A628]
  004CE206    85C0                      TEST    EAX,EAX
  004CE208    74 19                     JE      SHORT hsl2.004CE223                     ; 关闭已经打开的设备
  004CE20A    68 D4A14C00               PUSH    hsl2.004CA1D4
  004CE20F    33F6                      XOR     ESI,ESI
  004CE211    56                        PUSH    ESI
  004CE212    68 04080000               PUSH    804
  004CE217    50                        PUSH    EAX
  004CE218    FF15 1CB44C00             CALL    DWORD PTR DS:[<&WINMM.mciSendCommandA>] ; WINMM.mciSendCommandA
  004CE21E    A3 28A64700               MOV     DWORD PTR DS:[47A628],EAX
  004CE223    8B15 04A54C00             MOV     EDX,DWORD PTR DS:[4CA504]
  004CE229    E8 F2FDFFFF               CALL    hsl2.004CE020
  004CE22E    68 40A34C00               PUSH    hsl2.004CA340                           ; 重新打开设备
  004CE233    68 0A020000               PUSH    20A
  004CE238    68 03080000               PUSH    803
  004CE23D    50                        PUSH    EAX
  004CE23E    A3 40A34C00               MOV     DWORD PTR DS:[4CA340],EAX
  004CE243    C705 48A34C00 00E04C00    MOV     DWORD PTR DS:[4CA348],hsl2.004CE000     ; ASCII "waveaudio"
  004CE24D    C705 4CA34C00 10E04C00    MOV     DWORD PTR DS:[4CA34C],hsl2.004CE010     ; ASCII "mp3\track??.mp3"
  004CE257    FF15 1CB44C00             CALL    DWORD PTR DS:[<&WINMM.mciSendCommandA>] ; WINMM.mciSendCommandA
  004CE25D    85C0                      TEST    EAX,EAX
  004CE25F    75 44                     JNZ     SHORT hsl2.004CE2A5
  004CE261    A1 44A34C00               MOV     EAX,DWORD PTR DS:[4CA344]
  004CE266    A3 28A64700               MOV     DWORD PTR DS:[47A628],EAX
  004CE26B    BF 60A34C00               MOV     EDI,hsl2.004CA360
  004CE270    8B15 04A54C00             MOV     EDX,DWORD PTR DS:[4CA504]
  004CE276    4A                        DEC     EDX
  004CE277    C1E2 02                   SHL     EDX,2
  004CE27A    03FA                      ADD     EDI,EDX
  004CE27C    8B0F                      MOV     ECX,DWORD PTR DS:[EDI]
  004CE27E    68 00A54C00               PUSH    hsl2.004CA500                           ; 播放
  004CE283    6A 0C                     PUSH    0C
  004CE285    68 06080000               PUSH    806
  004CE28A    50                        PUSH    EAX
  004CE28B    890D 08A54C00             MOV     DWORD PTR DS:[4CA508],ECX
  004CE291    C705 04A54C00 00000000    MOV     DWORD PTR DS:[4CA504],0
  004CE29B    FF15 1CB44C00             CALL    DWORD PTR DS:[<&WINMM.mciSendCommandA>] ; WINMM.mciSendCommandA
  004CE2A1    85C0                      TEST    EAX,EAX
  004CE2A3    75 00                     JNZ     SHORT hsl2.004CE2A5
  004CE2A5    61                        POPAD
  004CE2A6    C3                        RETN
  
  把原来458C49处调用函数的上面改成:
  
  00458C1C    C705 00A54C00 00000000    MOV     DWORD PTR DS:[4CA500],0                 ; lpPlay
  00458C26    8935 04A54C00             MOV     DWORD PTR DS:[4CA504],ESI               ; 播放开始位置
  00458C2C    A3 08A54C00               MOV     DWORD PTR DS:[4CA508],EAX               ; 播放结束位置
  00458C31    B9 0C000000               MOV     ECX,0C                                  ; MCI_TO | MCI_FROM
  00458C36    7E 05                     JLE     SHORT hsl2.00458C3D
  00458C38    B9 04000000               MOV     ECX,4
  00458C3D    E8 BE550700               CALL    hsl2.004CE200
  00458C42    EB 0F                     JMP     SHORT hsl2.00458C53
  00458C44    90                        NOP
  00458C45    90                        NOP
  00458C46    90                        NOP
  00458C47    90                        NOP
  00458C48    52                        PUSH    EDX
  00458C49    FF15 1CB44C00             CALL    DWORD PTR DS:[<&WINMM.mciSendCommandA>] ; WINMM.mciSendCommandA
  00458C4F    85C0                      TEST    EAX,EAX
  00458C51    75 16                     JNZ     SHORT hsl2.00458C69
  00458C53    56                        PUSH    ESI
  00458C54    C705 5C534C00 01000000    MOV     DWORD PTR DS:[4C535C],1
  
  利用新的播放函数取代原来的函数,原来4CA504处存放的是要播放的音轨号,现在可以需要把音轨号码更改为对应的文件路径.并取得对应文件长度,放在4CA504和4CA508处.
  
  改完之后,取出光盘,程序就可以运行了.并且音乐也正常播放.
  
  但是运行时有一点不好,就是一开始初始化时,由于要取得所有MP3的文件长度,需要反复打开和关闭文件,需要的时间比较长,并且由于还没有进行窗口的初始化,所以窗口都没有显示出来,给人感觉好像程序没有运行一样.
  由于文件长度只是在播放时需要用到,所以想到在初始化时不取文件长度,在播放时一起做这个工作,这样程序启动时间会缩短.
  根据这个思路,把458E90处更改为:
  
  00458E90    60                        PUSHAD
  00458E91    E8 AAFFFFFF               CALL    hsl2.00458E40
  00458E96    8B1D 1CB44C00             MOV     EBX,DWORD PTR DS:[<&WINMM.mciSendComman>; WINMM.mciSendCommandA
  00458E9C    B9 64000000               MOV     ECX,64
  00458EA1    83C8 FF                   OR      EAX,FFFFFFFF
  00458EA4    BF 60A34C00               MOV     EDI,hsl2.004CA360
  00458EA9    33F6                      XOR     ESI,ESI
  00458EAB    F3:AB                     REP     STOS DWORD PTR ES:[EDI]                 ; 初始化成FFFFFFFF
  00458EAD    B8 00000000               MOV     EAX,0
  00458EB2    A3 28A64700               MOV     DWORD PTR DS:[47A628],EAX
  00458EB7    61                        POPAD
  00458EB8    C3                        RETN
  
  只需要把对应文件长度的地方初始化即可.把4CE200处代码更改为:
  
  004CE200    60                        PUSHAD
  004CE201    A1 28A64700               MOV     EAX,DWORD PTR DS:[47A628]
  004CE206    85C0                      TEST    EAX,EAX
  004CE208    74 19                     JE      SHORT hsl2.004CE223                     ; 关闭已经打开的设备
  004CE20A    68 D4A14C00               PUSH    hsl2.004CA1D4
  004CE20F    33F6                      XOR     ESI,ESI
  004CE211    56                        PUSH    ESI
  004CE212    68 04080000               PUSH    804
  004CE217    50                        PUSH    EAX
  004CE218    FF15 1CB44C00             CALL    DWORD PTR DS:[<&WINMM.mciSendCommandA>] ; WINMM.mciSendCommandA
  004CE21E    A3 28A64700               MOV     DWORD PTR DS:[47A628],EAX
  004CE223    8B15 04A54C00             MOV     EDX,DWORD PTR DS:[4CA504]
  004CE229    E8 F2FDFFFF               CALL    hsl2.004CE020
  004CE22E    68 40A34C00               PUSH    hsl2.004CA340                           ; 重新打开设备
  004CE233    68 0A020000               PUSH    20A
  004CE238    68 03080000               PUSH    803
  004CE23D    50                        PUSH    EAX
  004CE23E    A3 40A34C00               MOV     DWORD PTR DS:[4CA340],EAX
  004CE243    C705 48A34C00 00E04C00    MOV     DWORD PTR DS:[4CA348],hsl2.004CE000     ; ASCII "waveaudio"
  004CE24D    C705 4CA34C00 10E04C00    MOV     DWORD PTR DS:[4CA34C],hsl2.004CE010     ; ASCII "mp3\track??.mp3"
  004CE257    FF15 1CB44C00             CALL    DWORD PTR DS:[<&WINMM.mciSendCommandA>] ; WINMM.mciSendCommandA
  004CE25D    85C0                      TEST    EAX,EAX
  004CE25F    75 44                     JNZ     SHORT hsl2.004CE2A5
  004CE261    A1 44A34C00               MOV     EAX,DWORD PTR DS:[4CA344]
  004CE266    A3 28A64700               MOV     DWORD PTR DS:[47A628],EAX
  004CE26B    BF 60A34C00               MOV     EDI,hsl2.004CA360
  004CE270    8B15 04A54C00             MOV     EDX,DWORD PTR DS:[4CA504]
  004CE276    4A                        DEC     EDX
  004CE277    C1E2 02                   SHL     EDX,2
  004CE27A    03FA                      ADD     EDI,EDX
  004CE27C    8B0F                      MOV     ECX,DWORD PTR DS:[EDI]
  004CE27E    83F9 FF                   CMP     ECX,-1                                  ; 如果长度是-1,则先获取文件长度
  004CE281    75 2F                     JNZ     SHORT hsl2.004CE2B2
  004CE283    68 B0A14C00               PUSH    hsl2.004CA1B0
  004CE288    68 00010000               PUSH    100
  004CE28D    68 14080000               PUSH    814
  004CE292    50                        PUSH    EAX
  004CE293    33F6                      XOR     ESI,ESI
  004CE295    8935 B0A14C00             MOV     DWORD PTR DS:[4CA1B0],ESI
  004CE29B    A3 B8A14C00               MOV     DWORD PTR DS:[4CA1B8],EAX
  004CE2A0    FF15 1CB44C00             CALL    DWORD PTR DS:[<&WINMM.mciSendCommandA>] ; WINMM.mciSendCommandA
  004CE2A6    85C0                      TEST    EAX,EAX
  004CE2A8    75 34                     JNZ     SHORT hsl2.004CE2DE
  004CE2AA    8B0D B4A14C00             MOV     ECX,DWORD PTR DS:[4CA1B4]
  004CE2B0    890F                      MOV     DWORD PTR DS:[EDI],ECX
  004CE2B2    68 00A54C00               PUSH    hsl2.004CA500                           ; 播放
  004CE2B7    6A 0C                     PUSH    0C
  004CE2B9    68 06080000               PUSH    806
  004CE2BE    A1 28A64700               MOV     EAX,DWORD PTR DS:[47A628]
  004CE2C3    50                        PUSH    EAX
  004CE2C4    C705 04A54C00 00000000    MOV     DWORD PTR DS:[4CA504],0
  004CE2CE    890D 08A54C00             MOV     DWORD PTR DS:[4CA508],ECX
  004CE2D4    FF15 1CB44C00             CALL    DWORD PTR DS:[<&WINMM.mciSendCommandA>] ; WINMM.mciSendCommandA
  004CE2DA    85C0                      TEST    EAX,EAX
  004CE2DC    75 00                     JNZ     SHORT hsl2.004CE2DE
  004CE2DE    61                        POPAD
  004CE2DF    C3                        RETN
  
  这时再运行程序,发现反而没有声音了,并且458C00处的程序段也没有被调用.使用更改前的程序在458C00处下断,发现调用是来自42C820处的程序段:
  
  0042C820    A1 384B4C00               MOV     EAX,DWORD PTR DS:[4C4B38]
  0042C825    56                        PUSH    ESI
  0042C826    85C0                      TEST    EAX,EAX
  0042C828    74 65                     JE      SHORT hsl2.0042C88F                ;更改之后从这里就跳走了
  0042C82A    A1 408C4700               MOV     EAX,DWORD PTR DS:[478C40]
  0042C82F    85C0                      TEST    EAX,EAX
  0042C831    74 53                     JE      SHORT hsl2.0042C886
  0042C833    8B7424 08                 MOV     ESI,DWORD PTR SS:[ESP+8]
  0042C837    83FE FF                   CMP     ESI,-1
  0042C83A    74 53                     JE      SHORT hsl2.0042C88F
  0042C83C    56                        PUSH    ESI
  0042C83D    E8 BEC30200               CALL    hsl2.00458C00                     ;在这里调用播放音乐的程序段
  0042C842    83C4 04                   ADD     ESP,4
  0042C845    83F8 FF                   CMP     EAX,-1
  0042C848    A3 184B4C00               MOV     DWORD PTR DS:[4C4B18],EAX
  0042C84D    75 1B                     JNZ     SHORT hsl2.0042C86A
  0042C84F    6A 2A                     PUSH    2A
  0042C851    C705 384B4C00 00000000    MOV     DWORD PTR DS:[4C4B38],0
  0042C85B    A3 2C8C4700               MOV     DWORD PTR DS:[478C2C],EAX
  0042C860    E8 44340300               CALL    hsl2.0045FCA9
  0042C865    83C4 04                   ADD     ESP,4
  0042C868    5E                        POP     ESI
  0042C869    C3                        RETN
  
  更改之后从42C828处就跳走了,不再执行播放音乐的程序段,把跳走的指令直接NOP掉,就可以了.
  
  顺便说一下,这个程序是用FindWindow函数来使程序只有一个实例运行,调试时有进需要两个同时运行进行对比,把调用这个函数之后的跳转指令修改就可以了.
  
--------------------------------------------------------------------------------
【经验总结】
  第一次真正自己修改一个程序,虽然现在回想起来还是不算困难的,但是中间动手做的过程确实费了很大周折.从中学到了不
  少东西,也找到了不少乐趣.
  与所有学习加密解密,软件调试的人共勉!
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2008年10月26日 上午 12:42:31