VMProfiler  v1.8
vmprofiler is a c++ library which is used to statically analyze VMProtect 2 polymorphic virtual machines. This project is inherited in vmprofiler-qt, vmprofiler-cli, and vmemu.
Classes | Enumerations | Functions
vm::instrs Namespace Reference

contains all functions related to virtual instructions... More...

Classes

struct  virt_instr_t
 
struct  jcc_data
 
struct  code_block_t
 

Enumerations

enum class  jcc_type { none , branching , absolute }
 

Functions

bool get_rva_decrypt (const zydis_routine_t &vm_entry, std::vector< zydis_decoded_instr_t > &transform_instrs)
 gets the native instructions that are used to decrypt the relative virtual address to virtual instructions located on the stack at RSP+0xA0... you can learn about this https://back.engineering/17/05/2021/#vm_entry More...
 
std::pair< std::uint64_t, std::uint64_t > decrypt_operand (transform::map_t &transforms, std::uint64_t operand, std::uint64_t rolling_key)
 decrypt virtual instruction operand given the decryption transformations... you can read about these transformations https://back.engineering/17/05/2021/#operand-decryption More...
 
std::pair< std::uint64_t, std::uint64_t > encrypt_operand (transform::map_t &transforms, std::uint64_t operand, std::uint64_t rolling_key)
 encrypt a virtual instructions operand given the transformations to decrypt the operand... the transformations are inversed by this functions so you dont need to worry about doing that. More...
 
std::optional< virt_instr_tget (vm::ctx_t &ctx, vmp2::v2::entry_t &entry)
 get virt_instr_t filled in with data given a vmp2 trace entry and vm context... More...
 
std::optional< std::uint64_t > get_imm (vm::ctx_t &ctx, std::uint8_t imm_size, std::uintptr_t vip)
 gets the encrypted second operand (imm) given vip and vm::ctx_t... More...
 
std::optional< jcc_dataget_jcc_data (vm::ctx_t &ctx, code_block_t &code_block)
 get jcc data out of a code block... this function will loop over the code block and look for the last LCONSTDW in the virtual instructions. More...
 
std::uintptr_t code_block_addr (const vm::ctx_t &ctx, const vmp2::v2::entry_t &entry)
 the top of the stack will contain the lower 32bits of the RVA to the virtual instructions that will be jumping too... the RVA is image based (not module based, but optional header image based)... this means the value ontop of the stack could be "40007fd8" with image base being 0x140000000... as you can see the 0x100000000 is missing... the below statement deals with this... More...
 
std::uintptr_t code_block_addr (const vm::ctx_t &ctx, const std::uint32_t lower_32bits)
 same routine as above except lower_32bits is passed directly and not extracted from the stack... More...
 

Detailed Description

contains all functions related to virtual instructions...

Enumeration Type Documentation

◆ jcc_type

enum vm::instrs::jcc_type
strong
Enumerator
none 
branching 
absolute 

Function Documentation

◆ code_block_addr() [1/2]

std::uintptr_t vm::instrs::code_block_addr ( const vm::ctx_t ctx,
const std::uint32_t  lower_32bits 
)

same routine as above except lower_32bits is passed directly and not extracted from the stack...

Parameters
ctxvm context
lower_32bitslower 32bits of the relative virtual address...
Returns
returns full linear virtual address of code block...

◆ code_block_addr() [2/2]

std::uintptr_t vm::instrs::code_block_addr ( const vm::ctx_t ctx,
const vmp2::v2::entry_t entry 
)

the top of the stack will contain the lower 32bits of the RVA to the virtual instructions that will be jumping too... the RVA is image based (not module based, but optional header image based)... this means the value ontop of the stack could be "40007fd8" with image base being 0x140000000... as you can see the 0x100000000 is missing... the below statement deals with this...

Parameters
ctxvm context
entrycurrent trace entry for virtual JMP instruction
Returns
returns linear virtual address of the next code block...

◆ decrypt_operand()

std::pair< std::uint64_t, std::uint64_t > vm::instrs::decrypt_operand ( transform::map_t transforms,
std::uint64_t  operand,
std::uint64_t  rolling_key 
)

decrypt virtual instruction operand given the decryption transformations... you can read about these transformations https://back.engineering/17/05/2021/#operand-decryption

Parameters
transformsdecryption transformations...
operandencrypted virtual instruction operand...
rolling_keythe decryption key (RBX)...
Returns

◆ encrypt_operand()

std::pair< std::uint64_t, std::uint64_t > vm::instrs::encrypt_operand ( transform::map_t transforms,
std::uint64_t  operand,
std::uint64_t  rolling_key 
)

encrypt a virtual instructions operand given the transformations to decrypt the operand... the transformations are inversed by this functions so you dont need to worry about doing that.

you can learn about transformations https://back.engineering/17/05/2021/#operand-decryption

Parameters
transformstransformations to decrypt operand, these transformations are inversed by the function...
operandoperand to be encrypted...
rolling_keyencryption key... (RBX)...
Returns

◆ get()

std::optional< virt_instr_t > vm::instrs::get ( vm::ctx_t ctx,
vmp2::v2::entry_t entry 
)

get virt_instr_t filled in with data given a vmp2 trace entry and vm context...

Parameters
ctxcurrent vm context
entryvmp2 trace entry containing all of the native/virtual register/stack values...
Returns
returns a filled in virt_instr_t on success...

◆ get_imm()

std::optional< std::uint64_t > vm::instrs::get_imm ( vm::ctx_t ctx,
std::uint8_t  imm_size,
std::uintptr_t  vip 
)

gets the encrypted second operand (imm) given vip and vm::ctx_t...

Parameters
ctxvm context
imm_sizeimmediate value size in bits...
vipvirtual instruction pointer, linear virtual address...
Returns
returns immediate value if imm_size is not 0...

◆ get_jcc_data()

std::optional< jcc_data > vm::instrs::get_jcc_data ( vm::ctx_t ctx,
code_block_t code_block 
)

get jcc data out of a code block... this function will loop over the code block and look for the last LCONSTDW in the virtual instructions.

it will then loop and look for all PUSHVSP's, checking each to see if the stack contains two encrypted rva's to each branch.. if there is not two encrypted rva's then the virtual jmp instruction only has one dest...

Parameters
ctxvm context
code_blockcode block that does not have its jcc_data yet
Returns
if last lconstdw is found, return filled in jcc_data structure...

◆ get_rva_decrypt()

bool vm::instrs::get_rva_decrypt ( const zydis_routine_t vm_entry,
std::vector< zydis_decoded_instr_t > &  transform_instrs 
)

gets the native instructions that are used to decrypt the relative virtual address to virtual instructions located on the stack at RSP+0xA0... you can learn about this https://back.engineering/17/05/2021/#vm_entry

Parameters
vm_entrypass by reference of the specific vm entry you want to get the decryption instructions from...
transform_instrspass by reference vector that will be filled with the decryption instructions...
Returns
returns true if the decryption instructions are extracted...