smallyou93 发表于 2009-10-28 18:24

[转载]Polycrypt PE2.1.5外壳分析

本帖最后由 smallyou93 于 2009-10-28 18:30 编辑

作者:bugmans
博客:http://hi.baidu.com/bugmans

一、开始3段数据解密:
1.第一段
0040D00D > 60                   pushad
0040D00E    E8 EDFFFFFF          call NotePad_.0040D000 //解密1
0040D013 - EB 80                jmp short NotePad_.0040CF95
0040D015    F5                   cmc
0040D016    3E:F5                cmc
0040D018    A0 50F53891          mov al,byte ptr ds:

解密函数1:
0040D000    91                   xchg eax,ecx
0040D001    8BF4               mov esi,esp
0040D003    AD                   lods dword ptr ds:
0040D004    FEC9               dec cl
0040D006    803408 93            xor byte ptr ds:,93
0040D00A ^ E2 FA                loopd short NotePad_.0040D006
0040D00C    C3                   retn

解密函数很简单,就简单的XOR加密,密匙为0x93

2.第二段
0040D028    91                   xchg eax,ecx
0040D029    9C                   pushfd
0040D02A    55                   push ebp
0040D02B    C141 02 00         rol dword ptr ds:,0
0040D02F    C141 11 00         rol dword ptr ds:,0
0040D033    81E9 0F624000      sub ecx,NotePad_.0040620F
0040D039    51                   push ecx
0040D03A    8BE9               mov ebp,ecx
0040D03C    8DB5 52624000      lea esi,dword ptr ss:
0040D042    8BFE               mov edi,esi
0040D044    B9 11000000          mov ecx,11
0040D049    66:8B9D 636E4000   mov bx,word ptr ss:
0040D050    E8 C0FFFFFF          call NotePad_.0040D015 //解密2
0040D055    90                   nop

解密函数2:
0040D015    66:AD                lods word ptr ds:
0040D017    66:33C3            xor ax,bx
0040D01A    66:AB                stos word ptr es:
0040D01C    02DF               add bl,bh
0040D01E    86DF               xchg bh,bl
0040D020    66:D1CB            ror bx,1
0040D023    66:43                inc bx
0040D025 ^ E2 EE                loopd short NotePad_.0040D015
0040D027    C3                   retn

解密函数也很简单,也是简单的XOR加密,但是密匙不是固定的,都是计算后再进行解密的

3.第三段
0040D055    90                   nop
0040D056    8DBD 24624000      lea edi,dword ptr ss:
0040D05C    32C0               xor al,al
0040D05E    B9 3B000000          mov ecx,3B
0040D063    F3:AA                rep stos byte ptr es:
0040D065    8DB5 74624000      lea esi,dword ptr ss:
0040D06B    8BFE               mov edi,esi
0040D06D    B9 F7050000          mov ecx,5F7
0040D072    E8 9EFFFFFF          call NotePad_.0040D015 //解密3
0040D077    90                   nop

解密函数同解密函数2


3段解密后,外壳的代码已经全部解密了,下面开始真正的外壳段

二、SEH的大量应用,构造内存访问异常,以改变调试流程
这个壳大量的利用了SEH异常,后面还会看见大量的int3异常,使得程序在调试器里运行显得很卡

0040D078    8D85 90624000      lea eax,dword ptr ss:
0040D07E    50                   push eax
0040D07F    8DBD AD664000      lea edi,dword ptr ss:
0040D085    57                   push edi                                     ; SEH Handler入栈,回调地址为0040D4B1
0040D086    64:8B11            mov edx,dword ptr fs:
0040D089    52                   push edx
0040D08A    64:8921            mov dword ptr fs:,esp
0040D08D    8909               mov dword ptr ds:,ecx                   ; 由于ecx=0,故构造个内存访问异常
0040D08F    E9 5B010000          jmp NotePad_.0040D1EF
0040D094    5D                   pop ebp                                    ; 第一个SEH出口地址
0040D095    8DBD BC664000      lea edi,dword ptr ss:
0040D09B    57                   push edi
0040D09C    33C0               xor eax,eax
0040D09E    64:FF30            push dword ptr fs:                      ; SEH Handler入栈,回调地址为0040D4C0
0040D0A1    64:8920            mov dword ptr fs:,esp
0040D0A4    8B10               mov edx,dword ptr ds:                   ; 再次构造内存访问异常
0040D0A6    33C0               xor eax,eax                                  ; 第二个SEH的出口地址

