VMAssembler  v1.2
VMProtect 2 Virtual Instruction Assembler
gen_code.hpp
Go to the documentation of this file.
1 #pragma once
2 #include <fstream>
3 #include <vmprofiler.hpp>
4 #include <xtils.hpp>
5 
6 #include "compiler.h"
7 
8 namespace gen
9 {
17  template < typename... Args > std::string string_format( const std::string &format, Args... args )
18  {
19  int size_s = std::snprintf( nullptr, 0, format.c_str(), args... ) + 1;
20  auto size = static_cast< size_t >( size_s );
21  auto buf = std::make_unique< char[] >( size );
22  std::snprintf( buf.get(), size, format.c_str(), args... );
23  return std::string( buf.get(), buf.get() + size - 1 );
24  }
25 
33  inline std::string code( std::vector< vm::compiled_label_data > &labels, std::string image_path, vm::ctx_t& vmctx )
34  {
35  std::string result, raw_file_array;
36  std::vector< std::uint8_t > raw_file;
37  xtils::um_t::get_instance()->open_binary_file( image_path, raw_file );
38 
39  for ( auto idx = 0u; idx < raw_file.size(); ++idx )
40  raw_file_array.append( string_format( "0x%x, ", raw_file[ idx ] ) );
41 
42  result.append( "#pragma once\n"
43  "#pragma section( \".xmp2\" )\n"
44  "#pragma comment( linker, \"/section:.xmp2,RWE\" ) \n\n" );
45 
46  result.append( "namespace vm\n"
47  "{\n" );
48 
49  result.append( R"( using u8 = unsigned char;
50  using s8 = signed char;
51 
52  using u16 = unsigned short;
53  using s16 = signed short;
54 
55  using u32 = unsigned int;
56  using s32 = signed int;
57 
58  using u64 = unsigned long long;
59  using s64 = signed long long;
60  using __vmcall_t = void* (*)(...);
61 
62  constexpr u8 IMAGE_DIRECTORY_ENTRY_BASERELOC = 5;
63  constexpr u8 IMAGE_REL_BASED_ABSOLUTE = 0;
64  constexpr u8 IMAGE_REL_BASED_DIR64 = 10;
65 
66  typedef struct _IMAGE_DOS_HEADER
67  {
68  /* 0x0000 */ unsigned short e_magic;
69  /* 0x0002 */ unsigned short e_cblp;
70  /* 0x0004 */ unsigned short e_cp;
71  /* 0x0006 */ unsigned short e_crlc;
72  /* 0x0008 */ unsigned short e_cparhdr;
73  /* 0x000a */ unsigned short e_minalloc;
74  /* 0x000c */ unsigned short e_maxalloc;
75  /* 0x000e */ unsigned short e_ss;
76  /* 0x0010 */ unsigned short e_sp;
77  /* 0x0012 */ unsigned short e_csum;
78  /* 0x0014 */ unsigned short e_ip;
79  /* 0x0016 */ unsigned short e_cs;
80  /* 0x0018 */ unsigned short e_lfarlc;
81  /* 0x001a */ unsigned short e_ovno;
82  /* 0x001c */ unsigned short e_res[ 4 ];
83  /* 0x0024 */ unsigned short e_oemid;
84  /* 0x0026 */ unsigned short e_oeminfo;
85  /* 0x0028 */ unsigned short e_res2[ 10 ];
86  /* 0x003c */ long e_lfanew;
87  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; /* size: 0x0040 */
88 
89  typedef struct _IMAGE_FILE_HEADER
90  {
91  /* 0x0000 */ unsigned short Machine;
92  /* 0x0002 */ unsigned short NumberOfSections;
93  /* 0x0004 */ unsigned long TimeDateStamp;
94  /* 0x0008 */ unsigned long PointerToSymbolTable;
95  /* 0x000c */ unsigned long NumberOfSymbols;
96  /* 0x0010 */ unsigned short SizeOfOptionalHeader;
97  /* 0x0012 */ unsigned short Characteristics;
98  } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; /* size: 0x0014 */
99 
100  typedef struct _IMAGE_DATA_DIRECTORY
101  {
102  /* 0x0000 */ unsigned long VirtualAddress;
103  /* 0x0004 */ unsigned long Size;
104  } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; /* size: 0x0008 */
105 
106  typedef struct _IMAGE_OPTIONAL_HEADER64
107  {
108  /* 0x0000 */ unsigned short Magic;
109  /* 0x0002 */ unsigned char MajorLinkerVersion;
110  /* 0x0003 */ unsigned char MinorLinkerVersion;
111  /* 0x0004 */ unsigned long SizeOfCode;
112  /* 0x0008 */ unsigned long SizeOfInitializedData;
113  /* 0x000c */ unsigned long SizeOfUninitializedData;
114  /* 0x0010 */ unsigned long AddressOfEntryPoint;
115  /* 0x0014 */ unsigned long BaseOfCode;
116  /* 0x0018 */ unsigned __int64 ImageBase;
117  /* 0x0020 */ unsigned long SectionAlignment;
118  /* 0x0024 */ unsigned long FileAlignment;
119  /* 0x0028 */ unsigned short MajorOperatingSystemVersion;
120  /* 0x002a */ unsigned short MinorOperatingSystemVersion;
121  /* 0x002c */ unsigned short MajorImageVersion;
122  /* 0x002e */ unsigned short MinorImageVersion;
123  /* 0x0030 */ unsigned short MajorSubsystemVersion;
124  /* 0x0032 */ unsigned short MinorSubsystemVersion;
125  /* 0x0034 */ unsigned long Win32VersionValue;
126  /* 0x0038 */ unsigned long SizeOfImage;
127  /* 0x003c */ unsigned long SizeOfHeaders;
128  /* 0x0040 */ unsigned long CheckSum;
129  /* 0x0044 */ unsigned short Subsystem;
130  /* 0x0046 */ unsigned short DllCharacteristics;
131  /* 0x0048 */ unsigned __int64 SizeOfStackReserve;
132  /* 0x0050 */ unsigned __int64 SizeOfStackCommit;
133  /* 0x0058 */ unsigned __int64 SizeOfHeapReserve;
134  /* 0x0060 */ unsigned __int64 SizeOfHeapCommit;
135  /* 0x0068 */ unsigned long LoaderFlags;
136  /* 0x006c */ unsigned long NumberOfRvaAndSizes;
137  /* 0x0070 */ struct _IMAGE_DATA_DIRECTORY DataDirectory[ 16 ];
138  } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; /* size: 0x00f0 */
139 
140  typedef struct _IMAGE_NT_HEADERS64
141  {
142  /* 0x0000 */ unsigned long Signature;
143  /* 0x0004 */ struct _IMAGE_FILE_HEADER FileHeader;
144  /* 0x0018 */ struct _IMAGE_OPTIONAL_HEADER64 OptionalHeader;
145  } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; /* size: 0x0108 */
146 
147  typedef struct _IMAGE_SECTION_HEADER
148  {
149  /* 0x0000 */ unsigned char Name[ 8 ];
150  union
151  {
152  union
153  {
154  /* 0x0008 */ unsigned long PhysicalAddress;
155  /* 0x0008 */ unsigned long VirtualSize;
156  }; /* size: 0x0004 */
157  } /* size: 0x0004 */ Misc;
158  /* 0x000c */ unsigned long VirtualAddress;
159  /* 0x0010 */ unsigned long SizeOfRawData;
160  /* 0x0014 */ unsigned long PointerToRawData;
161  /* 0x0018 */ unsigned long PointerToRelocations;
162  /* 0x001c */ unsigned long PointerToLinenumbers;
163  /* 0x0020 */ unsigned short NumberOfRelocations;
164  /* 0x0022 */ unsigned short NumberOfLinenumbers;
165  /* 0x0024 */ unsigned long Characteristics;
166  } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; /* size: 0x0028 */
167 
168  typedef struct _IMAGE_BASE_RELOCATION
169  {
170  unsigned int VirtualAddress;
171  unsigned int SizeOfBlock;
172  } IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;)" );
173 
174  result.append( "\n\n\ttemplate < class T, class U > struct _pair_t\n"
175  "\t{\n"
176  "\t\tT first;\n"
177  "\t\tU second;\n"
178  "\t};\n\n" );
179 
180  result.append( string_format( "\tconstexpr auto entry_rva = 0x%x;\n\n", vmctx.vm_entry_rva ) );
181 
182  result.append( "\tenum class calls : u32\n"
183  "\t{\n" );
184 
185  for ( auto idx = 0u; idx < labels.size(); ++idx )
186  result.append( string_format( "\t\t%s = 0x%x,\n", labels[ idx ].label_name, labels[ idx ].enc_alloc_rva ) );
187 
188  result.append( "\t};\n\n" );
189  result.append( string_format( "\tinline _pair_t< u8, calls > call_map[%d] = \n"
190  "\t{\n",
191  labels.size() ) );
192 
193  for ( auto idx = 0u; idx < labels.size(); ++idx )
194  result.append( string_format( "\t\t{ %d, calls::%s },\n", idx, labels[ idx ].label_name.c_str() ) );
195 
196  result.append( "\t};\n\n" );
197  result.append( string_format( "\t__declspec(align(1)) struct _gen_data\n"
198  "\t{\n"
199  "\t\tu8 bin[%d] =\n"
200  "\t\t{\n"
201  "\t\t\t%s\n",
202  raw_file.size(), raw_file_array.c_str() ) );
203 
204  result.append( "\t\t};\n\n" );
205  result.append( string_format( "\t\tu8 map_area[0x%x];\n\n", vmctx.image_size ) );
206 
207  for ( auto &label : labels )
208  {
209  result.append(
210  string_format( "\t\tu8 __%s_vinstrs[%d] =\n", label.label_name.c_str(), label.vinstrs.size() ) );
211  result.append( "\t\t{\n\t\t\t" );
212  for ( auto &byte : label.vinstrs )
213  result.append( string_format( "0x%x, ", byte ) );
214  result.append( "\n\t\t};\n\n" );
215  }
216 
217  result.append( string_format( "\t\tu8 __vmcall_shell_code[%d][15] =\n"
218  "\t\t{\n",
219  labels.size() ) );
220 
221  for ( auto idx = 0u; idx < labels.size(); ++idx )
222  {
223  std::string jmp_code;
224 
225  // two push instructions...
226  for ( auto i = 0u; i < 2; ++i )
227  {
228  jmp_code.append( "0x68, " ); // push opcode...
229 
230  for ( auto _idx = 0u; _idx < 4; ++_idx )
231  jmp_code.append( "0x0, " );
232  }
233 
234  // one jmp instruction...
235  jmp_code.append( "0xE9, " );
236  for ( auto i = 0u; i < 4; ++i )
237  jmp_code.append( "0x0, " );
238 
239  result.append( string_format( "\t\t\t{ %s },\n", jmp_code.c_str() ) );
240  }
241 
242  result.append( "\t\t};\n\n" );
243  result.append( R"( bool init()
244  {
245  static const auto _memcpy = []( void *dest, const void *src, size_t len ) -> void * {
246  char *d = ( char * )dest;
247  const char *s = ( char * )src;
248  while ( len-- )
249  *d++ = *s++;
250 
251  return dest;
252  };
253 
254  const auto dos_header = reinterpret_cast< IMAGE_DOS_HEADER * >( bin );
255  const auto nt_headers = reinterpret_cast< PIMAGE_NT_HEADERS64 >( bin + dos_header->e_lfanew );
256 
257  _memcpy( map_area, bin, nt_headers->OptionalHeader.SizeOfHeaders );
258 
259  auto sections = reinterpret_cast< PIMAGE_SECTION_HEADER >( ( u8 * )&nt_headers->OptionalHeader +
260  nt_headers->FileHeader.SizeOfOptionalHeader );
261 
262  // map sections...
263  for ( u32 i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i )
264  {
265  PIMAGE_SECTION_HEADER section = &sections[ i ];
266 
267  _memcpy( ( void * )( map_area + section->VirtualAddress ),
268  ( void * )( bin + section->PointerToRawData ), section->SizeOfRawData );
269  }
270 
271  // handle relocations...
272  const auto reloc_dir = &nt_headers->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ];
273 
274  if ( reloc_dir->VirtualAddress )
275  {
276  auto reloc = reinterpret_cast< IMAGE_BASE_RELOCATION * >( map_area + reloc_dir->VirtualAddress );
277 
278  for ( auto current_size = 0u; current_size < reloc_dir->Size; )
279  {
280  u32 reloc_count = ( reloc->SizeOfBlock - sizeof( IMAGE_BASE_RELOCATION ) ) / sizeof( u16 );
281  u16 *reloc_data = ( u16 * )( ( u8 * )reloc + sizeof( IMAGE_BASE_RELOCATION ) );
282  u8 *reloc_base = map_area + reloc->VirtualAddress;
283 
284  for ( auto idx = 0; idx < reloc_count; ++idx, ++reloc_data )
285  {
286  u16 data = *reloc_data;
287  u16 type = data >> 12;
288  u16 offset = data & 0xFFF;
289 
290  switch ( type )
291  {
292  case IMAGE_REL_BASED_ABSOLUTE:
293  break;
294  case IMAGE_REL_BASED_DIR64:
295  {
296  u64 *rva = ( u64 * )( reloc_base + offset );
297  *rva = ( u64 )( map_area + ( *rva - nt_headers->OptionalHeader.ImageBase ) );
298  break;
299  }
300  default:
301  break;
302  }
303  }
304 
305  current_size += reloc->SizeOfBlock;
306  reloc = ( IMAGE_BASE_RELOCATION * )reloc_data;
307  }
308  }
309 
310  // fix shellcode up...
311  for ( auto idx = 0u; idx < ( sizeof( __vmcall_shell_code ) / 15 ); ++idx )
312  {
313  // first push encrypted rva value...
314  *reinterpret_cast< u32 * >( &__vmcall_shell_code[ idx ][ 1 ] ) =
315  static_cast< u32 >( call_map[ idx ].second );
316 
317  // second push encrypted rva value...
318  *reinterpret_cast< u32 * >( &__vmcall_shell_code[ idx ][ 6 ] ) =
319  static_cast< u32 >( call_map[ idx ].second );
320 
321  // signed rip relative rva to vm entry...
322  *reinterpret_cast< u32 * >( &__vmcall_shell_code[ idx ][ 11 ] ) = reinterpret_cast< s32 >(
323  ( map_area - ( reinterpret_cast< u64 >( &__vmcall_shell_code[ idx ] ) + 15 ) ) + entry_rva );
324  }
325 
326  return true; // only a bool so i can use static/call init only once...
327  })" );
328 
329  result.append( "\n\t};\n\n" );
330  result.append( "\t__declspec(allocate(\".xmp2\")) inline _gen_data gen_data;\n\n" );
331 
332  result.append( R"( template < calls e_call, class T, class ... Ts > auto call(const Ts... args) -> T
333  {
334  static auto __init_result = gen_data.init();
335 
336  __vmcall_t vmcall = nullptr;
337  for ( auto idx = 0u; idx < sizeof( call_map ) / sizeof( _pair_t< u8, calls > ); ++idx )
338  if ( call_map[ idx ].second == e_call )
339  vmcall = reinterpret_cast< __vmcall_t >( &gen_data.__vmcall_shell_code[ idx ] );
340 
341  return reinterpret_cast< T >( vmcall( args... ) );
342  })" );
343 
344  result.append( "\n}" );
345  return result;
346  }
347 } // namespace gen
Definition: gen_code.hpp:9
std::string code(std::vector< vm::compiled_label_data > &labels, std::string image_path, vm::ctx_t &vmctx)
generates c++ header file which MUST BE COMPILED USING CLANG BECAUSE MSVC CANT HANDLE HUGE STATIC INI...
Definition: gen_code.hpp:33
std::string string_format(const std::string &format, Args... args)
function pasted from https://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf
Definition: gen_code.hpp:17