Merge branch 'dev' into 'master'

Dev

See merge request vmp2/vmprofiler!2
merge-requests/3/merge v1.4
_xeroxz 4 years ago
commit 1bae371c88

@ -0,0 +1,18 @@
---
BasedOnStyle: Microsoft
AlignAfterOpenBracket: Align
AllowAllArgumentsOnNextLine: 'true'
AllowAllParametersOfDeclarationOnNextLine: 'true'
AllowShortIfStatementsOnASingleLine: Never
BreakBeforeBraces: Allman
IndentWidth: '4'
Language: Cpp
NamespaceIndentation: All
SpacesInAngles: 'true'
SpacesInCStyleCastParentheses: 'true'
SpacesInContainerLiterals: 'true'
SpacesInParentheses: 'true'
SpacesInSquareBrackets: 'true'
UseTab: Never
...

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <map>
#include <Zydis/Zydis.h> #include <Zydis/Zydis.h>
#include <stdexcept>
#include <functional> #include <functional>
#include <map>
#include <stdexcept>
#include <vmutils.h> #include <vmutils.h>
namespace vm namespace vm
@ -34,17 +34,40 @@ namespace vm
} }
// taken from ida... // taken from ida...
inline u8 __ROL1__(u8 value, int count) { return __ROL__((u8)value, count); } inline u8 __ROL1__( u8 value, int count )
inline u16 __ROL2__(u16 value, int count) { return __ROL__((u16)value, count); } {
inline u32 __ROL4__(u32 value, int count) { return __ROL__((u32)value, count); } return __ROL__( ( u8 )value, count );
inline u64 __ROL8__(u64 value, int count) { return __ROL__((u64)value, count); } }
inline u8 __ROR1__(u8 value, int count) { return __ROL__((u8)value, -count); } inline u16 __ROL2__( u16 value, int count )
inline u16 __ROR2__(u16 value, int count) { return __ROL__((u16)value, -count); } {
inline u32 __ROR4__(u32 value, int count) { return __ROL__((u32)value, -count); } return __ROL__( ( u16 )value, count );
inline u64 __ROR8__(u64 value, int count) { return __ROL__((u64)value, -count); } }
inline u32 __ROL4__( u32 value, int count )
template <typename T> {
using transform_t = std::function<T(T, T)>; return __ROL__( ( u32 )value, count );
}
inline u64 __ROL8__( u64 value, int count )
{
return __ROL__( ( u64 )value, count );
}
inline u8 __ROR1__( u8 value, int count )
{
return __ROL__( ( u8 )value, -count );
}
inline u16 __ROR2__( u16 value, int count )
{
return __ROL__( ( u16 )value, -count );
}
inline u32 __ROR4__( u32 value, int count )
{
return __ROL__( ( u32 )value, -count );
}
inline u64 __ROR8__( u64 value, int count )
{
return __ROL__( ( u64 )value, -count );
}
template < typename T > using transform_t = std::function< T( T, T ) >;
enum class type enum class type
{ {
@ -56,11 +79,10 @@ namespace vm
update_key update_key
}; };
using map_t = std::map<transform::type, ZydisDecodedInstruction>; using map_t = std::map< transform::type, zydis_decoded_instr_t >;
template < class T > template < class T >
inline const auto _bswap = [](T a, T b) -> T inline const auto _bswap = []( T a, T b ) -> T {
{
if constexpr ( std::is_same_v< T, std::uint64_t > ) if constexpr ( std::is_same_v< T, std::uint64_t > )
return _byteswap_uint64( a ); return _byteswap_uint64( a );
if constexpr ( std::is_same_v< T, std::uint32_t > ) if constexpr ( std::is_same_v< T, std::uint32_t > )
@ -71,39 +93,18 @@ namespace vm
throw std::invalid_argument( "invalid type size..." ); throw std::invalid_argument( "invalid type size..." );
}; };
template <class T> template < class T > inline const auto _add = []( T a, T b ) -> T { return a + b; };
inline const auto _add = [](T a, T b) -> T
{
return a + b;
};
template <class T> template < class T > inline const auto _xor = []( T a, T b ) -> T { return a ^ b; };
inline const auto _xor = [](T a, T b) -> T
{
return a ^ b;
};
template <class T> template < class T > inline const auto _sub = []( T a, T b ) -> T { return a - b; };
inline const auto _sub = [](T a, T b) -> T
{
return a - b;
};
template <class T> template < class T > inline const auto _neg = []( T a, T b ) -> T { return a * -1; };
inline const auto _neg = [](T a, T b) -> T
{
return a * -1;
};
template <class T> template < class T > inline const auto _not = []( T a, T b ) -> T { return ~a; };
inline const auto _not = [](T a, T b) -> T
{
return ~a;
};
template < class T > template < class T >
inline const auto _ror = [](T a, T b) -> T inline const auto _ror = []( T a, T b ) -> T {
{
if constexpr ( std::is_same_v< T, std::uint64_t > ) if constexpr ( std::is_same_v< T, std::uint64_t > )
return __ROR8__( a, b ); return __ROR8__( a, b );
if constexpr ( std::is_same_v< T, std::uint32_t > ) if constexpr ( std::is_same_v< T, std::uint32_t > )
@ -117,8 +118,7 @@ namespace vm
}; };
template < class T > template < class T >
inline const auto _rol = [](T a, T b) -> T inline const auto _rol = []( T a, T b ) -> T {
{
if constexpr ( std::is_same_v< T, std::uint64_t > ) if constexpr ( std::is_same_v< T, std::uint64_t > )
return __ROL8__( a, b ); return __ROL8__( a, b );
if constexpr ( std::is_same_v< T, std::uint32_t > ) if constexpr ( std::is_same_v< T, std::uint32_t > )
@ -131,52 +131,64 @@ namespace vm
throw std::invalid_argument( "invalid type size..." ); throw std::invalid_argument( "invalid type size..." );
}; };
template <class T> template < class T > inline const auto _inc = []( T a, T b ) -> T { return a + 1; };
inline const auto _inc = [](T a, T b) -> T
{
return a + 1;
};
template <class T> template < class T > inline const auto _dec = []( T a, T b ) -> T { return a - 1; };
inline const auto _dec = [](T a, T b) -> T
{
return a - 1;
};
template < class T > template < class T >
inline std::map<ZydisMnemonic, transform_t<T>> transforms = inline std::map< ZydisMnemonic, transform_t< T > > transforms = {
{ { ZYDIS_MNEMONIC_ADD, _add< T > }, { ZYDIS_MNEMONIC_XOR, _xor< T > }, { ZYDIS_MNEMONIC_BSWAP, _bswap< T > },
{ ZYDIS_MNEMONIC_ADD, _add<T> }, { ZYDIS_MNEMONIC_SUB, _sub< T > }, { ZYDIS_MNEMONIC_NEG, _neg< T > }, { ZYDIS_MNEMONIC_NOT, _not< T > },
{ ZYDIS_MNEMONIC_XOR, _xor<T> }, { ZYDIS_MNEMONIC_ROR, _ror< T > }, { ZYDIS_MNEMONIC_ROL, _rol< T > }, { ZYDIS_MNEMONIC_INC, _inc< T > },
{ ZYDIS_MNEMONIC_BSWAP, _bswap<T> }, { ZYDIS_MNEMONIC_DEC, _dec< T > } };
{ ZYDIS_MNEMONIC_SUB, _sub<T>},
{ ZYDIS_MNEMONIC_NEG, _neg<T>}, inline std::map< ZydisMnemonic, ZydisMnemonic > inverse = {
{ ZYDIS_MNEMONIC_NOT, _not<T>}, { ZYDIS_MNEMONIC_ADD, ZYDIS_MNEMONIC_SUB }, { ZYDIS_MNEMONIC_XOR, ZYDIS_MNEMONIC_XOR },
{ ZYDIS_MNEMONIC_ROR, _ror<T>}, { ZYDIS_MNEMONIC_BSWAP, ZYDIS_MNEMONIC_BSWAP }, { ZYDIS_MNEMONIC_SUB, ZYDIS_MNEMONIC_ADD },
{ ZYDIS_MNEMONIC_ROL, _rol<T>}, { ZYDIS_MNEMONIC_NEG, ZYDIS_MNEMONIC_NEG }, { ZYDIS_MNEMONIC_NOT, ZYDIS_MNEMONIC_NOT },
{ ZYDIS_MNEMONIC_INC, _inc<T>}, { ZYDIS_MNEMONIC_ROR, ZYDIS_MNEMONIC_ROL }, { ZYDIS_MNEMONIC_ROL, ZYDIS_MNEMONIC_ROR },
{ ZYDIS_MNEMONIC_DEC, _dec<T>} { ZYDIS_MNEMONIC_INC, ZYDIS_MNEMONIC_DEC }, { ZYDIS_MNEMONIC_DEC, ZYDIS_MNEMONIC_INC } };
};
inline void inverse_transforms( transform::map_t &transforms, transform::map_t &inverse )
{
inverse[ transform::type::generic0 ] = transforms[ transform::type::generic0 ];
inverse[ transform::type::generic0 ].mnemonic =
transform::inverse[ transforms[ transform::type::generic0 ].mnemonic ];
inverse[ transform::type::rolling_key ] = transforms[ transform::type::rolling_key ];
inverse[ transform::type::rolling_key ].mnemonic =
transform::inverse[ transforms[ transform::type::rolling_key ].mnemonic ];
inverse[ transform::type::generic1 ] = transforms[ transform::type::generic1 ];
inverse[ transform::type::generic1 ].mnemonic =
transform::inverse[ transforms[ transform::type::generic1 ].mnemonic ];
inverse[ transform::type::generic2 ] = transforms[ transform::type::generic2 ];
inverse[ transform::type::generic2 ].mnemonic =
transform::inverse[ transforms[ transform::type::generic2 ].mnemonic ];
inverse[ transform::type::generic3 ] = transforms[ transform::type::generic3 ];
inverse[ transform::type::generic3 ].mnemonic =
transform::inverse[ transforms[ transform::type::generic3 ].mnemonic ];
inverse[ transform::type::update_key ] = transforms[ transform::type::update_key ];
inverse[ transform::type::update_key ].mnemonic =
transform::inverse[ transforms[ transform::type::update_key ].mnemonic ];
}
inline std::map<ZydisMnemonic, ZydisMnemonic> inverse = inline auto inverse_transform( std::vector< zydis_decoded_instr_t > &instrs ) -> bool
{ {
{ZYDIS_MNEMONIC_ADD, ZYDIS_MNEMONIC_SUB}, for ( auto idx = 0u; idx < instrs.size() - 1; ++idx )
{ZYDIS_MNEMONIC_XOR, ZYDIS_MNEMONIC_XOR}, if ( !( instrs[ idx ].mnemonic = inverse[ instrs[ idx ].mnemonic ] ) )
{ZYDIS_MNEMONIC_BSWAP, ZYDIS_MNEMONIC_BSWAP}, return false;
{ZYDIS_MNEMONIC_SUB, ZYDIS_MNEMONIC_ADD},
{ZYDIS_MNEMONIC_NEG, ZYDIS_MNEMONIC_NEG}, return true;
{ZYDIS_MNEMONIC_NOT, ZYDIS_MNEMONIC_NOT}, }
{ZYDIS_MNEMONIC_ROR, ZYDIS_MNEMONIC_ROL},
{ZYDIS_MNEMONIC_ROL, ZYDIS_MNEMONIC_ROR},
{ZYDIS_MNEMONIC_INC, ZYDIS_MNEMONIC_DEC},
{ZYDIS_MNEMONIC_DEC, ZYDIS_MNEMONIC_INC}
};
// max size of a and b is 64 bits, a and b is then converted to // max size of a and b is 64 bits, a and b is then converted to
// the number of bits in bitsize, the transformation is applied, // the number of bits in bitsize, the transformation is applied,
// finally the result is converted back to 64bits... zero extended... // finally the result is converted back to 64bits... zero extended...
inline auto apply(std::uint8_t bitsize, ZydisMnemonic op, inline auto apply( std::uint8_t bitsize, ZydisMnemonic op, std::uint64_t a, std::uint64_t b ) -> std::uint64_t
std::uint64_t a, std::uint64_t b) -> std::uint64_t
{ {
switch ( bitsize ) switch ( bitsize )
{ {
@ -193,10 +205,9 @@ namespace vm
} }
} }
inline bool has_imm(ZydisDecodedInstruction* instr) inline bool has_imm( zydis_decoded_instr_t *instr )
{ {
return instr->operand_count > 1 && return instr->operand_count > 1 && ( instr->operands[ 1 ].type & ZYDIS_OPERAND_TYPE_IMMEDIATE );
(instr->operands[1].type & ZYDIS_OPERAND_TYPE_IMMEDIATE);
}
}
} }
} // namespace transform
} // namespace vm