看下第二个回调函数:
下面的异常都是这个地址做为异常的回调地址,然后在这个函数里,对不同的SEH进行不同的处理

0040D4C0    64:67:A1 3000      mov eax,dword ptr fs:
0040D4C5    0FB658 02            movzx ebx,byte ptr ds:
0040D4C9    0ADB               or bl,bl
0040D4CB ^ 75 9D                jnz short NotePad_.0040D46A
0040D4CD    8B45 10            mov eax,dword ptr ss:
0040D4D0    8B90 B8000000      mov edx,dword ptr ds:                ; edx保存异常地址
0040D4D6    2B90 B4000000      sub edx,dword ptr ds:
0040D4DC    81FA A0624000      cmp edx,NotePad_.004062A0
0040D4E2    74 19                je short NotePad_.0040D4FD                   ; 对不同的异常,进行不同的处理
0040D4E4    81FA AA644000      cmp edx,NotePad_.004064AA
0040D4EA    74 21                je short NotePad_.0040D50D
0040D4EC    8B90 B8000000      mov edx,dword ptr ds:
0040D4F2    803A CC            cmp byte ptr ds:,0CC
0040D4F5    74 3F                je short NotePad_.0040D536                   ; 判断异常处的指令是否为OxCC,也就是int3
0040D4F7    B8 01000000          mov eax,1
0040D4FC    C3                   retn
0040D4FD    C780 B0000000 001040>mov dword ptr ds:,NotePad_.00401000
0040D507    B8 00000000          mov eax,0
0040D50C    C3                   retn
0040D50D    8BF8               mov edi,eax
0040D50F    8B9F A4000000      mov ebx,dword ptr ds:
0040D515    8B8F B0000000      mov ecx,dword ptr ds:
0040D51B    86CD               xchg ch,cl
0040D51D    66:D1C9            ror cx,1
0040D520    66:2BCB            sub cx,bx
0040D523    66:C1C1 02         rol cx,2
0040D527    66:33CB            xor cx,bx
0040D52A    899F A4000000      mov dword ptr ds:,ebx
0040D530    898F B0000000      mov dword ptr ds:,ecx
0040D536    FF80 B8000000      inc dword ptr ds:                  ; 把出口地址改为EIP+1
0040D53C    B8 00000000          mov eax,0
0040D541    C3                   retn

三、获取外壳所要的API函数的地址
0040D0A8    64:8B40 30         mov eax,dword ptr fs:
0040D0AC    0FB658 02            movzx ebx,byte ptr ds:
0040D0B0    0ADB               or bl,bl
0040D0B2    0F85 B2030000      jnz NotePad_.0040D46A
0040D0B8    8B40 0C            mov eax,dword ptr ds:
0040D0BB    8B70 1C            mov esi,dword ptr ds:
0040D0BE    AD                   lods dword ptr ds:
0040D0BF    8B40 08            mov eax,dword ptr ds:               ; kernel32.dll地址的基址的获取
0040D0C2    8985 256E4000      mov dword ptr ss:,eax            ; kernel32.7C800000
0040D0C8    E8 E7080000          call NotePad_.0040D9B4   //获取地址函数
0040D0CD    64:67:A1 3000      mov eax,dword ptr fs:
0040D0D2    0FB658 02            movzx ebx,byte ptr ds:
0040D0D6    0ADB               or bl,bl
0040D0D8    0F85 8C030000      jnz NotePad_.0040D46A
0040D0DE    6A 00                push 0
0040D0E0    FF95 D16B4000      call dword ptr ss:


