VMProfiler  v1.8
vmprofiler is a c++ library which is used to statically analyze VMProtect 2 polymorphic virtual machines. This project is inherited in vmprofiler-qt, vmprofiler-cli, and vmemu.
transform.hpp
Go to the documentation of this file.
1 #pragma once
2 #include <Zydis/Zydis.h>
3 #include <functional>
4 #include <map>
5 #include <stdexcept>
6 #include <vmutils.hpp>
7 
8 namespace vm::transform
9 {
17  template < class T > inline T __ROL__( T value, int count )
18  {
19  const unsigned int nbits = sizeof( T ) * 8;
20 
21  if ( count > 0 )
22  {
23  count %= nbits;
24  T high = value >> ( nbits - count );
25  if ( T( -1 ) < 0 ) // signed value
26  high &= ~( ( T( -1 ) << count ) );
27  value <<= count;
28  value |= high;
29  }
30  else
31  {
32  count = -count % nbits;
33  T low = value << ( nbits - count );
34  value >>= count;
35  value |= low;
36  }
37  return value;
38  }
39 
46  inline u8 __ROL1__( u8 value, int count )
47  {
48  return __ROL__( ( u8 )value, count );
49  }
50 
57  inline u16 __ROL2__( u16 value, int count )
58  {
59  return __ROL__( ( u16 )value, count );
60  }
61 
68  inline u32 __ROL4__( u32 value, int count )
69  {
70  return __ROL__( ( u32 )value, count );
71  }
72 
79  inline u64 __ROL8__( u64 value, int count )
80  {
81  return __ROL__( ( u64 )value, count );
82  }
83 
90  inline u8 __ROR1__( u8 value, int count )
91  {
92  return __ROL__( ( u8 )value, -count );
93  }
94 
101  inline u16 __ROR2__( u16 value, int count )
102  {
103  return __ROL__( ( u16 )value, -count );
104  }
105 
112  inline u32 __ROR4__( u32 value, int count )
113  {
114  return __ROL__( ( u32 )value, -count );
115  }
116 
123  inline u64 __ROR8__( u64 value, int count )
124  {
125  return __ROL__( ( u64 )value, -count );
126  }
127 
132  template < typename T > using transform_t = std::function< T( T, T ) >;
133 
137  enum class type
138  {
139  generic0,
140  rolling_key,
141  generic1,
142  generic2,
143  generic3,
144  update_key
145  };
146 
150  using map_t = std::map< transform::type, zydis_decoded_instr_t >;
151 
152  template < class T >
153  inline const auto _bswap = []( T a, T b ) -> T {
154  if constexpr ( std::is_same_v< T, std::uint64_t > )
155  return _byteswap_uint64( a );
156  if constexpr ( std::is_same_v< T, std::uint32_t > )
157  return _byteswap_ulong( a );
158  if constexpr ( std::is_same_v< T, std::uint16_t > )
159  return _byteswap_ushort( a );
160 
161  throw std::invalid_argument( "invalid type size..." );
162  };
163 
164  template < class T > inline const auto _add = []( T a, T b ) -> T { return a + b; };
165 
166  template < class T > inline const auto _xor = []( T a, T b ) -> T { return a ^ b; };
167 
168  template < class T > inline const auto _sub = []( T a, T b ) -> T { return a - b; };
169 
170  template < class T > inline const auto _neg = []( T a, T b ) -> T { return a * -1; };
171 
172  template < class T > inline const auto _not = []( T a, T b ) -> T { return ~a; };
173 
174  template < class T >
175  inline const auto _ror = []( T a, T b ) -> T {
176  if constexpr ( std::is_same_v< T, std::uint64_t > )
177  return __ROR8__( a, b );
178  if constexpr ( std::is_same_v< T, std::uint32_t > )
179  return __ROR4__( a, b );
180  if constexpr ( std::is_same_v< T, std::uint16_t > )
181  return __ROR2__( a, b );
182  if constexpr ( std::is_same_v< T, std::uint8_t > )
183  return __ROR1__( a, b );
184 
185  throw std::invalid_argument( "invalid type size..." );
186  };
187 
188  template < class T >
189  inline const auto _rol = []( T a, T b ) -> T {
190  if constexpr ( std::is_same_v< T, std::uint64_t > )
191  return __ROL8__( a, b );
192  if constexpr ( std::is_same_v< T, std::uint32_t > )
193  return __ROL4__( a, b );
194  if constexpr ( std::is_same_v< T, std::uint16_t > )
195  return __ROL2__( a, b );
196  if constexpr ( std::is_same_v< T, std::uint8_t > )
197  return __ROL1__( a, b );
198 
199  throw std::invalid_argument( "invalid type size..." );
200  };
201 
202  template < class T > inline const auto _inc = []( T a, T b ) -> T { return a + 1; };
203 
204  template < class T > inline const auto _dec = []( T a, T b ) -> T { return a - 1; };
205 
206  template < class T >
207  inline std::map< zydis_mnemonic_t, transform_t< T > > transforms = {
208  { ZYDIS_MNEMONIC_ADD, _add< T > }, { ZYDIS_MNEMONIC_XOR, _xor< T > }, { ZYDIS_MNEMONIC_BSWAP, _bswap< T > },
209  { ZYDIS_MNEMONIC_SUB, _sub< T > }, { ZYDIS_MNEMONIC_NEG, _neg< T > }, { ZYDIS_MNEMONIC_NOT, _not< T > },
210  { ZYDIS_MNEMONIC_ROR, _ror< T > }, { ZYDIS_MNEMONIC_ROL, _rol< T > }, { ZYDIS_MNEMONIC_INC, _inc< T > },
211  { ZYDIS_MNEMONIC_DEC, _dec< T > } };
212 
213  inline std::map< zydis_mnemonic_t, zydis_mnemonic_t > inverse = {
214  { ZYDIS_MNEMONIC_ADD, ZYDIS_MNEMONIC_SUB }, { ZYDIS_MNEMONIC_XOR, ZYDIS_MNEMONIC_XOR },
215  { ZYDIS_MNEMONIC_BSWAP, ZYDIS_MNEMONIC_BSWAP }, { ZYDIS_MNEMONIC_SUB, ZYDIS_MNEMONIC_ADD },
216  { ZYDIS_MNEMONIC_NEG, ZYDIS_MNEMONIC_NEG }, { ZYDIS_MNEMONIC_NOT, ZYDIS_MNEMONIC_NOT },
217  { ZYDIS_MNEMONIC_ROR, ZYDIS_MNEMONIC_ROL }, { ZYDIS_MNEMONIC_ROL, ZYDIS_MNEMONIC_ROR },
218  { ZYDIS_MNEMONIC_INC, ZYDIS_MNEMONIC_DEC }, { ZYDIS_MNEMONIC_DEC, ZYDIS_MNEMONIC_INC } };
219 
225  inline bool valid( zydis_mnemonic_t op )
226  {
227  return transforms< std::uint64_t >.find( op ) != transforms< std::uint64_t >.end();
228  }
229 
236  {
238  inverse[ transform::type::generic0 ].mnemonic =
240 
244 
246  inverse[ transform::type::generic1 ].mnemonic =
248 
250  inverse[ transform::type::generic2 ].mnemonic =
252 
254  inverse[ transform::type::generic3 ].mnemonic =
256 
260  }
261 
267  inline auto inverse_transforms( std::vector< zydis_decoded_instr_t > &instrs ) -> bool
268  {
269  for ( auto idx = 0u; idx < instrs.size(); idx++ )
270  if ( !( instrs[ idx ].mnemonic = inverse[ instrs[ idx ].mnemonic ] ) )
271  return false;
272 
273  std::reverse( instrs.begin(), instrs.end() );
274  return true;
275  }
276 
277  // max size of a and b is 64 bits, a and b is then converted to
278  // the number of bits in bitsize, the transformation is applied,
279  // finally the result is converted back to 64bits... zero extended...
280  inline auto apply( std::uint8_t bitsize, ZydisMnemonic op, std::uint64_t a, std::uint64_t b ) -> std::uint64_t
281  {
282  switch ( bitsize )
283  {
284  case 8:
285  return transforms< std::uint8_t >[ op ]( a, b );
286  case 16:
287  return transforms< std::uint16_t >[ op ]( a, b );
288  case 32:
289  return transforms< std::uint32_t >[ op ]( a, b );
290  case 64:
291  return transforms< std::uint64_t >[ op ]( a, b );
292  default:
293  throw std::invalid_argument( "invalid bit size..." );
294  }
295  }
296 
302  inline bool has_imm( const zydis_decoded_instr_t *instr )
303  {
304  return instr->operand_count > 1 && ( instr->operands[ 1 ].type == ZYDIS_OPERAND_TYPE_IMMEDIATE );
305  }
306 } // namespace vm::transform
Definition: transform.hpp:9
const auto _inc
Definition: transform.hpp:202
const auto _dec
Definition: transform.hpp:204
u8 __ROR1__(u8 value, int count)
rotate right a one byte value...
Definition: transform.hpp:90
const auto _add
Definition: transform.hpp:164
u8 __ROL1__(u8 value, int count)
rotate left a one byte value...
Definition: transform.hpp:46
void inverse_transforms(transform::map_t &transforms, transform::map_t &inverse)
inverse operand decryption transformations...
Definition: transform.hpp:235
const auto _xor
Definition: transform.hpp:166
auto apply(std::uint8_t bitsize, ZydisMnemonic op, std::uint64_t a, std::uint64_t b) -> std::uint64_t
Definition: transform.hpp:280
u32 __ROL4__(u32 value, int count)
rotate left a four byte value...
Definition: transform.hpp:68
std::function< T(T, T) > transform_t
transform function, such as ADD, SUB, BSWAP... etc...
Definition: transform.hpp:132
const auto _bswap
Definition: transform.hpp:153
std::map< zydis_mnemonic_t, zydis_mnemonic_t > inverse
Definition: transform.hpp:213
const auto _neg
Definition: transform.hpp:170
u32 __ROR4__(u32 value, int count)
rotate right a four byte value...
Definition: transform.hpp:112
u64 __ROR8__(u64 value, int count)
rotate right an eight byte value...
Definition: transform.hpp:123
const auto _sub
Definition: transform.hpp:168
T __ROL__(T value, int count)
rotate left template function take from IDA SDK...
Definition: transform.hpp:17
const auto _rol
Definition: transform.hpp:189
bool has_imm(const zydis_decoded_instr_t *instr)
determines if a given decoded instruction has a second operand that is an immediate value....
Definition: transform.hpp:302
bool valid(zydis_mnemonic_t op)
determines if the given mnemonic is a valid transformation...
Definition: transform.hpp:225
type
type of transformation...
Definition: transform.hpp:138
const auto _ror
Definition: transform.hpp:175
std::map< zydis_mnemonic_t, transform_t< T > > transforms
Definition: transform.hpp:207
u64 __ROL8__(u64 value, int count)
rotate left an eight byte value...
Definition: transform.hpp:79
u16 __ROR2__(u16 value, int count)
rotate right a two byte value...
Definition: transform.hpp:101
const auto _not
Definition: transform.hpp:172
std::map< transform::type, zydis_decoded_instr_t > map_t
map of transform type to zydis decoded instruction of the transform...
Definition: transform.hpp:150
u16 __ROL2__(u16 value, int count)
rotate left a two byte value...
Definition: transform.hpp:57
unsigned long long u64
Definition: vmutils.hpp:15
unsigned int u32
Definition: vmutils.hpp:14
unsigned short u16
Definition: vmutils.hpp:13
ZydisMnemonic zydis_mnemonic_t
Definition: vmutils.hpp:20
ZydisDecodedInstruction zydis_decoded_instr_t
Definition: vmutils.hpp:18
unsigned char u8
Definition: vmutils.hpp:12