@ -1,51 +0,0 @@
#pragma once
#include <transform.hpp>
#include <vmutils.h>
#include <vmprofiler.hpp>
namespace vm
{
std::pair<std::uint64_t, std::uint64_t> decrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key);
std::pair<std::uint64_t, std::uint64_t> encrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key);
void inverse_transforms(transform::map_t& transforms, transform::map_t& inverse);
bool get_calc_jmp(const zydis_routine_t& vm_entry, zydis_routine_t& calc_jmp);
bool get_vinstr_rva_transform(
const zydis_routine_t& vm_entry, ZydisDecodedInstruction* transform_instr);
struct handler_t
{
u8 imm_size; // size in bits...
vm::transform::map_t transforms;
vm::handler::profile_t* profile;
zydis_routine_t instrs;
std::uintptr_t address;
};
namespace handler
{
bool has_imm(const zydis_routine_t& vm_handler);
std::uint8_t imm_size(const zydis_routine_t& vm_handler);
bool get(zydis_routine_t& vm_entry, zydis_routine_t& vm_handler, std::uintptr_t handler_addr);
// may throw an exception...
bool get_all(std::uintptr_t module_base, std::uintptr_t image_base,
zydis_routine_t& vm_entry, std::uintptr_t* vm_handler_table, std::vector<vm::handler_t>& vm_handlers);
// can be used on calc_jmp...
bool get_operand_transforms(const zydis_routine_t& vm_handler, transform::map_t& transforms);
vm::handler::profile_t* get_profile(vm::handler_t& vm_handler);
namespace table
{
std::uintptr_t* get(const zydis_routine_t& vm_entry);
bool get_transform(const zydis_routine_t& vm_entry, ZydisDecodedInstruction* transform_instr);
std::uint64_t encrypt(ZydisDecodedInstruction& transform_instr, std::uint64_t val);
std::uint64_t decrypt(ZydisDecodedInstruction& transform_instr, std::uint64_t val);
}
}
}

@ -1,29 +0,0 @@
#pragma once
#include <vm.h>
#include <vmp2.hpp>
namespace vm
{
class vmctx_t
{
public:
explicit vmctx_t(
vmp2::file_header* file_header,
vmp2::entry_t* entry_list,
std::vector<vm::handler_t>& vm_handlers,
std::uintptr_t module_base,
std::uintptr_t image_base
);
std::pair<std::string, const vmp2::entry_t*> step() const;
private:
std::uintptr_t get_imm(vmp2::exec_type_t exec_type_t,
std::uint32_t vip_offset, std::uint8_t imm_size) const;
mutable std::uint32_t idx;
const std::uintptr_t image_base, module_base;
const vmp2::entry_t* entry_list;
const vmp2::file_header* file_header;
std::vector<vm::handler_t> vm_handlers;
};
}

@ -1,5 +1,5 @@
#pragma once #pragma once
#include "vm.h" #include <vmprofiler.hpp>
namespace vmp2 namespace vmp2
{ {
@ -69,4 +69,4 @@ namespace vmp2
u8 raw[ 0x100 ]; u8 raw[ 0x100 ];
} vsp; } vsp;
}; };
} } // namespace vmp2

@ -3,365 +3,157 @@
namespace vm namespace vm
{ {
namespace handler namespace calc_jmp
{
enum extention_t
{
none,
sign_extend,
zero_extend
};
struct profile_t
{
const char* name;
u8 imm_size;
std::vector<std::vector<u8>> signature;
extention_t extention;
};
namespace profile
{
// store a value from the stack into scratch register X (RDI+X)...
// where X is an 8bit immediate value...
inline vm::handler::profile_t sregq =
{
"SREGQ", 8,
{
{ 0x48, 0x8B, 0x55, 0x0 }, // mov rdx, [rbp+0]
{ 0x48, 0x83, 0xC5, 0x8 }, // add rbp, 8
{ 0x48, 0x89, 0x14, 0x38 }, // mov [rax+rdi], rdx
}
};
inline vm::handler::profile_t sregdw =
{
"SREGDW", 8,
{
{ 0x8B, 0x55, 0x00 },
{ 0x48, 0x83, 0xC5, 0x04 },
{ 0x89, 0x14, 0x38 }
}
};
inline vm::handler::profile_t sregw =
{
"SREGW", 8,
{
{ 0x66, 0x8B, 0x55, 0x00 }, // mov dx, [rbp]
{ 0x48, 0x83, 0xC5, 0x02 }, // add rbp, 0x02
{ 0x66, 0x89, 0x14, 0x38 } // mov [rax+rdi], dx
}
};
// load scratch register value onto virtual stack...
inline vm::handler::profile_t lregq =
{
"LREGQ", 8,
{
{0x48, 0x8B, 0x14, 0x38}, // mov rdx, [rax+rdi]
{0x48, 0x83, 0xED, 0x08}, // sub rbp, 8
{0x48, 0x89, 0x55, 0x0} // mov [rbp+0], rdx
}
};
/*
> 0x00007FF64724445C mov edx, [rax+rdi*1]
> 0x00007FF647244463 sub rbp, 0x04
> 0x00007FF647246333 mov [rbp], edx
*/
inline vm::handler::profile_t lregdw =
{
"LREGDW", 8,
{
{ 0x8B, 0x14, 0x38 },
{ 0x48, 0x83, 0xED, 0x04 },
{ 0x89, 0x55, 0x00 }
}
};
// load constant value into stack....
inline vm::handler::profile_t lconstq =
{
"LCONSTQ", 64,
{ {
{0x48, 0x83, 0xED, 0x08}, // sub rbp, 8 bool get( const zydis_routine_t &vm_entry, zydis_routine_t &calc_jmp );
{0x48, 0x89, 0x45, 0x00} // mov [rbp+0], rax
} }
};
// load 1 byte constant zero extended into 2bytes on the stack... namespace instrs
inline vm::handler::profile_t lconstbzx =
{
"LCONSTBZX", 8,
{ {
{0x48, 0x83, 0xED, 0x02}, // sub rbp, 2 // decrypt transformations for encrypted virtual instruction rva...
{0x66, 0x89, 0x45, 0x00} // mov [rbp+0], ax bool get_rva_decrypt( const zydis_routine_t &vm_entry, std::vector< zydis_decoded_instr_t > &transform_instrs );
}
};
inline vm::handler::profile_t lconstbsx = std::pair< std::uint64_t, std::uint64_t > decrypt_operand( transform::map_t &transforms, std::uint64_t operand,
{ std::uint64_t rolling_key );
"LCONSTBSX", 8,
{
{ 0x98 },
{ 0x48, 0x83, 0xED, 0x04 },
{ 0x89, 0x45, 0x00 }
},
vm::handler::extention_t::sign_extend
};
// load 4 byte constant value sign extended qword into vsp... std::pair< std::uint64_t, std::uint64_t > encrypt_operand( transform::map_t &transforms, std::uint64_t operand,
inline vm::handler::profile_t lconstbsx1 = std::uint64_t rolling_key );
{ } // namespace instrs
"LCONSTBSX", 8,
{
{0x48, 0x98}, // cdqe
{0x48, 0x83, 0xED, 0x8}, // sub rbp, 8
{0x48, 0x89, 0x45, 0x0}, // mov [rbp+0], rax
},
vm::handler::extention_t::sign_extend
};
// load 4 byte constant value sign extended qword into vsp... namespace handler
inline vm::handler::profile_t lconstdsx =
{
"LCONSTDSX", 32,
{ {
{0x48, 0x98}, // cdqe using instr_callback_t = bool ( * )( const zydis_decoded_instr_t &instr );
{0x48, 0x83, 0xED, 0x8}, // sub rbp, 8
{0x48, 0x89, 0x45, 0x0}, // mov [rbp+0], rax
},
vm::handler::extention_t::sign_extend
};
// load 2 byte constant value sign extended qword into vsp... enum mnemonic_t
inline vm::handler::profile_t lconstwsx =
{
"LCONSTWSX", 16,
{ {
{0x48, 0x98}, // cdqe INVALID,
{0x48, 0x83, 0xED, 0x8}, // sub rbp, 8 PUSHVSP,
{0x48, 0x89, 0x45, 0x0}, // mov [rbp+0], rax SHRQ,
}, MULQ,
vm::handler::extention_t::sign_extend DIVQ,
}; JMP,
VMEXIT,
inline vm::handler::profile_t lconstw = SREGQ,
{ SREGDW,
"LCONSTW", 8, SREGW,
{
{ 0x48, 0x83, 0xED, 0x02 }, // sub rbp, 0x02
{ 0x66, 0x89, 0x45, 0x00 } // mov [rbp], ax
}
};
inline vm::handler::profile_t lconstdw = LREGQ,
{ LREGDW,
"LCONSTDW", 32,
{
{ 0x48, 0x83, 0xED, 0x04 },
{ 0x89, 0x45, 0x00 }
}
};
inline vm::handler::profile_t pushvsp = LCONSTQ,
{ LCONSTBZXW,
"PUSHVSP", 0, LCONSTBSXDW,
{ LCONSTDWSXQ,
{0x48, 0x89, 0xE8}, // mov rax, rbp LCONSTWSXQ,
{0x48, 0x83, 0xED, 0x08}, // sub rbp, 8 LCONSTDW,
{0x48, 0x89, 0x45, 0x0} // mov [rbp+0], rax
}
};
// add two stack values together... READQ,
inline vm::handler::profile_t addq = READDW,
{ READW,
"ADDQ", 0,
{
{0x48, 0x1, 0x45, 0x8}, // add [rbp+8], rax
{0x9C}, // pushfq
{0x8F, 0x45, 0x0} // pop qword ptr [rbp+0]
}
};
inline vm::handler::profile_t adddw = WRITEQ,
{ WRITEDW,
"ADDDW", 0, WRITEW,
{
{ 0x01, 0x45, 0x08 }, // add [rbp+0x08], eax
{ 0x9C }, // pushfq
{ 0x8F, 0x45, 0x00 } // pop [rbp]
}
};
// two qwords on the top of the stack together then not the result... ADDQ,
// ~(VSP[0] | VSP[1])... ADDDW,
inline vm::handler::profile_t nandq =
{
"NANDQ", 0,
{
{0x48, 0x8B, 0x45, 0x0}, // mov rax, [rbp+0]
{0x48, 0x8B, 0x55, 0x8}, // mov rdx, [rbp+8]
{0x48, 0xF7, 0xD0}, // not rax
{0x48, 0xF7, 0xD2}, // not rdx
{0x48, 0x21, 0xD0}, // and rax, rdx
{0x48, 0x89, 0x45, 0x8}, // mov [rbp+8], rax
{0x9C}, // pushfq
{0x8F, 0x45, 0x0} // pop qword ptr [rbp+0]
}
};
// leaves the virtual machine... SHLQ,
inline vm::handler::profile_t vmexit = SHLDW,
{
"VMEXIT", 0,
{
{0x48, 0x89, 0xec}, // mov rsp, rbp
{0x9d}, // popfq
{0xc3} // ret
}
};
inline vm::handler::profile_t jmp = NANDQ,
{ NANDDW
"JMP", 0,
{
{ 0x8B, 0x75, 0x00 }, // mov esi, [rbp]
{ 0x48, 0x01, 0xC6 }, // add rsi, rax
{ 0x48, 0x89, 0xF3 }, // mov rbx, rsi
{ 0x48, 0x03, 0x75, 0x00 } // add rsi, [rbp]
}
}; };
inline vm::handler::profile_t readw = enum extention_t
{
"READW", 0,
{ {
{ 0x48, 0x8B, 0x45, 0x00 }, // mov rax, [rbp] none,
{ 0x48, 0x83, 0xC5, 0x06 }, // add rbp, 0x06 sign_extend,
{ 0x36, 0x66, 0x8B, 0x00 }, // mov ax, ss:[rax] zero_extend
{ 0x66, 0x89, 0x45, 0x00 } // mov [rbp], ax
}
}; };
inline vm::handler::profile_t writeq = struct profile_t
{
"WRITEQ", 0,
{ {
{ 0x48, 0x8B, 0x45, 0x00 }, // mov rax, [rbp] const char *name;
{ 0x48, 0x8B, 0x55, 0x08 }, // mov rdx, [rbp+0x08] mnemonic_t mnemonic;
{ 0x48, 0x83, 0xC5, 0x10 }, // add rbp, 0x10 u8 imm_size;
{ 0x36, 0x48, 0x89, 0x10 }, // mov ss:[rax], rdx std::vector< instr_callback_t > signature;
} extention_t extention;
}; };
inline vm::handler::profile_t writeq1 = struct handler_t
{ {
"WRITEQ", 0, u8 imm_size; // size in bits...
{ vm::transform::map_t transforms;
{ 0x48, 0x8B, 0x45, 0x00 }, // mov rax, [rbp] vm::handler::profile_t *profile;
{ 0x48, 0x8B, 0x55, 0x08 }, // mov rdx, [rbp+0x08] zydis_routine_t instrs;
{ 0x48, 0x83, 0xC5, 0x10 }, // add rbp, 0x10 std::uintptr_t address;
{ 0x48, 0x89, 0x10 } // mov [rax], rdx
}
}; };
inline vm::handler::profile_t shrw = bool has_imm( const zydis_routine_t &vm_handler );
{ std::uint8_t imm_size( const zydis_routine_t &vm_handler );
"SHRW", 0, bool get( zydis_routine_t &vm_entry, zydis_routine_t &vm_handler, std::uintptr_t handler_addr );
{
{ 0x66, 0x8B, 0x45, 0x00 },
{ 0x8A, 0x4D, 0x02 },
{ 0x48, 0x83, 0xED, 0x06 },
{ 0x66, 0xD3, 0xE8 },
{ 0x66, 0x89, 0x45, 0x08 },
{ 0x9C },
{ 0x8F, 0x45, 0x00 }
}
};
inline vm::handler::profile_t shrdw = // may throw an exception...
{ bool get_all( std::uintptr_t module_base, std::uintptr_t image_base, zydis_routine_t &vm_entry,
"SHRDW", 0, std::uintptr_t *vm_handler_table, std::vector< handler_t > &vm_handlers );
{
{ 0x8B, 0x45, 0x00 },
{ 0x8A, 0x4D, 0x04 },
{ 0x48, 0x83, 0xED, 0x06 },
{ 0xD3, 0xE8 },
{ 0x89, 0x45, 0x08 },
{ 0x9C },
{ 0x8F, 0x45, 0x00 }
}
};
inline vm::handler::profile_t shrq = // can be used on calc_jmp...
{ bool get_operand_transforms( const zydis_routine_t &vm_handler, transform::map_t &transforms );
"SHRQ", 0, vm::handler::profile_t *get_profile( handler_t &vm_handler );
{
{ 0x48, 0x8B, 0x45, 0x00 },
{ 0x8A, 0x4D, 0x08 },
{ 0x48, 0x83, 0xED, 0x06 },
{ 0x48, 0xD3, 0xE8 },
{ 0x48, 0x89, 0x45, 0x08 },
{ 0x9C },
{ 0x8F, 0x45, 0x00 },
}
};
inline vm::handler::profile_t nanddw = namespace table
{ {
"NANDDW", 0, std::uintptr_t *get( const zydis_routine_t &vm_entry );
{ bool get_transform( const zydis_routine_t &vm_entry, zydis_decoded_instr_t *transform_instr );
{ 0x48, 0xF7, 0x55, 0x00 }, // not qword ptr [rbp+0]
{ 0x8B, 0x45, 0x00 }, // mov eax, [rbp+0]
{ 0x48, 0x83, 0xED, 0x04 }, // sub rbp, 4
{ 0x21, 0x45, 0x08 }, // and [rbp+8], eax
{ 0x9C }, // pushfq
{ 0x8F, 0x45, 0x00 } // pop qword ptr [rbp+0]
}
};
inline vm::handler::profile_t lvsp = std::uint64_t encrypt( zydis_decoded_instr_t &transform_instr, std::uint64_t val );
{ std::uint64_t decrypt( zydis_decoded_instr_t &transform_instr, std::uint64_t val );
"LVSP", 0, } // namespace table
{
{ 0x48, 0x8B, 0x6D, 0x00 } // mov rbp, [rbp]
}
};
inline std::vector<vm::handler::profile_t*> all = namespace profile
{ {
&sregq, extern vm::handler::profile_t sregq;
&lregq, extern vm::handler::profile_t sregdw;
&lconstq, extern vm::handler::profile_t sregw;
&lconstdsx,
&lconstwsx, extern vm::handler::profile_t lregq;
&lconstbzx, extern vm::handler::profile_t lregdw;
&addq,
&nandq, extern vm::handler::profile_t lconstq;
&pushvsp, extern vm::handler::profile_t lconstbzxw;
&vmexit, extern vm::handler::profile_t lconstbsxdw;
&jmp, extern vm::handler::profile_t lconstdwsxq;
&adddw, extern vm::handler::profile_t lconstwsxq;
&writeq, extern vm::handler::profile_t lconstdw;
&sregw,
&lconstw, extern vm::handler::profile_t addq;
&shrw, extern vm::handler::profile_t adddw;
&shrq,
&writeq1, extern vm::handler::profile_t shlq;
&readw, extern vm::handler::profile_t shldw;
&lregdw,
&shrdw, extern vm::handler::profile_t nandq;
&sregdw, extern vm::handler::profile_t nanddw;
&lconstbsx,
&lconstbsx1, extern vm::handler::profile_t writeq;
&shrq, extern vm::handler::profile_t writedw;
&lvsp,
&lconstdw, extern vm::handler::profile_t shrq;
&nanddw extern vm::handler::profile_t pushvsp;
}; extern vm::handler::profile_t mulq;
} extern vm::handler::profile_t divq;
} extern vm::handler::profile_t jmp;
} extern vm::handler::profile_t readq;
extern vm::handler::profile_t vmexit;
inline std::vector< vm::handler::profile_t * > all = {
&sregq, &sregdw, &sregw, &lregq, &lregdw, &lconstq, &lconstbzxw,
&lconstbsxdw, &lconstdwsxq, &lconstwsxq, &lconstdw, &addq, &adddw, &shlq,
&shldw, &writeq, &writedw, &nandq, &nanddw,
&shrq, &readq, &mulq, &pushvsp, &divq, &jmp, &vmexit };
} // namespace profile
} // namespace handler
} // namespace vm

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <vector>
#include <Zydis/Zydis.h>
#include <Zydis/Utils.h> #include <Zydis/Utils.h>
#include <Zydis/Zydis.h>
#include <vector>
#include <xmmintrin.h> #include <xmmintrin.h>
using u8 = unsigned char; using u8 = unsigned char;
@ -10,9 +10,12 @@ using u32 = unsigned int;
using u64 = unsigned long long; using u64 = unsigned long long;
using u128 = __m128; using u128 = __m128;
using zydis_decoded_instr_t = ZydisDecodedInstruction;
using zydis_register_t = ZydisRegister;
struct zydis_instr_t struct zydis_instr_t
{ {
ZydisDecodedInstruction instr; zydis_decoded_instr_t instr;
std::vector< u8 > raw; std::vector< u8 > raw;
std::uintptr_t addr; std::uintptr_t addr;
}; };
@ -26,15 +29,15 @@ namespace vm
namespace reg namespace reg
{ {
// converts say... AL to RAX... // converts say... AL to RAX...
ZydisRegister to64(ZydisRegister reg); zydis_register_t to64( zydis_register_t reg );
bool compare(ZydisRegister a, ZydisRegister b); bool compare( zydis_register_t a, zydis_register_t b );
} } // namespace reg
void print( zydis_routine_t &routine ); void print( zydis_routine_t &routine );
void print(const ZydisDecodedInstruction& instr); void print( const zydis_decoded_instr_t &instr );
bool is_jmp(const ZydisDecodedInstruction& instr); bool is_jmp( const zydis_decoded_instr_t &instr );
bool flatten( zydis_routine_t &routine, std::uintptr_t routine_addr, bool keep_jmps = false ); bool flatten( zydis_routine_t &routine, std::uintptr_t routine_addr, bool keep_jmps = false );
void deobfuscate( zydis_routine_t &routine ); void deobfuscate( zydis_routine_t &routine );
} } // namespace util
} } // namespace vm

