邪恶八进制信息安全团队技术讨论组's Archiver

cnhcerkf 2006-11-25 00:33

[转载]Softwrap脱壳总结

原始链接: [url]http://bbs.unpack.cn/viewthread.php?tid=8408[/url]
8100303 发表于: 2006-11-14 20:44
本文中的程序:[url]http://www.fractalpc.com/resources/SetupFractalPC30.exe[/url]
取得完整的输入表:
断点:GetModuleHandleA,普通断点要下在函数末尾,否则会被检测到,当堆栈出现如下内容时,返回:
0012FF98  00459CF5  返回到 FractalP.00459CF5
0012FF9C  00000000
0012FFA0  00B20000
0012FFA4  0012FFE0  指向下一个 SEH 记录的指针
壳会检测单步执行,如果能避开检测的话,会来到这里:
0045B7F6   F6C3 02      test   bl, 2
0045B7F9   74 21        je    short 0045B81C      这里决定是否把函数代码抽走,改成jmp
0045B7FB   FFB5 DF1C0000  push   dword ptr [ebp+1CDF]
0045B801   6A 10        push   10
0045B803   50          push   eax
0045B804   FFB5 DF1C0000  push   dword ptr [ebp+1CDF]
下面是循环的底部:
0045B827   C1E2 02      shl    edx, 2
0045B82A   83C6 04      add    esi, 4
0045B82D   57          push   edi
0045B82E   51          push   ecx
0045B82F   6A 03        push   3                push 3,所以每个函数会储存3次
0045B831   59          pop    ecx
0045B832   8D7E F4      lea    edi, dword ptr [esi-C]
0045B835   F3:AB        rep    stos dword ptr es:[edi]  这里储存需要用到的函数,数据窗口定位在edi上
0045B837   59          pop    ecx
0045B838   5F          pop    edi
0045B839   35 BB82506D    xor    eax, 6D5082BB
0045B83E   890413       mov    dword ptr [ebx+edx], eax
0045B841  ^ E9 58FFFFFF    jmp    0045B79E
0045B846   41          inc    ecx
0045B847  ^ E9 94FEFFFF    jmp    0045B6E0
0045B84C   FFB5 E31C0000  push   dword ptr [ebp+1CE3]    在这里下断,运行,数据窗口会看见函数列表,复制出来.

然后,找到oep,在oep处中断,把复制出来的输入函数列表挪到原来的输入表的位置,记住每个函数只复制一次就行了,不同的dll中间需要用一行00000000隔开,以利于区分.

