淺談Armadillo V.3.75 與 V.3.78的保護【原創】

看雪資料發表於2004-12-06

淺談Armadillo V.3.75  與 V.3.78的保護

闊別脫殼已有四年了,沒想到Armadillo與ASprotect都變得如此變態,這是四年多來第一篇脫文,有不對的地方,還請各位多加指教,這篇文章只是心得分享.
首先ArmadilloV.3.75與V.3.78最大的不同點是V.3.75是由子程式自行解壓而父程式只處理CC,而V.3.78是子程式解壓後又會再度加密,然後在執行時產生異常,而由父程式處理異常,處理子程式的解壓,所以在父程式在此時的角色變為處理子程式解碼與CC。我們主要要處理幾個部分:
(1)  得到IAT
(2)  Dump程式與修復IAT
(3)  找OEP
(4)  修復CC
我們分別來談:
[得到IAT] 想要得到IAT一般是修改Magic Jmp  在 Armadillo中有兩處,如下:
00E49C2A   8B0D 74B7E700    MOV ECX,DWORD PTR DS:[E7B774]
00E49C30   89040E           MOV DWORD PTR DS:[ESI+ECX],EAX
00E49C33   A1 74B7E700      MOV EAX,DWORD PTR DS:[E7B774]
00E49C38   391C06           CMP DWORD PTR DS:[ESI+EAX],EBX
00E49C3B   75 16            JNZ SHORT 00E49C53
00E49C3D   8D85 B4FEFFFF    LEA EAX,DWORD PTR SS:[EBP-14C]
00E49C43   50               PUSH EAX
00E49C44   FF15 DC00E700    CALL DWORD PTR DS:[E700DC]               ; KERNEL32.LoadLibraryA
00E49C4A   8B0D 74B7E700    MOV ECX,DWORD PTR DS:[E7B774]
00E49C50   89040E           MOV DWORD PTR DS:[ESI+ECX],EAX
00E49C53   A1 74B7E700      MOV EAX,DWORD PTR DS:[E7B774]
00E49C58   391C06           CMP DWORD PTR DS:[ESI+EAX],EBX
00E49C5B   0F84 32010000    JE 00E49D93                              ;Magic Jmp1



00E76BE8   3985 90C4FFFF    CMP DWORD PTR SS:[EBP-3B70],EAX          ; Armadill.00400000
00E76BEE   75 0F            JNZ SHORT 00E76BFF
00E76BF0   C785 8CC4FFFF 80>MOV DWORD PTR SS:[EBP-3B74],0E85180
00E76BFA   E9 C4000000      JMP 00E76CC3
00E76BFF   83A5 68C2FFFF 00 AND DWORD PTR SS:[EBP-3D98],0
00E76C06   C785 64C2FFFF C0>MOV DWORD PTR SS:[EBP-3D9C],0E857C0
00E76C10   EB 1C            JMP SHORT 00E76C2E
00E76C12   8B85 64C2FFFF    MOV EAX,DWORD PTR SS:[EBP-3D9C]
00E76C18   83C0 0C          ADD EAX,0C
00E76C1B   8985 64C2FFFF    MOV DWORD PTR SS:[EBP-3D9C],EAX
00E76C21   8B85 68C2FFFF    MOV EAX,DWORD PTR SS:[EBP-3D98]
00E76C27   40               INC EAX
00E76C28   8985 68C2FFFF    MOV DWORD PTR SS:[EBP-3D98],EAX
00E76C2E   8B85 64C2FFFF    MOV EAX,DWORD PTR SS:[EBP-3D9C]
00E76C34   8338 00          CMP DWORD PTR DS:[EAX],0
00E76C37   0F84 86000000    JE 00E76CC3                              ;Magic Jmp2
00E76C3D   8B85 64C2FFFF    MOV EAX,DWORD PTR SS:[EBP-3D9C]
00E76C43   8B40 08          MOV EAX,DWORD PTR DS:[EAX+8]
00E76C46   83E0 01          AND EAX,1
00E76C49   85C0             TEST EAX,EAX
00E76C4B   74 25            JE SHORT 00E76C72
00E76C4D   A1 2800E900      MOV EAX,DWORD PTR DS:[E90028]
00E76C52   8B0D 2800E900    MOV ECX,DWORD PTR DS:[E90028]            ; Armadill.004B3310
00E76C58   8B40 30          MOV EAX,DWORD PTR DS:[EAX+30]
00E76C5B   3341 20          XOR EAX,DWORD PTR DS:[ECX+20]
00E76C5E   8B0D 2800E900    MOV ECX,DWORD PTR DS:[E90028]            ; Armadill.004B3310
00E76C64   3341 70          XOR EAX,DWORD PTR DS:[ECX+70]
00

