《鐵甲風暴之黑色戰線》免CD破解手記
By: bood E-mail: boodweb@263.net 2002/2/14
看人家的破文(可不是指人家的文章破),在正式開始前總是有一段講述自己破解這個軟體的原因,至少也要說一下這個軟體的大致功能。這篇文章是我的處女作,當然也不能例外啦:))。有什麼問題還請大蝦們多多指教才是。
這個遊戲大家應該都聽說過吧,還是目標在幾年前出的,當時還紅過一段時間,那時我朋友買了個光碟版,幾天前他不知哪根經搭錯了,想要聯機對戰,這樣就要兩張光碟,現在還哪兒去搞啊。算了,我自己動手吧,還能增加點經驗值呢。
破CD嘛,當然先找GetDriveTypeA函式,mk.exe中共有三個地方用到,但是大致結構都一樣,現在僅挑一個地方出來分析(還有兩個地方在004820D3和0048248D):
:00481CED 8A44241C mov
al, byte ptr [esp+1C] ;初始磁碟機代號
:00481CF1 8D4C241C lea
ecx, dword ptr [esp+1C]
:00481CF5 FEC0
inc al ;下一個磁碟機代號
:00481CF7 51
push ecx
:00481CF8 88442420 mov
byte ptr [esp+20], al
* Reference To: KERNEL32.GetDriveTypeA, Ord:00DFh
|
:00481CFC FF15DC175300 Call dword ptr
[005317DC]
:00481D02 83F805
cmp eax, 00000005 ;光碟機?
:00481D05 754E
jne 00481D55 ;不是則轉,然後測試下一個磁碟機代號
:004824A7 8DBC249C000000 lea edi, dword ptr
[esp+0000009C] ;是光碟機
:004824AE 83C9FF
or ecx, FFFFFFFF ;以下程式碼在磁碟機代號後面加檔名
:004824B1 33C0
xor eax, eax
GetDriveTypeA函式的返回值是這樣的:
#define DRIVE_UNKNOWN 0
#define DRIVE_NO_ROOT_DIR 1
#define DRIVE_REMOVABLE 2 //可移動
#define DRIVE_FIXED 3 //硬碟
#define DRIVE_REMOTE 4
#define DRIVE_CDROM 5 //光碟機
#define DRIVE_RAMDISK 6
那我們就把cmp eax,5改成cmp eax,3,讓它在第一個硬碟上檢查(一般是C盤),也便於我偽造資料嘛。用softice跟下去會發現加的檔名一處是overmax0.avi,另一處是gen0.avi。不是有三個地方嗎?這個我不知道,反正用光碟啟動時只有兩次出現動畫。把這兩個檔案拷到C盤根目錄,再執行遊戲,兩次動畫順利透過,然後在出現選項介面的時候又跳出來說要光碟。這下可要費力氣了...
經過一番痛苦的對比跟蹤(就是看插光碟和不插光碟流程有什麼不同),發現系統函式mciSendString的返回值不同,這下搞清楚了,玩遊戲的時候不是還有CD音樂嘛,怎麼早沒想到呢!用MSDN查查mciSendString發現返回0是成功,那我讓它永遠返回0不就行了,為了不讓光碟機受苦,乾脆一了百了,把整個mciSendString函式都給切了,呵呵,夠毒吧。
:00449F28 6A00
push 00000000
:00449F2A 6800010000 push 00000100
:00449F2F 50
push eax
:00449F30 51
push ecx
* Reference To: WINMM.mciSendStringA, Ord:0034h
|
:00449F31 FF158C1A5300 Call dword ptr
[00531A8C]
:00449F37 33D2
xor edx, edx
:00449F39 85C0
test eax, eax
:00449F3B 0F94C2
sete dl
:00449F3E 8BC2
mov eax, edx
:00449F40 C20800
ret 0008
把Call dword ptr [00531A8C](就是mciSendString)改成:
83C410 add esp,10
33C0 xor eax,eax
90 nop
再試試,好用了!不過還要想辦法幹掉硬碟上的那兩個累贅(沒辦法,有客觀原因在:硬碟太小)。在CreateFileA設斷,注意應該先設GetDriveTypeA的斷,攔下來後再設CreateFileA的斷,因為系統好像一直在頻繁的呼叫CreateFileA(要不就是我的機器有問題)。F12跳出後發現:
* Reference To: KERNEL32.CreateFileA, Ord:0031h
|
:004A348A FF1520175300 Call dword ptr
[00531720]
:004A3490 8945FC
mov dword ptr [ebp-04], eax
:004A3493 837DFCFF cmp
dword ptr [ebp-04], FFFFFFFF ;返回值是否是-1?
:004A3497 7523
jne 004A34BC ;不是-1則轉
... ...
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004A3497(C)
|
:004A34BC 8B4DFC
mov ecx, dword ptr [ebp-04]
:004A34BF 51
push ecx
* Reference To: KERNEL32.GetFileType, Ord:00EFh
|
:004A34C0 FF1500185300 Call dword ptr
[00531800] ;檢查檔案型別
:004A34C6 8945F4
mov dword ptr [ebp-0C], eax
:004A34C9 837DF400 cmp
dword ptr [ebp-0C], 00000000 ;相等則錯誤
:004A34CD 752D
jne 004A34FC ;不是0則轉
... ...
;下面轉到004A351C就差不多正確了,GetFileType函式倒沒仔細研究過
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004A34CD(C)
|
:004A34FC 837DF402 cmp
dword ptr [ebp-0C], 00000002
:004A3500 750B
jne 004A350D
:004A3502 8A4DC8
mov cl, byte ptr [ebp-38]
:004A3505 80C940
or cl, 40
:004A3508 884DC8
mov byte ptr [ebp-38], cl
:004A350B EB0F
jmp 004A351C
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004A3500(C)
|
:004A350D 837DF403 cmp
dword ptr [ebp-0C], 00000003
:004A3511 7509
jne 004A351C
:004A3513 8A55C8
mov dl, byte ptr [ebp-38]
:004A3516 80CA08
or dl, 08
:004A3519 8855C8
mov byte ptr [ebp-38], dl
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004A350B(U), :004A3511(C)
|
:004A351C 8B45FC
mov eax, dword ptr [ebp-04]
我轉到004A351C的方法是在CreateFileA後的比較那裡插個jmp直接跳到004A3502,即把那裡改成:
* Reference To: KERNEL32.CreateFileA, Ord:0031h
|
:004A348A FF1520175300 Call dword ptr
[00531720]
:004A3490 8945FC
mov dword ptr [ebp-04], eax
:004A3493 E96A000000 jmp 004A3502
;6A = 4A3502-(4A3493+5) 5是jmp指令本身長度
:004A3498 90
nop
全部搞定,清理戰場,把C盤上的兩個avi刪了:))。可以開始對戰了,呵呵!