SmartCheck 6.03的InstallShield序列號破解。
Passion
2001.8.20
SmartCheck 6.03對於破解者來說不但是對付VB的利器,而且它自個兒也算是典型的InstallShield安裝的破解範例。Numega的產品的檢驗過程似乎都類似。我以前不完全地破過SoftICE,因為不全,感覺總不對,這次拿SmartCheck重新來一次,希望過程還算完整。
先拿Windows instalshield decompiler也就是wisdec反setup.ins,反出來一大段。有過一點破Sice的經驗,也不浪費時間查詢字串“The
Serial Number……”了,反正找不到。看看它匯入了什麼DLL檔案,也就是看MISC選單下的DLL import,有倆比較特別,是UTILITY.DLL和NMINST32.DLL,其中UTILITY.DLL有個匯出的函式叫DigitCheck,一個引數還是STRING,似乎專門就是檢驗序列號的,這麼容易?
在反編譯後的文字中找字串UTILITY.DLL,很容易就找到一段:
StrLocal[0007] = SUPPORTDIR ^ "UTILITY.dll"
00004C96: 0128 IF (UseDLL (StrLocal[0007]) = 00000000) THEN
00004CB6: 00B4 NumLocal[0001] = UTILITY.DigitCheck
(StrLocal[0002])
00004CC6: 00B3 UnUseDLL (StrLocal[0007])
00004CC7: 0000 ENDIF
――這是典型的動態載入UTILITY.DLL,檢驗序列號再釋放該DLL的過程。
動態載入好辦,至少可以斷LoadLibraryA。
好,現在開始動態跟蹤。啟動SmartCheck的setup.exe,下一步下一步,嗯?怎麼序列號沒填就透過了?――對了,SmartCheck安裝的時候會檢驗登錄檔裡是否有現存的NUmega的同種產品,有的話就自動讀出序列號來填到序列號框裡去,真是體貼人哇。――我們們這群人誰沒裝Numega的東西?^_^
算了算了,按上一步回到序列號填寫的介面。Ctrl+D切入Sice,下斷bpx loadlibrarya do "d esp->4"
回來按下一步,斷了,正是載入utility.dll。
且慢,這是正確的序列號,倘若亂填的呢?――真的亂填一氣,按下一步,糟!直接出來序列號錯誤的訊息框了。
看來序列號有兩步檢驗過程,第一步透過後才loadlibraryA來載入UTILITY.DLL來進行第二次檢驗。怎麼辦?
斷messageboxa的話也有效,斷後返回nminst32.dll的領空(在我的機子上call messageboxa的地址是2491cf9,mod
nmi命令可看見NMINST32.DLL的基址是2490000),只是只能跳過檢驗,不能幫我們弄出正確的序列號來。
看來是nminst32.dll在弄鬼,再靜態的反反看,用Win32Dasm反一下nminst32.dll,10001cf9處果然是Call MessageBoxa,往上看,一大段REPNE
SCANSB加MOVSB的,也不知道在幹什麼。
往上面找個斷點,既不能太遠進不來,也不能太近(怕已經出錯了)。――這段過程好像是用SendDlgItemmessagea來獲取文字框內容並且進行第一步檢驗,對了就EndDialog。前後找找看就知道了。
選個斷點1A70,也就是2491a70,是輸出函式的開始:
:10001A70 8B442408 mov
eax, dword ptr [esp+08]
:10001A74 81EC64020000 sub esp, 00000264
:10001A7A 83E810
sub eax, 00000010
:10001A7D 53
push ebx
:10001A7E 55
push ebp
:10001A7F 56
push esi
:10001A80 57
push edi
:10001A81 0F8490050000 je 10002017
:10001A87 2D00010000 sub eax,
00000100
:10001A8C 0F841C040000 je 10001EAE
:10001A92 48
dec eax
:10001A93 0F858E050000 jne 10002027
:10001A99 8B842480020000 mov eax, dword ptr
[esp+00000280]
:10001AA0 25FFFF0000 and eax,
0000FFFF
:10001AA5 83F80C
cmp eax, 0000000C
:10001AA8 0F8F76030000 jg 10001E24
:10001AAE 0F8461030000 je 10001E15
:10001AB4 48
dec eax
:10001AB5 7416
je 10001ACD
:10001AB7 48
dec eax
:10001AB8 0F8569050000 jne 10002027
其實這個斷點沒啥效果,程式沒事就進來(這段輸出函式是對話方塊的過程,隨便動點什麼東西都會進來)。
不過跟了幾次後覺得前面的是檢查點選了什麼按鈕的,看看這兒1AB5處的跳
:10001AB5 7416
je 10001ACD
其他幾個跳都很遠(差不多就是直接退出對話方塊過程),而且這個跳指向的地方附近就有SendDlgItemMessagea函式引用。估計這裡跳的話可能有文章,於是下斷2491acd
(不知怎的,setup介面中直接CTRL+D切入再下斷的話大多數不成功,不是沒效果就是Invalid address,難道填序列號的時候nminsl32.dll還沒裝進來?不管它,填滿後先斷hmemcpy進來,回Nminst32領空再來下斷bpx
2491acd,注意得清掉hmemcpy的斷點。)
好,斷了!F10往下走:
* Reference To: USER32.SendDlgItemMessageA, Ord:01D8h
|
:10001AD4 8B1D30230210 mov ebx, dword
ptr [10022330]
…………
:10001AEC FFD3
call ebx
…………
:10001B00 FFD3
call ebx
…………
:10001B11 FFD3
call ebx
連續三次Call USER32.SendDlgItemMessageA,目的八成就是獲得三個序列號框中的內容。
:10001B1A 33C0
xor eax, eax
:10001B1C F2
repnz //這裡看看EDI,就是輸入的序列號的前四個字元。
:10001B1D AE
scasb
跟下來一大段REPNE MOVSB SCANSB之類的,不容易弄明白什麼功能,直到下面這裡:
:10001C52 8D442410 lea
eax, dword ptr [esp+10]
//這裡EAX看看,是序列號第一部分的前三個字元,於是可以明白,前面是取三個字元。^_^
:10001C56 33F6
xor esi, esi
:10001C58 50
push eax
:10001C59 68608F0110 push 10018F60
:10001C5E E8DD860000 call 1000A340
//對這前三個字元進行檢驗。
10001C5E這裡來個d *esp,看見什麼了?一大堆數字:640 641 480 481 490 491 510 511 520 521
跟進去看看,原來:10001C5E處的這個Call是檢驗輸入的序列號的前三位數字是不是這一堆中的,不是?不是當然就不行!
:10001C66 85C0
test eax, eax
:10001C68 7542
jne 10001CAC
//屬於這一堆的話,返回那個符合的地址,否則返回0,不跳就完了。
稍微改改資料,接著跳:
:10001CAC 6820A60110 push 1001A620
:10001CB1 E85A810000 call 10009E10
//這裡是第二步檢驗。
:10001CB6 83C404
add esp, 00000004
:10001CB9 8BF0
mov esi, eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001CAA(C)
|
:10001CBB 85F6
test esi, esi
:10001CBD 7552
jne 10001D11 //這裡不跳也完蛋。
現在,序列號判斷的流程都清楚了。――如果從:10001CB1處的CALL進去,裡面會來個Loadlibrarya,這才真正的裝入utility.dll檔案。接著GetProcAddress,傳引數
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10009E75(C)
|
:10009E80 6890A20110 push 1001A290
//含utility.dll路徑的字串
* Reference To: KERNEL32.LoadLibraryA, Ord:0190h
|
:10009E85 FF1518220210 Call dword ptr
[10022218] //裝utility.dll
:10009E8B 8BF0
mov esi, eax
:10009E8D 85F6
test esi, esi //esi返回DLL的控制程式碼。
:10009E8F 7539
jne 10009ECA //成功則跳。
接著GetProcAddress,傳引數呼叫
* Possible StringData Ref from Data Obj ->"DigitCheck"
|
:10009ECA 68C0520110 push 100152C0
:10009ECF 56
push esi
* Reference To: KERNEL32.GetProcAddress, Ord:0116h
|
:10009ED0 FF151C220210 Call dword ptr
[1002221C] //取DigitCheck函式的地址
:10009ED6 85C0
test eax, eax
:10009ED8 740E
je 10009EE8
:10009EDA 8D4C240C lea
ecx, dword ptr [esp+0C]
//ECX指向我們輸入的序列號,已經去掉了“-”號的,
:10009EDE 51
push ecx
:10009EDF FFD0
call eax //呼叫,
:10009EE1 83C404
add esp, 00000004
:10009EE4 8BD8
mov ebx, eax
:10009EE6 EB2D
jmp 10009F15
10009EDF處以剛剛推入堆疊的序列號的地址為引數呼叫utility.DigitCheck,是應該跟進去的時候了。