获取壳所需要的API函数地址:
0040D9B4    8DB5 D16B4000      lea esi,dword ptr ss:
0040D9BA    8BFE               mov edi,esi
0040D9BC    AD                   lods dword ptr ds:
0040D9BD    83F8 00            cmp eax,0
0040D9C0    74 12                je short NotePad_.0040D9D4                   ; 判断是否解密完毕,是则跳出
0040D9C2    03C5               add eax,ebp
0040D9C4    50                   push eax                                     ; eax中保存着所要获取地址的字符串信息
0040D9C5    FFB5 256E4000      push dword ptr ss:
0040D9CB    FF95 C26E4000      call dword ptr ss:               ; GetProcAddress
0040D9D1    AB                   stos dword ptr es:
0040D9D2 ^ EB E8                jmp short NotePad_.0040D9BC
0040D9D4    C3                   retn


所获取的的函数如下:
0040D9D5 7C80B6A1 kernel32.GetModuleHandleA
0040D9D9 7C802442 kernel32.Sleep
0040D9DD 7C801D77 kernel32.LoadLibraryA
0040D9E1 7C801AD0 kernel32.VirtualProtect
0040D9E5 7C810637 kernel32.CreateThread
0040D9E9 7C80C058 kernel32.ExitThread
0040D9ED 7C81CDDA kernel32.ExitProcess
0040D9F1 7C801A24 kernel32.CreateFileA
0040D9F5 7C80B4CF kernel32.GetModuleFileNameA
0040D9F9 7C831EAB kernel32.DeleteFileA
0040D9FD 7C809B47 kernel32.CloseHandle
0040DA01 7C80180E kernel32.ReadFile
0040DA05 7C80BAA1 kernel32.lstrcmpiA
0040DA09 7C80FD2D kernel32.GlobalAlloc
0040DA0D 7C80FC2F kernel32.GlobalFree
0040DA11 7C8286EE kernel32.CopyFileA
0040DA15 7C810A77 kernel32.GetFileSize
0040DA19 7C810D87 kernel32.WriteFile
0040DA1D 7C80929C kernel32.GetTickCount
0040DA21 7C821982 kernel32.OpenFile
0040DA25 7C810B8E kernel32.SetFilePointer

四、虚拟机检测
0040D0E6    8985 696E4000      mov dword ptr ss:,eax            ; NotePad_.00400000
0040D0EC    8D85 CC6E4000      lea eax,dword ptr ss:
0040D0F2    0F0108               sidt fword ptr ds:                      ; 获取idt的特征值,用来判断是否在虚拟机环境
0040D0F5    81BD CE6E4000 000000>cmp dword ptr ss:,D0000000
0040D0FF    7C 20                jl short NotePad_.0040D121
0040D101    81BD CE6E4000 000000>cmp dword ptr ss:,F0000000
0040D10B    0F8E 59030000      jle NotePad_.0040D46A                        ; 检测到在虚拟机,则做关机处理
0040D111    81BD CE6E4000 000000>cmp dword ptr ss:,FF000000
0040D11B    0F8F 49030000      jg NotePad_.0040D46A                         ; 检测到在虚拟机,则做关机处理
0040D121    8DBD 5F624000      lea edi,dword ptr ss:


看下0040D46A:
0040D46A    E8 0B000000          call NotePad_.0040D47A //变形CALL,F7进
0040D46F    55                   push ebp
0040D470    53                   push ebx
0040D471    45                   inc ebp
0040D472    52                   push edx
0040D473    3332               xor esi,dword ptr ds:
0040D475    2E:44                inc esp
0040D477    4C                   dec esp

0040D47A    FF95 D96B4000      call dword ptr ss:               ; hUDll=eax=LoadLibraryA("USER32.dll")
0040D480    E8 0E000000          call NotePad_.0040D493                     ; 继续变形CALL,F7
0040D485    45                   inc ebp
0040D486    78 69                js short NotePad_.0040D4F1
0040D488    74 57                je short NotePad_.0040D4E1
0040D48A    696E 64 6F777345   imul ebp,dword ptr ds:,4573776F
0040D491    78 00                js short NotePad_.0040D493
0040D493    50                   push eax                                     ; user32.77D10000
0040D494    FF95 C26E4000      call dword ptr ss:               ; eax=GetProcAddress(hUDll,"ExitWindowsEx")
0040D49A    8985 A9664000      mov dword ptr ss:,eax
0040D4A0    6A 04                push 4
0040D4A2    FF95 A9664000      call dword ptr ss:               ; 执行ExitWindowsEx,关机
0040D4A8    E9 23080000          jmp NotePad_.0040DCD0
0040D4AD    45                   inc ebp

