• 标 题:浅谈Armadillo V.3.75 与 V.3.78的保护【原创】
  • 作 者:C-pen
  • 时 间:2004-12-06,10:03
  • 链 接:http://bbs.pediy.com

浅谈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好象又能找到当年的一点感觉,我脱壳总喜欢慢慢的去品尝保护程序带给我的惊喜。脱这些硬壳,需要的是除了知识外,还需要耐心与恒心。最重要的是对脱壳的热爱,希望本文能对你有所帮助。