破解用ASProtect v1.2x加殼後程式使用限制的通用方法 (15千字)

看雪資料發表於2002-04-27

主要目標:
    不脫殼的情況下解除Delphi Application Peeper Pro v2.3.1.9的時間限制,並找到通用的方法(有待驗證).

程式簡介:
    主要用來檢視Borland Delphi (versions 2-6) and Borland C++ Builder (versions 1-5)程式的視窗,控制元件資訊,這個版本已經可以檢視加殼了的程式,可能還有其它實用功能.

使用工具:
    Trw2000,SuperBPM,ASProtect v1.2註冊版,紙&筆

    此軟體分Pro版和Lite版,Pro是完整版,但要註冊,程式用ASProtect 1.22加殼(Fi 2.49報告),註冊方式完全採用ASProtect加殼時的30天試用選項,不註冊會顯示NAG提示剩下天數,過期後也能使用,但程式會不定時出現過期視窗.此軟體已經由fwnl脫過殼,論壇精華里有,脫殼後程式同時去掉時間保護,因為ASProtect的註冊保護都是在殼裡的,但程式脫殼後熱鍵Ctrl同時失去,About選單也不能顯示.

    剛開始破解時我沒想到它的註冊是由ASProtect來保護的,因為ASProtect 1.2的過期對話方塊只是一個簡單的MessageBox,於是先去找Keyfile保護,再找登錄檔,經過連日苦戰才找到重點,因為本人水平有限,請大家指正!

    我們先來看看用ASProtect加殼時的一些保護選項,主要有:天數限制,次數限制,未註冊提示等,另外有個登錄檔選項,可以生成註冊名對應的註冊碼,可選註冊碼的儲存地址,生成註冊碼應該是用RSA的演算法,隨機生成一些數來參與運算,以保證每個程式不會重複.它在登錄檔裡的儲存的資訊只有兩個,一個是儲存時間資訊,一個是儲存註冊碼,用ASProtect加殼後的程式在第一次執行時會生成儲存時間的鍵值,儲存註冊碼的鍵值要使用者加入,程式第一次執行先檢查註冊碼,如果沒有就讀時間資訊,經過複雜運算得出剩下時間.所以我們的破解要從這兩個地方入手.那怎麼找到它們呢,對於註冊碼的儲存就比較好找,因為ASProtect在加殼時註冊碼儲存的地方有限制,它一定要儲存在HKEY_CURRENT_USER\SOFTWARE\下,而且是儲存在字串值"Key"裡的,所以用RegMon很容易就能找到.而時間標誌的儲存就沒這麼好找了,且來看看我是怎樣找到的.

    先用SuperBPM,用TRW載入主程式DAP_Pro.exe,下bpx regqueryvalueexa,F5,程式被攔下,F12退出系統CALL以後下d edi看看程式讀了什麼內容,其中被我看到了53321-005-6928712-14614,這個看來是有用的東西,先到登錄檔裡查詢一下發現原來是我的ProductId,那就bpm來看看程式在幹什麼,程式先是用它做了個標準的MD5演算法,再經過複雜的演算法得到一個資料:AC 19 BC F0 4F F0 E7 29 6B 18 DB 35 EB 92 D5 F8,然後這串資料經過幾個Call後得到了一個字串"F0BC19AC-F04F-29E7-186B-35DBF8D592EB",好了,這個我還以為是註冊碼,誰知它最後變成了...CLSID\{.....}的字串,呵呵,這不就是登錄檔裡的鍵值嗎,果然程式跟著就以此鍵值讀取,中斷在我下的斷點裡,讀出鍵值"ltwZlD7mov/qsLc3",我們再下bpm設斷,經過漫長的運算,發現這個鍵值算出的是現在的日期和安裝日期,程式拿資料一比較,就得出了使用的天數.如果將此鍵值刪除你會發現程式又可以使用30天了,當然這個主鍵你也可以用RegMon來找,只要找到以上形式的字串就對了,另外過期後的形式類似這樣:V4UTu+16

    來個總結:受保護的程式先用ProductId(這個每臺機都不會一樣)來算出一組數,將此數轉成字元,用它做為儲存時間標誌的主鍵,此主鍵儲存在HKEY_LOCAL_MACHINE\SOFTWARE\CLASSES\CLSID\下,不好找,但可以用RegMon