個人覺得第一處比較好。既可得到完整的IAT又可以避開時間的檢驗,至於如何找到IAT與Dump出IAT,我想大家應該沒有問題。
[ Dump出程式與修復IAT ]  在這個步驟,首先你需要一個觀念,你必須時時刻刻問自己程式在做什麼?為什麼這麼做?這時IAT亂序已完成,程式在以下的程式碼段寫下CALL的位置.即CALL(Address)

00E67E16   8B85 BCB0FFFF    MOV EAX,DWORD PTR SS:[EBP+FFFFB0BC]
00E67E1C   40               INC EAX
00E67E1D   8985 BCB0FFFF    MOV DWORD PTR SS:[EBP+FFFFB0BC],EAX
00E67E23   8B85 BCB0FFFF    MOV EAX,DWORD PTR SS:[EBP+FFFFB0BC]
00E67E29   8B8D 18C8FFFF    MOV ECX,DWORD PTR SS:[EBP-37E8]
00E67E2F   833C81 00        CMP DWORD PTR DS:[ECX+EAX*4],0
00E67E33   0F84 90000000    JE 00E67EC9
00E67E39   8B85 BCB0FFFF    MOV EAX,DWORD PTR SS:[EBP+FFFFB0BC]
00E67E3F   8B8D 18C8FFFF    MOV ECX,DWORD PTR SS:[EBP-37E8]
00E67E45   8B95 00C7FFFF    MOV EDX,DWORD PTR SS:[EBP-3900]
00E67E4B   031481           ADD EDX,DWORD PTR DS:[ECX+EAX*4]
00E67E4E   8995 ACB0FFFF    MOV DWORD PTR SS:[EBP+FFFFB0AC],EDX
00E67E54   8B85 ACB0FFFF    MOV EAX,DWORD PTR SS:[EBP+FFFFB0AC]
00E67E5A   8B00             MOV EAX,DWORD PTR DS:[EAX]
00E67E5C   8985 A8B0FFFF    MOV DWORD PTR SS:[EBP+FFFFB0A8],EAX
00E67E62   81BD A8B0FFFF 90>CMP DWORD PTR SS:[EBP+FFFFB0A8],90909090
00E67E6C   74 56            JE SHORT 00E67EC4
00E67E6E   8B85 A8B0FFFF    MOV EAX,DWORD PTR SS:[EBP+FFFFB0A8]
00E67E74   2B85 B8B0FFFF    SUB EAX,DWORD PTR SS:[EBP+FFFFB0B8]
00E67E7A   8985 A8B0FFFF    MOV DWORD PTR SS:[EBP+FFFFB0A8],EAX
00E67E80   FFB5 A8B0FFFF    PUSH DWORD PTR SS:[EBP+FFFFB0A8]
00E67E86   8B85 BCB0FFFF    MOV EAX,DWORD PTR SS:[EBP+FFFFB0BC]
00E67E8C   33D2             XOR EDX,EDX
00E67E8E   6A 10            PUSH 10
00E67E90   59               POP ECX
00E67E91   F7F1             DIV ECX
00E67E93   FF1495 7807E700  CALL DWORD PTR DS:[EDX*4+E70778]
00E67E9A   59               POP ECX
00E67E9B   8985 A8B0FFFF    MOV DWORD PTR SS:[EBP+FFFFB0A8],EAX
00E67EA1   8B85 A8B0FFFF    MOV EAX,DWORD PTR SS:[EBP+FFFFB0A8]
00E67EA7   8B8D D8C6FFFF    MOV ECX,DWORD PTR SS:[EBP-3928]
00E67EAD   8D0481           LEA EAX,DWORD PTR DS:[ECX+EAX*4]
00E67EB0   8985 A8B0FFFF    MOV DWORD PTR SS:[EBP+FFFFB0A8],EAX
00E67EB6   8B85 ACB0FFFF    MOV EAX,DWORD PTR SS:[EBP+FFFFB0AC]
00E67EBC   8B8D A8B0FFFF    MOV ECX,DWORD PTR SS:[EBP+FFFFB0A8]
00E67EC2   8908             MOV DWORD PTR DS:[EAX],ECX
00E67EC4  ^E9 4DFFFFFF      JMP 00E67E16

