ASPROTECT 2.0 脫殼示例

ASPROTECT  2.0 脫殼示例
【目    標】:Win98’s notepad
【工    具】:Olydbg1.1(diy版)、LORDPE、ImportREC1.6F
【任    務】:簡單的脫一下asprotect的殼
【操作平臺】:Windows Xp sp2
【作    者】:loveboom[DFCG][FCG][US]
【簡要說明】:有一段時間沒寫文章了,這篇文章本來是想在奧運會那時寫出來,因爲公事比較多,有空的時候心情不好等原因,所以一直放到現在才寫.
【詳細過程】:
設置忽略全部異常,去掉調試標誌。
載入後到這裏:
00401000 >  68 01D040>PUSH 0040D001                            ; EP殼的入口
00401005    E8 010000>CALL 0040100B
載入後,直接g LoadLibraryA運行到LoadLibraryA這個API處.
7C801D77 >  8BFF      MOV EDI,EDI                              ; LoadLibraryA
7C801D79    55        PUSH EBP
到了後,ALT+F9執行到返回:
009884B7    8985 4D29>MOV DWORD PTR SS:[EBP+44294D],EAX        ; 返回到這裏
009884BD    C785 5129>MOV DWORD PTR SS:[EBP+442951],0
……
009885C1    61        POPAD
009885C2    75 08     JNZ SHORT 009885CC                       ; 看到這裏,跟過Aspack的朋友就是知道這裏是什麼了
009885C4    B8 010000>MOV EAX,1
009885C9    C2 0C00   RETN 0C
009885CC    68 000000>PUSH 0                                   ; 如果解壓完殼代碼這裏會push 一個返回的地址
009885D1    C3        RETN
返回到009884B7處後,右鍵查找全部字符串,然後在字符串窗中查找250這樣就會看到這些東西:
雙擊10那裏到了cpu窗口處:
0096CD66   /75 0A     JNZ SHORT 0096CD72
0096CD68   |68 C8D096>PUSH 96D0C8                              ; 雙擊到這裏,這裏向上找到代碼開始處
0096CD6D   |E8 BE6DFF>CALL 00963B30
向上找到這裏:
0096CC70   /EB 01     JMP SHORT 0096CC73
0096CC72   |90        NOP
0096CC73   /8B43 08   MOV EAX,DWORD PTR DS:[EBX+8]             ; 這裏開始對IAT進行處理
0096CC76    8B30      MOV ESI,DWORD PTR DS:[EAX]
0096CC78    8343 08 0>ADD DWORD PTR DS:[EBX+8],4
0096CC7C    8B43 08   MOV EAX,DWORD PTR DS:[EBX+8]
0096CC7F    8A00      MOV AL,BYTE PTR DS:[EAX]
0096CC81    884424 07 MOV BYTE PTR SS:[ESP+7],AL
0096CC85    FF43 08   INC DWORD PTR DS:[EBX+8]
0096CC88    85F6      TEST ESI,ESI
0096CC8A    75 1A     JNZ SHORT 0096CCA6                       ; 這裏比較輸入表是否處理完畢,如果沒有就跳下去
0096CC8C    EB 01     JMP SHORT 0096CC8F
……
0096CCC9    FF43 08   INC DWORD PTR DS:[EBX+8]
0096CCCC    84C0      TEST AL,AL                               ; 這裏開始對AL的值的不同而進行相關的處理
0096CCCE    75 20     JNZ SHORT 0096CCF0
……
0096CD59    8B4424 14 MOV EAX,DWORD PTR SS:[ESP+14]
0096CD5D    E8 DEECFF>CALL 0096BA40                            ; GetProcAddress
0096CD62    8BE8      MOV EBP,EAX
0096CD64    85ED      TEST EBP,EBP
0096CD66    75 0A     JNZ SHORT 0096CD72                       ; 判斷獲取API是否成功
0096CD68    68 C8D096>PUSH 96D0C8                              ; 雙擊到這裏,這裏向上找到代碼開始處
0096CD6D    E8 BE6DFF>CALL 00963B30
0096CD72    837C24 20>CMP DWORD PTR SS:[ESP+20],0
……
0096CDF7    E8 8469FF>CALL 00963780                            ; 當AL爲2時對IAT的處理,跟進去
0096CDFC  ^ E9 72FEFF>JMP 0096CC73                             ; 處理完跳回去
……
跟進看看:
00963756    8BC0      MOV EAX,EAX
00963758    55        PUSH EBP
00963759    8BEC      MOV EBP,ESP
0096375B    53        PUSH EBX
0096375C    8BD8      MOV EBX,EAX
0096375E    8BC2      MOV EAX,EDX
00963760    8BD1      MOV EDX,ECX
00963762    E8 79FFFF>CALL 009636E0
00963767    C603 E9   MOV BYTE PTR DS:[EBX],0E9                ; 先在這裏也下個斷,因爲這裏就是程序的OEP
0096376A    8D53 01   LEA EDX,DWORD PTR DS:[EBX+1]             ; 這裏原程跳就是殼抽程序代碼的開始地方
0096376D    8902      MOV DWORD PTR DS:[EDX],EAX
0096376F    8B45 08   MOV EAX,DWORD PTR SS:[EBP+8]
00963772    8910      MOV DWORD PTR DS:[EAX],EDX
00963774    B8 050000>MOV EAX,5
00963779    5B        POP EBX
0096377A    5D        POP EBP
0096377B    C2 0400   RETN 4
0096377E    8BC0      MOV EAX,EAX
00963780    53        PUSH EBX                                 ; 進到這裏
00963781    8BD8      MOV EBX,EAX
00963783    8BC3      MOV EAX,EBX
00963785    E8 56FFFF>CALL 009636E0
0096378A    C603 E8   MOV BYTE PTR DS:[EBX],0E8                ; 這裏把IAT的改成call xxxxxx的樣式,所以我們這裏要進去處理
0096378D    43        INC EBX
0096378E    8903      MOV DWORD PTR DS:[EBX],EAX
00963790    5B        POP EBX
00963791    C3        RETN
現在這裏我們來修復一下:
先自己申請兩塊空間,當然你也可以直接找空閒的地方來寫代碼,我分別申請了00B90000和00BA0000這個塊內存空間,00b90000這塊是用來寫patch代碼,00ba0000是用來保存臨時要存放的數據。
00BA0000用來保存DLL的基址,00BA0010用來保存要存放IAT的地址。
搞清這些東西后,我們開始寫代碼:
00963781    8BD8      MOV EBX,EAX
00963783    8BC3      MOV EAX,EBX
00963785    E8 56FFFF>CALL 009636E0
0096378A    E8 71C822>CALL 00B90000                            ; 調用我們改的代碼處
0096378F    90        NOP
00963790    5B        POP EBX
00963791    C3        RETN
 