找再以主鍵裡的內容來判斷.其實這裡對於這次的目的來說已經是錯誤的了,因為程式只有沒找到註冊碼或註冊碼錯誤才會執行到這裡來的,這裡我浪費了太多時間,但至少知道了ASProtect保護的時間標誌是如何產生的.

    既然我們知道註冊碼儲存地址的限制,那麼用RegMon很容易就找到程式在讀HKEY_CURRENT_USER\Software\SecondDream\DAP_Pro這個主鍵,我們自己建立一個,並在裡面建一個字串值Key,為了保證除錯過程順利,我用ASProtect生成了一個長度和形式都應該正確的註冊碼填入,當然這個註冊碼對於DAP_Pro來說是假的,用TRW載入程式下bpx regqueryvalueexa,很快發現程式用假註冊碼查表得到了一組資料,經過運算後得到一個128位的資料,然後再與其它兩個128位的資料運算,然後......我就暈掉了,搞不懂程式的判斷在何處,它的演算法太複雜了,我只能跟著它運算的結果慢慢找!!

    差點就放棄了,抱著試一試的態度決定除錯一下ASProtect 1.2是怎樣生成註冊碼和如何驗證註冊碼的,看看能不能找到一點線索.當然為了方便觀察記憶體裡的資料我用了和剛才一樣的註冊名Sam.com生成了同樣的註冊碼,然後發現程式是這樣驗證註冊碼的,下面是ASProtect的程式碼:

==Part I====================================================
0187:00449268  LEA      ESI,[EBP+FFFFD800]
0187:0044926E  INC      ESI
0187:0044926F  MOV      EDI,ESI
0187:00449271  PUSH    EDI
0187:00449272  MOV      EAX,[EBX+04]
0187:00449275  PUSH    EAX
0187:00449276  MOV      EAX,[EBX+08]
0187:00449279  PUSH    EAX
0187:0044927A  PUSH    EDI
0187:0044927B  CALL    00448894    <---變形後資料的運算--重點
0187:00449280  MOV      EAX,[EBX]  <---位數80h
0187:00449282  MOV      AL,[EDI+EAX-01]  <---結果的最後一位
0187:00449286  MOV      EDX,[EBX]
0187:00449288  MOV      CL,[EDI]        <---結果的第一位
0187:0044928A  MOV      [EDI+EDX-01],CL  <---放到最後
0187:0044928E  MOV      [EDI],AL        <---最後一位放到第一
0187:00449290  MOV      EAX,[EBP+FFFFD7FC]  <---結果首地址
0187:00449296  MOV      AX,[EAX]
0187:00449299  CMP      AX,[00462814]    <---[00462814]==0
0187:004492A0  JZ      004492B9        <---跳就對啦

運算的結果:
0030:006CCFC5 00 00 02 00 2B 00 01 00-02 00 01 00 10 00 07 00 ....+...........
0030:006CCFD5 53 61 6D 2E 63 6F 6D 20-00 10 00 5C 58 84 9D 8A Sam.com ...\X?
0030:006CCFE5 EB 7E 26 E8 D3 76 57 9C-16 33 25 FF FF 00 00 00 ~&櫨vW?3%...
.....後面全0共128位

總結:
    如果在ASProtect中生成註冊碼時沒有輸入Hardware ID的話最後結果我的註冊名是明碼顯示的,經過分析它的內容是這樣的:資料前兩位必須為0,最後一位也為0,第三個位元組應該是標誌,第5個位元組2B表示後面有多少個位元組的有用資料,有用資料以FF FF結尾,第15位元組7表示註冊名的個數,註冊名後的20應該是註冊名結束的標誌,再後面的資料應該是提供給程式用的,後面還要用到這16個數做運算,但用處何在我未搞清楚,DAP_Pro破解的不完全也就栽倒在這些數里,以上結果裡的2個10應該是資料的開始標誌.再接著往下看你會發現程式在複製我的註冊名和16個位元組的資料,如果這時你將記憶體裡的Sam.com改成Sam Von,ASProtect會顯示對應此註冊碼的註冊名是Sam Von,那麼我們可以基本確定這就是最終結果了.到此我有一個想法,如果在DAP_Pro中,等程式運算完後我就它的結果改成以上結果會怎樣呢?結果請看後部分.另外如果在生成註冊碼時輸入了Hardware ID的話,以上結果不會看到明碼的註冊名,資料也有變化,但ASProtect在這部分就做得比較簡單,它只是用Hardware ID與上面的資料做xor運算而已.
    我們先進入上面的Call看看它是怎樣運算的:

