老殼petite不完全分析

0040D042 >  B8 00D04000     MOV EAX,Notepad.0040D000      ;最後一節的起始地址         
0040D047    68 4C584000     PUSH Notepad.0040584C         ;異常處理例程
0040D04C    64:FF35 0000000>PUSH DWORD PTR FS:[0]
0040D053    64:8925 0000000>MOV DWORD PTR FS:[0],ESP      ;建立異常處理鏈
0040D05A    66:9C           PUSHFW                        ;這裏入棧2字節
0040D05C    60              PUSHAD                        ;入棧32字節
0040D05D    50              PUSH EAX                      ;入棧4字節
0040D05E    68 00004000     PUSH Notepad.00400000         ;IMAGEBASE  入棧4字節  一共入棧了2A H字節數 後面需要用到 
0040D063    8B3C24          MOV EDI,DWORD PTR SS:[ESP]    ;IMAGEBASE 送EDI
0040D066    8B30            MOV ESI,DWORD PTR DS:[EAX]    ;[40d000]裏存放的是USER32.DLL的IMAGE_IMPORT_DESCRIPTOR結構相對於最後一節的偏移2B4H
0040D068    66:81C7 8007    ADD DI,780                    ;將要存放導入表部分內容的地址[400780]
0040D06D    8D7406 08       LEA ESI,DWORD PTR DS:[ESI+EAX+8]
0040D071    8938            MOV DWORD PTR DS:[EAX],EDI
0040D073    8B5E 10         MOV EBX,DWORD PTR DS:[ESI+10] ;得到VirtualProtect的地址 是在導入表中得到的
0040D076    50              PUSH EAX
0040D077    56              PUSH ESI
0040D078    6A 02           PUSH 2
0040D07A    68 80080000     PUSH 880
0040D07F    57              PUSH EDI

0040D080    6A 12           PUSH 12
0040D082    6A 06           PUSH 6

0040D084    56              PUSH ESI                         ;&oldProtect
0040D085    6A 04           PUSH 4                           ;PAGE_READWRITE
0040D087    68 80080000     PUSH 880                         ;size
0040D08C    57              PUSH EDI                         ;起始地址IMAGEBASE
0040D08D    FFD3            CALL EBX                         ;修改內存屬性爲 PAGE_READWRITE // kernel32.VirtualProtect
0040D08F    83EE 08         SUB ESI,8
0040D092    59              POP ECX
0040D093    F3:A5           REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI];複製導入表中函數地址
0040D095    59              POP ECX
0040D096    66:83C7 68      ADD DI,68
0040D09A    81C6 B6000000   ADD ESI,0B6
0040D0A0    F3:A5           REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI];複製導入表中DLL名稱
0040D0A2    FFD3            CALL EBX                         ;修改屬性爲只讀
0040D0A4    58              POP EAX

從40D1B8開始的數據類似一個數據結構
struct _PETITE
{
+0 dd number;number的最高位爲1的話 則低位字 爲複製數據的DWORD數目 
+4 dd start;複製數據的原始內存RVA   複製的數據其實就是壓縮後的數據 (由於DF置位 複製是從後往前的)
+8 dd target;複製數據的目的內存RVA
+c dd start2;壓縮數據的起始內存RVA  這個字段+IMAGEBASE後 實際上就是target複製完後EDI-4(就是複製後的數據的起始內存)
+10 dd ??    ;跟壓縮算法有關 估計類似 解壓過程 中循環的 次數 不熟悉壓縮算法  
+14 dd target2;壓縮數據的目的內存RVA 這個字段+IMAGEBASE後 就是start複製完後ESI-4(複製前的數據起始內存)
+18 dd xx     
}PETITE, *PPETITE;

