以前的精都没了,今天拿 PECompact 开个刀,小分析一下,高手勿笑。*_^
废话少说,拿出神器IDA,OD....
OD载入加壳文件到入口点:
01001000 notepad_.> B8 04150101 mov eax, 01011504
01001005 50 push eax ; SEH 句柄
01001006 64:FF35 00000000 push dword ptr fs:[0]
0100100D 64:8925 00000000 mov dword ptr fs:[0], esp ; 添加SEH链
01001014 33C0 xor eax, eax
01001016 8908 mov dword ptr ds:[eax], ecx ; 内存访问异常
01001018 50 push eax
程序一开始就添加一个结构化异常处理,在1011504地址处下断点(bp 1011504), F9 掉转到
异常处理(1011504)
.rsrc:01011504 SEH_handler:
.rsrc:01011504 mov eax, 0F10102CEh
.rsrc:01011509 lea ecx, [eax+10001259h] ; 取 PEC_start 地址
.rsrc:0101150F mov [ecx+1], eax ; 修改 PEC_start 地址处的 12345678 为0F10102CE
.rsrc:01011512 mov edx, [esp+4]
.rsrc:01011516 mov edx, [edx+0Ch] ; 取异常发生处地址1001016
.rsrc:01011519 mov byte ptr [edx], 0E9h ; 修改异常地址处(1001016)指令为JMP
.rsrc:0101151C add edx, 5
.rsrc:0101151F sub ecx, edx
.rsrc:01011521 mov [edx-4], ecx ; 计算并修改异常地址到PEC_start处的偏移量
.rsrc:01011524 xor eax, eax ; 指令修改后从异常处继续执行(修改后的指令为JMP PEC_start)
.rsrc:01011526 retn
.rsrc:01011527 PEC_start:
.rsrc:01011527 mov eax, 12345678h
.rsrc:0101152C pop large dword ptr fs:0
.rsrc:01011533 add esp, 4
修改后的PEC_start
.rsrc:01011527 PEC_start:
.rsrc:01011527 mov eax, 0F10102CEh
.rsrc:0101152C pop large dword ptr fs:0
.rsrc:01011533 add esp, 4 ; 清除SEH链
.rsrc:01011536 push ebp
.rsrc:01011537 push ebx
.rsrc:01011538 push ecx
.rsrc:01011539 push edi
.rsrc:0101153A push esi
.rsrc:0101153B push edx
.rsrc:0101153C lea ebx, [eax+10001212h] ; ebx指向一个结构(10114E0)
结构如下:
.rsrc:010114E0 PEC_encode_data dd 10DB4h ; 编码后的PEC代码
.rsrc:010114E4 size dd 0DACh
.rsrc:010114E8 dd 178h
.rsrc:010114EC depack_fun_rva dd 11435h ; PECompact的解压缩引擎代码相对虚拟地址
.rsrc:010114F0 imp_VirtualAlloc_rva dd 10D08h ; 导入表中VirtualAlloc的相对虚拟地址
.rsrc:010114F4 imp_VirtualFree_rva dd 10D0Ch ; 导入表中VirtualFree的相对虚拟地址
.rsrc:010114F8 orig_ImageBase_rva dd offset __ImageBase ; 基址
.rsrc:010114FC imp_LoadLibrary_rva dd 10D00h ; 导入表中LoadLibrary的相对虚拟地址
.rsrc:01011500 imp_GetProcAddress_rva dd 10D04h ; 导入表中GetProcAddress的相对虚拟地址
.rsrc:01011542 mov edx, [ebx+18h] ; 取原程序ImageBase
.rsrc:01011545 push edx
.rsrc:01011546 mov ebp, eax
.rsrc:01011548 push 40h
.rsrc:0101154A push 1000h
.rsrc:0101154F push dword ptr [ebx+4] ;
.rsrc:01011552 push 0
.rsrc:01011554 mov ecx, [ebx+10h] ; 取 imp_VirtualAlloc_rva
.rsrc:01011557 add ecx, edx ; 计算导入表中VirtualAlloc的地址
.rsrc:01011559 mov eax, [ecx]
.rsrc:0101155B call eax ; 调用 VirtualAlloc 分配内存
.rsrc:0101155D pop edx
.rsrc:0101155E mov edi, eax
.rsrc:01011560 push eax
.rsrc:01011561 push edx
.rsrc:01011562 mov esi, [ebx] ; 取 PEC_encode_data
.rsrc:01011564 mov eax, [ebx+20h] ; 取 imp_GetProcAddress_rva
.rsrc:01011567 add eax, edx ; 计算导入表中GetProcAddress的地址
.rsrc:01011569 mov ecx, [eax] ; Kernel32导出函数GetProcAddress的地址
.rsrc:0101156B mov [ebx+20h], ecx ; 保存到EBX指向的结构中 imp_GetProcAddress_rva
.rsrc:0101156E mov eax, [ebx+1Ch] ; 取导入表中LoadLibrary的相对虚拟地址
.rsrc:01011571 add eax, edx ; 计算导入表中LoadLibrary的地址
.rsrc:01011573 mov ecx, [eax] ; Kernel32导出函数LoadLibrary的地址
.rsrc:01011575 mov [ebx+1Ch], ecx ; 把LoadLibrary的地址保存到 imp_LoadLibrary_rva
.rsrc:01011578 add esi, edx
.rsrc:0101157A mov ecx, [ebx+0Ch] ; 取解压缩引擎的相对虚拟地址
.rsrc:0101157D add ecx, edx ; 计算解压缩引擎地址
.rsrc:0101157F lea eax, [ebx+1Ch]
.rsrc:01011582 push eax
.rsrc:01011583 push edi
.rsrc:01011584 push esi
.rsrc:01011585 call ecx ; 调用解压缩引擎, 解压缩 PEC_encode_data
.rsrc:01011587 pop edx
.rsrc:01011588 pop eax
.rsrc:01011589 add eax, [ebx+8]
.rsrc:0101158C mov edi, eax
.rsrc:0101158E push edx
.rsrc:0101158F mov esi, eax
.rsrc:01011591 mov eax, [esi-4]
.rsrc:01011594 add eax, 4
.rsrc:01011597 sub esi, eax
.rsrc:01011599 mov [esi+8], edx
.rsrc:0101159C mov ecx, [ebx+0Ch]
.rsrc:0101159F mov [esi+14h], ecx
.rsrc:010115A2 call edi ; 关键,调用解压缩后的 PEC 代码 PEC_unpack
.rsrc:010115A4 mov [ebp+100012FAh], eax
.rsrc:010115AA mov esi, eax
.rsrc:010115AC mov ecx, [ebx+14h]
.rsrc:010115AF pop edx
.rsrc:010115B0 jmp short loc_10115BE
.rsrc:010115B0
.rsrc:010115B2 ; ---------------------------------------------------------------------------
.rsrc:010115B2 add ecx, edx
.rsrc:010115B4 push 8000h
.rsrc:010115B9 push 0
.rsrc:010115BB push edi
.rsrc:010115BC call dword ptr [ecx]
.rsrc:010115BC
.rsrc:010115BE
.rsrc:010115BE loc_10115BE:
.rsrc:010115BE mov eax, esi
.rsrc:010115C0 pop edx
.rsrc:010115C1 pop esi
.rsrc:010115C2 pop edi
.rsrc:010115C3 pop ecx
.rsrc:010115C4 pop ebx
.rsrc:010115C5 pop ebp
.rsrc:010115C6 jmp eax ; 跳转到OEP
.rsrc:010115C6
.rsrc:010115C6 ; ---------------------------------------------------------------------------
.rsrc:010115C8 dd 0Eh dup(0)
.rsrc:01011600 dd 280h dup(?)
.rsrc:01011600 _rsrc ends
解压缩后的 PEC 代码:
seg000:00000178 PEC_unpack proc near
seg000:00000178
seg000:00000178 arg_F = dword ptr 23h
seg000:00000178 arg_34 = dword ptr 48h
seg000:00000178
seg000:00000178 push ebx
seg000:00000179 push edi
seg000:0000017A push esi
seg000:0000017B push ebp
seg000:0000017C call $+5
seg000:00000181 pop ebp
seg000:00000182 sub ebp, 10001307h
seg000:00000188 lea esi, [ebp+100012FEh] ; 计算 PEC_unpack 地址
seg000:0000018E mov eax, [esi-4]
seg000:00000191 add eax, 4
seg000:00000194 sub esi, eax
seg000:00000196 cld
seg000:00000197 mov ebx, esi
seg000:00000199 mov edx, [esi+8]
seg000:0000019C mov esi, [esi+1Ch]
seg000:0000019F add esi, edx
seg000:000001A1 lea edi, [ebp+10001E21h]
seg000:000001A7 lodsd ; +0C9B 构建PEC用导入表
seg000:000001A8 stosd ; imp_LoadLibrary
seg000:000001A9 lodsd
seg000:000001AA stosd ; imp_GetProcAddress
seg000:000001AB lodsd
seg000:000001AC stosd ; imp_VirtualAlloc
seg000:000001AD lodsd
seg000:000001AE stosd ; imp_VirtualFree
seg000:000001AF nop
seg000:000001B0 cmp dword ptr [ebx+48h], 1
seg000:000001B4 jz short loc_1CB
seg000:000001B4
seg000:000001B6 mov esi, [ebx+44h]
seg000:000001B9 test esi, esi
seg000:000001BB jz short loc_1CB
seg000:000001BB
seg000:000001BD mov ecx, 23h
seg000:000001C2 add esi, edx
seg000:000001C4 mov edi, [ebx+40h]
seg000:000001C7 add edi, edx
seg000:000001C9 rep movsb
seg000:000001CB loc_1CB:
seg000:000001CB mov esi, ebx
seg000:000001CD lea edi, [ebp+10001E0Dh]
seg000:000001D3 add [edi], ebp
seg000:000001D5 add [edi+4], ebp
seg000:000001D8 add [edi+8], ebp
seg000:000001DB lea ecx, [ebp+10001D78h]
seg000:000001E1 push ecx ; +0BF2
seg000:000001E2 call PEC_import ; 构建 PEC 使用的导入函数表
PEC用导入表构建函数:
seg000:00000321 PEC_import proc near
seg000:00000321
seg000:00000321 hModule = dword ptr -4
seg000:00000321 arg_offset_BF2 = dword ptr 8
seg000:00000321
seg000:00000321 push ebp
seg000:00000322 mov ebp, esp
seg000:00000324 add esp, 0FFFFFFFCh
seg000:00000327 push ebx
seg000:00000328 push edi
seg000:00000329 push esi
seg000:0000032A call $+5
seg000:0000032F pop ebx ; EBX = +32F
seg000:00000330 sub ebx, 100014B5h
seg000:00000336 mov esi, [ebp+arg_offset_BF2]
seg000:00000339 loc_339:
seg000:00000339 mov ecx, [esi] ; ECX = 10001D94
seg000:0000033B add ecx, ebx ; ECX = 10001D94 + +32F -100014B5
seg000:0000033B ; = +0C0E = offset s_Kernel32
seg000:0000033D push ecx
seg000:0000033E call dword ptr [ebx+10001E21h] ; +0C9B: imp_LoadLibrary
seg000:00000344 mov [ebp+hModule], eax
seg000:00000347 mov edx, [esi+4]
seg000:0000034A mov edi, [esi+8]
seg000:0000034D add edx, ebx
seg000:0000034F add edi, ebx
seg000:00000351 loc_351:
seg000:00000351 xor eax, eax
seg000:00000353 add eax, [edx]
seg000:00000355 jz short loc_36D
seg000:00000357 push edx
seg000:00000358 mov eax, [edx]
seg000:0000035A add eax, ebx
seg000:0000035C push eax
seg000:0000035D push [ebp+hModule]
seg000:00000360 call dword ptr [ebx+10001E25h] ; +0C9F: imp_GetProcAddress
seg000:00000366 stosd
seg000:00000367 pop edx
seg000:00000368 add edx, 4
seg000:0000036B jmp short loc_351
seg000:0000036D ; ---------------------------------------------------------------------------
seg000:0000036D loc_36D:
seg000:0000036D add esi, 0Ch
seg000:00000370 add eax, [esi]
seg000:00000372 jnz short loc_339 ; ECX = 10001D94
seg000:00000374 pop esi
seg000:00000375 pop edi
seg000:00000376 pop ebx
seg000:00000377 leave
seg000:00000378 retn 4
seg000:00000378 PEC_import endp
构建后的导入数据如下:
seg000:00000BC1 BT_s_Messageboxa dd 10001D62h
seg000:00000BC5 BT_s_Wsprintfa dd 10001D6Eh
seg000:00000BC9 dd 0
seg000:00000BCD imp_MessageBoxA dd 0
seg000:00000BD1 imp_wsprintfA dd 0
seg000:00000BD5 s_User32 db 'user32',0
seg000:00000BDC s_Messageboxa db 'MessageBoxA',0
seg000:00000BE8 s_Wsprintfa db 'wsprintfA',0
seg000:00000BF2 BT_s_Kernel32 dd 10001D94h ; 字符串 s_Kernel32 的变形偏移地址
seg000:00000BF6 dd 10001DE1h
seg000:00000BFA BT_iat_kernel32 dd 10001DF9h ; 构建从 Kernel32 导入的函数表变形偏移
seg000:00000BFE BT_s_User32 dd 10001D5Bh ; 字符串 s_User32 的变形偏移地址
seg000:00000C02 dd 10001D47h
seg000:00000C06 dd 10001D53h
seg000:00000C0A dd 0
seg000:00000C0E s_Kernel32 db 'kernel32',0
seg000:00000C17 s_Exitprocess db 'ExitProcess',0
seg000:00000C23 s_Closehandle db 'CloseHandle',0
seg000:00000C2F s_Openprocess db 'OpenProcess',0
seg000:00000C3B s_Getmodulehandlea db 'GetModuleHandleA',0
seg000:00000C4C s_Virtualprotect db 'VirtualProtect',0
seg000:00000C5B BT_s_Exitprocess dd 10001D9Dh ; 字符串 s_Exitprocess 的变形偏移
seg000:00000C5F BT_s_Getmodulehandlea dd 10001DC1h ; 字符串 s_Getmodulehandlea 的变形偏移
seg000:00000C63 BT_s_Closehandle dd 10001DA9h ; 字符串 s_Closehanle 的变形偏移
seg000:00000C67 BT_s_Openprocess dd 10001DB5h ; 字符串 s_Openprocess 的变形偏移
seg000:00000C6B BT_s_VirtualProtect dd 10001DD2h ; 字符串 s_Virtualprotect 的变形偏移
seg000:00000C6F dd 0
seg000:00000C73 imp_ExitProcess dd 0 ; 构建从 Kernel32 导入的函数表
seg000:00000C77 imp_GetModuleHandleA dd 0
seg000:00000C7B imp_CloseHandle dd 0
seg000:00000C7F imp_OpenProcess dd 0
seg000:00000C83 imp_VirtualProtect dd 0
seg000:00000C87 func dd 10001C27h
seg000:00000C8B func_0 dd 10001C49h
seg000:00000C8F func_1 dd 10001952h
seg000:00000C93 dd 0
seg000:00000C97 dd 0
seg000:00000C9B imp_LoadLibrary dd 0
seg000:00000C9F imp_GetProcAddress dd 0
seg000:00000CA3 imp_VirtualAlloc dd 0
seg000:00000CA7 imp_VirtualFree dd 0
seg000:000001E1 push ecx ; +0BF2
seg000:000001E2 call PEC_import ; 构建 PEC 使用的导入函数
seg000:000001E2
seg000:000001E7 nop
seg000:000001E8 nop
seg000:000001E9 nop
seg000:000001EA nop
seg000:000001EB nop
seg000:000001EC nop
seg000:000001ED nop
seg000:000001EE nop
seg000:000001EF mov ecx, [esi+2Ch] ; +0E0
seg000:000001F2 mov [ebp+10001E1Dh], ecx ; +0C97
seg000:000001F8 push 40h
seg000:000001FA push 1000h
seg000:000001FF push ecx
seg000:00000200 push 0
seg000:00000202 call dword ptr [ebp+10001E29h] ; +0CA3: imp_VirtualAlloc
seg000:00000208 mov [ebp+10001E19h], eax
seg000:0000020E push esi ; ESI = +0B4
seg000:0000020F call depack_section ; 调用解压缩引擎解压缩节数据
解压缩引擎用 PEC+0偏移处的一个DWORD偏移值指向PEC压缩时定义的解压缩引擎
seg000:00000000 engine_offset dd 8 ; 这里是8, 就是从+8处是解压缩引擎
seg000:00000004 dd 0
seg000:00000008
seg000:00000008 ; =============== S U B R O U T I N E =======================================
seg000:00000008
seg000:00000008 depack_engine proc near
....解压缩代码略.
seg000:0000020F
seg000:00000214 lea ecx, [ebp+10001CC8h]
seg000:0000021A test eax, eax
seg000:0000021C jnz loc_2B6
seg000:0000021C
seg000:00000222 push esi ; ESI = +0B4
seg000:00000223 call rebuild_section ; 重新构建节的内存映象
seg000:00000223
seg000:00000228 push esi ; ESI = +0B4
seg000:00000229 call code_fix ; 修复变形的JMP, CALL指令
seg000:00000229
seg000:0000022E nop
seg000:0000022F nop
seg000:00000230 nop
seg000:00000231 nop
seg000:00000232 nop
seg000:00000233 nop
seg000:00000234 nop
seg000:00000235 nop
seg000:00000236 nop
seg000:00000237 nop
seg000:00000238 nop
seg000:00000239 nop
seg000:0000023A nop
seg000:0000023B nop
seg000:0000023C mov ecx, [esi+34h]
seg000:0000023F test ecx, ecx
seg000:00000241 jz loc_2D0
seg000:00000241
seg000:00000247 add ecx, [esi+8]
seg000:0000024A push ecx
seg000:0000024B push esi
seg000:0000024C call rebuild_IAT ; 重新构建源程序导入表
seg000:0000024C
seg000:00000251 test eax, eax
seg000:00000253 jz short loc_2D0
seg000:00000253
seg000:00000255 mov edx, [ebp+10001A57h]
seg000:0000025B mov ecx, [ebp+10001A5Bh]
seg000:00000261 test ecx, ecx
seg000:00000263 jnz short loc_26D
seg000:00000263
seg000:00000265 lea ecx, [ebp+10001D45h]
seg000:0000026B jmp short loc_29A
seg000:0000026B
seg000:0000026D ; ---------------------------------------------------------------------------
seg000:0000026D
seg000:0000026D loc_26D:
seg000:0000026D test ecx, 80000000h
seg000:00000273 jz short loc_293
seg000:00000273
seg000:00000275 push edx
seg000:00000276 and ecx, 7FFFFFFFh
seg000:0000027C push ecx
seg000:0000027D lea eax, [ebp+10001D12h]
seg000:00000283 push eax
seg000:00000284 lea eax, [ebp+10001E31h]
seg000:0000028A push eax
seg000:0000028B call dword ptr [ebp+10001D57h]
seg000:00000291 jmp short loc_2B0
seg000:00000291
seg000:00000293 ; ---------------------------------------------------------------------------
seg000:00000293
seg000:00000293 loc_293:
seg000:00000293 mov eax, [esi+8]
seg000:00000296 add ecx, eax
seg000:00000298 inc ecx
seg000:00000299 inc ecx
seg000:00000299
seg000:0000029A
seg000:0000029A loc_29A:
seg000:0000029A push edx
seg000:0000029B push ecx
seg000:0000029C lea eax, [ebp+10001CDDh]
seg000:000002A2 push eax
seg000:000002A3 lea eax, [ebp+10001E31h]
seg000:000002A9 push eax
seg000:000002AA call dword ptr [ebp+10001D57h]
seg000:000002AA
seg000:000002B0
seg000:000002B0 loc_2B0:
seg000:000002B0 lea ecx, [ebp+10001E31h]
seg000:000002B6
seg000:000002B6 loc_2B6:
seg000:000002B6 push 10h
seg000:000002B8 lea eax, [ebp+10001CB6h]
seg000:000002BE push eax
seg000:000002BF push ecx
seg000:000002C0 push 0
seg000:000002C2 call dword ptr [ebp+10001D53h]
seg000:000002C8 push 0
seg000:000002CA call dword ptr [ebp+10001DF9h]
seg000:000002CA
seg000:000002D0
seg000:000002D0 loc_2D0:
seg000:000002D0 mov edi, [ebx+8]
seg000:000002D3 mov ebx, esi
seg000:000002D5 cmp dword ptr [ebx+48h], 1
seg000:000002D9 jnz short loc_2F0
seg000:000002D9
seg000:000002DB mov eax, [ebx+0Ch]
seg000:000002DE mov ecx, [ebx+40h]
seg000:000002E1 mov esi, ecx
seg000:000002E3 add esi, edi
seg000:000002E5 mov byte ptr [esi], 0E9h
seg000:000002E8 add ecx, 5
seg000:000002EB sub eax, ecx
seg000:000002ED mov [esi+1], eax
seg000:000002ED
seg000:000002F0
seg000:000002F0 loc_2F0:
seg000:000002F0 mov esi, ebx
seg000:000002F2 nop
seg000:000002F3 nop
seg000:000002F4 nop
seg000:000002F5 nop
seg000:000002F6 nop
seg000:000002F7 nop
seg000:000002F8 nop
seg000:000002F9 nop
seg000:000002FA nop
seg000:000002FB nop
seg000:000002FC nop
seg000:000002FD nop
seg000:000002FE push edi
seg000:000002FF call sub_A39 ; 修改节属性不可写
seg000:000002FF
seg000:00000304 push 8000h
seg000:00000309 push 0
seg000:0000030B push dword ptr [ebp+10001E19h]
seg000:00000311 call dword ptr [ebp+10001E2Dh] ; +0CA7: imp_VirtualFree
seg000:00000317 mov eax, [esi+0Ch]
seg000:0000031A add eax, edi
seg000:0000031C pop ebp
seg000:0000031D pop esi
seg000:0000031E pop edi
seg000:0000031F pop ebx
seg000:00000320 retn
seg000:00000320 PEC_unpack endp
Berglob
2007-04-23