0187:00448894  PUSH    EBP
0187:00448895  MOV      EBP,ESP
0187:00448897  PUSH    EBX
0187:00448898  PUSH    ECX
0187:00448899  PUSH    EDX
0187:0044889A  PUSH    ESI
0187:0044889B  PUSH    EDI
0187:0044889C  CLD   
0187:0044889D  MOV      ESI,[EBP+08]  <---註冊碼的變形
0187:004488A0  LEA      EDI,[00465B48]
0187:004488A6  MOV      ECX,80
0187:004488AB  SHR      ECX,02
0187:004488AE  MOV      EDX,ECX
0187:004488B0  REP MOVSD
0187:004488B2  MOV      ESI,[EBP+0C] <---資料1
0187:004488B5  LEA      EDI,[00465AC8]
0187:004488BB  MOV      ECX,EDX
0187:004488BD  REP MOVSD
0187:004488BF  MOV      ESI,[EBP+10] <---資料2
0187:004488C2  LEA      EDI,[00465BC8]
0187:004488C8  MOV      ECX,EDX
0187:004488CA  REP MOVSD
0187:004488CC  LEA      ESI,[00465B48]<---註冊碼的變形
0187:004488D2  LEA      EDI,[00465C48]
0187:004488D8  MOV      ECX,EDX
0187:004488DA  REP MOVSD
0187:004488DC  MOV      [00465DDC],EDX
0187:004488E2  MOV      EAX,[00465AC8]

下面複雜的演算法就不貼了,這裡我們看到ASProtect將這3個資料連在一起去運算,它以這樣的形式儲存:

資料1
註冊碼變形
資料2
註冊碼變形

共512位,用它們來運算得到以上結果,如果你在上面的44889D處設一個斷點,再按生成註冊碼,你會發現程式斷下了,看esi的內容,原來註冊碼的變形變成了Part I裡的結果,也就是說生成註冊碼和驗證註冊碼用到了同一個CALL,按F12退出來到下面的地方:

==Part II===============================================
0187:00449129  CALL    00448894
0187:0044912E  MOV      ECX,[EBP-0C]
0187:00449131  MOV      ECX,[ECX]
0187:00449133  LEA      EDX,[EBP+FFFFD7C4] <---edx指向結果
0187:00449139  MOV      EAX,[EBP-08]
0187:0044913C  CALL    004052AC
0187:00449141  MOV      EAX,[EBP-10]
0187:00449144  POP      EDI
0187:00449145  POP      ESI
0187:00449146  POP      EBX
0187:00449147  MOV      ESP,EBP
0187:00449149  POP      EBP
0187:0044914A  RET   