壳没有抽取代码,其主要表现形式有三种:
第一种:
CALL [004XXXXX] 变成 CALL [00XXXXXX] 的形式,当然这个形式里面的 00XXXXXX 表现为不同的地址,这里的00XXXXXX是壳里的地址,由于我们跳开了抽取函数代码,所以最后会返回到函数的地址,修复的方法是找到所有这样的地址,然后跟踪一下
进入一个这样的call:
首先传递一些参数:
0045C013   6A 00        push   0
0045C015   9C          pushfd
0045C016   50          push   eax
0045C017   53          push   ebx
0045C018   8B5C24 10     mov    ebx, dword ptr [esp+10]
0045C01C   53          push   ebx
0045C01D   83EB 06      sub    ebx, 6
0045C020   68 E9260000    push   26E9
0045C025   68 0000B300    push   0B30000     变形call
0045C02A   C3          retn
来到00B30000,这里通过堆栈,利用产生的另外几个区段的数据计算出函数地址:
00B30000   55          push   ebp
00B30001   56          push   esi
00B30002   57          push   edi
00B30003   51          push   ecx
00B30004   52          push   edx
00B30005   50          push   eax
00B30006   BD 1A994500    mov    ebp, 45991A
00B3000B   016C24 18     add    dword ptr [esp+18], ebp
00B3000F   2B9D 962A0000  sub    ebx, dword ptr [ebp+2A96]
00B30015   8BBD DE2A0000  mov    edi, dword ptr [ebp+2ADE]
00B3001B   8B8D DA2A0000  mov    ecx, dword ptr [ebp+2ADA]
00B30021   8BC3        mov    eax, ebx
00B30023   2B85 D22A0000  sub    eax, dword ptr [ebp+2AD2]
00B30029   D3E8        shr    eax, cl
00B3002B   8B0487       mov    eax, dword ptr [edi+eax*4]
00B3002E   8BF0        mov    esi, eax
00B30030   81E6 FFFF0000  and    esi, 0FFFF
00B30036   C1E8 10      shr    eax, 10
00B30039   8BF8        mov    edi, eax
00B3003B   8D043E       lea    eax, dword ptr [esi+edi]
00B3003E   BA 06639227    mov    edx, 27926306
00B30043   D1E8        shr    eax, 1
00B30045   8BC8        mov    ecx, eax
00B30047   69C9 8466DA44  imul   ecx, ecx, 44DA6684
00B3004D   2BD1        sub    edx, ecx
00B3004F   8B8D FA2A0000  mov    ecx, dword ptr [ebp+2AFA]
00B30055   51          push   ecx
00B30056   8B0CC1       mov    ecx, dword ptr [ecx+eax*8]
00B30059   33CA        xor    ecx, edx
00B3005B   3BCB        cmp    ecx, ebx
00B3005D   59          pop    ecx
00B3005E   74 0C        je    short 00B3006C
00B30060   77 05        ja    short 00B30067
00B30062   8D78 01      lea    edi, dword ptr [eax+1]
00B30065  ^ EB D4        jmp    short 00B3003B
00B30067   8D70 FF      lea    esi, dword ptr [eax-1]
00B3006A  ^ EB CF        jmp    short 00B3003B
00B3006C   8B5C24 1C     mov    ebx, dword ptr [esp+1C]
00B30070   3354C1 04     xor    edx, dword ptr [ecx+eax*8+4]
00B30074   0FB61B       movzx  ebx, byte ptr [ebx]
00B30077   2BD3        sub    edx, ebx
00B30079   8BB5 EA2A0000  mov    esi, dword ptr [ebp+2AEA]
00B3007F   8B0496       mov    eax, dword ptr [esi+edx*4]
00B30082   35 67B6BDD0    xor    eax, D0BDB667
00B30087   50          push   eax
00B30088   8A00        mov    al, byte ptr [eax]
00B3008A   04 0F        add    al, 0F
00B3008C   74 11        je    short 00B3009F
00B3008E   F6D8        neg    al
00B30090   2C 23        sub    al, 23
00B30092   74 0B        je    short 00B3009F
00B30094   FEC8        dec    al
00B30096   74 07        je    short 00B3009F
00B30098   FEC8        dec    al
00B3009A   74 03        je    short 00B3009F
00B3009C   F8          clc
00B3009D   EB 1E        jmp    short 00B300BD
00B3009F   8B0424       mov    eax, dword ptr [esp]
00B300A2   8B00        mov    eax, dword ptr [eax]
00B300A4   330424       xor    eax, dword ptr [esp]
00B300A7   C1E8 18      shr    eax, 18
00B300AA   84C0        test   al, al
00B300AC  ^ 74 EE        je    short 00B3009C
00B300AE   8B0424       mov    eax, dword ptr [esp]
00B300B1   8A40 01      mov    al, byte ptr [eax+1]
00B300B4   34 C3        xor    al, 0C3
00B300B6  ^ 74 E4        je    short 00B3009C
00B300B8   83C4 04      add    esp, 4
00B300BB   50          push   eax
00B300BC   F9          stc
00B300BD   58          pop    eax
00B300BE   73 02        jnb    short 00B300C2
00B300C0   33C0        xor    eax, eax
00B300C2   50          push   eax
00B300C3   5B          pop    ebx
00B300C4   58          pop    eax
00B300C5   5A          pop    edx
00B300C6   59          pop    ecx
00B300C7   5F          pop    edi
00B300C8   5E          pop    esi
00B300C9   5D          pop    ebp
00B300CA   830424 08     add    dword ptr [esp], 8
00B300CE   C2 0400      retn   4
返回到这里:
0045C00F   5B          pop    ebx
0045C010   58          pop    eax
0045C011   9D          popfd
0045C012   C3          retn

这只是其中一种00XXXXXX地址 的 CALL [00XXXXXX] 的返回地址,如果里面的00XXXXXX 不同的话返回地址是不同的,跟一下就知道了,由于已经制造好了一个输入表,因此可以在这里比较输入表和这里的esp的值即产生的函数地址,相同的话,就把这句代码修复好.
比如:401000 call [00XXXXXX] 得到 esp 值是 74142545 而输入表 中 402000的地址也是 74142545 ,那就改成:401000 call [402000],具体操作可以通过path一段代码来自动完成.


第二种情况:
MOV EXX [004XXXXX] 变成 一个call
比如:mov    eax, dword ptr [402000]  mov    EDX, dword ptr [402000]  会变成:call 00XXXXXX ,当然这里的00XXXXXX 也不是唯一的。不过在运行中的表现是一样的。

跟进这个call:
同样先传递一些参数:
0045924A  /E9 19270000    jmp    0045B968

0045B968   9C          pushfd
0045B969   60          pushad
0045B96A   8B5C24 24     mov    ebx, dword ptr [esp+24]
0045B96E   43          inc    ebx
0045B96F   53          push   ebx
0045B970   83EB 06      sub    ebx, 6
0045B973   8BD3        mov    edx, ebx
0045B975   68 76200000    push   2076
0045B97A   68 0000B300    push   0B30000        这里同样是变形的call
0045B97F   C3          retn