@ -0,0 +1,31 @@
#include <vmprofiler.hpp>
namespace vm
{
namespace calc_jmp
{
bool get( const zydis_routine_t &vm_entry, zydis_routine_t &calc_jmp )
{
auto result =
std::find_if( vm_entry.begin(), vm_entry.end(), []( const zydis_instr_t &instr_data ) -> bool {
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if ( instr_data.instr.operand_count > 1 &&
( instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX ) &&
instr_data.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64( instr_data.instr.operands[ 0 ].reg.value ) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RSI )
return true;
return false;
} );
if ( result == vm_entry.end() )
return false;
calc_jmp.insert( calc_jmp.end(), result, vm_entry.end() );
return true;
}
} // namespace calc_jmp
} // namespace vm

@ -1,646 +0,0 @@
#include "vm.h"
namespace vm
{
std::pair<std::uint64_t, std::uint64_t> decrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key)
{
const auto generic_decrypt_0 = &transforms[transform::type::generic0];
const auto key_decrypt = &transforms[transform::type::rolling_key];
const auto generic_decrypt_1 = &transforms[transform::type::generic1];
const auto generic_decrypt_2 = &transforms[transform::type::generic2];
const auto generic_decrypt_3 = &transforms[transform::type::generic3];
const auto update_key = &transforms[transform::type::update_key];
if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID)
{
operand = transform::apply(
generic_decrypt_0->operands[0].size,
generic_decrypt_0->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_0) ?
generic_decrypt_0->operands[1].imm.value.u : 0);
}
// apply transformation with rolling decrypt key...
operand = transform::apply(key_decrypt->operands[0].size,
key_decrypt->mnemonic, operand, rolling_key);
// apply three generic transformations...
{
operand = transform::apply(
generic_decrypt_1->operands[0].size,
generic_decrypt_1->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_1) ?
generic_decrypt_1->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_2->operands[0].size,
generic_decrypt_2->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_2) ?
generic_decrypt_2->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_3->operands[0].size,
generic_decrypt_3->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_3) ?
generic_decrypt_3->operands[1].imm.value.u : 0);
}
// update rolling key...
auto result = transform::apply(update_key->operands[0].size,
update_key->mnemonic, rolling_key, operand);
// update decryption key correctly...
switch (update_key->operands[0].size)
{
case 8:
rolling_key = (rolling_key & ~0xFFull) + result;
break;
case 16:
rolling_key = (rolling_key & ~0xFFFFull) + result;
break;
default:
rolling_key = result;
break;
}
return { operand, rolling_key };
}
void inverse_transforms(transform::map_t& transforms, transform::map_t& inverse)
{
inverse[transform::type::generic0] = transforms[transform::type::generic0];
inverse[transform::type::generic0].mnemonic =
transform::inverse[transforms[transform::type::generic0].mnemonic];
inverse[transform::type::rolling_key] = transforms[transform::type::rolling_key];
inverse[transform::type::rolling_key].mnemonic =
transform::inverse[transforms[transform::type::rolling_key].mnemonic];
inverse[transform::type::generic1] = transforms[transform::type::generic1];
inverse[transform::type::generic1].mnemonic =
transform::inverse[transforms[transform::type::generic1].mnemonic];
inverse[transform::type::generic2] = transforms[transform::type::generic2];
inverse[transform::type::generic2].mnemonic =
transform::inverse[transforms[transform::type::generic2].mnemonic];
inverse[transform::type::generic3] = transforms[transform::type::generic3];
inverse[transform::type::generic3].mnemonic =
transform::inverse[transforms[transform::type::generic3].mnemonic];
inverse[transform::type::update_key] = transforms[transform::type::update_key];
inverse[transform::type::update_key].mnemonic =
transform::inverse[transforms[transform::type::update_key].mnemonic];
}
std::pair<std::uint64_t, std::uint64_t> encrypt_operand(transform::map_t& transforms,
std::uint64_t operand, std::uint64_t rolling_key)
{
transform::map_t inverse;
inverse_transforms(transforms, inverse);
const auto generic_decrypt_0 = &inverse[transform::type::generic0];
const auto key_decrypt = &inverse[transform::type::rolling_key];
const auto generic_decrypt_1 = &inverse[transform::type::generic1];
const auto generic_decrypt_2 = &inverse[transform::type::generic2];
const auto generic_decrypt_3 = &inverse[transform::type::generic3];
const auto update_key = &inverse[transform::type::update_key];
auto result = transform::apply(update_key->operands[0].size,
update_key->mnemonic, rolling_key, operand);
// make sure we update the rolling decryption key correctly...
switch (update_key->operands[0].size)
{
case 8:
rolling_key = (rolling_key & ~0xFFull) + result;
break;
case 16:
rolling_key = (rolling_key & ~0xFFFFull) + result;
break;
default:
rolling_key = result;
break;
}
{
operand = transform::apply(
generic_decrypt_3->operands[0].size,
generic_decrypt_3->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_3) ?
generic_decrypt_3->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_2->operands[0].size,
generic_decrypt_2->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_2) ?
generic_decrypt_2->operands[1].imm.value.u : 0);
operand = transform::apply(
generic_decrypt_1->operands[0].size,
generic_decrypt_1->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_1) ?
generic_decrypt_1->operands[1].imm.value.u : 0);
}
operand = transform::apply(key_decrypt->operands[0].size,
key_decrypt->mnemonic, operand, rolling_key);
if (generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID)
{
operand = transform::apply(
generic_decrypt_0->operands[0].size,
generic_decrypt_0->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm(generic_decrypt_0) ?
generic_decrypt_0->operands[1].imm.value.u : 0);
}
return { operand, rolling_key };
}
bool get_calc_jmp(const zydis_routine_t& vm_entry, zydis_routine_t& calc_jmp)
{
auto result = std::find_if(vm_entry.begin(), vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if (instr_data.instr.operand_count > 1 &&
(instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) &&
instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI)
return true;
return false;
}
);
if (result == vm_entry.end())
return false;
calc_jmp.insert(calc_jmp.end(), result, vm_entry.end());
return true;
}
bool get_vinstr_rva_transform(
const zydis_routine_t& vm_entry, ZydisDecodedInstruction* transform_instr)
{
//
// find mov esi, [rsp+0xA0]
//
auto result = std::find_if(vm_entry.begin(), vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
if (instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr_data.instr.operand_count == 2 &&
instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI &&
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSP &&
instr_data.instr.operands[1].mem.disp.has_displacement &&
instr_data.instr.operands[1].mem.disp.value == 0xA0)
return true;
return false;
}
);
if (result == vm_entry.end())
return false;
//
// find the next instruction with ESI as the dest...
//
result = std::find_if(++result, vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
if (instr_data.instr.operands[0].reg.value == ZYDIS_REGISTER_ESI)
return true;
return false;
}
);
if (result == vm_entry.end())
return false;
*transform_instr = result->instr;
transform_instr->mnemonic = transform::inverse[result->instr.mnemonic];
return true;
}
namespace handler
{
bool get(zydis_routine_t& calc_jmp, zydis_routine_t& vm_handler, std::uintptr_t handler_addr)
{
if (!vm::util::flatten(vm_handler, handler_addr))
return false;
vm::util::deobfuscate(vm_handler);
static const auto calc_jmp_check =
[&](std::uintptr_t addr) -> bool
{
for (const auto& [instr, instr_raw, instr_addr] : calc_jmp)
if (instr_addr == addr)
return true;
return false;
};
auto result = std::find_if(
vm_handler.begin(), vm_handler.end(),
[](const zydis_instr_t& instr) -> bool
{
if (instr.instr.mnemonic == ZYDIS_MNEMONIC_LEA &&
instr.instr.operands[0].reg.value == ZYDIS_REGISTER_RAX &&
instr.instr.operands[1].mem.base == ZYDIS_REGISTER_RDI &&
instr.instr.operands[1].mem.disp.value == 0xE0)
return true;
return calc_jmp_check(instr.addr);
}
);
// remove calc_jmp from the vm handler vector...
if (result != vm_handler.end())
vm_handler.erase(result, vm_handler.end());
else // locate the last mov al, [rsi],
// then remove all instructions after that...
{
zydis_routine_t::iterator last = vm_handler.end();
result = vm_handler.begin();
while (result != vm_handler.end())
{
result = std::find_if(
++result, vm_handler.end(),
[](const zydis_instr_t& instr_data) -> bool
{
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if (instr_data.instr.operand_count > 1 &&
(instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) &&
instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI)
return true;
return false;
}
);
if (result != vm_handler.end())
last = result;
}
if (last != vm_handler.end())
vm_handler.erase(last, vm_handler.end());
}
return true;
}
bool get_all(std::uintptr_t module_base, std::uintptr_t image_base,
zydis_routine_t& vm_entry, std::uintptr_t* vm_handler_table, std::vector<vm::handler_t>& vm_handlers)
{
ZydisDecodedInstruction instr;
if (!vm::handler::table::get_transform(vm_entry, &instr))
return false;
zydis_routine_t calc_jmp;
if (!vm::get_calc_jmp(vm_entry, calc_jmp))
return false;
for (auto idx = 0u; idx < 256; ++idx)
{
const auto decrypt_val =
vm::handler::table::decrypt(
instr, vm_handler_table[idx]);
vm::handler_t vm_handler;
vm::transform::map_t transforms;
zydis_routine_t vm_handler_instrs;
if (!vm::handler::get(calc_jmp, vm_handler_instrs, (decrypt_val - image_base) + module_base))
return false;
const auto has_imm =
vm::handler::has_imm(vm_handler_instrs);
const auto imm_size =
vm::handler::imm_size(vm_handler_instrs);
if (has_imm && !vm::handler::get_operand_transforms(vm_handler_instrs, transforms))
return false;
vm_handler.address = (decrypt_val - image_base) + module_base;
vm_handler.instrs = vm_handler_instrs;
vm_handler.imm_size = imm_size;
vm_handler.transforms = transforms;
vm_handler.profile = vm::handler::get_profile(vm_handler);
vm_handlers.push_back(vm_handler);
}
return true;
}
bool has_imm(const zydis_routine_t& vm_handler)
{
const auto result = std::find_if(
vm_handler.begin(), vm_handler.end(),
[](const zydis_instr_t& instr_data) -> bool
{
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if (instr_data.instr.operand_count > 1 &&
(instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) &&
instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI)
return true;
return false;
}
);
return result != vm_handler.end();
}
std::uint8_t imm_size(const zydis_routine_t& vm_handler)
{
const auto result = std::find_if(
vm_handler.begin(), vm_handler.end(),
[](const zydis_instr_t& instr_data) -> bool
{
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if (instr_data.instr.operand_count > 1 &&
(instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) &&
instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI)
return true;
return false;
}
);
if (result == vm_handler.end())
return 0u;
return result->instr.operands[1].size;
}
bool get_operand_transforms(const zydis_routine_t& vm_handler, transform::map_t& transforms)
{
auto imm_fetch = std::find_if(
vm_handler.begin(), vm_handler.end(),
[](const zydis_instr_t& instr_data) -> bool
{
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if (instr_data.instr.operand_count > 1 &&
(instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) &&
instr_data.instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64(instr_data.instr.operands[0].reg.value) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI)
return true;
return false;
}
);
if (imm_fetch == vm_handler.end())
return false;
// this finds the first transformation which looks like:
// transform rax, rbx <--- note these registers can be smaller so we to64 them...
auto key_transform = std::find_if(imm_fetch, vm_handler.end(),
[](const zydis_instr_t& instr_data) -> bool
{
if (util::reg::compare(instr_data.instr.operands[0].reg.value, ZYDIS_REGISTER_RAX) &&
util::reg::compare(instr_data.instr.operands[1].reg.value, ZYDIS_REGISTER_RBX))
return true;
return false;
}
);
if (key_transform == vm_handler.end())
return false;
// look for a primer/instruction that alters RAX prior to the 5 transformations...
auto generic0 = std::find_if(imm_fetch + 1, key_transform,
[](const zydis_instr_t& instr_data) -> bool
{
return util::reg::compare(
instr_data.instr.operands[0].reg.value, ZYDIS_REGISTER_RAX) &&
!util::reg::compare(instr_data.instr.operands[1].reg.value, ZYDIS_REGISTER_RBX);
}
);
ZydisDecodedInstruction nogeneric0;
nogeneric0.mnemonic = ZYDIS_MNEMONIC_INVALID;
transforms[transform::type::generic0] =
generic0 != key_transform ? generic0->instr : nogeneric0;
// last transformation is the same as the first except src and dest are swwapped...
transforms[transform::type::rolling_key] = key_transform->instr;
auto instr_copy = key_transform->instr;
instr_copy.operands[0].reg.value = key_transform->instr.operands[1].reg.value;
instr_copy.operands[1].reg.value = key_transform->instr.operands[0].reg.value;
transforms[transform::type::update_key] = instr_copy;
// three generic transformations...
auto generic_transform = key_transform;
for (auto idx = 2u; idx < 5; ++idx)
{
generic_transform = std::find_if(++generic_transform, vm_handler.end(),
[](const zydis_instr_t& instr_data) -> bool
{
if (util::reg::compare(instr_data.instr.operands[0].reg.value, ZYDIS_REGISTER_RAX))
return true;
return false;
}
);
if (generic_transform == vm_handler.end())
return false;
transforms[(transform::type)(idx)] = generic_transform->instr;
}
return true;
}
vm::handler::profile_t* get_profile(vm::handler_t& vm_handler)
{
static const auto vcontains =
[](vm::handler::profile_t* vprofile, vm::handler_t* vm_handler) -> bool
{
if (vprofile->imm_size != vm_handler->imm_size)
return false;
for (auto& instr : vprofile->signature)
{
const auto contains = std::find_if
(
vm_handler->instrs.begin(),
vm_handler->instrs.end(),
[&](zydis_instr_t& instr_data) -> bool
{
if (instr_data.raw.size() != instr.size())
return false;
return std::equal
(
instr_data.raw.begin(),
instr_data.raw.end(),
instr.begin()
);
}
);
if (contains == vm_handler->instrs.end())
return false;
}
return true;
};
for (auto profile : vm::handler::profile::all)
if (vcontains(profile, &vm_handler))
return profile;
return nullptr;
}
namespace table
{
std::uintptr_t* get(const zydis_routine_t& vm_entry)
{
const auto result = std::find_if(
vm_entry.begin(), vm_entry.end(),
[](const zydis_instr_t& instr_data) -> bool
{
const auto instr = &instr_data.instr;
// lea r12, vm_handlers... (always r12)...
if (instr->mnemonic == ZYDIS_MNEMONIC_LEA &&
instr->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr->operands[0].reg.value == ZYDIS_REGISTER_R12 &&
!instr->raw.sib.base) // no register used for the sib base...
return true;
return false;
}
);
if (result == vm_entry.end())
return nullptr;
std::uintptr_t ptr = 0u;
ZydisCalcAbsoluteAddress(&result->instr,
&result->instr.operands[1], result->addr, &ptr);
return reinterpret_cast<std::uintptr_t*>(ptr);
}
bool get_transform(const zydis_routine_t& vm_entry, ZydisDecodedInstruction* transform_instr)
{
ZydisRegister rcx_or_rdx = ZYDIS_REGISTER_NONE;
auto handler_fetch = std::find_if(
vm_entry.begin(), vm_entry.end(),
[&](const zydis_instr_t& instr_data) -> bool
{
const auto instr = &instr_data.instr;
if (instr->mnemonic == ZYDIS_MNEMONIC_MOV &&
instr->operand_count == 2 &&
instr->operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr->operands[1].mem.base == ZYDIS_REGISTER_R12 &&
instr->operands[1].mem.index == ZYDIS_REGISTER_RAX &&
instr->operands[1].mem.scale == 8 &&
instr->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
(instr->operands[0].reg.value == ZYDIS_REGISTER_RDX ||
instr->operands[0].reg.value == ZYDIS_REGISTER_RCX))
{
rcx_or_rdx = instr->operands[0].reg.value;
return true;
}
return false;
}
);
// check to see if we found the fetch instruction and if the next instruction
// is not the end of the vector...
if (handler_fetch == vm_entry.end() || ++handler_fetch == vm_entry.end() ||
// must be RCX or RDX... else something went wrong...
(rcx_or_rdx != ZYDIS_REGISTER_RCX && rcx_or_rdx != ZYDIS_REGISTER_RDX))
return false;
// find the next instruction that writes to RCX or RDX...
// the register is determined by the vm handler fetch above...
auto handler_transform = std::find_if(
handler_fetch, vm_entry.end(),
[&](const zydis_instr_t& instr_data) -> bool
{
if (instr_data.instr.operands[0].reg.value == rcx_or_rdx &&
instr_data.instr.operands[0].actions & ZYDIS_OPERAND_ACTION_WRITE)
return true;
return false;
}
);
if (handler_transform == vm_entry.end())
return false;
*transform_instr = handler_transform->instr;
return true;
}
std::uint64_t encrypt(ZydisDecodedInstruction& transform_instr, std::uint64_t val)
{
assert(transform_instr.operands[0].size == 64,
"invalid transformation for vm handler table entries...");
const auto operation = vm::transform::inverse[transform_instr.mnemonic];
const auto bitsize = transform_instr.operands[0].size;
const auto imm = vm::transform::has_imm(&transform_instr) ?
transform_instr.operands[1].imm.value.u : 0u;
return vm::transform::apply(bitsize, operation, val, imm);
}
std::uint64_t decrypt(ZydisDecodedInstruction& transform_instr, std::uint64_t val)
{
assert(transform_instr.operands[0].size == 64,
"invalid transformation for vm handler table entries...");
const auto operation = transform_instr.mnemonic;
const auto bitsize = transform_instr.operands[0].size;
const auto imm = vm::transform::has_imm(&transform_instr) ?
transform_instr.operands[1].imm.value.u : 0u;
return vm::transform::apply(bitsize, operation, val, imm);
}
}
}
}

