VB Crypt Payload分析
· 5 分钟阅读 · @admin

分析VB样本的时候发现有几种混淆方式,记录下。
替换函数指针
>样本shah:a66f989e58ada2eff729ac2032ff71a159c521e7372373f4a1c1cf13f8ae2f0c
载入vb.idc脚本,脚本分析完后,查看event handle函数,
.text:00463E14 _O_Pub_Obj_Inf1_Ctl_Inf0x3_0x7_lpForm_Load dd offset Hdr_Jmp_Addr_0x46549A ; Ptr to Form Load Event Code.
....
.text:00463E78 sub [esp+arg_0], 0FFFFh
.text:00463E80 jmp _O_Pub_Obj_Inf1_Method0x1
.text:00463E85 Hdr_Jmp_Addr_0x46549A: ; DATA XREF:.text:_O_Pub_Obj_Inf1_Ctl_Inf0x3_0x7_lpForm_Load↑o
.text:00463E85 sub dword ptr [esp+4], 3Bh ; ';' ; Flags and Code Address
.text:00463E8D jmp _O_Pub_Obj_Inf1_Event0x2
_O_Pub_Obj_Inf1_Event0x2就是处理Form_load的函数,一般malicious code都是在这里实现。
接着往下看。
这里计算处shellcode的地址。0x43AF4B=1526C77h/(sqr(25.0))
.text:00465D83 mov [ebp+var_50], 1526C77h
.text:00465D8A fld ds:dbl_401118 ;25.0
.text:00465D90 push ecx
.text:00465D91 push ecx
.text:00465D92 fstp qword ptr [esp+8+var_8]
.text:00465D95 call rtcSqr
.text:00465D9A call __vbaFpI4
.text:00465D9F mov ecx, eax
在 [eax+0x6f8] 这个函数将shellcode地址替换,arg_0为Form_load的第一个参数,也就是Form类。
.text:00465DA8 mov eax, [ebp+arg_0]
.text:00465DAB mov eax, [eax]
.text:00465DAD push [ebp+arg_0]
.text:00465DB0 call dword ptr [eax+6F8h]
[eax]中存放的是地址虚表,[eax+6f8h]地址正好是_O_Pub_Obj_Inf1_Method0x1方法,
.data:0046737C dd offset msvbvm60_BASIC_CLASS_QueryInterface
.data:00467380 dd offset msvbvm60_BASIC_CLASS_AddRef
.data:00467384 dd offset msvbvm60_BASIC_CLASS_Release
...
.data:00467A6C dd 72A44A98h
.data:00467A70 dd 72A44AA0h
.data:00467A74 dd 463E80h ; ptr _O_Pub_Obj_Inf1_Method0x1
.data:00467A78 dd 463E8Dh ; ptr _O_Pub_Obj_Inf1_Event0x2
...
替换指针,进入shellcode执行代码
.text:00464434 add eax, 2B0h
.text:00464439 jo loc_465495
.text:0046443F mov [ebp+var_20], eax
.text:00464442 push [ebp+arg_4] ;shellcode地址
.text:00464445 push [ebp+var_20] ;[eax+0x2b0]
.text:00464448 call replace_ptr
....
.text:004644C3 call dword ptr [eax+2B0h]
在shellcode中并没有使用常规的方式获取api地址,而是先找到msvbvm60模块的地址,再通过到处函数DllFunction来获得对应API的地址。 中间穿插了大量的花指令。
.text:0043B10F get_api_address proc near ; CODE XREF: sub_43AF88:loc_43AF89↑p
.text:0043B10F ; sub_43B07C+2B↑p
.text:0043B10F
.text:0043B10F var_14 = dword ptr -14h
.text:0043B10F anonymous_2 = dword ptr -10h
.text:0043B10F anonymous_1 = dword ptr -0Ch
.text:0043B10F anonymous_0 = dword ptr -8
.text:0043B10F var_4 = dword ptr -4
.text:0043B10F
.text:0043B10F mov eax, large fs:30h ;peb地址
.text:0043B115 packuswb mm1, mm1
.text:0043B118 mov eax, [eax+0Ch] ;PEB_LDR_DATA
.text:0043B11B pcmpgtb mm5, mm4
.text:0043B11E mov eax, [eax+14h];get InMemoryOrderModuleList
.text:0043B121 pcmpeqw mm2, mm7
.text:0043B124
.text:0043B124 loc_43B124: ; CODE XREF: get_api_address+29↓j
.text:0043B124 ; get_api_address+36↓j
.text:0043B124 mov eax, [eax]
.text:0043B126 punpckhdq mm1, mm3
.text:0043B129 mov ebx, [eax+28h]
.text:0043B12C pcmpgtw xmm7, xmm6
.text:0043B130 mov esi, 53004Ch ;
.text:0043B135 inc esi ;MS for msvbvm60.dll
.text:0043B136 cmp [ebx], esi
.text:0043B138 jnz short loc_43B124
.text:0043B13A pcmpgtb xmm3, xmm7
.text:0043B13E cmp dword ptr [ebx+4], 420056h ;VB for MS for msvbvm60.dll
.text:0043B145 jnz short loc_43B124
.text:0043B147 pcmpgtd xmm0, xmm3
.text:0043B14B mov esi, [eax+10h]
.text:0043B14E pcmpgtw xmm6, xmm6
.text:0043B152 push esi
.text:0043B153 pcmpgtb mm3, mm4
.text:0043B156 mov ebx, [esi+3Ch]
.text:0043B159 punpckhwd xmm0, xmm2
.text:0043B15D mov esi, [esp+4+var_4]
.text:0043B160 punpckhbw xmm5, xmm1
.text:0043B164 add esi, ebx
.text:0043B166 pcmpeqd xmm0, xmm1
.text:0043B16A mov ebx, [esi+78h]
.text:0043B16D pcmpeqw mm6, mm3
.text:0043B170 mov eax, [esp+4+var_4]
.text:0043B173 punpckhwd xmm3, xmm7
.text:0043B177 add eax, ebx
.text:0043B179 punpckhbw xmm4, xmm4
.text:0043B17D mov esi, eax
.text:0043B17F pcmpeqb xmm4, xmm6
.text:0043B183 add esi, 28h ; '('
.text:0043B186 pcmpeqw mm1, mm2
.text:0043B189
.text:0043B189 loc_43B189: ; CODE XREF: get_api_address+80↓j
.text:0043B189 get_api_address+94↓j ...
.text:0043B189 lodsd
.text:0043B18A punpckhdq mm0, mm6
.text:0043B18D test eax, eax
.text:0043B18F jz short loc_43B189
.text:0043B191 packssdw xmm4, xmm7
.text:0043B195 add eax, [esp+4+var_4]
.text:0043B198 pcmpeqb xmm6, xmm2
.text:0043B19C mov ebx, 83EC8B55h ;DllFunctionCall 函数特征
.text:0043B1A1 cmp [eax], ebx
.text:0043B1A3 jnz short loc_43B189
.text:0043B1A5 punpckhwd mm0, mm4
.text:0043B1A8 cmp dword ptr [eax+4], 8D560CECh ;DllFunctionCall 函数特征
.text:0043B1AF jnz short loc_43B189
.text:0043B1B1 pcmpgtb mm6, mm4
.text:0043B1B4 pop ebx
.text:0043B1B5 pcmpeqd xmm0, xmm1
.text:0043B1B9 xor ebx, ebx
.text:0043B1BB pcmpeqw mm6, mm3
.text:0043B1BE push ebx
.text:0043B1BF punpckhwd xmm3, xmm7
.text:0043B1C3 push ebx
.text:0043B1C4 punpckhbw xmm4, xmm4
.text:0043B1C8 push ebx
.text:0043B1C9 pcmpeqb xmm4, xmm6
.text:0043B1CD push esp
.text:0043B1CE pcmpeqw mm1, mm2
.text:0043B1D1 push 0
.text:0043B1D3 punpckhdq mm0, mm6
.text:0043B1D6 add [esp+14h+var_14], 40000h
.text:0043B1DD packssdw xmm4, xmm7
.text:0043B1E1 push edx
.text:0043B1E2 pcmpeqb xmm6, xmm2
.text:0043B1E6 push ecx
.text:0043B1E7 punpckhwd mm0, mm4
.text:0043B1EA push esp
.text:0043B1EB pcmpgtb mm6, mm4
.text:0043B1EE call eax
.text:0043B1F0 pcmpeqd xmm0, xmm1
.text:0043B1F4 add esp, 1Ch
.text:0043B1F7 pcmpeqw mm6, mm3
.text:0043B1FA retn
.text:0043B1FA get_api_address endp
通过get_api_address函数获得shellNoitdyIconW函数。并调用两次。
第一次调用的时候dwMessage参数为NIM_ADD,打开控制面板\所有控制面板项\通知区域图标会发现下面有一个空白的
这是因为PNOTIFYICONDATA被垃圾数据填充了。第二次传入NIM_DELETE删除托盘图标。
.text:0043AF89 call get_api_address
.text:0043AF8E push eax
.text:0043AF8F push dword ptr [ebp+52h] ;NOTIFYICONDATA结构体
.text:0043AF92 push 0 ;NIM_ADD
.text:0043AF94 call eax
.text:0043AF96 cmp eax, 1
.text:0043AF99 jz short $+2
.text:0043AF9B
.text:0043AF9B loc_43AF9B: ; CODE XREF: .text:0043AF99↑j
.text:0043AF9B pop eax
.text:0043AF9C push dword ptr [ebp+52h]
.text:0043AF9F push 2 ;NIM_DELETE
.text:0043AFA1 call eax
使用ZwSetInformationProcess绕过DEP保护的原理如下
ULONG ExecuteFlags = MEM_EXECUTE_OPTION_ENABLE;
NtSetInformationProcess(
-1,//当前进程
ProcessExecuteFlags, // 0x22
&ExecuteFlags, // executeFlag=2; 设置为2关闭DEP
sizeof(ExecuteFlags)); // 0x4
关闭DEP以避免在栈上执行代码出现异常等问题。
.text:0043B1FF push 'ssf'
.text:0043B204 dec dword ptr [esp+0] ;sse
.text:0043B207 push 'corQ'
.text:0043B20C dec [esp+4+var_4] ;corP
.text:0043B20F push 'noiu'
.text:0043B214 dec [esp+8+var_8] ;noit
.text:0043B217 push 'amrp'
.text:0043B21C dec [esp+0Ch+var_C] ;amro
.text:0043B21F push 'fnIu'
.text:0043B224 dec [esp+10h+var_10] ;fnIt
.text:0043B227 push 'eSw['
.text:0043B22C dec [esp+14h+var_14] ;eSwZ
.text:0043B22F mov edx, esp ZwSetInformationProcess
.text:0043B231 jmp loc_43B0A1
...
.text:0043B0A1 punpckhwd mm2, mm6
.text:0043B0A4 pcmpeqd mm2, mm5 ; a10
.text:0043B0A7 call get_api_address
.text:0043B0AC add esp, 18h
.text:0043B0AF punpckhwd mm0, mm1
.text:0043B0B2 push 4 ;sizeof(ExecuteFlags)
.text:0043B0B4 packsswb mm0, mm2
.text:0043B0B7 push 0 //0
.text:0043B0B9 pcmpgtw mm7, mm4
.text:0043B0BC add [esp+4+var_4], 400004h
.text:0043B0C3 pcmpeqb mm4, mm0
.text:0043B0C6 push 22h ; '"' ;ProcessExecuteFlags
.text:0043B0C8 punpckhwd xmm1, xmm3
.text:0043B0CC push 0FFFFFFFFh ;当前进程
.text:0043B0CE punpckhdq mm5, mm5
.text:0043B0D1 call eax ;ZwSetInformationProcess
反调试
这里使用三处反调试,
- PEB.BeingDebugged
- PEB.NtGlobalFlag
Stack[00000B48]:0012D7A8 push ebp
Stack[00000B48]:0012D7A9 mov ebp, esp
Stack[00000B48]:0012D7AB mov eax, large fs:18h
Stack[00000B48]:0012D7B1 mov eax, [eax+30h]
Stack[00000B48]:0012D7B4 cmp byte ptr [eax+2], 1 ;BeingDebugged,改成0绕过
Stack[00000B48]:0012D7B8 jz loc_12DAEF
Stack[00000B48]:0012D7BE nop
Stack[00000B48]:0012D7BF nop
Stack[00000B48]:0012D7C0 mov eax, large fs:30h
Stack[00000B48]:0012D7C6 nop
Stack[00000B48]:0012D7C7 nop
Stack[00000B48]:0012D7C8 mov al, [eax+68h]
Stack[00000B48]:0012D7CB nop
Stack[00000B48]:0012D7CC nop
Stack[00000B48]:0012D7CD and al, 70h ;NtGlobalFlag,将al改成0绕过
Stack[00000B48]:0012D7CF nop
Stack[00000B48]:0012D7D0 nop
Stack[00000B48]:0012D7D1 cmp al, 70h ; 'p'
Stack[00000B48]:0012D7D3 jz loc_12DAEF
Stack[00000B48]:0012D7D9 mov eax, 1 ;检测虚拟机
Stack[00000B48]:0012D7DE cpuid
Stack[00000B48]:0012D7E0 mov eax, edx
Stack[00000B48]:0012D7E2 shr eax, 17h
Stack[00000B48]:0012D7E5 and eax, 1
Stack[00000B48]:0012D7E8 cmp eax, 1 ;如果为1则是运行在虚拟机内
接着往下走,还有一处反调试
Stack[00000B48]:0012D94B loc_12D94B: ; CODE XREF: Stack[00000B48]:0012D965↓j
Stack[00000B48]:0012D94B push eax
Stack[00000B48]:0012D94C push 0Fh
Stack[00000B48]:0012D94E call dword ptr [ebp+94h] ; sleep
Stack[00000B48]:0012D954 pop eax
Stack[00000B48]:0012D955 push eax
Stack[00000B48]:0012D956 call eax ; ntdll_NtYieldExecution
Stack[00000B48]:0012D958 cmp eax, 40000024h
Stack[00000B48]:0012D95D jz short loc_12D960
Stack[00000B48]:0012D95F inc edi
Stack[00000B48]:0012D960
Stack[00000B48]:0012D960 loc_12D960: ; CODE XREF: Stack[00000B48]:0012D95D↑j
Stack[00000B48]:0012D960 pop eax
Stack[00000B48]:0012D961 inc esi
Stack[00000B48]:0012D962 cmp esi, 20h ; ' '
Stack[00000B48]:0012D965 jnz short loc_12D94B