[Address]是指同一個API Armadillo為什麼會留下這個最容易被攻擊的地方呢?那是因為他的IAT亂序表的地址是動態產生的,它不得不在這個時候寫入正確的地址,所以在這個時候他的屬性就非得變為可讀可寫了.嘻嘻!也因此你就能使用Lordpe等工具去Dump出子程式來,這時你可以在Memory中找到IAT亂序表與CALL的位置表,它們是緊連著的.你把它們Dump出來,配合之前得到的IAT你就能修復他,或是直接寫入一些程式碼,讓CALL指向你自己的IAT,隨便你,在這裡你可以為所欲為.

[得到OEP] 在Armadillo中OEP倒有許多方法可找到.你可以He GetCurrenthreadId去找那個CALL EDI V.3.75與V.3.78均同.

[修復CC]:在這個階段大部分是手工活了,也是最花時間的Armadillo 的  Nanomites保護,其特徵程式碼如下:

0048F1F7   C785 94EBFFFF 00>MOV DWORD PTR SS:[EBP-146C],0
0048F201   6A FF            PUSH -1
0048F203   6A 04            PUSH 4
0048F205   8D95 50ECFFFF    LEA EDX,DWORD PTR SS:[EBP-13B0]
0048F20B   52               PUSH EDX
0048F20C   E8 7F7DFEFF      CALL Armadill.00476F90
0048F211   83C4 0C          ADD ESP,0C
0048F214   8985 68EEFFFF    MOV DWORD PTR SS:[EBP-1198],EAX
0048F21A   8B85 68EEFFFF    MOV EAX,DWORD PTR SS:[EBP-1198]
0048F220   33D2             XOR EDX,EDX
0048F222   B9 10000000      MOV ECX,10
0048F227   F7F1             DIV ECX
0048F229   8995 64EEFFFF    MOV DWORD PTR SS:[EBP-119C],EDX
0048F22F   8B95 50ECFFFF    MOV EDX,DWORD PTR SS:[EBP-13B0]
0048F235   52               PUSH EDX
0048F236   8B85 64EEFFFF    MOV EAX,DWORD PTR SS:[EBP-119C]
0048F23C   FF1485 A8784B00  CALL DWORD PTR DS:[EAX*4+4B78A8]
0048F243   83C4 04          ADD ESP,4
0048F246   8985 94EBFFFF    MOV DWORD PTR SS:[EBP-146C],EAX
0048F24C   C785 90EBFFFF 00>MOV DWORD PTR SS:[EBP-1470],0
0048F256   8B8D 64EEFFFF    MOV ECX,DWORD PTR SS:[EBP-119C]
0048F25C   8B148D 88994B00  MOV EDX,DWORD PTR DS:[ECX*4+4B9988]
0048F263   8995 70EEFFFF    MOV DWORD PTR SS:[EBP-1190],EDX
0048F269   8B85 90EBFFFF    MOV EAX,DWORD PTR SS:[EBP-1470]
0048F26F   3B85 70EEFFFF    CMP EAX,DWORD PTR SS:[EBP-1190]
0048F275   7D 5C            JGE SHORT Armadill.0048F2D3
0048F277   8B85 70EEFFFF    MOV EAX,DWORD PTR SS:[EBP-1190]
0048F27D   2B85 90EBFFFF    SUB EAX,DWORD PTR SS:[EBP-1470]
0048F283   99               CDQ
0048F284   2BC2             SUB EAX,EDX
0048F286   D1F8             SAR EAX,1