00B90000用來寫我們自己的修復代碼:
00B90000    51        PUSH ECX                                 ; 保護現場
00B90001    52        PUSH EDX
00B90002    8B5424 28 MOV EDX,DWORD PTR SS:[ESP+28]            ; 取出基址到EDX中
00B90006    3B15 0000>CMP EDX,DWORD PTR DS:[BA0000]            ; 比較基址是否相同
00B9000C    74 0D     JE SHORT 00B9001B
00B9000E    8915 0000>MOV DWORD PTR DS:[BA0000],EDX            ; 如果不同就寫入新的基址
00B90014    8305 1000>ADD DWORD PTR DS:[BA0010],4              ; 並把填入IAT的地址再加上4
00B9001B    8B0D 1000>MOV ECX,DWORD PTR DS:[BA0010]            ; 如果是第一次我們要手工寫一下保存IAT的地址,我選擇的是40C000
00B90021    8929      MOV DWORD PTR DS:[ECX],EBP               ; 寫入正確的函數
00B90023    66:C703 F>MOV WORD PTR DS:[EBX],15FF               ; 這裏要看程序的情況而定,如果是DELPHI之類的,這果就可能是FF25了,因爲是C的,所以這裏是ff15
00B90028    890E      MOV DWORD PTR DS:[ESI],ECX               ; 把存放IAT的地址放到程序裏
00B9002A    8305 1000>ADD DWORD PTR DS:[BA0010],4              ; 保存IAT的地址+4
00B90031    5A        POP EDX                                  ; 還原現場
00B90032    59        POP ECX
00B90033    C3        RETN                                     ; 返回到殼那邊繼續
 