@ -1,115 +0,0 @@
#include "vmctx.h"
namespace vm
{
vmctx_t::vmctx_t(
vmp2::file_header* file_header,
vmp2::entry_t* entry_list,
std::vector<vm::handler_t>& vm_handlers,
std::uintptr_t module_base,
std::uintptr_t image_base
)
: module_base(module_base),
image_base(image_base),
entry_list(entry_list),
file_header(file_header),
vm_handlers(vm_handlers),
idx(0)
{}
std::pair<std::string, const vmp2::entry_t*> vmctx_t::step() const
{
if (idx >= file_header->entry_count)
return {};
const auto vm_handler = &vm_handlers[entry_list[idx].handler_idx];
if (vm_handler->imm_size)
{
const auto operand = get_imm(file_header->advancement,
entry_list[idx].vip, vm_handler->imm_size / 8);
auto transforms = vm_handler->transforms;
auto [decrypted_operand, rolling_key] =
vm::decrypt_operand(transforms,
operand, entry_list[idx].decrypt_key);
if (vm_handler->profile)
{
if (vm_handler->profile->extention ==
vm::handler::extention_t::sign_extend)
{
switch (vm_handler->imm_size)
{
case 8:
{
if ((u8)(decrypted_operand >> 7))
decrypted_operand += ~0xFFull;
break;
}
case 16:
{
if ((u16)(decrypted_operand >> 15))
decrypted_operand += ~0xFFFFull;
break;
}
case 32:
{
if ((u32)(decrypted_operand >> 31))
decrypted_operand += ~0xFFFFFFFFull;
break;
}
default:
throw std::invalid_argument(
"invalid imm size for sign extention...\n");
}
}
}
char buff[256];
if (vm_handler->profile)
{
snprintf(buff, sizeof buff, "%s 0x%p",
vm_handler->profile->name, decrypted_operand);
}
else
{
snprintf(buff, sizeof buff, "UNK(%d) 0x%p",
entry_list[idx].handler_idx, decrypted_operand);
}
return { buff, &entry_list[idx++] };
}
if (vm_handler->profile)
return { vm_handler->profile->name, &entry_list[idx++] };
char buff[256];
snprintf(buff, sizeof buff, "UNK(%d)", entry_list[idx++].handler_idx);
return { buff, &entry_list[idx++] };
}
std::uintptr_t vmctx_t::get_imm(vmp2::exec_type_t exec_type_t,
std::uint32_t vip_offset, std::uint8_t imm_size) const
{
std::uintptr_t operand = 0u;
if (file_header->advancement == vmp2::exec_type_t::forward)
{
const auto operand_ptr =
reinterpret_cast<void*>((entry_list[idx].vip -
file_header->module_base) + module_base);
memcpy(&operand, operand_ptr, imm_size);
}
else
{
const auto operand_ptr =
reinterpret_cast<void*>(((entry_list[idx].vip -
file_header->module_base) + module_base) - imm_size);
memcpy(&operand, operand_ptr, imm_size);
}
return operand;
}
}

