對Crunch v1.1加殼程式的手動脫殼及反跟蹤程式碼的一點分析 (15千字)

看雪資料發表於2000-10-02

對Crunch v1.1加殼程式的手動脫殼及反跟蹤程式碼的一點分析

【宣告】
我寫文章以交流為主,希望大家在轉載時能保持文章的完整性。

【前言】
由於我現在還沒有破解版的Crunch v1.1,所以就拿未註冊版的Crunch來測試。好象未註冊版的Crunch加殼的程式的名字有限制,其他的我就不清楚了。由於我DOWN的這個檔案是根據看雪論壇的一個貼子提供的地址下載的。連幫助檔案也沒有。:-( 
而且目前我手頭也沒有註冊版的Crunch,所以只好以未註冊版的Crunch加殼Notepad.EXE程式來進行說明。

樣例檔案:    bitarts_evaluation.exe    (把Notepad.EXE加殼後的檔案)
            (未註冊版Crunch加殼的程式檔名都是這個,不過可以在跟蹤中發現檔名比較的地方)
加殼方式:    未註冊版Crunch v1.1加殼
目標:        手動脫殼
作者:        ljttt
寫作日期:    2000-10-02

1、這次我們用ProcDump提供的Bhrama Server的功能來手動脫殼,這樣可以簡化一點手動脫殼的麻煩。所以首先我們啟動ProcDump,選擇Option/Rebuild new import table。點選Bhrama Server,這時就啟動了伺服器,將等待客戶命令。

2、Ctrl-D進入SoftICE,設斷點
bpint 3

3、啟動PEditor,開啟bitarts_evaluation.exe,點選break'n'enter。單擊Run。這時將中斷進入SoftICE。可以看到如下提示。
?You have to enter "eb eip 55" before you continue ! ? 

為了繼續跟蹤,我們根據提示下指令
eb eip 55

現在將顯示如下:
015F:0040D000  55                  PUSH      EBP        <--這就是我們修改後的結果
015F:0040D001  E800000000          CALL      0040D006
015F:0040D006  5D                  POP      EBP

4、繼續跟蹤到如下處:
015F:0040D0AC  FF95B1320000        CALL      [EBP+000032B1]
015F:0040D0B2  83C408              ADD      ESP,08
015F:0040D0B5  8BB5AD320000        MOV      ESI,[EBP+000032AD]
015F:0040D0BB  BFC6000000          MOV      EDI,000000C6
015F:0040D0C0  03FD                ADD      EDI,EBP
015F:0040D0C2  8BC8                MOV      ECX,EAX
015F:0040D0C4  F3A4                REPZ MOVSB                <--在此處停下,此指令執行後,以下的指令將改變,這就是SMC的技巧,以後還有多處,就不一一列舉了。
015F:0040D0C6  8B07                MOV      EAX,[EDI]    <--現在我們看到的是加密的程式碼,只有上一指令執行後才會顯示正確的指令程式碼
015F:0040D0C8  D581                AAD
015F:0040D0CA  C23813              RET      1338

5、在REPZ MOVSB指令執行後我們將看到如下的正確程式碼:
015F:0040D0C6  8BD5                MOV      EDX,EBP
015F:0040D0C8  81C238130000        ADD      EDX,00001338
015F:0040D0CE  52                  PUSH      EDX
015F:0040D0CF  33C0                XOR      EAX,EAX
015F:0040D0D1  8CD8                MOV      AX,DS
015F:0040D0D3  A804                TEST      AL,04
015F:0040D0D5  7408                JZ        0040D0DF
015F:0040D0D7  B402                MOV      AH,02
015F:0040D0D9  CD1A                INT      1A
015F:0040D0DB  8BC2                MOV      EAX,EDX
015F:0040D0DD  EB02                JMP      0040D0E1
015F:0040D0DF  0F31                RDTSC
015F:0040D0E1  33D2                XOR      EDX,EDX
015F:0040D0E3  69C00D661900        IMUL      EAX,EAX,0019660D
015F:0040D0E9  05CD0D0100          ADD      EAX,00010DCD
015F:0040D0EE  8985383A0000        MOV      [EBP+00003A38],EAX
015F:0040D0F4  BB56340200          MOV      EBX,00023456
015F:0040D0F9  43                  INC      EBX
015F:0040D0FA  F7F3                DIV      EBX
015F:0040D0FC  8BC2                MOV      EAX,EDX
015F:0040D0FE  5A                  POP      EDX
015F:0040D0FF  90                  NOP
015F:0040D100  FFD2                CALL      EDX        <--在此處我們要停下,如果你想了解反跟蹤程式碼,可以進入看看
015F:0040D102  CC                  INT      3
015F:0040D103  CC                  INT      3
015F:0040D104  E80E130000          CALL      0040E417
015F:0040D109  E838100000          CALL      0040E146    <--反跟蹤

6、在執行到 CALL EDX 指令處時,我們下指令
r eip eip+E
r esi 10
這樣就可以跳過這一段反跟蹤的程式碼。

7、這裡我們來了解一下 CALL EDX 中的一段反跟蹤程式碼
015F:0040E369  0F010B              SIDT      FWORD PTR [EBX]    <--取IDTR的內容
015F:0040E36C  8B7302              MOV      ESI,[EBX+02]        <--取IDT表的基地址
015F:0040E36F  83C608              ADD      ESI,08
015F:0040E372  8B1E                MOV      EBX,[ESI]            <--取int 1的低位偏移
015F:0040E374  53                  PUSH      EBX
015F:0040E375  56                  PUSH      ESI
015F:0040E376  83C610              ADD      ESI,10
015F:0040E379  8B36                MOV      ESI,[ESI]            <--取int 3的低位偏移
015F:0040E37B  81E6FFFF0000        AND      ESI,0000FFFF
015F:0040E381  81E3FFFF0000        AND      EBX,0000FFFF
015F:0040E387  2BF3                SUB      ESI,EBX
015F:0040E389  83FE1E              CMP      ESI,1E                <--比較低位偏移
015F:0040E38C  B090                MOV      AL,90
015F:0040E38E  7427                JZ        0040E3B7            <--關鍵了!
015F:0040E390  8BDD                MOV      EBX,EBP
015F:0040E392  81C311140000        ADD      EBX,00001411
015F:0040E398  0F010B              SIDT      FWORD PTR [EBX]    <--取IDTR的內容
015F:0040E39B  8B7B02              MOV      EDI,[EBX+02]        <--取IDT表的基地址
015F:0040E39E  83C708              ADD      EDI,08
015F:0040E3A1  8B4704              MOV      EAX,[EDI+04]        <--取int 1的高位偏移
015F:0040E3A4  668B07              MOV      AX,[EDI]            <--取int 1的低位偏移
015F:0040E3A7  8038E9              CMP      BYTE PTR [EAX],E9    <--判斷int 1中斷處理程式第一個位元組是否為JMP指令
015F:0040E3AA  B090                MOV      AL,90
015F:0040E3AC  7409                JZ        0040E3B7            <--關鍵了!
015F:0040E3AE  83FE1E              CMP      ESI,1E
015F:0040E3B1  B090                MOV      AL,90
015F:0040E3B3  7402                JZ        0040E3B7            <--關鍵了!
015F:0040E3B5  045B                ADD      AL,5B

8、這裡我們來了解一下 CALL 0040E146 中的反跟蹤程式碼
015F:0040E146  8B8587390000        MOV      EAX,[EBP+00003987]
015F:0040E14C  8B8DC5300000        MOV      ECX,[EBP+000030C5]
015F:0040E152  C1E908              SHR      ECX,08
015F:0040E155  33D2                XOR      EDX,EDX
015F:0040E157  B902000000          MOV      ECX,00000002
015F:0040E15C  F7F1                DIV      ECX
015F:0040E15E  0BD2                OR        EDX,EDX
015F:0040E160  7502                JNZ      0040E164            <--關鍵了!
015F:0040E162  EB27                JMP      0040E18B
==> 0040E164  8BDD                MOV      EBX,EBP
015F:0040E166  81C38B390000        ADD      EBX,0000398B
015F:0040E16C  0F010B              SIDT      FWORD PTR [EBX]    <--取IDTR的內容
015F:0040E16F  8B7302              MOV      ESI,[EBX+02]        <--取IDT表的基地址
015F:0040E172  83C608              ADD      ESI,08
015F:0040E175  8B1E                MOV      EBX,[ESI]            <--取int 1的低位偏移
015F:0040E177  83C610              ADD      ESI,10
015F:0040E17A  8B36                MOV      ESI,[ESI]            <--取int 3的低位偏移
015F:0040E17C  81E6FFFF0000        AND      ESI,0000FFFF
015F:0040E182  81E3FFFF0000        AND      EBX,0000FFFF
015F:0040E188  2BF3                SUB      ESI,EBX            <--ESI返回低位偏移之差
015F:0040E18A  C3                  RET
015F:0040E18B  BE10000000          MOV      ESI,00000010        <--ESI返回0x10
015F:0040E190  C3                  RET

9、我們繼續跟蹤來到如下,(這也是由SMC得來的)
015F:0040D1F7  49                  DEC      ECX
015F:0040D1F8  83F900              CMP      ECX,00
015F:0040D1FB  75EB                JNZ      0040D1E8
015F:0040D1FD  59                  POP      ECX
015F:0040D1FE  81E942000000        SUB      ECX,00000042
015F:0040D204  51                  PUSH      ECX
015F:0040D205  E873100000          CALL      0040E27D            <--內有反跟蹤程式碼
015F:0040D20A  33C0                XOR      EAX,EAX
015F:0040D20C  59                  POP      ECX
015F:0040D20D  8AC1                MOV      AL,CL
015F:0040D20F  8BDD                MOV      EBX,EBP
015F:0040D211  81C3A5320000        ADD      EBX,000032A5
015F:0040D217  8BB57D390000        MOV      ESI,[EBP+0000397D]
015F:0040D21D  50                  PUSH      EAX
015F:0040D21E  51                  PUSH      ECX
015F:0040D21F  53                  PUSH      EBX
015F:0040D220  E8D10E0000          CALL      0040E0F6
015F:0040D225  5B                  POP      EBX

10、進入 CALL 0040E27D 我們來看看其中的反跟蹤程式碼。
==> 0040E29D  8BDD                MOV      EBX,EBP
015F:0040E29F  81C311140000        ADD      EBX,00001411
015F:0040E2A5  0F010B              SIDT      FWORD PTR [EBX]    <--取IDTR內容
015F:0040E2A8  8B7B02              MOV      EDI,[EBX+02]        <--取IDT表基地址
015F:0040E2AB  83C708              ADD      EDI,08
015F:0040E2AE  8B4704              MOV      EAX,[EDI+04]        <--取int 1的高位偏移
015F:0040E2B1  668B07              MOV      AX,[EDI]            <--取int 1的低位偏移
015F:0040E2B4  8038E9              CMP      BYTE PTR [EAX],E9    <--判斷int 1中斷處理程式第一個位元組是否為JMP指令
015F:0040E2B7  750B                JNZ      0040E2C4            <--關鍵了!
015F:0040E2B9  BE1E000000          MOV      ESI,0000001E        <--發現跟蹤ESI=1E
015F:0040E2BE  8BDD                MOV      EBX,EBP
015F:0040E2C0  52                  PUSH      EDX
015F:0040E2C1  53                  PUSH      EBX
015F:0040E2C2  EB28                JMP      0040E2EC
015F:0040E2C4  8BDD                MOV      EBX,EBP
015F:0040E2C6  52                  PUSH      EDX
015F:0040E2C7  53                  PUSH      EBX
015F:0040E2C8  81C311140000        ADD      EBX,00001411
015F:0040E2CE  0F010B              SIDT      FWORD PTR [EBX]    <--取IDTR內容
015F:0040E2D1  8B7302              MOV      ESI,[EBX+02]        <--取IDT表基地址
015F:0040E2D4  83C608              ADD      ESI,08
015F:0040E2D7  8B1E                MOV      EBX,[ESI]            <--取int 1的低位偏移
015F:0040E2D9  83C610              ADD      ESI,10
015F:0040E2DC  8B36                MOV      ESI,[ESI]            <--取int 3的低位偏移
015F:0040E2DE  81E6FFFF0000        AND      ESI,0000FFFF
015F:0040E2E4  81E3FFFF0000        AND      EBX,0000FFFF
015F:0040E2EA  2BF3                SUB      ESI,EBX            <--計算低位偏移之差
015F:0040E2EC  8BDE                MOV      EBX,ESI
015F:0040E2EE  8BD3                MOV      EDX,EBX            <--發現跟蹤EDX=ESI=1E
015F:0040E2F0  5B                  POP      EBX
015F:0040E2F1  81C3DB110000        ADD      EBX,000011DB        <--以後用不正確的EDX和ESI來SMC自身的程式碼,你說會發生什麼現象!
015F:0040E2F7  33C0                XOR      EAX,EAX
015F:0040E2F9  8A03                MOV      AL,[EBX]
015F:0040E2FB  03C6                ADD      EAX,ESI
015F:0040E2FD  8803                MOV      [EBX],AL
015F:0040E2FF  83C304              ADD      EBX,04
015F:0040E302  8A03                MOV      AL,[EBX]
015F:0040E304  8BF2                MOV      ESI,EDX
015F:0040E306  C1E602              SHL      ESI,02
015F:0040E309  03C6                ADD      EAX,ESI
015F:0040E30B  8803                MOV      [EBX],AL
015F:0040E30D  5A                  POP      EDX
015F:0040E30E  C3                  RET
015F:0040E30F  8BDD                MOV      EBX,EBP
015F:0040E311  BE10000000          MOV      ESI,00000010
015F:0040E316  BA10000000          MOV      EDX,00000010        <--未發現跟蹤時ESI=10,EDX=10
015F:0040E31B  81C3DB110000        ADD      EBX,000011DB        <--以下是用SMC的技巧來還原以後的程式碼
015F:0040E321  33C0                XOR      EAX,EAX
015F:0040E323  8A03                MOV      AL,[EBX]
015F:0040E325  03C6                ADD      EAX,ESI
015F:0040E327  8803                MOV      [EBX],AL
015F:0040E329  83C304              ADD      EBX,04
015F:0040E32C  8A03                MOV      AL,[EBX]
015F:0040E32E  8BF2                MOV      ESI,EDX
015F:0040E330  C1E602              SHL      ESI,02
015F:0040E333  03C6                ADD      EAX,ESI
015F:0040E335  8803                MOV      [EBX],AL
015F:0040E337  C3                  RET

11、看完反跟蹤程式碼,我們回到主程式繼續跟蹤到如下程式碼處
015F:0040D9C2  FFB54C210000        PUSH      DWORD PTR [EBP+0000214C]
015F:0040D9C8  FF956E1E0000        CALL      [EBP+00001E6E]
015F:0040D9CE  83854021000014      ADD      DWORD PTR [EBP+00002140],14
015F:0040D9D5  FF8D94300000        DEC      DWORD PTR [EBP+00003094]
015F:0040D9DB  6683BD9430000000    CMP      WORD PTR [EBP+00003094],00
015F:0040D9E3  0F85FAFDFFFF        JNZ      0040D7E3
015F:0040D9E9  B8BB140000          MOV      EAX,000014BB
015F:0040D9EE  03C5                ADD      EAX,EBP
015F:0040D9F0  FFE0                JMP      EAX            <--此處將跳轉到檔名比較的地方
015F:0040D9F2  FFA5AB390000        JMP      [EBP+000039AB]    <--跳到以下程式碼處
我們分別先在 JMP EAX 和 JMP [EBP+000039AB] 處設下斷點。先我們來看看加殼程式是如何進行檔名比較來防止你修改檔名的。

12、在 JMP EAX 跳轉後,我們將來到如下程式碼處
.....之前的程式碼將呼叫GetModuleName得到檔名稱,以下的程式碼是分析比較的部分
015F:0040E503  740F                JZ        0040E514
015F:0040E505  8A1E                MOV      BL,[ESI]    <--[ESI]指向檔名稱字串
015F:0040E507  80FB5C              CMP      BL,5C        <--判斷是否為"\"字元
015F:0040E50A  7415                JZ        0040E521
015F:0040E50C  80C320              ADD      BL,20        <--轉換成小寫字母
015F:0040E50F  881E                MOV      [ESI],BL
015F:0040E511  4E                  DEC      ESI
015F:0040E512  EBF1                JMP      0040E505
015F:0040E514  90                  NOP
015F:0040E515  8A1E                MOV      BL,[ESI]
015F:0040E517  80FB5C              CMP      BL,5C
015F:0040E51A  7405                JZ        0040E521
015F:0040E51C  881E                MOV      [ESI],BL
015F:0040E51E  4E                  DEC      ESI
015F:0040E51F  EBF4                JMP      0040E515
015F:0040E521  46                  INC      ESI
015F:0040E522  BF66160000          MOV      EDI,00001666
015F:0040E527  03FD                ADD      EDI,EBP    <--EDI指向字串"bitarts"
015F:0040E529  33C9                XOR      ECX,ECX
015F:0040E52B  33C0                XOR      EAX,EAX
015F:0040E52D  8A06                MOV      AL,[ESI]
015F:0040E52F  3C00                CMP      AL,00
015F:0040E531  7438                JZ        0040E56B    <--判斷字串是否比較結束
015F:0040E533  83F905              CMP      ECX,05
015F:0040E536  7433                JZ        0040E56B    <--是否匹配完全相同,是則跳走
015F:0040E538  3807                CMP      [EDI],AL    <--判斷檔名稱是否相等
015F:0040E53A  7505                JNZ      0040E541    <--不等,則跳走
015F:0040E53C  46                  INC      ESI
015F:0040E53D  47                  INC      EDI
015F:0040E53E  41                  INC      ECX
015F:0040E53F                      JMP      0040E52D    <--迴圈

13、知道了程式如何比較檔名稱,按F5繼續,將中斷在我們設好的斷點 JMP [EBP+000039AB] 處。我們繼續跟蹤到如下程式碼
015F:00410D99  BBCD150000          MOV      EBX,000015CD
015F:00410D9E  03DD                ADD      EBX,EBP
015F:00410DA0  53                  PUSH      EBX
015F:00410DA1  50                  PUSH      EAX
015F:00410DA2  FF955E1E0000        CALL      [EBP+00001E5E]
015F:00410DA8  FFD0                CALL      EAX
015F:00410DAA  8B8554210000        MOV      EAX,[EBP+00002154]
015F:00410DB0  0185C1300000        ADD      [EBP+000030C1],EAX
015F:00410DB6  FFA59B390000        JMP      [EBP+0000399B]            <--此處跳轉到最後的一段程式碼
015F:00410DBC  C3                  RET

14、在 JMP [EBP+0000399B] 處跳轉到如下最後一處程式碼。這裡我們可以DUMP得到完整的檔案了。
015F:0040D0C6  61                  POPAD
015F:0040D0C7  5D                  POP      EBP
015F:0040D0C8  8B85C1300000        MOV      EAX,[EBP+000030C1]
015F:0040D0CE  5D                  POP      EBP
015F:0040D0CF  FFE0                JMP      EAX                <--此時,EAX就是OEP。在此處我們DUMP的時候到了
在 JMP EAX 處我們下指令(這裡我使用的是ICEDUMP 6.0168的命令使用方法)
/bhrama ProcDump32 - Dumper Server
這時程式將回到WINDOWS,過一段時間,如果成功,將出現檔案儲存對話方塊讓你選擇想儲存的檔名。存完將回到SoftICE,好!我們按F5結束工作。

【後記】
應該說以上我介紹的並不是以脫殼為主,而是介紹一些Crunch加殼程式的特徵,也希望大家以此能進行更多的分析來相互交流。
如果你按此法脫殼,可能你要花費大把大把的時間。如果你想更快的脫殼,可以參考我寫的ProcDump的Script,或者根據其中脫殼的方法在加密程式碼還原後搜尋特徵程式碼,那樣來得更快。

相關文章