不同的是从这个变形的call返回后来到这样的地址:
此时,ebx是运算得到的函数地址,而edx则决定了MOV EXX [004XXXXX] 中的EXX 是EAX还是EBX或者EDX、EDI、ESI、EPB。

从上到下的顺序是按照寄存器的顺序生成的
EAX 7FFDF000
ECX 0012FA04
EDX 00009164
EBX 00000000
ESP 0012F9E8
EBP 0045991A FractalP.0045991A
ESI 00B300D1
EDI 0012FD6C

0045B9AC   5A          pop    edx
0045B9AD   8D9402 0A000000 lea    edx, dword ptr [edx+eax+A]
0045B9B4   FFE2        jmp    edx
0045B9B6   895C24 1C     mov    dword ptr [esp+1C], ebx
0045B9BA   EB 27        jmp    short 0045B9E3
0045B9BC   895C24 18     mov    dword ptr [esp+18], ebx
0045B9C0   EB 21        jmp    short 0045B9E3
0045B9C2   895C24 14     mov    dword ptr [esp+14], ebx
0045B9C6   EB 1B        jmp    short 0045B9E3
0045B9C8   895C24 10     mov    dword ptr [esp+10], ebx
0045B9CC   EB 15        jmp    short 0045B9E3
0045B9CE   895C24 0C     mov    dword ptr [esp+C], ebx
0045B9D2   EB 0F        jmp    short 0045B9E3
0045B9D4   895C24 08     mov    dword ptr [esp+8], ebx
0045B9D8   EB 09        jmp    short 0045B9E3
0045B9DA   895C24 04     mov    dword ptr [esp+4], ebx
0045B9DE   EB 03        jmp    short 0045B9E3
0045B9E0   891C24       mov    dword ptr [esp], ebx
0045B9E3   61          popad
0045B9E4   FF4424 04     inc    dword ptr [esp+4]
0045B9E8   9D          popfd

