Dev See merge request vmp2/vmprofiler!2merge-requests/3/merge v1.4
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,202 +1,213 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <Zydis/Zydis.h>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <vmutils.h>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
namespace transform
|
||||
{
|
||||
// taken from ida...
|
||||
template<class T> inline T __ROL__(T value, int count)
|
||||
{
|
||||
const unsigned int nbits = sizeof(T) * 8;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
count %= nbits;
|
||||
T high = value >> (nbits - count);
|
||||
if (T(-1) < 0) // signed value
|
||||
high &= ~((T(-1) << count));
|
||||
value <<= count;
|
||||
value |= high;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = -count % nbits;
|
||||
T low = value << (nbits - count);
|
||||
value >>= count;
|
||||
value |= low;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// taken from ida...
|
||||
inline u8 __ROL1__(u8 value, int count) { return __ROL__((u8)value, 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); }
|
||||
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
|
||||
{
|
||||
generic0,
|
||||
rolling_key,
|
||||
generic1,
|
||||
generic2,
|
||||
generic3,
|
||||
update_key
|
||||
};
|
||||
|
||||
using map_t = std::map<transform::type, ZydisDecodedInstruction>;
|
||||
|
||||
template <class T>
|
||||
inline const auto _bswap = [](T a, T b) -> T
|
||||
{
|
||||
if constexpr (std::is_same_v<T, std::uint64_t>)
|
||||
return _byteswap_uint64(a);
|
||||
if constexpr (std::is_same_v<T, std::uint32_t>)
|
||||
return _byteswap_ulong(a);
|
||||
if constexpr (std::is_same_v<T, std::uint16_t>)
|
||||
return _byteswap_ushort(a);
|
||||
|
||||
throw std::invalid_argument("invalid type size...");
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const auto _add = [](T a, T b) -> T
|
||||
{
|
||||
return a + b;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const auto _xor = [](T a, T b) -> T
|
||||
{
|
||||
return a ^ b;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const auto _sub = [](T a, T b) -> T
|
||||
{
|
||||
return a - b;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const auto _neg = [](T a, T b) -> T
|
||||
{
|
||||
return a * -1;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const auto _not = [](T a, T b) -> T
|
||||
{
|
||||
return ~a;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const auto _ror = [](T a, T b) -> T
|
||||
{
|
||||
if constexpr (std::is_same_v<T, std::uint64_t>)
|
||||
return __ROR8__(a, b);
|
||||
if constexpr (std::is_same_v<T, std::uint32_t>)
|
||||
return __ROR4__(a, b);
|
||||
if constexpr (std::is_same_v<T, std::uint16_t>)
|
||||
return __ROR2__(a, b);
|
||||
if constexpr (std::is_same_v <T, std::uint8_t>)
|
||||
return __ROR1__(a, b);
|
||||
|
||||
throw std::invalid_argument("invalid type size...");
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const auto _rol = [](T a, T b) -> T
|
||||
{
|
||||
if constexpr (std::is_same_v<T, std::uint64_t>)
|
||||
return __ROL8__(a, b);
|
||||
if constexpr (std::is_same_v<T, std::uint32_t>)
|
||||
return __ROL4__(a, b);
|
||||
if constexpr (std::is_same_v<T, std::uint16_t>)
|
||||
return __ROL2__(a, b);
|
||||
if constexpr (std::is_same_v <T, std::uint8_t>)
|
||||
return __ROL1__(a, b);
|
||||
|
||||
throw std::invalid_argument("invalid type size...");
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const auto _inc = [](T a, T b) -> T
|
||||
{
|
||||
return a + 1;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const auto _dec = [](T a, T b) -> T
|
||||
{
|
||||
return a - 1;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
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_SUB, _sub<T>},
|
||||
{ ZYDIS_MNEMONIC_NEG, _neg<T>},
|
||||
{ ZYDIS_MNEMONIC_NOT, _not<T>},
|
||||
{ ZYDIS_MNEMONIC_ROR, _ror<T>},
|
||||
{ ZYDIS_MNEMONIC_ROL, _rol<T>},
|
||||
{ ZYDIS_MNEMONIC_INC, _inc<T>},
|
||||
{ ZYDIS_MNEMONIC_DEC, _dec<T>}
|
||||
};
|
||||
|
||||
inline std::map<ZydisMnemonic, ZydisMnemonic> inverse =
|
||||
{
|
||||
{ZYDIS_MNEMONIC_ADD, ZYDIS_MNEMONIC_SUB},
|
||||
{ZYDIS_MNEMONIC_XOR, ZYDIS_MNEMONIC_XOR},
|
||||
{ZYDIS_MNEMONIC_BSWAP, ZYDIS_MNEMONIC_BSWAP},
|
||||
{ZYDIS_MNEMONIC_SUB, ZYDIS_MNEMONIC_ADD},
|
||||
{ZYDIS_MNEMONIC_NEG, ZYDIS_MNEMONIC_NEG},
|
||||
{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
|
||||
// the number of bits in bitsize, the transformation is applied,
|
||||
// finally the result is converted back to 64bits... zero extended...
|
||||
inline auto apply(std::uint8_t bitsize, ZydisMnemonic op,
|
||||
std::uint64_t a, std::uint64_t b) -> std::uint64_t
|
||||
{
|
||||
switch (bitsize)
|
||||
{
|
||||
case 8:
|
||||
return transforms<std::uint8_t>[op](a, b);
|
||||
case 16:
|
||||
return transforms<std::uint16_t>[op](a, b);
|
||||
case 32:
|
||||
return transforms<std::uint32_t>[op](a, b);
|
||||
case 64:
|
||||
return transforms<std::uint64_t>[op](a, b);
|
||||
default:
|
||||
throw std::invalid_argument("invalid bit size...");
|
||||
}
|
||||
}
|
||||
|
||||
inline bool has_imm(ZydisDecodedInstruction* instr)
|
||||
{
|
||||
return instr->operand_count > 1 &&
|
||||
(instr->operands[1].type & ZYDIS_OPERAND_TYPE_IMMEDIATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace transform
|
||||
{
|
||||
// taken from ida...
|
||||
template < class T > inline T __ROL__( T value, int count )
|
||||
{
|
||||
const unsigned int nbits = sizeof( T ) * 8;
|
||||
|
||||
if ( count > 0 )
|
||||
{
|
||||
count %= nbits;
|
||||
T high = value >> ( nbits - count );
|
||||
if ( T( -1 ) < 0 ) // signed value
|
||||
high &= ~( ( T( -1 ) << count ) );
|
||||
value <<= count;
|
||||
value |= high;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = -count % nbits;
|
||||
T low = value << ( nbits - count );
|
||||
value >>= count;
|
||||
value |= low;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// taken from ida...
|
||||
inline u8 __ROL1__( u8 value, int count )
|
||||
{
|
||||
return __ROL__( ( u8 )value, 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 );
|
||||
}
|
||||
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
|
||||
{
|
||||
generic0,
|
||||
rolling_key,
|
||||
generic1,
|
||||
generic2,
|
||||
generic3,
|
||||
update_key
|
||||
};
|
||||
|
||||
using map_t = std::map< transform::type, zydis_decoded_instr_t >;
|
||||
|
||||
template < class T >
|
||||
inline const auto _bswap = []( T a, T b ) -> T {
|
||||
if constexpr ( std::is_same_v< T, std::uint64_t > )
|
||||
return _byteswap_uint64( a );
|
||||
if constexpr ( std::is_same_v< T, std::uint32_t > )
|
||||
return _byteswap_ulong( a );
|
||||
if constexpr ( std::is_same_v< T, std::uint16_t > )
|
||||
return _byteswap_ushort( a );
|
||||
|
||||
throw std::invalid_argument( "invalid type size..." );
|
||||
};
|
||||
|
||||
template < class T > inline const auto _add = []( T a, T b ) -> T { return a + b; };
|
||||
|
||||
template < class T > inline const auto _xor = []( T a, T b ) -> T { return a ^ b; };
|
||||
|
||||
template < class T > inline const auto _sub = []( T a, T b ) -> T { return a - b; };
|
||||
|
||||
template < class T > inline const auto _neg = []( T a, T b ) -> T { return a * -1; };
|
||||
|
||||
template < class T > inline const auto _not = []( T a, T b ) -> T { return ~a; };
|
||||
|
||||
template < class T >
|
||||
inline const auto _ror = []( T a, T b ) -> T {
|
||||
if constexpr ( std::is_same_v< T, std::uint64_t > )
|
||||
return __ROR8__( a, b );
|
||||
if constexpr ( std::is_same_v< T, std::uint32_t > )
|
||||
return __ROR4__( a, b );
|
||||
if constexpr ( std::is_same_v< T, std::uint16_t > )
|
||||
return __ROR2__( a, b );
|
||||
if constexpr ( std::is_same_v< T, std::uint8_t > )
|
||||
return __ROR1__( a, b );
|
||||
|
||||
throw std::invalid_argument( "invalid type size..." );
|
||||
};
|
||||
|
||||
template < class T >
|
||||
inline const auto _rol = []( T a, T b ) -> T {
|
||||
if constexpr ( std::is_same_v< T, std::uint64_t > )
|
||||
return __ROL8__( a, b );
|
||||
if constexpr ( std::is_same_v< T, std::uint32_t > )
|
||||
return __ROL4__( a, b );
|
||||
if constexpr ( std::is_same_v< T, std::uint16_t > )
|
||||
return __ROL2__( a, b );
|
||||
if constexpr ( std::is_same_v< T, std::uint8_t > )
|
||||
return __ROL1__( a, b );
|
||||
|
||||
throw std::invalid_argument( "invalid type size..." );
|
||||
};
|
||||
|
||||
template < class T > inline const auto _inc = []( T a, T b ) -> T { return a + 1; };
|
||||
|
||||
template < class T > inline const auto _dec = []( T a, T b ) -> T { return a - 1; };
|
||||
|
||||
template < class T >
|
||||
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_SUB, _sub< T > }, { ZYDIS_MNEMONIC_NEG, _neg< T > }, { ZYDIS_MNEMONIC_NOT, _not< T > },
|
||||
{ ZYDIS_MNEMONIC_ROR, _ror< T > }, { ZYDIS_MNEMONIC_ROL, _rol< T > }, { ZYDIS_MNEMONIC_INC, _inc< T > },
|
||||
{ ZYDIS_MNEMONIC_DEC, _dec< T > } };
|
||||
|
||||
inline std::map< ZydisMnemonic, ZydisMnemonic > inverse = {
|
||||
{ ZYDIS_MNEMONIC_ADD, ZYDIS_MNEMONIC_SUB }, { ZYDIS_MNEMONIC_XOR, ZYDIS_MNEMONIC_XOR },
|
||||
{ ZYDIS_MNEMONIC_BSWAP, ZYDIS_MNEMONIC_BSWAP }, { ZYDIS_MNEMONIC_SUB, ZYDIS_MNEMONIC_ADD },
|
||||
{ ZYDIS_MNEMONIC_NEG, ZYDIS_MNEMONIC_NEG }, { 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 } };
|
||||
|
||||
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 auto inverse_transform( std::vector< zydis_decoded_instr_t > &instrs ) -> bool
|
||||
{
|
||||
for ( auto idx = 0u; idx < instrs.size() - 1; ++idx )
|
||||
if ( !( instrs[ idx ].mnemonic = inverse[ instrs[ idx ].mnemonic ] ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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,
|
||||
// finally the result is converted back to 64bits... zero extended...
|
||||
inline auto apply( std::uint8_t bitsize, ZydisMnemonic op, std::uint64_t a, std::uint64_t b ) -> std::uint64_t
|
||||
{
|
||||
switch ( bitsize )
|
||||
{
|
||||
case 8:
|
||||
return transforms< std::uint8_t >[ op ]( a, b );
|
||||
case 16:
|
||||
return transforms< std::uint16_t >[ op ]( a, b );
|
||||
case 32:
|
||||
return transforms< std::uint32_t >[ op ]( a, b );
|
||||
case 64:
|
||||
return transforms< std::uint64_t >[ op ]( a, b );
|
||||
default:
|
||||
throw std::invalid_argument( "invalid bit size..." );
|
||||
}
|
||||
}
|
||||
|
||||
inline bool has_imm( zydis_decoded_instr_t *instr )
|
||||
{
|
||||
return instr->operand_count > 1 && ( 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,72 +1,72 @@
|
||||
#pragma once
|
||||
#include "vm.h"
|
||||
#include <vmprofiler.hpp>
|
||||
|
||||
namespace vmp2
|
||||
{
|
||||
enum class exec_type_t
|
||||
{
|
||||
forward,
|
||||
backward
|
||||
};
|
||||
enum class exec_type_t
|
||||
{
|
||||
forward,
|
||||
backward
|
||||
};
|
||||
|
||||
enum class version_t
|
||||
{
|
||||
invalid,
|
||||
v1 = 0x101
|
||||
};
|
||||
enum class version_t
|
||||
{
|
||||
invalid,
|
||||
v1 = 0x101
|
||||
};
|
||||
|
||||
struct file_header
|
||||
{
|
||||
u32 magic; // VMP2
|
||||
u64 epoch_time;
|
||||
u64 module_base;
|
||||
exec_type_t advancement;
|
||||
version_t version;
|
||||
struct file_header
|
||||
{
|
||||
u32 magic; // VMP2
|
||||
u64 epoch_time;
|
||||
u64 module_base;
|
||||
exec_type_t advancement;
|
||||
version_t version;
|
||||
|
||||
u32 entry_count;
|
||||
u32 entry_offset;
|
||||
};
|
||||
u32 entry_count;
|
||||
u32 entry_offset;
|
||||
};
|
||||
|
||||
struct entry_t
|
||||
{
|
||||
u8 handler_idx;
|
||||
u64 decrypt_key;
|
||||
u64 vip;
|
||||
struct entry_t
|
||||
{
|
||||
u8 handler_idx;
|
||||
u64 decrypt_key;
|
||||
u64 vip;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u64 r15;
|
||||
u64 r14;
|
||||
u64 r13;
|
||||
u64 r12;
|
||||
u64 r11;
|
||||
u64 r10;
|
||||
u64 r9;
|
||||
u64 r8;
|
||||
u64 rbp;
|
||||
u64 rdi;
|
||||
u64 rsi;
|
||||
u64 rdx;
|
||||
u64 rcx;
|
||||
u64 rbx;
|
||||
u64 rax;
|
||||
u64 rflags;
|
||||
};
|
||||
u64 raw[16];
|
||||
} regs;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u64 r15;
|
||||
u64 r14;
|
||||
u64 r13;
|
||||
u64 r12;
|
||||
u64 r11;
|
||||
u64 r10;
|
||||
u64 r9;
|
||||
u64 r8;
|
||||
u64 rbp;
|
||||
u64 rdi;
|
||||
u64 rsi;
|
||||
u64 rdx;
|
||||
u64 rcx;
|
||||
u64 rbx;
|
||||
u64 rax;
|
||||
u64 rflags;
|
||||
};
|
||||
u64 raw[ 16 ];
|
||||
} regs;
|
||||
|
||||
union
|
||||
{
|
||||
u64 qword[0x28];
|
||||
u8 raw[0x140];
|
||||
} vregs;
|
||||
union
|
||||
{
|
||||
u64 qword[ 0x28 ];
|
||||
u8 raw[ 0x140 ];
|
||||
} vregs;
|
||||
|
||||
union
|
||||
{
|
||||
u64 qword[0x20];
|
||||
u8 raw[0x100];
|
||||
} vsp;
|
||||
};
|
||||
}
|
||||
union
|
||||
{
|
||||
u64 qword[ 0x20 ];
|
||||
u8 raw[ 0x100 ];
|
||||
} vsp;
|
||||
};
|
||||
} // namespace vmp2
|
@ -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
|
@ -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
|
Loading…
Reference in new issue