至於怎麼到這裡不用我說了吧!He GetThreadContext在這個部分你需要找到四個表《INT3地址+1表(Armadillo利用這來計算跳轉的,記做Table1),跳轉型別表(JMP,JZ,JNZ…)記做 Table2,跳的話距離是多少記做Table3,不跳的話距離又是多少記做Table4。為什麼需要這四個表呢?舉個例子:

                  00401D1B     CC     INT3
                  00401D1C     56     push ESI
                  
我們可以在Armadillo中找到
Table1:00401D1C
Table2:Jmp
Table3:04
Table4: 04
這是個絕對的跳轉JMP,但他只跳04Byte這其實是一個NOP怎麼說,你看00401D1C+04=00401D20你改為
00401D1B 90 NOP
00401D1C 90 NOP
00401D1D 90 NOP
00401D1E 90 NOP
00401D1F 90  NOP
00401D20 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]

或直接改為:
00401D1B  E900000000   JMP00401D20
00401D20  8B4508     MOV EAX,DWORD PTR SS:[EBP+8]

都必須可實現,或你不放心那可改為:
00401D1B  EB 03      JMP  00401D20
00401D1D  105678     ADC  BYTE  DS:[EST+78],DL
00401D20   8B4508    MOV  EAX,DWORD PTR SS:[EB+8]
也可以,另外還有一些修復技巧,後面再詳述.

首先找Table1亦就是發生INT3的下一個地址,它就在上述的0048F205  8D95 50ECFFFF LEA EDX,DWPRO PTR SS:[EBP-13BO]就在[EBP-13BO]中,V.3.75你可以用點選所有的功能表來獲得大部分有用的地址.但V.3.78就難了.還有一個方法是使用IDA去反彙編你已Dump出來的程式,IDA就會幫你做記號“Trap to Debugger”利用它你幾乎可以得到所有INT3地址,但有許多是用不到的,因為你不會走到那裡.你或許會問為什麼不用Armadillo的運算表去還原地址呢?舊版的或許可以,但新版的他不只把跳轉做成表,也把不是的也加在裡面,那就算你能還原它,也不一定是你需要的。
再來就是Table2的處理了,其程式碼如下:

0048F372   8B85 64EEFFFF    MOV EAX,DWORD PTR SS:[EBP-119C]
0048F378   8B0C85 C8994B00  MOV ECX,DWORD PTR DS:[EAX*4+4B99C8]
0048F37F   8B95 90EBFFFF    MOV EDX,DWORD PTR SS:[EBP-1470]
0048F385   33C0             XOR EAX,EAX
0048F387   8A0411           MOV AL,BYTE PTR DS:[ECX+EDX]
0048F38A   8985 74EBFFFF    MOV DWORD PTR SS:[EBP-148C],EAX
0048F390   8B85 74EBFFFF    MOV EAX,DWORD PTR SS:[EBP-148C]
0048F396   99               CDQ
0048F397   83E2 0F          AND EDX,0F
0048F39A   03C2             ADD EAX,EDX
0048F39C   C1F8 04          SAR EAX,4
0048F39F   8985 7CEBFFFF    MOV DWORD PTR SS:[EBP-1484],EAX
0048F3A5   8B8D 74EBFFFF    MOV ECX,DWORD PTR SS:[EBP-148C]
0048F3AB   81E1 0F000080    AND ECX,8000000F
0048F3B1   79 05            JNS SHORT Armadill.0048F3B8
0048F3B3   49               DEC ECX
0048F3B4   83C9 F0          OR ECX,FFFFFFF0
0048F3B7   41               INC ECX
0048F3B8   898D 78EBFFFF    MOV DWORD PTR SS:[EBP-1488],ECX
0048F3BE   8B95 7CEBFFFF    MOV EDX,DWORD PTR SS:[EBP-1484]
0048F3C4   3B95 78EBFFFF    CMP EDX,DWORD PTR SS:[EBP-1488]
0048F3CA   75 1B            JNZ SHORT Armadill.0048F3E7
0048F3CC   8B85 78EBFFFF    MOV EAX,DWORD PTR SS:[EBP-1488]
0048F3D2   83C0 01          ADD EAX,1
0048F3D5   25 0F000080      AND EAX,8000000F
0048F3DA   79 05            JNS SHORT Armadill.0048F3E1
0048F3DC   48               DEC EAX
0048F3DD   83C8 F0          OR EAX,FFFFFFF0
0048F3E0   40               INC EAX
0048F3E1   8985 78EBFFFF    MOV DWORD PTR SS:[EBP-1488],EAX
0048F3E7   8B8D 74EBFFFF    MOV ECX,DWORD PTR SS:[EBP-148C]
0048F3ED   8B95 7CEBFFFF    MOV EDX,DWORD PTR SS:[EBP-1484]
0048F3F3   8B048D 388F4B00  MOV EAX,DWORD PTR DS:[ECX*4+4B8F38]
0048F3FA   330495 AC324B00  XOR EAX,DWORD PTR DS:[EDX*4+4B32AC]
0048F401   8B8D 78EBFFFF    MOV ECX,DWORD PTR SS:[EBP-1488]
0048F407   33048D AC324B00  XOR EAX,DWORD PTR DS:[ECX*4+4B32AC]
0048F40E   8985 84EBFFFF    MOV DWORD PTR SS:[EBP-147C],EAX
0048F414   8B95 58ECFFFF    MOV EDX,DWORD PTR SS:[EBP-13A8]
0048F41A   81E2 D70F0000    AND EDX,0FD7
0048F420   52               PUSH EDX
0048F421   8B85 74EBFFFF    MOV EAX,DWORD PTR SS:[EBP-148C]
0048F427   0FBE88 A0774B00  MOVSX ECX,BYTE PTR DS:[EAX+4B77A0]
0048F42E   FF148D A8784B00  CALL DWORD PTR DS:[ECX*4+4B78A8]
0048F435   83C4 04          ADD ESP,4
0048F438   8985 88EBFFFF    MOV DWORD PTR SS:[EBP-1478],EAX
0048F43E   8B95 44ECFFFF    MOV EDX,DWORD PTR SS:[EBP-13BC]
0048F444   52               PUSH EDX
0048F445   8B85 88EBFFFF    MOV EAX,DWORD PTR SS:[EBP-1478]
0048F44B   50               PUSH EAX
0048F44C   FF95 84EBFFFF    CALL DWORD PTR SS:[EBP-147C]
0048F452   83C4 08          ADD ESP,8
0048F455   50               PUSH EAX
0048F456   8B8D 74EBFFFF    MOV ECX,DWORD PTR SS:[EBP-148C]
0048F45C   0FBE91 A0774B00  MOVSX EDX,BYTE PTR DS:[ECX+4B77A0]
0048F463   FF1495 E8784B00  CALL DWORD PTR DS:[EDX*4+4B78E8]
0048F46A   83C4 04          ADD ESP,4
0048F46D   8985 80EBFFFF    MOV DWORD PTR SS:[EBP-1480],EAX
0048F473   8B85 80EBFFFF    MOV EAX,DWORD PTR SS:[EBP-1480]
0048F479   83E0 01          AND EAX,1
0048F47C   85C0             TEST EAX,EAX
0048F47E   0F84 AE000000    JE Armadill.0048F532
0048F484   60               PUSHAD
0048F485   33C0             XOR EAX,EAX
0048F487   75 02            JNZ SHORT Armadill.0048F48B
0048F489   EB 15            JMP SHORT Armadill.0048F4A0
0048F48B   EB 33            JMP SHORT Armadill.0048F4C0

這段程式碼就是利用EFL值與前面運算得出的值做運算,算出子程式是跳或不是跳,意思即0048F47C TEST EAX,EAX;  EAX=1,子程式跳EAX=0子程式不跳,我們利用它來模擬進而得到跳轉型別。如何做呢?let’s go!
我們用到的旗標有CF、PF、ZF、SF、OF
       CF=1→1h
       PF=1→4h
       ZF=1→40h
       SF=1→80h
       OF=1→800h

走到0048F420 Push EDX,此時EDX=EFL值,我們把EDX值改為1意即只有CF旗標有作用,結果0048F47C的EAX值為1用筆記下來,再至0048F372重建EIP,如此依序更改為EDX的值,我們發現一個有趣的現象: 
EFL=1  EAX=1
EFL=4   EAX=1
EFL=40  EAX=1
EFL=80  EAX=1
EFL=800 EAX=1