0040D0A5    8D90 B8010000   LEA EDX,DWORD PTR DS:[EAX+1B8]
0040D0AB    8B0A            MOV ECX,DWORD PTR DS:[EDX]       ;[40D1B8] PETITE.number
0040D0AD    0FBAF1 1F       BTR ECX,1F                       ;測試最高位 並清零
0040D0B1    73 16           JNB SHORT Notepad.0040D0C9
0040D0B3    8B0424          MOV EAX,DWORD PTR SS:[ESP]       ;IMAGEBASE 
0040D0B6    FD              STD                              ;標誌位置位 
0040D0B7    8BF0            MOV ESI,EAX                      
0040D0B9    8BF8            MOV EDI,EAX
0040D0BB    0372 04         ADD ESI,DWORD PTR DS:[EDX+4]     ;PETITE.start
0040D0BE    037A 08         ADD EDI,DWORD PTR DS:[EDX+8]     ;PETITE.target
0040D0C1    F3:A5           REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
0040D0C3    83C2 0C         ADD EDX,0C
0040D0C6    FC              CLD
0040D0C7  ^ EB E2           JMP SHORT Notepad.0040D0AB
0040D0C9    83C2 10         ADD EDX,10
0040D0CC    8B5A F4         MOV EBX,DWORD PTR DS:[EDX-C]     ;PETITE.??
0040D0CF    85DB            TEST EBX,EBX
0040D0D1  ^ 74 D8           JE SHORT Notepad.0040D0AB
0040D0D3    8B0424          MOV EAX,DWORD PTR SS:[ESP]
0040D0D6    8B7A F8         MOV EDI,DWORD PTR DS:[EDX-8]     ;PETITE.target2
0040D0D9    03F8            ADD EDI,EAX
0040D0DB    52              PUSH EDX
0040D0DC    8D3401          LEA ESI,DWORD PTR DS:[ECX+EAX]
0040D0DF    EB 17           JMP SHORT Notepad.0040D0F8
0040D0E1    58              POP EAX
0040D0E2    58              POP EAX
0040D0E3    58              POP EAX
0040D0E4    5A              POP EDX
0040D0E5  ^ 74 C4           JE SHORT Notepad.0040D0AB
0040D0E7  ^ E9 1CFFFFFF     JMP Notepad.0040D008
0040D0EC    02D2            ADD DL,DL
0040D0EE    75 07           JNZ SHORT Notepad.0040D0F7
0040D0F0    8A16            MOV DL,BYTE PTR DS:[ESI]
0040D0F2    83EE FF         SUB ESI,-1
0040D0F5    12D2            ADC DL,DL
0040D0F7    C3              RETN

0040D0F8    81FB 00000100   CMP EBX,10000                                        ; 
0040D0FE    73 0E           JNB SHORT Notepad.0040D10E
0040D100    68 60C0FFFF     PUSH -3FA0
0040D105    68 60FCFFFF     PUSH -3A0
0040D10A    B6 05           MOV DH,5
0040D10C    EB 22           JMP SHORT Notepad.0040D130
0040D10E    81FB 00000400   CMP EBX,40000
0040D114    73 0E           JNB SHORT Notepad.0040D124
0040D116    68 8081FFFF     PUSH FFFF8180
0040D11B    68 80F9FFFF     PUSH -680
0040D120    B6 07           MOV DH,7
0040D122    EB 0C           JMP SHORT Notepad.0040D130
0040D124    68 0083FFFF     PUSH FFFF8300
0040D129    68 00FBFFFF     PUSH -500
0040D12E    B6 08           MOV DH,8
0040D130    6A 00           PUSH 0
0040D132    32D2            XOR DL,DL
0040D134    4B              DEC EBX                                             ;PETITE.??  自減      (猜測 循環次數爲PETITE.??/4)
0040D135    A4              MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]            ;解壓開始   PETITE結構共有2個  解壓2次 最後這裏觸發一個異常

第一次解壓起始地址40AF2C 目的地址爲407C04  
第二次解壓起始地址404448 目的地址爲401000
整個過程其實就是把壓縮後的數據 複製到一塊內存區 解壓後再複製回來
兩次解壓將PE文件的 第一個節和第2個節 解壓完  然後觸發異常 轉到異常
處理例程

第一次異常處理
0040584C    E8 4F000000     CALL Notepad.004058A0


