SmartCheck 6.03的InstallShield序列號破解(上)――好久沒研究了。 (7千字)

看雪資料發表於2001-08-20

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,是應該跟進去的時候了。

相關文章