意即所有的旗標都無法影響到跳轉,它肯定是一個絕對的跳轉,意即JMP。

再看下一個例子:                
EFL=1  EAX=0
EFL=4   EAX=0
EFL=40  EAX=1
EFL=80  EAX=0
EFL=800 EAX=0

此時只有零旗標ZF會影響跳轉,意即等於零跳轉,那就是JZ or JE

那JNZ呢?如下:                
EFL=1  EAX=1
EFL=4   EAX=1
EFL=40  EAX=0
EFL=80  EAX=1
EFL=800 EAX=1

跟JZ相反,等於零不跳,意即不等於零才會跳

歸納出:
(1)  11111→JMP(EB)                                               
(2)  00100→JZ(74)
(3)  11011→JNZ(75)
(4)  00011→JL(7C)  漏掉了許多跳轉,這只是告訴你原理,你可以查閱跳轉的資料
(5)  00111→JLE(7E) 去編你自己的跳轉型別判斷表,自由發揮吧!
(6)  11100→JGE(7D)
(7)  10000→JB(72)
(8)  01111→JAE(73)

接下來是Table3其程式碼如下:

0048F4B0   8B0C8D E8984B00  MOV ECX,DWORD PTR DS:[ECX*4+4B98E8]
0048F4B7   8B85 90EBFFFF    MOV EAX,DWORD PTR SS:[EBP-1470]
0048F4BD   33D2             XOR EDX,EDX
0048F4BF   BE 10000000      MOV ESI,10
0048F4C4   F7F6             DIV ESI
0048F4C6   8B85 90EBFFFF    MOV EAX,DWORD PTR SS:[EBP-1470]
0048F4CC   8B0C81           MOV ECX,DWORD PTR DS:[ECX+EAX*4]
0048F4CF   338C95 8CEEFFFF  XOR ECX,DWORD PTR SS:[EBP+EDX*4-1174]
0048F4D6   8B95 50ECFFFF    MOV EDX,DWORD PTR SS:[EBP-13B0]
0048F4DC   03D1             ADD EDX,ECX
0048F4DE   8995 50ECFFFF    MOV DWORD PTR SS:[EBP-13B0],EDX

走過0048F4CF後這個ECX的值就是我們要的了。

最後是Table4了,其程式碼如下:

0048F53D   8B85 64EEFFFF    MOV EAX,DWORD PTR SS:[EBP-119C]
0048F543   8B0C85 109A4B00  MOV ECX,DWORD PTR DS:[EAX*4+4B9A10]
0048F54A   8B95 90EBFFFF    MOV EDX,DWORD PTR SS:[EBP-1470]
0048F550   33C0             XOR EAX,EAX
0048F552   8A0411           MOV AL,BYTE PTR DS:[ECX+EDX]
0048F555   8B8D 50ECFFFF    MOV ECX,DWORD PTR SS:[EBP-13B0]
0048F55B   03C8             ADD ECX,EAX
0048F55D   898D 50ECFFFF    MOV DWORD PTR SS:[EBP-13B0],ECX

走過0048F552後這個EAX的值就是我們要的了。
在程式內寫入程式碼,依序去得到想要的Table,然後用它來修復CC,修復CC時注意事項 



例1:                                           
                                     
Table1  00401213
Table2  JZ
Table3  55FFFFFF
Table4  05
改00401212 OF 84 50FFFFFF


例2:                                 
Table1  00401213
Table2  JZ
Table3  EFFFFFFF
Table4  01
改00401212   74 EE

例3:                                 
Table1  00401213
Table2  JZ
Table3  28
Table4  01
改00401212   74 27

例4:                                 
Table1  00401213
Table2  JZ
Table3  B5
Table4  05
改00401212   0F 84 B0000000


[後記]:許久沒有脫殼與寫脫殼文了,甚至連電腦都很少碰,最近脫了新版本ASprotect 與Armadillo好象又能找到當年的一點感覺,我脫殼總喜歡慢慢的去品嚐保護程式帶給我的驚喜。脫這些硬殼,需要的是除了知識外,還需要耐心與恆心。最重要的是對脫殼的熱愛,希望本文能對你有所幫助。

相關文章