五、破坏PE头,使之无法正常的dump,anti-dump
0040D142    8B9D 696E4000      mov ebx,dword ptr ss:
0040D148    8D8D 296E4000      lea ecx,dword ptr ss:
0040D14E    51                   push ecx
0040D14F    6A 40                push 40
0040D151    6A 01                push 1
0040D153    53                   push ebx
0040D154    FF95 DD6B4000      call dword ptr ss:               ; 修改PE头的属性为可读写,为下面的破坏PE头行为做准备
0040D15A    8B95 3F6E4000      mov edx,dword ptr ss:
0040D160    03D3               add edx,ebx
0040D162    66:C742 06 FFFF      mov word ptr ds:,0FFFF                ; 1,修改取段数,NOP
0040D168    C742 20 00000000   mov dword ptr ds:,0                  ; 2,修改SizeOfInitializeData数,NOP
0040D16F    C742 28 00000000   mov dword ptr ds:,0                  ; 3,修改AddressOfEntryPoint,NOP
0040D176    C742 2C FFFFFF0F   mov dword ptr ds:,0FFFFFFF         ; 4,BaseOfCode,NOP
0040D17D    C742 34 FFFFFF0F   mov dword ptr ds:,0FFFFFFF         ; 5,ImageBase,NOP
0040D184    039D 376E4000      add ebx,dword ptr ss:            ; 定位到第一个区段的起始RVA处
0040D18A    8BFB               mov edi,ebx                                  ; EDI中为全部区段的信息
0040D18C    8B8D 3B6E4000      mov ecx,dword ptr ss:            ; ecx=0x0F0,填充的长度
0040D192    B0 FF                mov al,0FF
0040D194    F3:AA                rep stos byte ptr es:                   ; 6,EDI处填充垃圾数据FF,长度为F0,NOP
0040D196    83BD 656E4000 01   cmp dword ptr ss:,1
0040D19D    74 50                je short NotePad_.0040D1EF
0040D19F    80BD 316E4000 00   cmp byte ptr ss:,0
0040D1A6    74 47                je short NotePad_.0040D1EF
0040D1A8    68 04010000          push 104
0040D1AD    6A 40                push 40
0040D1AF    FF95 056C4000      call dword ptr ss:               ; GlobalAlloc,分配个全局堆
0040D1B5    8985 336E4000      mov dword ptr ss:,eax
0040D1BB    68 04010000          push 104
0040D1C0    FFB5 336E4000      push dword ptr ss:
0040D1C6    6A 00                push 0
0040D1C8    FF95 F16B4000      call dword ptr ss:               ; GetModuleFileNameA,获取完整的路径,放新申请的全局堆中
0040D1CE    6A 00                push 0
0040D1D0    6A 00                push 0
0040D1D2    6A 04                push 4
0040D1D4    6A 00                push 0
0040D1D6    6A 00                push 0
0040D1D8    68 00000080          push 80000000
0040D1DD    FFB5 336E4000      push dword ptr ss:
0040D1E3    FF95 ED6B4000      call dword ptr ss:               ; CreateFileA,读取本身文件,eax放获得的句柄。
                                                                              ; 目的是占用该文件的句柄,使得dump跟修复的时候,无法获得该文件的句柄
上面填充垃圾数据的处理方法,只要全NOP掉即可,对于占文件句柄来anti-dump,可这样处理:
方法一:
0040D1CE    6A 00                push 0
0040D1D0    6A 00                push 0
0040D1D2    6A 04                push 4
0040D1D4    6A 00                push 0
0040D1D6    6A 00                push 0
0040D1D8    68 00000080          push 80000000
0040D1DD    FFB5 336E4000      push dword ptr ss:
0040D1E3    FF95 ED6B4000      call dword ptr ss: ;CreateFileA
把这些代码全NOP掉,或者把push 0处的机器码6A 00修改为EB 19

