VMProtect 2 Virtual Instruction Assembler
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
Go to file
John Doe 8ded84e0a6
updated README icon
11 months ago
demo updated vmprofiler dep, ported to cmkr... 11 months ago
dependencies updated vmprofiler dep, ported to cmkr... 11 months ago
doxygen changed icon to vmprotect's icon 11 months ago
include porting the project to cmkr... 11 months ago
src updated vmprofiler dep, ported to cmkr... 11 months ago
.clang-format porting the project to cmkr... 11 months ago
.gitignore porting the project to cmkr... 11 months ago
.gitmodules added vmprofiler v1.5, still needs some work 2 years ago
CMakeLists.txt added "_UNICODE" macro 11 months ago
LICENSE Add LICENSE 2 years ago
README.md updated README icon 11 months ago
cmake.toml added "_UNICODE" macro 11 months ago
cmkr.cmake porting the project to cmkr... 11 months ago

README.md

VMAssembler - VMProtect 2 Virtual Instruction Assembler

VMAssembler is a small C++ project which uses flex and bison to parse .vasm files and assemble virtual instructions. The project inherits vmprofiler which is used to identify vm handler's, provide them with a name, immidate value size, and other meta data to aid in assembling virtual instructions.

Doxygen Documentation

Contents

The repo contains the following notable folders and files:

  • dependencies/ - vmprofiler is the only dependency for this project...
  • src/ - source code for the vmassembler...
    • compiler.cpp - responsible for encoding and encrypting virtual instructions...
    • parser.cpp - a singleton class which is used in parser.y...
    • parser.y - bison rules for parsing tokens. This contains only a handful of rules...
    • lexer.l - lex rules for the vmassembler...

Usage Requirements

In order to use the virtual instruction assembler you must first have a few values at hand. You must have an unpacked vmprotect 2 binary. This file cannot be a dump, it must be unpacked. Second, you must know the RVA to the vm entry address of the first push instruction. This first push instruction must not be push contant_value, it must be of type push reg as the constant values are pushed onto the stack by the generated c++ header file. The last thing you need is a virtual instruction assembly file. You can make one of these easily. Simply open a text editor and create your first label:

Note: you can use ANY virtual instruction which is defined by vmprofiler... you can see them all here

get_hello:
	SREGQ 0x90
	SREGQ 0x88
	SREGQ 0x80
	SREGQ 0x78
	SREGQ 0x70
	SREGQ 0x68
	SREGQ 0x60
	SREGQ 0x58
	SREGQ 0x50
	SREGQ 0x48
	SREGQ 0x40
	SREGQ 0x38
	SREGQ 0x30
	SREGQ 0x28
	SREGQ 0x20
	SREGQ 0x18
	SREGQ 0x10
	SREGQ 0x8
	SREGQ 0x0
	
	LCONSTQ 0x6F6C6C6568
	SREGQ 0x78
	SREGQ 0x0
	SREGQ 0x0

	LREGQ 0x0
	LREGQ 0x8
	LREGQ 0x10
	LREGQ 0x18
	LREGQ 0x20
	LREGQ 0x28
	LREGQ 0x30
	LREGQ 0x38
	LREGQ 0x40
	LREGQ 0x48
	LREGQ 0x50
	LREGQ 0x58
	LREGQ 0x60
	LREGQ 0x68
	LREGQ 0x70
	LREGQ 0x78
	LREGQ 0x80
	LREGQ 0x88
	LREGQ 0x90
	VMEXIT
	
get_world:
	SREGQ 0x90
	SREGQ 0x88
	SREGQ 0x80
	SREGQ 0x78
	SREGQ 0x70
	SREGQ 0x68
	SREGQ 0x60
	SREGQ 0x58
	SREGQ 0x50
	SREGQ 0x48
	SREGQ 0x40
	SREGQ 0x38
	SREGQ 0x30
	SREGQ 0x28
	SREGQ 0x20
	SREGQ 0x18
	SREGQ 0x10
	SREGQ 0x8
	SREGQ 0x0
	
	LCONSTQ 0x646C726F77
	SREGQ 0x78
	SREGQ 0x0
	SREGQ 0x0

	LREGQ 0x0
	LREGQ 0x8
	LREGQ 0x10
	LREGQ 0x18
	LREGQ 0x20
	LREGQ 0x28
	LREGQ 0x30
	LREGQ 0x38
	LREGQ 0x40
	LREGQ 0x48
	LREGQ 0x50
	LREGQ 0x58
	LREGQ 0x60
	LREGQ 0x68
	LREGQ 0x70
	LREGQ 0x78
	LREGQ 0x80
	LREGQ 0x88
	LREGQ 0x90
	VMEXIT

Usage Example

Once you have defined a vasm file, you can now generate the c++ header file which will handle everything for you. Simply execute the following command:

vmassembler.exe --input [filename] --vmpbin [vmprotect'ed binary] --vmentry [make sure this rva is correct!] --out test.hpp

If the file is generated without any errors you can now include this file inside of your project. This header file uses no STL, nor any CRT functions, however it does create a RWX section so if you want to use this in a driver it cannot run on HVCI systems...

To call your vasm routine all you must do is pass the label name as a template param...

#include <iostream>
#include "test.hpp"

int main()
{
    // note, the header file generates an enum call "calls", inside of this enum will be an entry with the same name as your label!
    // note, the second template param is the return type...
    const auto hello = vm::call< vm::calls::get_hello, vm::u64 >();
    const auto world = vm::call< vm::calls::get_world, vm::u64 >();
    std::printf( "> %s %s\n", ( char * )&hello, (char*)&world );
}