Tuesday, March 13, 2018

decode_vmprotect_blog

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:

  1. The protector is weakly obfuscating the sample.
  2. can find ProtectedFunc(s).
  3. 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();

Thanks.

No comments:

Post a Comment