得到:
0030:006CA7D9 E2 D5 91 A8 1A 50 51 3A-58 7A 15 8D 3A 5D F6 6A 庹.PQ:Xz.?]j
0030:006CA7E9 63 96 BA C8 6B 49 81 EA-F4 B2 A4 FD CB F8 BB 76 c喝kI牯菠v
0030:006CA7F9 7B 85 D2 3C 8C 5B F7 6A-9F 86 C7 F6 B7 86 CA AB {<[j泅詩
......共128位

    這個結果好眼熟呀,原來這個就是註冊碼的變形,在DAP_Pro我也看到過,程式後面會用此資料查表得到註冊碼.好了,原來它生成註冊碼不是直接用使用者名稱的,程式之前就用註冊名做了一些運算,Part I裡的結果就是算註冊碼的資料,它們都用了同一個CALL,兩個結果能否可逆呢?如果我找到DAP_Pro裡的兩個資料,將它複製到這裡來,生成的註冊碼不就是正確的嗎?於是我做了個試驗,在生成註冊碼時我將資料1裡的一個位元組修改,生成另外一個註冊碼,在驗證此註冊碼時同樣修改資料1裡的同一位元組,結果....."錯誤的註冊碼",呵呵,看來我的想法是行不通的,程式應該還有其它的資料參與運算,這部分我就沒精力再追了,這麼強勁的演算法應該是不可逆的.

    既然軟的不行我們就來硬的,我剛才講過,如果在加殼的程式驗證註冊碼算出結果後將記憶體裡的結果改成Part I裡的結果會怎樣呢,因為它可以算是一個正確的結果呀,於是用了一些小程式來做試驗,結果是完全可以的,它的判斷很簡單,只要結果裡的格式符合標準就行了,後面那16個資料對一般程式一點影響也沒有,程式就和已經註冊的一模一樣,這就是我所說的通用的方法.現在我們回到DAP_Pro中,方法是可行的,問題是如何找到Part I中的程式碼,因為演算法CALL後的一大段程式碼都是比較用的,還必須跳到很遠的地方,也就是說我們有足夠的地方來利用,我的想法是做一個Loader.

    下面是DAP_Pro的程式碼,和Part I是否很相似,其它凡用ASProtect保護的程式都會有這一段,要注意的是因為這一段是殼解壓縮後產生的,每臺機都不一樣,但同一臺機第次執行都是一樣的,這一段是不在任何領空的.

0187:0114EA2A 8B4304          MOV      EAX,[EBX+04]
0187:0114EA2D 8A4407FF        MOV      AL,[EDI+EAX-01]
0187:0114EA31 8B5304          MOV      EDX,[EBX+04]
0187:0114EA34 8A0F            MOV      CL,[EDI]
0187:0114EA36 884C17FF        MOV      [EDI+EDX-01],CL
0187:0114EA3A 8807            MOV      [EDI],AL
0187:0114EA3C 8B85FC6FFEFF    MOV      EAX,[EBP+FFFE6FFC]
0187:0114EA42 668B00          MOV      AX,[EAX]
0187:0114EA45 663B0530231501  CMP      AX,[01152330]
0187:0114EA4C 7417            JZ      0114EA65  <---必須跳
0187:0114EA4E C785F06FFEFF02000000 MOV      DWORD [EBP+FFFE6FF0],02
0187:0114EA58 33C0            XOR      EAX,EAX
0187:0114EA5A 5A              POP      EDX
0187:0114EA5B 59              POP      ECX
0187:0114EA5C 59              POP      ECX
0187:0114EA5D 648910          MOV      [FS:EAX],EDX
0187:0114EA60 E976010000      JMP      0114EBDB
0187:0114EA65 8B8DF46FFEFF    MOV      ECX,[EBP+FFFE6FF4]
0187:0114EA6B 49              DEC      ECX
0187:0114EA6C 8B7B04          MOV      EDI,[EBX+04]
0187:0114EA6F 3BCF            CMP      ECX,EDI
0187:0114EA71 7E25            JNG      0114EA98 <---一定跳,就是說我們至少有
0187:0114EA73 8D0431          LEA      EAX,[ECX+ESI]  114EA2A<->114EA98這一段
0187:0114EA76 8BF0            MOV      ESI,EAX        是可以拿來Patch的
0187:0114EA78 8BC1            MOV      EAX,ECX
0187:0114EA7A 99              CDQ   
0187:0114EA7B F7FF            IDIV    EDI
0187:0114EA7D 85C0            TEST    EAX,EAX
0187:0114EA7F 7E17            JNG      0114EA98
0187:0114EA81 89C7            MOV      EDI,EAX
0187:0114EA83 2B7304          SUB      ESI,[EBX+04]
0187:0114EA86 56              PUSH    ESI
0187:0114EA87 8B4308          MOV      EAX,[EBX+08]
0187:0114EA8A 50              PUSH    EAX
0187:0114EA8B 8B430C          MOV      EAX,[EBX+0C]
0187:0114EA8E 50              PUSH    EAX
0187:0114EA8F 56              PUSH    ESI
0187:0114EA90 E8B7F7FFFF      CALL    0114E24C
0187:0114EA95 4F              DEC      EDI
0187:0114EA96 75EB            JNZ      0114EA83

    我用了序號產生器編寫器的記憶體補丁,補完後執行,哈哈!程式的NAG沒有了,不過~~~~~~~倒是出現了一個提示框,顯示Access violation at address 0114C6F3. Write of address 8D07E07F.唉,寫記憶體錯誤,於是下bpx 114C6F3

0187:0114C6C8  PUSH    EBP
0187:0114C6C9  MOV      EBP,ESP
0187:0114C6CB  PUSH    EBX
0187:0114C6CC  PUSH    ESI
0187:0114C6CD  PUSH    EDI
0187:0114C6CE  MOV      EDI,01153554
0187:0114C6D3  MOV      EBX,[01153654]<---指向16位資料運算的結果
0187:0114C6D9  MOV      EAX,[01153658]
0187:0114C6DE  MOV      ECX,0C
0187:0114C6E3  CDQ   
0187:0114C6E4  IDIV    ECX
0187:0114C6E6  MOV      ESI,EAX
0187:0114C6E8  TEST    ESI,ESI
0187:0114C6EA  JNG      0114C733
0187:0114C6EC  MOV      EAX,[EDI]
0187:0114C6EE  MOV      EAX,[EAX]    <---eax=40000
0187:0114C6F0  ADD      EAX,[EBX]    <---eax+[ebx]=8D07E07F
0187:0114C6F2  INC      EAX
0187:0114C6F3  MOV      DWORD [EAX],01<---錯誤在這裡,[eax]等於8D07E07F
0187:0114C6F9  MOV      EAX,[EDI]
0187:0114C6FB  MOV      EAX,[EAX]
0187:0114C6FD  ADD      EAX,[EBX+04]
0187:0114C700  MOV      EDX,[EBX+08]
0187:0114C703  CALL    0114C68C

    也就是說Part I裡的結果最後的16位資料被程式利用了,如果這裡修改一下程式碼跳過的話出了這個CALL就到了DAP_Pro的領空,分析它的程式碼,是DAP_Pro在呼叫解壓後的一個子程式,也許那16位資料是指向我們的註冊資訊或者某個窗體的資料,因為我們的資料和原定的不同,所以指標亂了,可能程式在啟動時會顯示一些資訊,應該影響不大,因為關掉提示框後程式一切正常,只是About選項沒了,這個情形和fwnl脫掉殼以後是一樣的,還好這些資料不是拿來做功能限制的.由於我沒有ASProtect的高版本,這一步只能跳過(誰能提供???),於是想辦法跳過這個提示框.

    出現提示框後下bpx lockmytask,分析程式碼:

0187:0044E46D  MOV      EDX,[00407C60] <---指向提示框的標題
0187:0044E473  CALL    00402FA4      <---比較是否是發生錯誤的提示框
0187:0044E478  TEST    AL,AL
0187:0044E47A  JNZ      0044E4BF      <---跳就沒事
0187:0044E47C  CMP      WORD [EBX+BA],BYTE +00

    Patch的時候把這裡也改掉,問題是以後再有錯誤就沒有提示啦!方法如下,用序號產生器編寫器的記憶體補丁:

地址      長度        原碼        修改
114EA2A      6    8B43048A4407      C70700000200
114EA30      7    FF8B53048A0F88    C747042B000100
114EA37      7    4C17FF88078B85    C7470802000100
114EA3E      7    FC6FFEFF668B00    C7470C10000700
114EA45      7    663B0530231501    C7471053616D2E  <---此行原碼各機不同,請自行修改
114EA4C      7    7417C785F06FFE    C74714636F6D20      其它的照搬
114EA53      7    FF0200000033C0    C747180010005C
114EA5A      7    5A5959648910E9    C7471C58849D8A
114EA61      7    760100008B8DF4    C74720EB7E26E8
114EA68      7    6FFEFF498B7B04    C74724D376579C
114EA6F      7    3BCF7E258D0431    C74728163325FF
114EA76      7    8BF08BC199F7FF    C7472CFF000000
114EA7D      7    85C07E1789C72B    C7477C00000000
114EA84      7    7304568B430850    C6057AE44400EB  <---Patch提示框
114EA8B      2    8B43            EB0B

    現在,整個世界清靜了,用此方法DAP_Pro的熱鍵可用,其它功能未發現缺少,雖然此法對此程式破解並不算完美,但相信此方法對ASProtect 1.2以上加殼的程式破解時間限制都有效,至少我試過好幾個都行.請大家幫忙測試.但此方法有個問題就是難以找到以上要修改的程式碼,我總結了個方法:先找到程式註冊碼儲存的主鍵,輸入任意大於8位的註冊碼,用TRW載入,下bpx regqueryvalueexa,中斷後下d *(esp+8),當看到記憶體裡出現"Key"時,查詢8A 0F 88 4C 17 FF或33 C0 5A 59 59 64 89 10 E9,附近就是了.如果找不到的話就只能慢慢跟了----痛苦呀.如果你想用你自己的註冊名可以用ASProtect生成,方法參閱Part I&II

    另外在追註冊碼時經常會碰到一些SEH,這東西我不大懂,如下:

0187:0114FDE9  PUSH    BYTE +10
0187:0114FDEB  PUSH    DWORD 0115366C
0187:0114FDF0  MOV      EAX,[EBX+02]  <---EBX=0
0187:0114FDF3  PUSH    EAX
0187:0114FDF4  LEA      EAX,[EBX+06]
0187:0114FDF7  PUSH    EAX
0187:0114FDF8  CALL    0114BFF4

    F8或F12的話就完了,如果不幸來到此只能重來,記住這個Call不要進入,只能F10代過,真是所謂的步步為營呀,所以我對脫殼不感冒:-)

-=End=-


      _/_/_/
    _/        _/_/_/  _/_/_/  _/_/
    _/_/    _/    _/  _/    _/    _/
        _/  _/  _/  _/    _/    _/
_/_/_/      _/_/_/  _/    _/    _/

                                              Sam.com
                                          6:15 2002-4-27

相關文章