方法二:
把CreateFileA的第三个参数ShareMode修改为FILE_SHARE_READ|FILE_SHARE_WRITE,数值为3

0040D1CE    6A 00                push 0
0040D1D0    6A 00                push 0
0040D1D2    6A 04                push 4
0040D1D4    6A 00                push 0
0040D1D6    6A 00                push 3
0040D1D8    68 00000080          push 80000000
0040D1DD    FFB5 336E4000      push dword ptr ss:
0040D1E3    FF95 ED6B4000      call dword ptr ss: ;CreateFileA

六、再次大量的SEH(int3)

0040D239    CC                   int3
0040D23A    8D85 0F624000      lea eax,dword ptr ss:
0040D240    2B85 4D6D4000      sub eax,dword ptr ss:
0040D246    83E8 13            sub eax,13
0040D249    8985 516D4000      mov dword ptr ss:,eax
0040D24F    8BB5 556D4000      mov esi,dword ptr ss:
0040D255    8BFD               mov edi,ebp
0040D257    83FE 00            cmp esi,0
0040D25A    0F84 8D000000      je NotePad_.0040D2ED
0040D260    CC                   int3
0040D261    8B9D 516D4000      mov ebx,dword ptr ss:
0040D267    8B87 596D4000      mov eax,dword ptr ds:
0040D26D    03D8               add ebx,eax
0040D26F    8B8F 5D6D4000      mov ecx,dword ptr ds:
0040D275    B8 40000000          mov eax,40
0040D27A    E8 A7FFFFFF          call NotePad_.0040D226
0040D27F    D1E9               shr ecx,1
0040D281    56                   push esi
0040D282    57                   push edi
0040D283    8BF3               mov esi,ebx
0040D285    8BFE               mov edi,esi
0040D287    60                   pushad
0040D288    66:8B9D 636E4000   mov bx,word ptr ss:
0040D28F    E8 81FDFFFF          call NotePad_.0040D015
0040D294    61                   popad
0040D295    33D2               xor edx,edx
0040D297    66:8B9C2A 4F6E4000   mov bx,word ptr ds:
0040D29F    E8 94010000          call NotePad_.0040D438
0040D2A4    66:899C2A 4F6E4000   mov word ptr ds:,bx
0040D2AC    66:AD                lods word ptr ds:
0040D2AE    CC                   int3 //这个SEH处理得小心
0040D2AF    66:AB                stos word ptr es:

这个处理流程在上面各SEH处理分支的第二个,需手动置EIP+1,直接NOP掉会导致出错

后面还有很多,由于这些SEH的出口地址都在异常下面,也就是EIP+1处,故处理方法只要全NOP掉这些int3指令即可

七、跳过输入表的加密
0040D371    FFB5 356D4000      push dword ptr ss:
0040D377    FF95 C26E4000      call dword ptr ss:               ; GetProcAddress
0040D37D    80BD 326E4000 01   cmp byte ptr ss:,1               ; 是否加密标志,把下面的跳直接改JMP,即可跳过加密
0040D384    75 5E                jnz short NotePad_.0040D3E4
0040D386    3B85 0D6C4000      cmp eax,dword ptr ss:            ; CopyFileA
0040D38C    75 08                jnz short NotePad_.0040D396
0040D38E    8D85 40674000      lea eax,dword ptr ss:            ; 填充加密的地址,下面同
0040D394    EB 4E                jmp short NotePad_.0040D3E4
0040D396    3B85 1D6C4000      cmp eax,dword ptr ss:            ; OpenFile
0040D39C    75 08                jnz short NotePad_.0040D3A6
0040D39E    8D85 026A4000      lea eax,dword ptr ss:
0040D3A4    EB 3E                jmp short NotePad_.0040D3E4
0040D3A6    3B85 ED6B4000      cmp eax,dword ptr ss:            ; CreateFileA
0040D3AC    75 08                jnz short NotePad_.0040D3B6
0040D3AE    8D85 726A4000      lea eax,dword ptr ss:
0040D3B4    EB 2E                jmp short NotePad_.0040D3E4
0040D3B6    3B85 D16B4000      cmp eax,dword ptr ss:            ; GetModuleHandleA
0040D3BC    75 08                jnz short NotePad_.0040D3C6
0040D3BE    8D85 256B4000      lea eax,dword ptr ss:
0040D3C4    EB 1E                jmp short NotePad_.0040D3E4
0040D3C6    3B85 F16B4000      cmp eax,dword ptr ss:            ; GetModuleFileNameA
0040D3CC    75 08                jnz short NotePad_.0040D3D6
0040D3CE    8D85 566B4000      lea eax,dword ptr ss:
0040D3D4    EB 0E                jmp short NotePad_.0040D3E4
0040D3D6    3B85 F96B4000      cmp eax,dword ptr ss:            ; CloseHandle
0040D3DC    75 06                jnz short NotePad_.0040D3E4
0040D3DE    8D85 F26A4000      lea eax,dword ptr ss:
0040D3E4    8907               mov dword ptr ds:,eax
0040D3E6    8385 3D6D4000 04   add dword ptr ss:,4
0040D3ED ^ E9 3CFFFFFF          jmp NotePad_.0040D32E
0040D3F2    CC                   int3
0040D3F3    83C6 14            add esi,14
0040D3F6    8B95 516D4000      mov edx,dword ptr ss:
0040D3FC ^ E9 FBFEFFFF          jmp NotePad_.0040D2FC
0040D401    8DBD D7644000      lea edi,dword ptr ss:            ; 处理完毕
0040D407    32C0               xor al,al