004058A0    33C0            XOR EAX,EAX                                         ;EAX置0
004058A2    5E              POP ESI                                             ;405851
004058A3    64:8B18         MOV EBX,DWORD PTR FS:[EAX]                          ;FS:[0]   Ptr32 _EXCEPTION_REGISTRATION_RECORD
004058A6    8B1B            MOV EBX,DWORD PTR DS:[EBX]                          ;_EXCEPTION_REGISTRATION_RECORD.Next
;這裏是找到第一次異常處理鏈堆棧
004058A8    8D63 D6         LEA ESP,DWORD PTR DS:[EBX-2A]                       ;重置ESP   注意這裏的2A與開始的入棧的2A H對應
004058AB    5D              POP EBP                                             ;取出IMAGEBASE            -4 H
004058AC    8D8E BD020000   LEA ECX,DWORD PTR DS:[ESI+2BD]                      ;新的異常處理例程地址                   
004058B2    894B 04         MOV DWORD PTR DS:[EBX+4],ECX                        ;直接寫到了第一次異常發生前的_EXCEPTION_REGISTRATION_RECORD.Handler
004058B5    64:891D 0000000>MOV DWORD PTR FS:[0],EBX                            ;新的異常處理建立
004058BC    8B3C24          MOV EDI,DWORD PTR SS:[ESP]                          ;最後一節的起始VA
004058BF    81C7 39000000   ADD EDI,39                                          ;
004058C5    6A 0E           PUSH 0E
004058C7    59              POP ECX
004058C8    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]        ;複製從405851開始的14個字節到 40D039處 執行完畢後EDI = 40D047
004058CA    FF33            PUSH DWORD PTR DS:[EBX]                             ; 異常處理鏈的尾端的  _EXCEPTION_REGISTRATION_RECORD.Next                    
004058CC    56              PUSH ESI
004058CD    57              PUSH EDI                                            ;三次PUSH +c H
004058CE    8DB7 71010000   LEA ESI,DWORD PTR DS:[EDI+171]                      ;ESI = 40D1B8 正好到了PETITE結構
004058D4    8BCE            MOV ECX,ESI
004058D6    2BCF            SUB ECX,EDI                                         
004058D8    F3:AA           REP STOS BYTE PTR ES:[EDI]                          ;內存以0填充  執行完畢後 EDI = ESI
004058DA    60              PUSHAD                                              ;+ 20 H
004058DB    66:9C           PUSHFW
004058DD    0FBA3C24 08     BTC DWORD PTR SS:[ESP],8                            ;位測試並取反  傳說中的單步異常 設置TF位
004058E2    66:9D           POPFW
004058E4    5B              POP EBX                                             ; 
004058E5    5A              POP EDX                                             ;單步異常   
004058E6    64:8F05 0000000>POP DWORD PTR FS:[0]

第二次異常處理
00405B0E    33C0            XOR EAX,EAX
00405B10    64:8B18         MOV EBX,DWORD PTR FS:[EAX]                          ;FS[0]   Ptr32 _EXCEPTION_REGISTRATION_RECORD
00405B13    8B1B            MOV EBX,DWORD PTR DS:[EBX]                          ;_EXCEPTION_REGISTRATION_RECORD.Next
;這裏找到建立第二次異常鏈後的堆棧
00405B15    8D63 AE         LEA ESP,DWORD PTR DS:[EBX-52]                       ;兩次異常處理鏈  52H = 2AH -4H + 0CH +20H 定位到了異常鏈建立好後
;pushad後的 堆棧
00405B18    61              POPAD                                               
00405B19    833E 00         CMP DWORD PTR DS:[ESI],0
00405B1C  ^ 0F84 C2FDFFFF   JE Notepad.004058E4
00405B22    0FBA26 1F       BT DWORD PTR DS:[ESI],1F                            ;測試最高位PETITE.number
00405B26    73 05           JNB SHORT Notepad.00405B2D                          ;CF 爲0 則跳
00405B28    83C6 0C         ADD ESI,0C
00405B2B  ^ EB EC           JMP SHORT Notepad.00405B19
00405B2D    8B7E 08         MOV EDI,DWORD PTR DS:[ESI+8]                         ;PETITE.target2
00405B30    03FD            ADD EDI,EBP                                          ;定位到解壓後的節中
00405B32    8B4E 0C         MOV ECX,DWORD PTR DS:[ESI+C]                         ;PETITE.xx
00405B35    D1F9            SAR ECX,1
00405B37    51              PUSH ECX
00405B38    72 15           JB SHORT Notepad.00405B4F
00405B3A    037E 04         ADD EDI,DWORD PTR DS:[ESI+4]                          ;PETITE.??(從這段代碼看 ??可能還是解壓後有效數據的大小        ?)
00405B3D    C1F9 02         SAR ECX,2
00405B40    33C0            XOR EAX,EAX
00405B42    F3:AB           REP STOS DWORD PTR ES:[EDI]                           ;清0  字節數爲PETITE.xx/2(XX看來跟解壓後的無效數據大小有關  ?)
00405B44    59              POP ECX
00405B45    83E1 03         AND ECX,3
00405B48    F3:AA           REP STOS BYTE PTR ES:[EDI]
00405B4A    83C6 10         ADD ESI,10
00405B4D  ^ EB CA           JMP SHORT Notepad.00405B19
                                                                                   ;下面就是最後的修正算法了 挺複雜的                                                                             