繼續到AL=1時的處理:
0096CE07  ^/E9 67FEFF>JMP 0096CC73
0096CE0C    3C 01     CMP AL,1                                 ; 當AL=1的處理
0096CE0E    0F85 B200>JNZ 0096CEC6
……
0096CE7E    A1 B8A697>MOV EAX,DWORD PTR DS:[97A6B8]
0096CE83    8B00      MOV EAX,DWORD PTR DS:[EAX]
0096CE85    FFD0      CALL EAX                                 ; GetProcAddress
0096CE87    8BE8      MOV EBP,EAX
0096CE89    85ED      TEST EBP,EBP
0096CE8B    75 0A     JNZ SHORT 0096CE97                       ; 如果獲取成功就跳
0096CE8D    68 D8D096>PUSH 96D0D8                              ; ASCII "11
"
0096CE92    E8 996CFF>CALL 00963B30
0096CE97    8B0424    MOV EAX,DWORD PTR SS:[ESP]
0096CE9A    50        PUSH EAX
0096CE9B    68 08BC96>PUSH 96BC08
0096CEA0    8D4C24 20 LEA ECX,DWORD PTR SS:[ESP+20]
0096CEA4    8BD5      MOV EDX,EBP
0096CEA6    8BC3      MOV EAX,EBX
0096CEA8    E8 BFF4FF>CALL 0096C36C
0096CEAD    8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C]             ; 這裏殼又要對IAT破壞處理,我們這裏又要自己修復一下
0096CEB1    8902      MOV DWORD PTR DS:[EDX],EAX               ; 這裏寫上我們自己的代碼
0096CEB3    8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]
0096CEB7    8906      MOV DWORD PTR DS:[ESI],EAX
0096CEB9    0FB74424 >MOVZX EAX,WORD PTR SS:[ESP+4]
0096CEBE    0143 08   ADD DWORD PTR DS:[EBX+8],EAX
0096CEC1  ^ E9 ADFDFF>JMP 0096CC73                             ; 處理完就跳回去
當AL=1時的修復代碼:
0096CEA8    E8 BFF4FF>CALL 0096C36C
0096CEAD    E8 8E3122>CALL 00B90040
0096CEB2    90        NOP
0096CEB3    90        NOP
0096CEB4    90        NOP
0096CEB5    90        NOP
0096CEB6    90        NOP
0096CEB7    90        NOP
0096CEB8    90        NOP
0096CEB9    0FB74424 >MOVZX EAX,WORD PTR SS:[ESP+4]
0096CEBE    0143 08   ADD DWORD PTR DS:[EBX+8],EAX
0096CEC1  ^ E9 ADFDFF>JMP 0096CC73
 