@ -0,0 +1,350 @@
#include <vmprofiler.hpp>
namespace vm
{
namespace handler
{
bool get( zydis_routine_t &calc_jmp, zydis_routine_t &vm_handler, std::uintptr_t handler_addr )
{
if ( !vm::util::flatten( vm_handler, handler_addr ) )
return false;
vm::util::deobfuscate( vm_handler );
static const auto calc_jmp_check = [ & ]( std::uintptr_t addr ) -> bool {
for ( const auto &[ instr, instr_raw, instr_addr ] : calc_jmp )
if ( instr_addr == addr )
return true;
return false;
};
auto result = std::find_if( vm_handler.begin(), vm_handler.end(), []( const zydis_instr_t &instr ) -> bool {
if ( instr.instr.mnemonic == ZYDIS_MNEMONIC_LEA &&
instr.instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RDI &&
instr.instr.operands[ 1 ].mem.disp.value == 0xE0 )
return true;
return calc_jmp_check( instr.addr );
} );
// remove calc_jmp from the vm handler vector...
if ( result != vm_handler.end() )
vm_handler.erase( result, vm_handler.end() );
else // locate the last mov al, [rsi],
// then remove all instructions after that...
{
zydis_routine_t::iterator last = vm_handler.end();
result = vm_handler.begin();
while ( result != vm_handler.end() )
{
result = std::find_if( ++result, vm_handler.end(), []( const zydis_instr_t &instr_data ) -> bool {
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if ( instr_data.instr.operand_count > 1 &&
( instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX ) &&
instr_data.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64( instr_data.instr.operands[ 0 ].reg.value ) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RSI )
return true;
return false;
} );
if ( result != vm_handler.end() )
last = result;
}
if ( last != vm_handler.end() )
vm_handler.erase( last, vm_handler.end() );
}
return true;
}
bool get_all( std::uintptr_t module_base, std::uintptr_t image_base, zydis_routine_t &vm_entry,
std::uintptr_t *vm_handler_table, std::vector< vm::handler::handler_t > &vm_handlers )
{
zydis_decoded_instr_t instr;
if ( !vm::handler::table::get_transform( vm_entry, &instr ) )
return false;
zydis_routine_t calc_jmp;
if ( !vm::calc_jmp::get( vm_entry, calc_jmp ) )
return false;
for ( auto idx = 0u; idx < 256; ++idx )
{
const auto decrypt_val = vm::handler::table::decrypt( instr, vm_handler_table[ idx ] );
handler_t vm_handler;
vm::transform::map_t transforms;
zydis_routine_t vm_handler_instrs;
if ( !vm::handler::get( calc_jmp, vm_handler_instrs, ( decrypt_val - image_base ) + module_base ) )
return false;
const auto has_imm = vm::handler::has_imm( vm_handler_instrs );
const auto imm_size = vm::handler::imm_size( vm_handler_instrs );
if ( has_imm && !vm::handler::get_operand_transforms( vm_handler_instrs, transforms ) )
return false;
vm_handler.address = ( decrypt_val - image_base ) + module_base;
vm_handler.instrs = vm_handler_instrs;
vm_handler.imm_size = imm_size;
vm_handler.transforms = transforms;
vm_handler.profile = vm::handler::get_profile( vm_handler );
vm_handlers.push_back( vm_handler );
}
return true;
}
bool has_imm( const zydis_routine_t &vm_handler )
{
const auto result =
std::find_if( vm_handler.begin(), vm_handler.end(), []( const zydis_instr_t &instr_data ) -> bool {
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if ( instr_data.instr.operand_count > 1 &&
( instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX ) &&
instr_data.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64( instr_data.instr.operands[ 0 ].reg.value ) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RSI )
return true;
return false;
} );
return result != vm_handler.end();
}
std::uint8_t imm_size( const zydis_routine_t &vm_handler )
{
const auto result =
std::find_if( vm_handler.begin(), vm_handler.end(), []( const zydis_instr_t &instr_data ) -> bool {
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if ( instr_data.instr.operand_count > 1 &&
( instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX ) &&
instr_data.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64( instr_data.instr.operands[ 0 ].reg.value ) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RSI )
return true;
return false;
} );
if ( result == vm_handler.end() )
return 0u;
return result->instr.operands[ 1 ].size;
}
bool get_operand_transforms( const zydis_routine_t &vm_handler, transform::map_t &transforms )
{
auto imm_fetch =
std::find_if( vm_handler.begin(), vm_handler.end(), []( const zydis_instr_t &instr_data ) -> bool {
// mov/movsx/movzx rax/eax/ax/al, [rsi]
if ( instr_data.instr.operand_count > 1 &&
( instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX ) &&
instr_data.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
util::reg::to64( instr_data.instr.operands[ 0 ].reg.value ) == ZYDIS_REGISTER_RAX &&
instr_data.instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr_data.instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RSI )
return true;
return false;
} );
if ( imm_fetch == vm_handler.end() )
return false;
// this finds the first transformation which looks like:
// transform rax, rbx <--- note these registers can be smaller so we to64 them...
auto key_transform =
std::find_if( imm_fetch, vm_handler.end(), []( const zydis_instr_t &instr_data ) -> bool {
if ( util::reg::compare( instr_data.instr.operands[ 0 ].reg.value, ZYDIS_REGISTER_RAX ) &&
util::reg::compare( instr_data.instr.operands[ 1 ].reg.value, ZYDIS_REGISTER_RBX ) )
return true;
return false;
} );
if ( key_transform == vm_handler.end() )
return false;
// look for a primer/instruction that alters RAX prior to the 5 transformations...
auto generic0 = std::find_if( imm_fetch + 1, key_transform, []( const zydis_instr_t &instr_data ) -> bool {
return util::reg::compare( instr_data.instr.operands[ 0 ].reg.value, ZYDIS_REGISTER_RAX ) &&
!util::reg::compare( instr_data.instr.operands[ 1 ].reg.value, ZYDIS_REGISTER_RBX );
} );
zydis_decoded_instr_t nogeneric0;
nogeneric0.mnemonic = ZYDIS_MNEMONIC_INVALID;
transforms[ transform::type::generic0 ] = generic0 != key_transform ? generic0->instr : nogeneric0;
// last transformation is the same as the first except src and dest are swwapped...
transforms[ transform::type::rolling_key ] = key_transform->instr;
auto instr_copy = key_transform->instr;
instr_copy.operands[ 0 ].reg.value = key_transform->instr.operands[ 1 ].reg.value;
instr_copy.operands[ 1 ].reg.value = key_transform->instr.operands[ 0 ].reg.value;
transforms[ transform::type::update_key ] = instr_copy;
// three generic transformations...
auto generic_transform = key_transform;
for ( auto idx = 2u; idx < 5; ++idx )
{
generic_transform =
std::find_if( ++generic_transform, vm_handler.end(), []( const zydis_instr_t &instr_data ) -> bool {
if ( util::reg::compare( instr_data.instr.operands[ 0 ].reg.value, ZYDIS_REGISTER_RAX ) )
return true;
return false;
} );
if ( generic_transform == vm_handler.end() )
return false;
transforms[ ( transform::type )( idx ) ] = generic_transform->instr;
}
return true;
}
vm::handler::profile_t *get_profile( handler_t &vm_handler )
{
static const auto vcontains = []( vm::handler::profile_t *vprofile, handler_t *vm_handler ) -> bool {
if ( vprofile->imm_size != vm_handler->imm_size )
return false;
zydis_routine_t::iterator contains = vm_handler->instrs.begin();
for ( auto &instr : vprofile->signature )
{
contains = std::find_if(contains, vm_handler->instrs.end(),
[ & ]( zydis_instr_t &instr_data ) -> bool { return instr( instr_data.instr ); } );
if ( contains == vm_handler->instrs.end() )
return false;
}
return true;
};
for ( auto profile : vm::handler::profile::all )
if ( vcontains( profile, &vm_handler ) )
return profile;
return nullptr;
}
namespace table
{
std::uintptr_t *get( const zydis_routine_t &vm_entry )
{
const auto result =
std::find_if( vm_entry.begin(), vm_entry.end(), []( const zydis_instr_t &instr_data ) -> bool {
const auto instr = &instr_data.instr;
// lea r12, vm_handlers... (always r12)...
if ( instr->mnemonic == ZYDIS_MNEMONIC_LEA &&
instr->operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr->operands[ 0 ].reg.value == ZYDIS_REGISTER_R12 &&
!instr->raw.sib.base ) // no register used for the sib base...
return true;
return false;
} );
if ( result == vm_entry.end() )
return nullptr;
std::uintptr_t ptr = 0u;
ZydisCalcAbsoluteAddress( &result->instr, &result->instr.operands[ 1 ], result->addr, &ptr );
return reinterpret_cast< std::uintptr_t * >( ptr );
}
bool get_transform( const zydis_routine_t &vm_entry, zydis_decoded_instr_t *transform_instr )
{
zydis_register_t rcx_or_rdx = ZYDIS_REGISTER_NONE;
auto handler_fetch =
std::find_if( vm_entry.begin(), vm_entry.end(), [ & ]( const zydis_instr_t &instr_data ) -> bool {
const auto instr = &instr_data.instr;
if ( instr->mnemonic == ZYDIS_MNEMONIC_MOV && instr->operand_count == 2 &&
instr->operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr->operands[ 1 ].mem.base == ZYDIS_REGISTER_R12 &&
instr->operands[ 1 ].mem.index == ZYDIS_REGISTER_RAX &&
instr->operands[ 1 ].mem.scale == 8 &&
instr->operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
( instr->operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX ||
instr->operands[ 0 ].reg.value == ZYDIS_REGISTER_RCX ) )
{
rcx_or_rdx = instr->operands[ 0 ].reg.value;
return true;
}
return false;
} );
// check to see if we found the fetch instruction and if the next instruction
// is not the end of the vector...
if ( handler_fetch == vm_entry.end() || ++handler_fetch == vm_entry.end() ||
// must be RCX or RDX... else something went wrong...
( rcx_or_rdx != ZYDIS_REGISTER_RCX && rcx_or_rdx != ZYDIS_REGISTER_RDX ) )
return false;
// find the next instruction that writes to RCX or RDX...
// the register is determined by the vm handler fetch above...
auto handler_transform =
std::find_if( handler_fetch, vm_entry.end(), [ & ]( const zydis_instr_t &instr_data ) -> bool {
if ( instr_data.instr.operands[ 0 ].reg.value == rcx_or_rdx &&
instr_data.instr.operands[ 0 ].actions & ZYDIS_OPERAND_ACTION_WRITE )
return true;
return false;
} );
if ( handler_transform == vm_entry.end() )
return false;
*transform_instr = handler_transform->instr;
return true;
}
std::uint64_t encrypt( zydis_decoded_instr_t &transform_instr, std::uint64_t val )
{
assert( transform_instr.operands[ 0 ].size == 64,
"invalid transformation for vm handler table entries..." );
const auto operation = vm::transform::inverse[ transform_instr.mnemonic ];
const auto bitsize = transform_instr.operands[ 0 ].size;
const auto imm =
vm::transform::has_imm( &transform_instr ) ? transform_instr.operands[ 1 ].imm.value.u : 0u;
return vm::transform::apply( bitsize, operation, val, imm );
}
std::uint64_t decrypt( zydis_decoded_instr_t &transform_instr, std::uint64_t val )
{
assert( transform_instr.operands[ 0 ].size == 64,
"invalid transformation for vm handler table entries..." );
const auto operation = transform_instr.mnemonic;
const auto bitsize = transform_instr.operands[ 0 ].size;
const auto imm =
vm::transform::has_imm( &transform_instr ) ? transform_instr.operands[ 1 ].imm.value.u : 0u;
return vm::transform::apply( bitsize, operation, val, imm );
}
} // namespace table
} // namespace handler
} // namespace vm