事实上,该壳仅仅处理了以上列出的几个函数。处理方法:
0040D384    75 5E                jnz short NotePad_.0040D3E4改JMP
或者把填充加密地址的lea指令全NOP,也或者把是否处理的跳转全修改了。
事实上,也就是对特定的函数,进行的IAT HOOK
以GetModuleHandleA为例,看下HOOK函数:
0040D929    C8 000000            enter 0,0
0040D92D    56                   push esi
0040D92E    E8 00000000          call NotePad_.0040D933
0040D933    812C24 2F6B4000      sub dword ptr ss:,NotePad_.00406B2F   ; ASCII "DlgCtrlID"
0040D93A    5E                   pop esi
0040D93B    8B45 08            mov eax,dword ptr ss:
0040D93E    83F8 00            cmp eax,0
0040D941    75 0B                jnz short NotePad_.0040D94E
0040D943    8B86 696E4000      mov eax,dword ptr ds:
0040D949    5E                   pop esi
0040D94A    C9                   leave
0040D94B    C2 0400            retn 4
0040D94E    50                   push eax
0040D94F    FF96 D16B4000      call dword ptr ds:               ; kernel32.GetModuleHandleA
0040D955    5E                   pop esi
0040D956    C9                   leave
0040D957    C2 0400            retn 4
0040D95A    C8 000000            enter 0,0
0040D95E    52                   push edx
0040D95F    E8 00000000          call NotePad_.0040D964
0040D964    812C24 606B4000      sub dword ptr ss:,NotePad_.00406B60   ; ASCII "nt"

八、革命完成,跳到OEP
0040D407    32C0               xor al,al
0040D409    B9 33010000          mov ecx,133
0040D40E    8B85 396D4000      mov eax,dword ptr ss:            ; 取出OEP
0040D414    0385 516D4000      add eax,dword ptr ss:            ; OEP RVA+ImageBase
0040D41A    8985 2B664000      mov dword ptr ss:,eax            ; 修改指令,把下面retn前的push地址改为了OEP地址
0040D420    8B0424               mov eax,dword ptr ss:
0040D423    64:67:A3 0000      mov dword ptr fs:,eax
0040D428    83C4 08            add esp,8
0040D42B    5D                   pop ebp
0040D42C    9D                   popfd
0040D42D    61                   popad
0040D42E    68 00000000          push 0
0040D433    C3                   retn                                       ; 跳去OEP
后被修改为:

0040D42E    68 CC104000          push NotePad_.004010CC                     ; 修改为OEP的值
0040D433    C3                   retn                                       ; 跳去


至此,脱壳完毕。

huzhao23 发表于 2009-10-29 00:29

能否上传附件呢
页: [1]
查看完整版本: [转载]Polycrypt PE2.1.5外壳分析