00B90040處的修復代碼:
00B90040    51        PUSH ECX                                 ; 保護現場
00B90041    52        PUSH EDX
00B90042    8B5424 20 MOV EDX,DWORD PTR SS:[ESP+20]            ; 取出當然要處理DLL的基址
00B90046    3B15 0000>CMP EDX,DWORD PTR DS:[BA0000]            ; 比較基址是否相同
00B9004C    74 0D     JE SHORT 00B9005B
00B9004E    8915 0000>MOV DWORD PTR DS:[BA0000],EDX
00B90054    8305 1000>ADD DWORD PTR DS:[BA0010],4
00B9005B    8B0D 1000>MOV ECX,DWORD PTR DS:[BA0010]            ; 1.0040C004
00B90061    8929      MOV DWORD PTR DS:[ECX],EBP               ; 把IAT寫到我們要指定的地址去也就是40c000那個段裏
00B90063    890E      MOV DWORD PTR DS:[ESI],ECX               ; 那保存函數的地址寫入程序中
00B90065    8305 1000>ADD DWORD PTR DS:[BA0010],4
00B9006C    5A        POP EDX
00B9006D    59        POP ECX                                  ; 還原現場
00B9006E    C3        RETN                                     ; 執行到返回
到了AL=4的處理了:
0096CEC6    3C 04     CMP AL,4                                 ; 當AL爲4有兩個分支
0096CEC8    0F85 F400>JNZ 0096CFC2
0096CECE    EB 01     JMP SHORT 0096CED1
0096CED0    90        NOP
0096CED1    8B43 08   MOV EAX,DWORD PTR DS:[EBX+8]
0096CED4    8A00      MOV AL,BYTE PTR DS:[EAX]
0096CED6    FF43 08   INC DWORD PTR DS:[EBX+8]
0096CED9    84C0      TEST AL,AL
0096CEDB    75 5B     JNZ SHORT 0096CF38                       ; 這裏跳的話就和AL=1時的處理一樣
0096CEDD    8B43 08   MOV EAX,DWORD PTR DS:[EBX+8]             ; 這裏是AL=4時的第一個分支
0096CEE0    8B30      MOV ESI,DWORD PTR DS:[EAX]
0096CEE2    8343 08 0>ADD DWORD PTR DS:[EBX+8],4
0096CEE6    8B43 08   MOV EAX,DWORD PTR DS:[EBX+8]
0096CEE9    8B28      MOV EBP,DWORD PTR DS:[EAX]
0096CEEB    8343 08 0>ADD DWORD PTR DS:[EBX+8],4
0096CEEF    8B43 08   MOV EAX,DWORD PTR DS:[EBX+8]
0096CEF2    8B00      MOV EAX,DWORD PTR DS:[EAX]
0096CEF4    894424 2C MOV DWORD PTR SS:[ESP+2C],EAX
0096CEF8    8343 08 0>ADD DWORD PTR DS:[EBX+8],4
0096CEFC    837B 30 0>CMP DWORD PTR DS:[EBX+30],0
0096CF00    75 0A     JNZ SHORT 0096CF0C
0096CF02    68 E8D096>PUSH 96D0E8                              ; ASCII "81
"
0096CF07    E8 246CFF>CALL 00963B30
0096CF0C    8D5424 30 LEA EDX,DWORD PTR SS:[ESP+30]
0096CF10    8BC3      MOV EAX,EBX
0096CF12    E8 8DF8FF>CALL 0096C7A4                            ; 這個CALL要進去,因爲這裏面就是計算將要保存IAT的地址
進去看看先:
0096C7A4    53        PUSH EBX
0096C7A5    56        PUSH ESI
0096C7A6    8BF2      MOV ESI,EDX
0096C7A8    8BD8      MOV EBX,EAX
0096C7AA    B8 040000>MOV EAX,4
0096C7AF    E8 985DFE>CALL 0095254C
0096C7B4    8906      MOV DWORD PTR DS:[ESI],EAX               ; 這裏把計算出來的地址填入[esi]中
0096C7B6    8B43 40   MOV EAX,DWORD PTR DS:[EBX+40]
0096C7B9    8946 04   MOV DWORD PTR DS:[ESI+4],EAX
0096C7BC    5E        POP ESI
0096C7BD    5B        POP EBX
0096C7BE    C3        RETN
這裏處理第一個分支先,第二個分支我們可以完全調用AL=1時的代碼,AL=4第一個分支的修復代碼:
0096C7A4    53        PUSH EBX
0096C7A5    56        PUSH ESI
0096C7A6    8BF2      MOV ESI,EDX
0096C7A8    8BD8      MOV EBX,EAX
0096C7AA    B8 040000>MOV EAX,4
0096C7AF    E8 985DFE>CALL 0095254C
0096C7B4    E8 C13822>CALL 00B9007A
0096C7B9    8946 04   MOV DWORD PTR DS:[ESI+4],EAX
0096C7BC    5E        POP ESI
0096C7BD    5B        POP EBX
0096C7BE    C3        RETN
 