00405B4F    8B5E 04         MOV EBX,DWORD PTR DS:[ESI+4]                           ;PETITE.??                                  
00405B52    83EB 06         SUB EBX,6                                              ;PETITE.??-6
00405B55    33D2            XOR EDX,EDX
00405B57  ^ 72 E1           JB SHORT Notepad.00405B3A
00405B59    8A043A          MOV AL,BYTE PTR DS:[EDX+EDI]
00405B5C    3C E8           CMP AL,0E8                                             ;E8和E9是CALL和JMP的機器碼 開始修正操作數 
00405B5E    74 0E           JE SHORT Notepad.00405B6E
00405B60    3C E9           CMP AL,0E9
00405B62    74 0A           JE SHORT Notepad.00405B6E
00405B64    3C 0F           CMP AL,0F                                              ;0F80 - 0F8F 查的書上 似乎都是段內跳轉指令的機器碼  修改跳轉指令的操作數
00405B66    74 12           JE SHORT Notepad.00405B7A
00405B68    42              INC EDX
00405B69    83EB 01         SUB EBX,1
00405B6C  ^ EB E9           JMP SHORT Notepad.00405B57
00405B6E    29543A 01       SUB DWORD PTR DS:[EDX+EDI+1],EDX                       ;如果是MOV指令 就把後面的操作數機器碼 - MOV指令機器碼相對於解密起始處的偏                                                                                                                                                           移
00405B72    83C2 05         ADD EDX,5
00405B75    83EB 05         SUB EBX,5
00405B78  ^ EB DD           JMP SHORT Notepad.00405B57
00405B7A    8A443A 01       MOV AL,BYTE PTR DS:[EDX+EDI+1]
00405B7E    3C 80           CMP AL,80
00405B80  ^ 72 E6           JB SHORT Notepad.00405B68
00405B82    3C 8F           CMP AL,8F
00405B84  ^ 77 E2           JA SHORT Notepad.00405B68
00405B86    29543A 02       SUB DWORD PTR DS:[EDX+EDI+2],EDX                       ;如果是段內跳轉指令就把                  
00405B8A    83C2 06         ADD EDX,6
00405B8D    83EB 06         SUB EBX,6
00405B90  ^ EB C5           JMP SHORT Notepad.00405B57
00405B92    59              POP ECX
00405B93    5E              POP ESI
00405B94    FD              STD
00405B95    33C0            XOR EAX,EAX
00405B97    B9 56030000     MOV ECX,356
00405B9C    E8 43B98624     CALL 24C714E4                                              ;解密後 從這裏F7(解密後 這個CALL的轉移地址要變的)
整個算法描述 有點囉嗦:如果碰到CALL和JMP指令或者段內轉移指令 就把它們的操作數機器碼 減去 本身相對於解密起始處的偏移

0040D039    5F              POP EDI                                              ; Notepad.00405BA1
0040D03A    F3:AA           REP STOS BYTE PTR ES:[EDI]
0040D03C    61              POPAD
0040D03D    66:9D           POPFW
0040D03F    83C4 08         ADD ESP,8
0040D042 >- E9 8540FFFF     JMP Notepad.004010CC                                 ; 哈哈 回到加殼後的入口點地址 跳到OEP 


總結:整個脫殼過程中 數據複製2次 解壓2次 解密一次 2次異常  而且 關鍵跳 就在處EP
快速脫殼 除了最後一次異常法還可以 用多次內存斷點 或者 直接在 載入後的入口點下個硬件執行斷點F9就可以了
http://www.namipan.com/d/ef1b6e368177df074308b74ac4b4f8e0d417e4a7c2450000
發佈了21 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章