@ -0,0 +1,166 @@
#include <vmprofiler.hpp>
namespace vm
{
namespace instrs
{
std::pair< std::uint64_t, std::uint64_t > decrypt_operand( transform::map_t &transforms, std::uint64_t operand,
std::uint64_t rolling_key )
{
const auto generic_decrypt_0 = &transforms[ transform::type::generic0 ];
const auto key_decrypt = &transforms[ transform::type::rolling_key ];
const auto generic_decrypt_1 = &transforms[ transform::type::generic1 ];
const auto generic_decrypt_2 = &transforms[ transform::type::generic2 ];
const auto generic_decrypt_3 = &transforms[ transform::type::generic3 ];
const auto update_key = &transforms[ transform::type::update_key ];
if ( generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID )
{
operand = transform::apply(
generic_decrypt_0->operands[ 0 ].size, generic_decrypt_0->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm( generic_decrypt_0 ) ? generic_decrypt_0->operands[ 1 ].imm.value.u : 0 );
}
// apply transformation with rolling decrypt key...
operand = transform::apply( key_decrypt->operands[ 0 ].size, key_decrypt->mnemonic, operand, rolling_key );
// apply three generic transformations...
{
operand = transform::apply(
generic_decrypt_1->operands[ 0 ].size, generic_decrypt_1->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm( generic_decrypt_1 ) ? generic_decrypt_1->operands[ 1 ].imm.value.u : 0 );
operand = transform::apply(
generic_decrypt_2->operands[ 0 ].size, generic_decrypt_2->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm( generic_decrypt_2 ) ? generic_decrypt_2->operands[ 1 ].imm.value.u : 0 );
operand = transform::apply(
generic_decrypt_3->operands[ 0 ].size, generic_decrypt_3->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm( generic_decrypt_3 ) ? generic_decrypt_3->operands[ 1 ].imm.value.u : 0 );
}
// update rolling key...
auto result =
transform::apply( update_key->operands[ 0 ].size, update_key->mnemonic, rolling_key, operand );
// update decryption key correctly...
switch ( update_key->operands[ 0 ].size )
{
case 8:
rolling_key = ( rolling_key & ~0xFFull ) + result;
break;
case 16:
rolling_key = ( rolling_key & ~0xFFFFull ) + result;
break;
default:
rolling_key = result;
break;
}
return { operand, rolling_key };
}
std::pair< std::uint64_t, std::uint64_t > encrypt_operand( transform::map_t &transforms, std::uint64_t operand,
std::uint64_t rolling_key )
{
transform::map_t inverse;
inverse_transforms( transforms, inverse );
const auto generic_decrypt_0 = &inverse[ transform::type::generic0 ];
const auto key_decrypt = &inverse[ transform::type::rolling_key ];
const auto generic_decrypt_1 = &inverse[ transform::type::generic1 ];
const auto generic_decrypt_2 = &inverse[ transform::type::generic2 ];
const auto generic_decrypt_3 = &inverse[ transform::type::generic3 ];
const auto update_key = &inverse[ transform::type::update_key ];
auto result =
transform::apply( update_key->operands[ 0 ].size, update_key->mnemonic, rolling_key, operand );
// make sure we update the rolling decryption key correctly...
switch ( update_key->operands[ 0 ].size )
{
case 8:
rolling_key = ( rolling_key & ~0xFFull ) + result;
break;
case 16:
rolling_key = ( rolling_key & ~0xFFFFull ) + result;
break;
default:
rolling_key = result;
break;
}
{
operand = transform::apply(
generic_decrypt_3->operands[ 0 ].size, generic_decrypt_3->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm( generic_decrypt_3 ) ? generic_decrypt_3->operands[ 1 ].imm.value.u : 0 );
operand = transform::apply(
generic_decrypt_2->operands[ 0 ].size, generic_decrypt_2->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm( generic_decrypt_2 ) ? generic_decrypt_2->operands[ 1 ].imm.value.u : 0 );
operand = transform::apply(
generic_decrypt_1->operands[ 0 ].size, generic_decrypt_1->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm( generic_decrypt_1 ) ? generic_decrypt_1->operands[ 1 ].imm.value.u : 0 );
}
operand = transform::apply( key_decrypt->operands[ 0 ].size, key_decrypt->mnemonic, operand, rolling_key );
if ( generic_decrypt_0->mnemonic != ZYDIS_MNEMONIC_INVALID )
{
operand = transform::apply(
generic_decrypt_0->operands[ 0 ].size, generic_decrypt_0->mnemonic, operand,
// check to see if this instruction has an IMM...
transform::has_imm( generic_decrypt_0 ) ? generic_decrypt_0->operands[ 1 ].imm.value.u : 0 );
}
return { operand, rolling_key };
}
bool get_rva_decrypt( const zydis_routine_t &vm_entry, std::vector< zydis_decoded_instr_t > &transform_instrs )
{
//
// find mov esi, [rsp+0xA0]
//
auto result =
std::find_if( vm_entry.begin(), vm_entry.end(), []( const zydis_instr_t &instr_data ) -> bool {
if ( instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV && instr_data.instr.operand_count == 2 &&
instr_data.instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_ESI &&
instr_data.instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RSP &&
instr_data.instr.operands[ 1 ].mem.disp.has_displacement &&
instr_data.instr.operands[ 1 ].mem.disp.value == 0xA0 )
return true;
return false;
} );
if ( result == vm_entry.end() )
return false;
//
// find the next three instruction with ESI as the dest...
//
for ( auto idx = 0u; idx < 3; ++idx )
{
result = std::find_if( ++result, vm_entry.end(), []( const zydis_instr_t &instr_data ) -> bool {
return instr_data.instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_ESI;
} );
if ( result == vm_entry.end() )
return false;
transform_instrs.push_back( result->instr );
}
return true;
}
} // namespace instrs
} // namespace vm

@ -100,8 +100,23 @@
</ProjectReference> </ProjectReference>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="vm.cpp" /> <ClCompile Include="calc_jmp.cpp" />
<ClCompile Include="vmctx.cpp" /> <ClCompile Include="vmhandler.cpp" />
<ClCompile Include="vminstrs.cpp" />
<ClCompile Include="vmprofiles\add.cpp" />
<ClCompile Include="vmprofiles\div.cpp" />
<ClCompile Include="vmprofiles\jmp.cpp" />
<ClCompile Include="vmprofiles\lconst.cpp" />
<ClCompile Include="vmprofiles\lreg.cpp" />
<ClCompile Include="vmprofiles\mul.cpp" />
<ClCompile Include="vmprofiles\nand.cpp" />
<ClCompile Include="vmprofiles\pushvsp.cpp" />
<ClCompile Include="vmprofiles\read.cpp" />
<ClCompile Include="vmprofiles\shl.cpp" />
<ClCompile Include="vmprofiles\shr.cpp" />
<ClCompile Include="vmprofiles\sreg.cpp" />
<ClCompile Include="vmprofiles\vmexit.cpp" />
<ClCompile Include="vmprofiles\write.cpp" />
<ClCompile Include="vmutils.cpp" /> <ClCompile Include="vmutils.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -149,9 +164,6 @@
<ClInclude Include="..\dependencies\zydis\msvc\ZycoreExportConfig.h" /> <ClInclude Include="..\dependencies\zydis\msvc\ZycoreExportConfig.h" />
<ClInclude Include="..\dependencies\zydis\msvc\ZydisExportConfig.h" /> <ClInclude Include="..\dependencies\zydis\msvc\ZydisExportConfig.h" />
<ClInclude Include="..\include\transform.hpp" /> <ClInclude Include="..\include\transform.hpp" />
<ClInclude Include="..\include\vm.h" />
<ClInclude Include="..\include\vmctx.h" />
<ClInclude Include="..\include\vmp2.hpp" />
<ClInclude Include="..\include\vmprofiler.hpp" /> <ClInclude Include="..\include\vmprofiler.hpp" />
<ClInclude Include="..\include\vmutils.h" /> <ClInclude Include="..\include\vmutils.h" />
</ItemGroup> </ItemGroup>
@ -160,6 +172,9 @@
<Project>{88a23124-5640-35a0-b890-311d7a67a7d2}</Project> <Project>{88a23124-5640-35a0-b890-311d7a67a7d2}</Project>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="..\.clang-format" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>

@ -24,15 +24,66 @@
<Filter Include="Header Files\Zycore\API"> <Filter Include="Header Files\Zycore\API">
<UniqueIdentifier>{a4d9e340-8f8c-4606-bce8-58b86119c829}</UniqueIdentifier> <UniqueIdentifier>{a4d9e340-8f8c-4606-bce8-58b86119c829}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Source Files\vmprofiles">
<UniqueIdentifier>{388154c1-cb08-493f-88fb-7e16cfffa010}</UniqueIdentifier>
</Filter>
<Filter Include="Resources">
<UniqueIdentifier>{5bb0ecc9-da37-4a13-8958-3c8eef2ceab5}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="vm.cpp"> <ClCompile Include="vmutils.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="vmutils.cpp"> <ClCompile Include="vmprofiles\add.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\div.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\jmp.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\lconst.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\lreg.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\mul.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\nand.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\pushvsp.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\read.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\sreg.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\vmexit.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\write.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\shl.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="vmprofiles\shr.cpp">
<Filter>Source Files\vmprofiles</Filter>
</ClCompile>
<ClCompile Include="calc_jmp.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="vmctx.cpp"> <ClCompile Include="vmhandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vminstrs.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
@ -40,15 +91,6 @@
<ClInclude Include="..\include\transform.hpp"> <ClInclude Include="..\include\transform.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\include\vm.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vmctx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vmp2.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\vmprofiler.hpp"> <ClInclude Include="..\include\vmprofiler.hpp">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -185,4 +227,9 @@
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="..\.clang-format">
<Filter>Resources</Filter>
</None>
</ItemGroup>
</Project> </Project>