00B9007A的修復代碼:
00B9007A    51        PUSH ECX                                 ; 保護現場
00B9007B    52        PUSH EDX
00B9007C    8B5424 2C MOV EDX,DWORD PTR SS:[ESP+2C]            ; 取出當然要處理DLL的基址
00B90080    3B15 0000>CMP EDX,DWORD PTR DS:[BA0000]            ; kernel32.7C800000
00B90086    74 0D     JE SHORT 00B90095
00B90088    8915 0000>MOV DWORD PTR DS:[BA0000],EDX
00B9008E    8305 1000>ADD DWORD PTR DS:[BA0010],4
00B90095    8B0D 1000>MOV ECX,DWORD PTR DS:[BA0010]            ; 1.0040C020
00B9009B    890E      MOV DWORD PTR DS:[ESI],ECX               ; 取出我們要保存IAT的址址到[ESI]中
00B9009D    8305 1000>ADD DWORD PTR DS:[BA0010],4
00B900A4    5A        POP EDX
00B900A5    59        POP ECX                                  ; 還原現場
00B900A6    8B43 40   MOV EAX,DWORD PTR DS:[EBX+40]            ; 執行我們前面所"喫"掉一行代碼
00B900A9    C3        RETN                                                                          ;執行到返回
……
0096CF17    8B4424 2C MOV EAX,DWORD PTR SS:[ESP+2C]
0096CF1B    50        PUSH EAX
0096CF1C    8D4424 34 LEA EAX,DWORD PTR SS:[ESP+34]
0096CF20    50        PUSH EAX
0096CF21    55        PUSH EBP
0096CF22    A1 70A597>MOV EAX,DWORD PTR DS:[97A570]
0096CF27    8B00      MOV EAX,DWORD PTR DS:[EAX]
0096CF29    50        PUSH EAX
0096CF2A    56        PUSH ESI
0096CF2B    8B4424 28 MOV EAX,DWORD PTR SS:[ESP+28]
0096CF2F    50        PUSH EAX
0096CF30    FF53 30   CALL DWORD PTR DS:[EBX+30]               ; 這裏計算函數並寫入地址
0096CF33  ^ E9 3BFDFF>JMP 0096CC73
0096CF38    8B43 08   MOV EAX,DWORD PTR DS:[EBX+8]
0096CF3B    8B00      MOV EAX,DWORD PTR DS:[EAX]
0096CF3D    890424    MOV DWORD PTR SS:[ESP],EAX
0096CF40    8343 08 0>ADD DWORD PTR DS:[EBX+8],4
0096CF44    8B43 08   MOV EAX,DWORD PTR DS:[EBX+8]
0096CF47    66:8B00   MOV AX,WORD PTR DS:[EAX]
0096CF4A    66:894424>MOV WORD PTR SS:[ESP+4],AX
0096CF4F    8343 08 0>ADD DWORD PTR DS:[EBX+8],2
0096CF53    8B0C24    MOV ECX,DWORD PTR SS:[ESP]
0096CF56    66:8B5424>MOV DX,WORD PTR SS:[ESP+4]
0096CF5B    8B43 08   MOV EAX,DWORD PTR DS:[EBX+8]
0096CF5E    E8 91ABFF>CALL 00967AF4
0096CF63    8B4424 10 MOV EAX,DWORD PTR SS:[ESP+10]
0096CF67    E8 E055FE>CALL 0095254C
0096CF6C    894424 0C MOV DWORD PTR SS:[ESP+C],EAX
0096CF70    8B43 08   MOV EAX,DWORD PTR DS:[EBX+8]
0096CF73    50        PUSH EAX
0096CF74    8B4424 18 MOV EAX,DWORD PTR SS:[ESP+18]
0096CF78    50        PUSH EAX
0096CF79    A1 B8A697>MOV EAX,DWORD PTR DS:[97A6B8]
0096CF7E    8B00      MOV EAX,DWORD PTR DS:[EAX]
0096CF80    FFD0      CALL EAX                                 ; GetProcAddress
0096CF82    8BE8      MOV EBP,EAX
0096CF84    85ED      TEST EBP,EBP
0096CF86    75 0C     JNZ SHORT 0096CF94                       ; 如果獲取成功就跳
0096CF88    68 F8D096>PUSH 96D0F8                              ; ASCII "250
"
0096CF8D    E8 9E6BFF>CALL 00963B30
0096CF92    EB 15     JMP SHORT 0096CFA9
0096CF94    A1 ECA597>MOV EAX,DWORD PTR DS:[97A5EC]
0096CF99    3B28      CMP EBP,DWORD PTR DS:[EAX]
0096CF9B    75 0C     JNZ SHORT 0096CFA9
0096CF9D    837B 34 0>CMP DWORD PTR DS:[EBX+34],0
0096CFA1    74 06     JE SHORT 0096CFA9
0096CFA3    8B6B 34   MOV EBP,DWORD PTR DS:[EBX+34]
0096CFA6    036B 40   ADD EBP,DWORD PTR DS:[EBX+40]
0096CFA9    8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]             ; 到這裏就是和AL=1的處理一樣,這裏就是第二個分支
0096CFAD    8928      MOV DWORD PTR DS:[EAX],EBP
0096CFAF    8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]
0096CFB3    8906      MOV DWORD PTR DS:[ESI],EAX
0096CFB5    0FB74424 >MOVZX EAX,WORD PTR SS:[ESP+4]
0096CFBA    0143 08   ADD DWORD PTR DS:[EBX+8],EAX
0096CFBD  ^ E9 B1FCFF>JMP 0096CC73
……
第二個分支的處理,這裏很簡單我們只改幾行代碼就行了,改成這樣子:
0096CFA9    E8 923022>CALL 00B90040                                                ;和AL=1一樣的處理
0096CFAE    90        NOP
0096CFAF    90        NOP
0096CFB0    90        NOP
0096CFB1    90        NOP
0096CFB2    90        NOP
0096CFB3    90        NOP
0096CFB4    90        NOP
這個程序裏沒有AL=3和AL=5的情況,所以我也就不多說了.
好了,處理完IAT後我們記住這裏:
00963767    C603 E9   MOV BYTE PTR DS:[EBX],0E9
直接在這00963767處下斷,然後運行,中斷在這裏後,我們就知道這裏的[EBX]就是保存我們的目標程序的OEP,這個對DELPHI的程序就可能不止在這裏中斷一次,但跳去的地方一定是殼抽程序的代碼。
00963756    8BC0      MOV EAX,EAX
00963758    55        PUSH EBP
00963759    8BEC      MOV EBP,ESP
0096375B    53        PUSH EBX
0096375C    8BD8      MOV EBX,EAX
0096375E    8BC2      MOV EAX,EDX
00963760    8BD1      MOV EDX,ECX
00963762    E8 79FFFF>CALL 009636E0
00963767    C603 E9   MOV BYTE PTR DS:[EBX],0E9
0096376A    8D53 01   LEA EDX,DWORD PTR DS:[EBX+1]             ; 這裏原程跳就是殼抽程序代碼的開始地方
0096376D    8902      MOV DWORD PTR DS:[EDX],EAX
0096376F    8B45 08   MOV EAX,DWORD PTR SS:[EBP+8]
00963772    8910      MOV DWORD PTR DS:[EAX],EDX
00963774    B8 050000>MOV EAX,5
00963779    5B        POP EBX
0096377A    5D        POP EBP
0096377B    C2 0400   RETN 4                                   ; 直接執行到這裏,然後到4010cc處看看
……
004010CC  - E9 48F177>JMP 00B80219                             ; 這裏跳去的地方就是殼抽程序的代碼的開始處
004010D1    7D 5E     JGE SHORT 00401131
004010D3    FF15 00C0>CALL DWORD PTR DS:[40C000]               ; kernel32.GetCommandLineA
00B80219就是殼執行原程序的開始處.所以我們直接在00B80219處下個斷,然後運行,再次中斷後我們就可以比較直觀的看到被抽的代碼。
00B80219    55        PUSH EBP                                 ; 在這裏下斷,這就是程序的第一行代碼
00B8021A    336C24 08 XOR EBP,DWORD PTR SS:[ESP+8]
00B8021E    336C24 28 XOR EBP,DWORD PTR SS:[ESP+28]
00B80222    8BEC      MOV EBP,ESP                              ; 第二行
……
00B80273    83EC 44   SUB ESP,44                               ; 第三行
00B80276    56        PUSH ESI                                 ; 最後一行代碼
00B80277  ^ E9 ADFFFF>JMP 00B80229
這樣程序被抽的代碼就找回來的,當然,如果是加的DELPHI或其它的C的程序抽的代碼就不是這麼少了。
好了,現在我們被上代碼,然後DUMP和修復一下就行了.
 
Greetz:
 Fly.Jingulong,yock,tDasm.David.ahao.UFO(brother).alan(sister).all of my friends and you!
 
By loveboom[DFCG][FCG]
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章