现在可以在0045B9B4   FFE2        jmp    edx 下断点然后根据edx和ebx的值来修复了,或者改成jmp  008D0010到代码处,自动的修复:
例子代码如下:
008D0000   A1 FC018D00    mov    eax, dword ptr [8D01FC]  
这里的8D01FC处的地址为存放所有存在这种变形call的地址的第一个地址-4
008D0005   83C0 04      add    eax, 4
008D0008   A3 FC018D00    mov    dword ptr [8D01FC], eax
008D000D   FF20        jmp    dword ptr [eax]
008D000F   90          nop
008D0010   B9 00500310    mov    ecx, 10035000        这里10035000是IAT起始地址,不是前面说的程序的
008D0015   8B01        mov    eax, dword ptr [ecx]
008D0017   3BC3        cmp    eax, ebx
008D0019   90          nop
008D001A   74 0C        je    short 008D0028
008D001C   83C1 04      add    ecx, 4
008D001F   81F9 B8530310  cmp    ecx, 100353B8        这里100353B8是IAT结束地址+4,不是前面说的程序的
008D0025  ^ 75 EE        jnz    short 008D0015
008D0027   90          nop                   这里下断,防止壳产生IAT里没有的函数,不过不会用到。
下面开始根据edx的值判断mov EXX 的修复,其中的值是另外程序的,不是前面的地址,可以根据顺序改过来。
008D0028   81FA 9C250B10  cmp    edx, 100B259C
008D002E   75 0F        jnz    short 008D003F
008D0030   A1 FC018D00    mov    eax, dword ptr [8D01FC]
008D0035   8B00        mov    eax, dword ptr [eax]
008D0037   C600 A1      mov    byte ptr [eax], 0A1
008D003A   8948 01      mov    dword ptr [eax+1], ecx
008D003D  ^ EB C1        jmp    short 008D0000
008D003F   81FA A2250B10  cmp    edx, 100B25A2
008D0045   75 11        jnz    short 008D0058
008D0047   A1 FC018D00    mov    eax, dword ptr [8D01FC]
008D004C   8B00        mov    eax, dword ptr [eax]
008D004E   66:C700 8B0D   mov    word ptr [eax], 0D8B
008D0053   8948 02      mov    dword ptr [eax+2], ecx
008D0056  ^ EB A8        jmp    short 008D0000
008D0058   81FA A8250B10  cmp    edx, 100B25A8
008D005E   75 11        jnz    short 008D0071
008D0060   A1 FC018D00    mov    eax, dword ptr [8D01FC]
008D0065   8B00        mov    eax, dword ptr [eax]
008D0067   66:C700 8B15   mov    word ptr [eax], 158B
008D006C   8948 02      mov    dword ptr [eax+2], ecx
008D006F  ^ EB 8F        jmp    short 008D0000
008D0071   81FA AE250B10  cmp    edx, 100B25AE
008D0077   75 11        jnz    short 008D008A
008D0079   A1 FC018D00    mov    eax, dword ptr [8D01FC]
008D007E   8B00        mov    eax, dword ptr [eax]
008D0080   66:C700 8B1D   mov    word ptr [eax], 1D8B
008D0085   8948 02      mov    dword ptr [eax+2], ecx
008D0088  ^ EB E5        jmp    short 008D006F
008D008A   81FA B4250B10  cmp    edx, 100B25B4
008D0090   75 11        jnz    short 008D00A3
008D0092   A1 FC018D00    mov    eax, dword ptr [8D01FC]
008D0097   8B00        mov    eax, dword ptr [eax]
008D0099   66:C700 8B25   mov    word ptr [eax], 258B
008D009E   8948 02      mov    dword ptr [eax+2], ecx
008D00A1  ^ EB E5        jmp    short 008D0088
008D00A3   81FA BA250B10  cmp    edx, 100B25BA
008D00A9   75 11        jnz    short 008D00BC
008D00AB   A1 FC018D00    mov    eax, dword ptr [8D01FC]
008D00B0   8B00        mov    eax, dword ptr [eax]
008D00B2   66:C700 8B2D   mov    word ptr [eax], 2D8B
008D00B7   8948 02      mov    dword ptr [eax+2], ecx
008D00BA  ^ EB E5        jmp    short 008D00A1
008D00BC   81FA C0250B10  cmp    edx, 100B25C0
008D00C2   75 11        jnz    short 008D00D5
008D00C4   A1 FC018D00    mov    eax, dword ptr [8D01FC]
008D00C9   8B00        mov    eax, dword ptr [eax]
008D00CB   66:C700 8B35   mov    word ptr [eax], 358B
008D00D0   8948 02      mov    dword ptr [eax+2], ecx
008D00D3  ^ EB E5        jmp    short 008D00BA
008D00D5   81FA C6250B10  cmp    edx, 100B25C6
008D00DB   75 11        jnz    short 008D00EE
008D00DD   A1 FC018D00    mov    eax, dword ptr [8D01FC]
008D00E2   8B00        mov    eax, dword ptr [eax]
008D00E4   66:C700 8B3D   mov    word ptr [eax], 3D8B
008D00E9   8948 02      mov    dword ptr [eax+2], ecx
008D00EC  ^ EB E5        jmp    short 008D00D3
008D00EE  - EB FE        jmp    short 008D00EE             如果没有成功会跳到这里死掉。
运行后,程序可能暂时运行无相应,另外这段代码里没有判断是否读取完所有的变形的call的地址,所以直接用到最后会提示0000000无法读取。

第三种:

call到壳里的某个地址,其地址和第二种的接近,但是不可执行,应该是中间CCCCCCCCC代码的变形,不用理它。

如果程序过期,无法运行并脱壳,可以在这里跳开:
0045BB9B   F3:AB        rep    stos dword ptr es:[edi]
0045BB9D   53          push   ebx
0045BB9E   57          push   edi
0045BB9F   56          push   esi
0045BBA0   FF73 08      push   dword ptr [ebx+8]
0045BBA3   56          push   esi
0045BBA4   50          push   eax
0045BBA5   FFD2        call   edx                 进入这里
0045BBA7   83C4 0C      add    esp, 0C
0045BBAA   8985 E9220000  mov    dword ptr [ebp+22E9], eax
0045BBB0   5E          pop    esi
0045BBB1   5F          pop    edi
0045BBB2   5B          pop    ebx

10001934 >  55          push   ebp                    ; FractalP.0045991A
10001935   8BEC        mov    ebp, esp
10001937   83EC 10      sub    esp, 10
1000193A   8B45 10      mov    eax, dword ptr [ebp+10]
1000193D   FF05 E88B0410  inc    dword ptr [10048BE8]
10001943   833D E88B0410 0>cmp    dword ptr [10048BE8], 2
1000194A   53          push   ebx
1000194B   56          push   esi
1000194C   57          push   edi
1000194D   A3 90B50410    mov    dword ptr [1004B590], eax
10001952   7C 56        jl    short 100019AA  
上面NOP掉,没有任何提示,程序就运行了,壳的注册功能已经被废掉了            
10001954   E8 286A0200    call   10028381
10001959   8BF0        mov    esi, eax

比较乱套,凑合着看吧。辛苦了。

页: [1]
© 1999-2008 EvilOctal Security Team