It may sound weird that I say decoding vmprotect instead of emulating it. Considering a packer as simple as UPX, we take it as archiver and decompress it; well, SOMETIMES, for vmprotect samples, decoding is also an option.
Last week I was asked to give an evaluation of IDA plugin VMAttack( https://github.com/anatolikalysch/VMAttack ), under this project there is a vmprotect sample addvm.vmp (md5 = B4E34E39CFDD13E65D070E9FB9717620 ); by analysing it, I found decoding vmprotect sample is possible when:
- The protector is weakly obfuscating the sample.
- can find ProtectedFunc(s).
- can find ProtectFunc(s)
With condition 1, WE can easily find ProtectedFunc(s) and ProtectFunc(s). After found ProtectFunc, vm inst stubs can also be found, group of vm insts then can be decoded and restored one by one to its ProtectedFunc( note: ProtectedFunc is inplaced protected ).
fundamentals of vmprotect
There are researchers in the internet researching vmprotect, by following them, one may become a vmprotecter, or we have option to analyse it ourself.
If you have analysed vmprotect, or you wanna follow internet researchers, simply skip this section.
Given a program, vmprotect can protect many funcs|slices of the code. For here, I am assuming there is only one ProtectedFunc, for short, pdf:
.text:0040102E ; .text:00401000
.text:0040102E ; .text:00401000 55 push ebp
.text:0040102E ; .text:00401001 89 E5 mov ebp, esp
.text:0040102E ; .text:00401003 8B 55 08 mov edx, [ebp+arg_0]
.text:0040102E ; .text:00401006 8B 45 0C mov eax, [ebp+arg_4]
.text:0040102E ; .text:00401009 01 D0 add eax, edx
.text:0040102E ; .text:0040100B 5D pop ebp
.text:0040102E ; .text:0040100C C3 retn
.text:0040102E ; .text:0040100C sub_401000 endp
protection is performed in an inplace-hack way. inplace-hack begins with an inline hook which hook to protect func caller(pfc). the values of changed remain bytes(here, 8 bytes) are explained by ProtectFunc (for short, pf):
.text:00401000 E9 F2 38 00 00 jmp pfc
.text:00401005 00 00 00 00 pdf_remains dd 0
.text:00401009 4F 0D 1D db 4Fh, 0Dh, 1Dh
.text:0040100C 2E db 2Eh
pfc simply push vm insts and call pf:
004048F7 pfc:
.vmp0:004048F7 68 9A 48 40 00 push offset vm_insts
.vmp0:004048FC E8 13 FA FF FF call ProtectFunc
.vmp0:004048FC ; ---------------------------------------------------------------------------
.vmp0:00404901
pf firstly accept CPU registers(if you research into the pf, you found it's not saving them, but accepting them, by push then pop to data slots), then set stack, data, then run vm insts one by one:
.vmp0:00404314 ProtectFunc proc near
.vmp0:00404314 arg0_insts_at_40489A= dword ptr 4
.vmp0:00404314 50 push eax
.vmp0:00404315 51 push ecx
.vmp0:00404316 52 push edx
.vmp0:00404317 55 push ebp
.vmp0:00404318 56 push esi
.vmp0:00404319 53 push ebx
.vmp0:0040431A 9C pushf
.vmp0:0040431B 57 push edi ;
.vmp0:0040431C 57 push edi
.vmp0:0040431D FF 35 05 10 40 00 push pdf_remains
.vmp0:00404323 68 00 00 00 00 push 0 ; next inst(here is the first) offset, some said the 0 here will be imagebase fixup, it's reasonable but I am not sure.
.vmp0:00404328 8B 74 24 30 mov esi, [esp+2Ch+arg0_insts_at_40489A] ; insts
.vmp0:0040432C 89 E5 mov ebp, esp ; vms_top
.vmp0:0040432E 81 EC C0 00 00 00 sub esp, 0C0h ; vmd num of bytes
.vmp0:00404334 89 E7 mov edi, esp ; vmd
.vmp0:00404336
.vmp0:00404336 loc404336_inst_to_next:
.vmp0:00404336 03 75 00 add esi, [ebp+0]
.vmp0:00404339
.vmp0:00404339 loc404339_query_inst_engine:
.vmp0:00404339 8A 06 mov al, [esi]
.vmp0:0040433B 0F B6 C0 movzx eax, al ; op code
.vmp0:0040433E 83 C6 01 add esi, 1
.vmp0:00404341 FF 24 85 9C 43 40 00 jmp dword ptr ds:inst_engines[eax*4]
...
protected inst 0(push ebp):
vm inst 0
vm inst 1
...
vm inst i
protected inst 1(mov ebp, esp):
vm inst i+1
vm inst i+2
...
details of vmprotect
I have created minic source code to tell the details of vmprotect, the minic is not full support of all vm insts, but made small and suitable for this sample. the mimic contains following modules:
- vm stack
- vm data
- vm insts
- vm context
- vmp
Also, a windbg trace log will be attached, debugging the source code and refering the windbg log, one may understand vmprotect better.
AT LAST , VERY IMPORTANT, IF VM INSTS INSIDE FOLLOWING MIMIC SRCS CAN BE IDENTIFIED, WE CAN THEN FULLY DECODE THIS PDF(PROTECTED FUNC):
pdf_401000_push_ebp();
pdf_401001_mov_ebp_esp();
pdf_401003_mov_edx_adder0();
pdf_401006_mov_eax_adder1();
pdf_401009_add_eax_edx();
pdf_40100B_pop_ebp();
pdf_40100C_ret();
No comments:
Post a Comment