@ -0,0 +1,64 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t addq = {
// ADD [RBP+8], RAX
// PUSHFQ
// POP [RBP]
"ADDQ",
ADDQ,
NULL,
{ { // ADD [RBP+8], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.disp.value == 0x8 &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
},
// PUSHFQ
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP;
} } } };
vm::handler::profile_t adddw = {
// ADD [RBP+8], EAX
// PUSHFQ
// POP [RBP]
"ADDDW",
ADDDW,
NULL,
{ { // ADD [RBP+8], EAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.disp.value == 0x8 &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_EAX;
},
// PUSHFQ
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP;
} } } };
} // namespace profile
} // namespace handler
} // namespace vm

@ -0,0 +1,74 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t divq = {
// MOV RDX, [RBP]
// MOV RAX, [RBP+0x8]
// DIV [RBP+0x10]
// MOV [RBP+0x8], RDX
// MOV [RBP+0x10], RAX
// PUSHFQ
// POP [RBP]
"DIVQ",
DIVQ,
NULL,
{ { // MOV RDX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// MOV RAX, [RBP+0x8]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].mem.index == 0x8;
},
// DIV [RBP+0x10]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_DIV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.index == 0x10;
},
// MOV [RBP+0x8], RDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.index == 0x8 &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RDX;
},
// MOV [RBP+0x10], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.index == 0x10 &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
},
// PUSHFQ
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP;
} } } };
}
} // namespace handler
} // namespace vm

@ -0,0 +1,51 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t jmp = {
// MOV ESI, [RBP]
// ADD RSI, RAX
// MOV RBX, RSI
// ADD RSI, [RBP]
"JMP",
JMP,
NULL,
{ { // MOV ESI, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_ESI &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// ADD RSI, RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RSI &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
},
// MOV RBX, RSI
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RSI;
},
// ADD RSI, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RSI &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
} } } };
}
} // namespace handler
} // namespace vm

@ -0,0 +1,162 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t lconstq = {
// MOV RAX, [RSI]
// SUB RBP, 8
// MOV [RBP], RAX
"LCONSTQ",
LCONSTQ,
64,
{ { // SUB RBP, 8
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x8;
},
// MOV [RBP], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
} } } };
vm::handler::profile_t lconstbzxw = {
// MOV AL, [RSI]
// SUB RBP, 2
// MOV [RBP], AX
"LCONSTBZXW",
LCONSTBZXW,
8,
{ { // SUB RBP, 2
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x2;
},
// MOV [RBP], AX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_AX;
} } } };
vm::handler::profile_t lconstbsxdw = {
// CWDE
// SUB RBP, 4
// MOV [RBP], EAX
"LCONSTBSXDW",
LCONSTBSXDW,
8,
{ { // CWDE
[]( const zydis_decoded_instr_t &instr ) -> bool { return instr.mnemonic == ZYDIS_MNEMONIC_CWDE; },
// SUB RBP, 4
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x4;
},
// MOV [RBP], EAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_EAX;
} } },
vm::handler::extention_t::sign_extend };
vm::handler::profile_t lconstdwsxq = {
// CDQE
// SUB RBP, 8
// MOV [RBP], RAX
"LCONSTDWSXQ",
LCONSTDWSXQ,
32,
{ // CDQE
[]( const zydis_decoded_instr_t &instr ) -> bool { return instr.mnemonic == ZYDIS_MNEMONIC_CDQE; },
// SUB RBP, 8
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x8;
},
// MOV [RBP], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
} },
vm::handler::extention_t::sign_extend };
vm::handler::profile_t lconstwsxq = {
// CDQE
// SUB RBP, 8
// MOV [RBP], RAX
"LCONSTWSXQ",
LCONSTWSXQ,
16,
{ { // CDQE
[]( const zydis_decoded_instr_t &instr ) -> bool { return instr.mnemonic == ZYDIS_MNEMONIC_CDQE; },
// SUB RBP, 8
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x8;
},
// MOV [RBP], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
} } },
vm::handler::extention_t::sign_extend };
vm::handler::profile_t lconstdw = {
// SUB RBP, 4
// MOV [RBP], EAX
"LCONSTDW",
LCONSTDW,
32,
{ { // SUB RBP, 4
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x4;
},
// MOV [RBP], EAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_EAX;
} } } };
} // namespace profile
} // namespace handler
} // namespace vm

@ -0,0 +1,81 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t lregq = {
// MOV RDX, [RAX+RDI]
// SUB RBP, 8
// MOV [RBP], RDX
"LREGQ",
LREGQ,
8,
{ { // MOV RDX, [RAX+RDI] or MOV RDX, [RDI+RAX]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
( instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RAX ||
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RDI ) &&
( instr.operands[ 1 ].mem.index == ZYDIS_REGISTER_RDI ||
instr.operands[ 1 ].mem.index == ZYDIS_REGISTER_RAX );
},
// SUB RBP, 8
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x8;
},
// MOV [RBP], RDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RDX;
} } } };
vm::handler::profile_t lregdw = {
// MOVZX AL, [RSI]
// MOV RDX, [RAX + RDI]
// SUB RBP, 0x4
// MOV [RBP], EDX
"LREGDW",
LREGDW,
8,
{ { // MOV RDX, [RAX + RDI] or MOV RDX, [RDI + RAX]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_EDX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
( instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RAX ||
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RDI ) &&
( instr.operands[ 1 ].mem.index == ZYDIS_REGISTER_RAX ||
instr.operands[ 1 ].mem.index == ZYDIS_REGISTER_RDI );
},
// SUB RBP, 0x4
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x4;
},
// MOV [RBP], EDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_EDX;
} } } };
} // namespace profile
} // namespace handler
} // namespace vm

@ -0,0 +1,73 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t mulq = {
// MOV RAX, [RBP+0x8]
// SUB RBP, 0x8
// MUL RDX
// MOV [RBP+0x8], RDX
// MOV [RBP+0x10], RAX
// PUSHFQ
// POP [RBP]
"MULQ",
MULQ,
NULL,
{ { // MOV RAX, [RBP+0x8]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].mem.disp.value == 0x8;
},
// SUB RBP, 0x8
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x8;
},
// MUL RDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MUL &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX;
},
// MOV [RBP+0x8], RDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.disp.value == 0x8 &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RDX;
},
// MOV [RBP+0x10], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.disp.value == 0x10 &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
},
// PUSHFQ
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP;
} } } };
}
} // namespace handler
} // namespace vm

@ -0,0 +1,131 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t nandq = {
// MOV RAX, [RBP]
// MOV RDX, [RBP+8]
// NOT RAX
// NOT RDX
// AND RAX, RDX
// MOV [RBP], RAX
// PUSHFQ
// POP [RBP]
"NANDQ",
NANDQ,
NULL,
{ { // MOV RAX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// MOV RDX, [RBP+8]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].mem.disp.value == 0x8;
},
// NOT RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_NOT &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX;
},
// NOT RDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_NOT &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX;
},
// AND RAX, RDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_AND &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RDX;
},
// MOV [RBP], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
},
// PUSHFQ
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP;
} } } };
vm::handler::profile_t nanddw = {
// NOT DWORD PTR [RBP]
// MOV AX, [RBP]
// SUB RBP, 0x6
// AND [RBP+0x8], AX
// PUSHFQ
// POP [RBP]
"NANDDW",
NANDDW,
NULL,
{ { // NOT DWORD PTR [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_NOT &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].size == 32 &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP;
},
// MOV AX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_AX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// SUB RBP, 0x6
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x6;
},
// AND [RBP+0x8], AX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_AND &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.disp.value == 0x8 &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_AX;
},
// PUSHFQ
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP;
} } } };
} // namespace profile
} // namespace handler
} // namespace vm

@ -0,0 +1,41 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t pushvsp = {
// MOV RAX, RBP
// SUB RBP, 8
"PUSHVSP",
PUSHVSP,
NULL,
{ { // MOV RAX, RBP
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RBP;
},
// SUB RBP, 8
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x8;
},
// MOV [RBP], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
} } } };
}
} // namespace handler
} // namespace vm

@ -0,0 +1,34 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t readq = {
// MOV RAX, [RAX]
// MOV [RBP], RAX
"READQ",
READQ,
NULL,
{ {
// MOV RAX, [RAX]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RAX;
},
// MOV [RBP], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
} } } };
}
} // namespace handler
} // namespace vm

@ -0,0 +1,138 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t shlq = {
// MOV RAX, [RBP]
// MOV CL, [RBP+0x8]
// SUB RBP, 0x6
// SHL RAX, CL
// MOV [RBP+0x8], RAX
// PUSHFQ
// POP [RBP]
"SHLQ",
SHLQ,
NULL,
{ { // MOV RAX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// MOV CL, [RBP+0x8]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_CL &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].mem.disp.value == 0x8;
},
// SUB RBP, 0x6
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x6;
},
// SHL RAX, CL
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SHL &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_CL;
},
// MOV [RBP+0x8], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.disp.value == 0x8 &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
},
// PUSHFQ
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP;
} } } };
vm::handler::profile_t shldw = {
// MOV EAX, [RBP]
// MOV CL, [RBP+0x4]
// SUB RBP, 0x6
// SHL EAX, CL
// MOV [RBP+0x8], EAX
// PUSHFQ
// POP [RBP]
"SHLQ",
SHLQ,
NULL,
{ { // MOV EAX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_EAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// MOV CL, [RBP+0x4]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_CL &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].mem.disp.value == 0x4;
},
// SUB RBP, 0x6
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x6;
},
// SHL EAX, CL
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SHL &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_EAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_CL;
},
// MOV [RBP+0x8], EAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.disp.value == 0x8 &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_EAX;
},
// PUSHFQ
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP;
} } } };
} // namespace profile
} // namespace handler
} // namespace vm

@ -0,0 +1,74 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t shrq = {
// MOV RAX, [RBP]
// MOV CL, [RBP+0x8]
// SUB RBP, 0x6
// SHR RAX, CL
// MOV [RBP+0x8], RAX
// PUSHFQ
// POP [RBP]
"SHRQ",
SHRQ,
NULL,
{ { // MOV RAX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// MOV CL, [RBP+0x8]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_CL &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].mem.disp.value == 0x8;
},
// SUB RBP, 0x6
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SUB &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x6;
},
// SHR RAX, CL
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_SHR &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_CL;
},
// MOV [RBP+0x8], RAX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 0 ].mem.disp.value == 0x8 &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RAX;
},
// PUSHFQ
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_PUSHFQ;
},
// POP [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_POP &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RBP;
} } } };
}
} // namespace handler
} // namespace vm

@ -0,0 +1,115 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t sregq = {
// MOV RDX, [RBP]
// ADD RBP, 8
// MOV [RAX+RDI], RDX
"SREGQ",
SREGQ,
8,
{ { // MOV RDX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// ADD RBP, 8
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 8;
},
// MOV [RAX+RDI], RDX or MOV [RDI+RAX], RDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
( instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RAX ||
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RDI ) &&
( instr.operands[ 0 ].mem.index == ZYDIS_REGISTER_RDI ||
instr.operands[ 0 ].mem.index == ZYDIS_REGISTER_RAX ) &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RDX;
} } } };
vm::handler::profile_t sregdw = {
// MOV EDX, [RBP]
// ADD RBP, 0x4
// MOV [RAX+RDI], EDX
"SREGDW",
SREGDW,
8,
{ { // MOV EDX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_EDX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// ADD RBP, 0x4
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x4;
},
// MOV [RAX+RDI], EDX or MOV [RDI+RAX], EDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
( instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RAX ||
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RDI ) &&
( instr.operands[ 0 ].mem.index == ZYDIS_REGISTER_RAX ||
instr.operands[ 0 ].mem.index == ZYDIS_REGISTER_RDI ) &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_EDX;
} } } };
vm::handler::profile_t sregw = {
// MOV DX, [RBP]
// ADD RBP, 0x2
// MOV [RAX+RDI], DX
"SREGW",
SREGW,
8,
{ { // MOV DX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_DX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// ADD RBP, 0x2
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x2;
},
// MOV [RAX+RDI], DX or MOV [RDI+RAX], DX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
( instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RAX ||
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RDI ) &&
( instr.operands[ 0 ].mem.index == ZYDIS_REGISTER_RDI ||
instr.operands[ 0 ].mem.index == ZYDIS_REGISTER_RAX ) &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_DX;
} } } };
} // namespace profile
} // namespace handler
} // namespace vm

@ -0,0 +1,32 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t vmexit = {
// MOV RAX, RBP
// POPFQ
// RET
"VMEXIT",
VMEXIT,
NULL,
{ { // MOV RAX, RBP
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RBP;
},
// POPFQ
[]( const zydis_decoded_instr_t &instr ) -> bool { return instr.mnemonic == ZYDIS_MNEMONIC_POPFQ; },
// RET
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_RET;
} } } };
}
} // namespace handler
} // namespace vm

@ -0,0 +1,94 @@
#include "../../include/vmprofiler.hpp"
namespace vm
{
namespace handler
{
namespace profile
{
vm::handler::profile_t writeq = {
// MOV RAX, [RBP]
// MOV RDX, [RBP+0x8]
// ADD RBP, 0x10
// MOV [RAX], RDX
"WRITEQ",
WRITEQ,
NULL,
{ { // MOV RAX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// MOV RDX, [RBP+0x8]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RDX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].mem.disp.value == 0x8;
},
// ADD RBP, 0x10
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0x10;
},
// MOV [RAX], RDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_RDX;
} } } };
vm::handler::profile_t writedw = {
// MOV RAX, [RBP]
// MOV EDX, [RBP+0x8]
// ADD RBP, 0xC
// MOV [RAX], EDX
"WRITEDW",
WRITEDW,
NULL,
{ { // MOV RAX, [RBP]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP;
},
// MOV EDX, [RBP+0x8]
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_EDX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].mem.disp.value == 0x8;
},
// ADD RBP, 0xC
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 0 ].reg.value == ZYDIS_REGISTER_RBP &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
instr.operands[ 1 ].imm.value.u == 0xC;
},
// MOV [RAX], EDX
[]( const zydis_decoded_instr_t &instr ) -> bool {
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
instr.operands[ 0 ].mem.base == ZYDIS_REGISTER_RAX &&
instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
instr.operands[ 1 ].reg.value == ZYDIS_REGISTER_EDX;
} } } };
} // namespace profile
} // namespace handler
} // namespace vm

@ -7,131 +7,23 @@ namespace vm
{ {
namespace reg namespace reg
{ {
ZydisRegister to64(ZydisRegister reg) zydis_register_t to64( zydis_register_t reg )
{ {
switch (reg) return ZydisRegisterGetLargestEnclosing( ZYDIS_MACHINE_MODE_LONG_64, reg );
{
case ZYDIS_REGISTER_AL:
return ZYDIS_REGISTER_RAX;
case ZYDIS_REGISTER_CL:
return ZYDIS_REGISTER_RCX;
case ZYDIS_REGISTER_DL:
return ZYDIS_REGISTER_RDX;
case ZYDIS_REGISTER_BL:
return ZYDIS_REGISTER_RBX;
case ZYDIS_REGISTER_AH:
return ZYDIS_REGISTER_RAX;
case ZYDIS_REGISTER_CH:
return ZYDIS_REGISTER_RCX;
case ZYDIS_REGISTER_DH:
return ZYDIS_REGISTER_RDX;
case ZYDIS_REGISTER_BH:
return ZYDIS_REGISTER_RBX;
case ZYDIS_REGISTER_SPL:
return ZYDIS_REGISTER_RSP;
case ZYDIS_REGISTER_BPL:
return ZYDIS_REGISTER_RBP;
case ZYDIS_REGISTER_SIL:
return ZYDIS_REGISTER_RSI;
case ZYDIS_REGISTER_DIL:
return ZYDIS_REGISTER_RDI;
case ZYDIS_REGISTER_R8B:
return ZYDIS_REGISTER_R8;
case ZYDIS_REGISTER_R9B:
return ZYDIS_REGISTER_R9;
case ZYDIS_REGISTER_R10B:
return ZYDIS_REGISTER_R10;
case ZYDIS_REGISTER_R11B:
return ZYDIS_REGISTER_R11;
case ZYDIS_REGISTER_R12B:
return ZYDIS_REGISTER_R12;
case ZYDIS_REGISTER_R13B:
return ZYDIS_REGISTER_R13;
case ZYDIS_REGISTER_R14B:
return ZYDIS_REGISTER_R14;
case ZYDIS_REGISTER_R15B:
return ZYDIS_REGISTER_R15;
case ZYDIS_REGISTER_AX:
return ZYDIS_REGISTER_RAX;
case ZYDIS_REGISTER_CX:
return ZYDIS_REGISTER_RCX;
case ZYDIS_REGISTER_DX:
return ZYDIS_REGISTER_RDX;
case ZYDIS_REGISTER_BX:
return ZYDIS_REGISTER_RBX;
case ZYDIS_REGISTER_SP:
return ZYDIS_REGISTER_RSP;
case ZYDIS_REGISTER_BP:
return ZYDIS_REGISTER_RBP;
case ZYDIS_REGISTER_SI:
return ZYDIS_REGISTER_RSI;
case ZYDIS_REGISTER_DI:
return ZYDIS_REGISTER_RDI;
case ZYDIS_REGISTER_R8W:
return ZYDIS_REGISTER_R8;
case ZYDIS_REGISTER_R9W:
return ZYDIS_REGISTER_R9;
case ZYDIS_REGISTER_R10W:
return ZYDIS_REGISTER_R10;
case ZYDIS_REGISTER_R11W:
return ZYDIS_REGISTER_R11;
case ZYDIS_REGISTER_R12W:
return ZYDIS_REGISTER_R12;
case ZYDIS_REGISTER_R13W:
return ZYDIS_REGISTER_R13;
case ZYDIS_REGISTER_R14W:
return ZYDIS_REGISTER_R14;
case ZYDIS_REGISTER_R15W:
return ZYDIS_REGISTER_R15;
case ZYDIS_REGISTER_EAX:
return ZYDIS_REGISTER_RAX;
case ZYDIS_REGISTER_ECX:
return ZYDIS_REGISTER_RCX;
case ZYDIS_REGISTER_EDX:
return ZYDIS_REGISTER_RDX;
case ZYDIS_REGISTER_EBX:
return ZYDIS_REGISTER_RBX;
case ZYDIS_REGISTER_ESP:
return ZYDIS_REGISTER_RSP;
case ZYDIS_REGISTER_EBP:
return ZYDIS_REGISTER_RBP;
case ZYDIS_REGISTER_ESI:
return ZYDIS_REGISTER_RSI;
case ZYDIS_REGISTER_EDI:
return ZYDIS_REGISTER_RDI;
case ZYDIS_REGISTER_R8D:
return ZYDIS_REGISTER_R8;
case ZYDIS_REGISTER_R9D:
return ZYDIS_REGISTER_R9;
case ZYDIS_REGISTER_R10D:
return ZYDIS_REGISTER_R10;
case ZYDIS_REGISTER_R11D:
return ZYDIS_REGISTER_R11;
case ZYDIS_REGISTER_R12D:
return ZYDIS_REGISTER_R12;
case ZYDIS_REGISTER_R13D:
return ZYDIS_REGISTER_R13;
case ZYDIS_REGISTER_R14D:
return ZYDIS_REGISTER_R14;
case ZYDIS_REGISTER_R15D:
return ZYDIS_REGISTER_R15;
}
return reg;
} }
bool compare(ZydisRegister a, ZydisRegister b) bool compare( zydis_register_t a, zydis_register_t b )
{ {
return to64( a ) == to64( b ); return to64( a ) == to64( b );
} }
} } // namespace reg
void print(const ZydisDecodedInstruction& instr) void print( const zydis_decoded_instr_t &instr )
{ {
char buffer[ 256 ]; char buffer[ 256 ];
ZydisFormatter formatter; ZydisFormatter formatter;
ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_INTEL ); ZydisFormatterInit( &formatter, ZYDIS_FORMATTER_STYLE_INTEL );
ZydisFormatterFormatInstruction(&formatter, &instr, ZydisFormatterFormatInstruction( &formatter, &instr, buffer, sizeof( buffer ), 0u );
buffer, sizeof(buffer), 0u);
puts( buffer ); puts( buffer );
} }
@ -145,14 +37,13 @@ namespace vm
for ( auto [ instr, raw, addr ] : routine ) for ( auto [ instr, raw, addr ] : routine )
{ {
std::printf( "> 0x%p ", addr ); std::printf( "> 0x%p ", addr );
ZydisFormatterFormatInstruction(&formatter, &instr, ZydisFormatterFormatInstruction( &formatter, &instr, buffer, sizeof( buffer ), addr );
buffer, sizeof(buffer), addr);
puts( buffer ); puts( buffer );
} }
} }
bool is_jmp(const ZydisDecodedInstruction& instr) bool is_jmp( const zydis_decoded_instr_t &instr )
{ {
switch ( instr.mnemonic ) switch ( instr.mnemonic )
{ {
@ -188,16 +79,14 @@ namespace vm
bool flatten( zydis_routine_t &routine, std::uintptr_t routine_addr, bool keep_jmps ) bool flatten( zydis_routine_t &routine, std::uintptr_t routine_addr, bool keep_jmps )
{ {
ZydisDecoder decoder; ZydisDecoder decoder;
ZydisDecodedInstruction instr; zydis_decoded_instr_t instr;
ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64 ); ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64 );
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, reinterpret_cast<void*>( while ( ZYAN_SUCCESS(
routine_addr), 0x1000, &instr))) ZydisDecoderDecodeBuffer( &decoder, reinterpret_cast< void * >( routine_addr ), 0x1000, &instr ) ) )
{ {
std::vector< u8 > raw_instr; std::vector< u8 > raw_instr;
raw_instr.insert(raw_instr.begin(), raw_instr.insert( raw_instr.begin(), ( u8 * )routine_addr, ( u8 * )routine_addr + instr.length );
(u8*)routine_addr,
(u8*)routine_addr + instr.length);
if ( is_jmp( instr ) ) if ( is_jmp( instr ) )
{ {
@ -228,9 +117,7 @@ namespace vm
void deobfuscate( zydis_routine_t &routine ) void deobfuscate( zydis_routine_t &routine )
{ {
static const auto _uses = static const auto _uses = []( ZydisDecodedOperand &op, zydis_register_t reg ) -> bool {
[](ZydisDecodedOperand& op, ZydisRegister reg) -> bool
{
switch ( op.type ) switch ( op.type )
{ {
case ZYDIS_OPERAND_TYPE_MEMORY: case ZYDIS_OPERAND_TYPE_MEMORY:
@ -246,9 +133,7 @@ namespace vm
return false; return false;
}; };
static const auto _writes = static const auto _writes = []( zydis_decoded_instr_t &inst ) -> bool {
[](ZydisDecodedInstruction& inst) -> bool
{
for ( auto idx = 0; idx < inst.operand_count; ++idx ) for ( auto idx = 0; idx < inst.operand_count; ++idx )
if ( inst.operands[ idx ].actions & ZYDIS_OPERAND_ACTION_MASK_WRITE ) if ( inst.operands[ idx ].actions & ZYDIS_OPERAND_ACTION_MASK_WRITE )
return true; return true;
@ -256,10 +141,8 @@ namespace vm
return false; return false;
}; };
static const auto _remove = static const auto _remove = []( zydis_routine_t &routine, zydis_routine_t::iterator itr,
[](zydis_routine_t& routine, zydis_routine_t::iterator itr, zydis_register_t reg, u32 opcode_size ) -> void {
ZydisRegister reg, u32 opcode_size) -> void
{
for ( ; itr >= routine.begin(); --itr ) for ( ; itr >= routine.begin(); --itr )
{ {
const auto instruction = &itr->instr; const auto instruction = &itr->instr;
@ -286,26 +169,26 @@ namespace vm
if ( op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE ) if ( op->actions & ZYDIS_OPERAND_ACTION_MASK_WRITE )
op->actions &= ~ZYDIS_OPERAND_ACTION_MASK_WRITE; op->actions &= ~ZYDIS_OPERAND_ACTION_MASK_WRITE;
else stop = true; else
stop = true;
} }
if ( !_writes( *instruction ) ) if ( !_writes( *instruction ) )
routine.erase( itr ); routine.erase( itr );
else if (stop) break; else if ( stop )
break;
} }
}; };
for ( const auto &instr_data : routine ) for ( const auto &instr_data : routine )
{ {
if (routine.empty() || routine.size() == 1 || if ( routine.empty() || routine.size() == 1 || instr_data.instr.mnemonic == ZYDIS_MNEMONIC_JMP )
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_JMP)
continue; continue;
for ( auto itr = routine.begin() + 1; itr != routine.end(); itr++ ) for ( auto itr = routine.begin() + 1; itr != routine.end(); itr++ )
{ {
if (itr->instr.mnemonic == ZYDIS_MNEMONIC_JMP || if ( itr->instr.mnemonic == ZYDIS_MNEMONIC_JMP || itr->instr.mnemonic == ZYDIS_MNEMONIC_RET )
itr->instr.mnemonic == ZYDIS_MNEMONIC_RET)
break; break;
// find the write operations that happen... // find the write operations that happen...
@ -330,5 +213,5 @@ namespace vm
} }
} }
} }
} } // namespace util
} } // namespace vm
Loading…
Cancel
Save