Get Demo
  • Windows
  • MacOS
  • Linux

File menu

  • Open — choose an executable you want to protect or a project file (*.vmp). You can also select a file to open from the list of previously protected applications shown in the File menu. The open dialog can also be accessed using the corresponding toolbar button . Finally, you can drag and drop the file directly into the VMProtect window;
  • Save Project — save application protection settings to a “*.vmp” file. The project settings file is saved in the same folder as the protected application’s executable. Saving is also available via the toolbar button ;
  • Save Project As… — save the project file under a new name;
  • Close — close the current project;
  • Exit — close VMProtect.
Last updated 10 days ago

Main menu

The main menu consists of the following items:

Last updated 10 days ago

GUI version

The main window consists of the following elements:

Last updated 10 days ago

SDK functions

SDK functions can be integrated into the source code of the protected application to define the boundaries of protected areas, as well as to detect debuggers or virtualization tools.

Code markers

Service functions

Licensing functions

Activation functions

!Important

After protection is applied, the application no longer requires the SDK library.

VMProtectBegin

void VMProtectBegin(const char *MarkerName);

The marker that identifies the beginning of a protected code block. A call to VMProtectBegin must be placed before the first instruction (or procedure/function call) of the protected code block. MarkerName defines the marker name that appears in VMProtect as “VMProtectMarker” + MarkerName. For example, the marker VMProtectBegin("CheckRegistration") will appear as VMProtectMarker “CheckRegistration”. If the marker name is not specified, a unique name in the form “VMProtectMarker” + marker_serial_number is generated automatically. You can assign a compilation type to the protected block within VMProtect.

VMProtectBeginVirtualization

void VMProtectBeginVirtualization(const char *MarkerName);

The marker that identifies the beginning of a protected code block with the predefined “virtualization” compilation type. MarkerName defines the marker name. The compilation type of this marker cannot be changed later in VMProtect.

VMProtectBeginMutation

void VMProtectBeginMutation(const char *MarkerName);

The marker that identifies the beginning of a protected code block with the predefined “mutation” compilation type. MarkerName defines the marker name. The compilation type of this marker cannot be changed later in VMProtect.

VMProtectBeginUltra

void VMProtectBeginUltra(const char *MarkerName);

The marker that identifies the beginning of a protected code block with the predefined “ultra (virtualization + mutation)” compilation type. MarkerName defines the marker name. The compilation type of this marker cannot be changed later in VMProtect.

VMProtectBeginVirtualizationByKey

void VMProtectBeginVirtualizationLockByKey(const char *MarkerName);

The marker that identifies the beginning of a protected code block with the predefined “virtualization” compilation type and the enabled “Lock to Serial Number” option. MarkerName defines the marker name. The compilation type of this marker cannot be changed later in VMProtect.

VMProtectBeginUltraLockByKey

void VMProtectBeginUltraLockByKey(const char *MarkerName);

The marker that identifies the beginning of a protected code block with the predefined “ultra (virtualization + mutation)” compilation type and the enabled “Lock to Serial Number” option. MarkerName defines the marker name. The compilation type of this marker cannot be changed later in VMProtect.

VMProtectEnd

void VMProtectEnd(void);

The marker that identifies the end of a protected code block. The call to VMProtectEnd must be placed after the last instruction (procedure or function call) of the protected block.

VMProtectIsProtected

bool VMProtectIsProtected(void);

The VMProtectIsProtected function returns True if the file has been processed by VMProtect.

VMProtectIsDebuggerPresent

bool VMProtectIsDebuggerPresent(bool CheckKernelMode);

The VMProtectIsDebuggerPresent function detects whether the application is running under a debugger. The result (True/False) can be processed by the application's internal protection mechanisms. If CheckKernelMode=False, the function checks only for user-mode debuggers (OllyDBG, WinDBG, etc.). If CheckKernelMode=True, both user-mode and kernel-mode debuggers (SoftICE, Syser, etc.) are checked. When protecting drivers, the value of CheckKernelMode is irrelevant because drivers always operate in kernel mode, so the presence of a kernel-mode debugger is always checked.

VMProtectIsVirtualMachinePresent

bool VMProtectIsVirtualMachinePresent(void);

The VMProtectIsVirtualMachinePresent function detects whether the application is running inside a virtualization environment such as VMware, Virtual PC, VirtualBox, or Sandboxie. The result (True/False) can be processed by the application's internal protection mechanisms.

VMProtectIsValidImageCRC

bool VMProtectIsValidImageCRC(void);

The VMProtectIsValidImageCRC function detects whether the executable module has been modified in process memory (only non-modifiable code and data segments are checked). The result (True/False) can be processed by the application's internal protection mechanisms.

VMProtectDecryptStringA

const char * VMProtectDecryptStringA(const char *Value);

The VMProtectDecryptStringA function decrypts an ANSI string constant — Value. To decrypt the constant, it must first be added to the list of protected objects.

VMProtectDecryptStringW

const wchar_t * VMProtectDecryptStringW(const wchar_t *Value);

The VMProtectDecryptStringW function decrypts a Unicode string constant — Value. To decrypt the constant, it must first be added to the list of protected objects.

VMProtectFreeString

bool VMProtectFreeString(const void *Value);

The VMProtectFreeString function frees the dynamically allocated memory used for a decrypted string. Releasing the memory is optional, but if you choose to do so, this function must be used. If VMProtectDecryptStringA or VMProtectDecryptStringW are called again with the same parameters before the previously decrypted string is destroyed, no additional memory is allocated.

Last updated 10 days ago

Using ObfuscationAttribute for .NET

VMProtect supports the following values for ObfuscationAttribute.Feature:

  • renaming — allows excluding a class/method from renaming. Possible values of ObfuscationAttribute.Exclude: true/false
  • virtualization, virtualizationlockbykey, ultra, ultralockbykey, mutation — allows specifying the compilation type for a specific method or methods of a class. Possible values of ObfuscationAttribute.ApplyToMembers: true/false.
  • strings — allows obfuscating strings for a specific method or methods of a class. Possible values of ObfuscationAttribute.ApplyToMembers: true/false.

For each class, method, or property, it is possible to specify multiple attributes at once:

[Obfuscation(Feature = "strings", Exclude = false)]
class Class
{
	[Obfuscation(Feature = "renaming", Exclude = true)]
	[Obfuscation(Feature = "virtualization", Exclude = false)]
	public Foo()
	{
...

Examples

The following example adds Class.Foo to the “Functions For Protection” section with the “Virtualization” compilation type:

class Class
{
	[Obfuscation(Feature = "virtualization")]
	public Foo()
	{
...

The following example excludes Class.Foo from renaming:

class Class
{
	[Obfuscation(Feature = "renaming", Exclude = true)]
	public Foo()
	{
...

The following example excludes all methods of Class from renaming:

[Obfuscation(Feature = "renaming", Exclude = true, ApplyToMembers = true)]
class Class
{
	public Foo()
	{
...
Last updated 10 days ago

Using markers

To protect individual code fragments and string constants, you can insert special markers into the source code of your application. Markers are implemented as calls to functions imported from the SDK library:

For .NET

  • VMProtect.SDK.dll

For Windows

  • 32-bit user-mode applications — VMProtectSDK32.dll
  • 32-bit kernel drivers — VMProtectDDK32.sys
  • 64-bit user-mode applications — VMProtectSDK64.dll
  • 64-bit kernel drivers — VMProtectDDK64.sys

For Linux

  • 32-bit applications — libVMProtectSDK32.so
  • 64-bit applications — libVMProtectSDK64.so

For macOS

  • libVMProtectSDK.dylib

The procedures and functions provided by the SDK do not perform any actions and serve only as labels used by VMProtect to determine the boundaries of protected code blocks. The beginning and end of a protected block are marked as follows:

C/C++

#include "VMProtectSDK.h"
VMProtectBegin(MARKER_TITLE);
...
VMProtectEnd();

C#

using System.Reflection;
class Foo
{
	[Obfuscation(Feature = "virtualization", Exclude = false)]
	// Feature = "virtualization", "ultra", "mutation",
	// "virtualizationlockbykey", "ultralockbykey"
	public Foo()
	{
...

Pascal

uses VMProtectSDK;
VMProtectBegin(MARKER_TITLE);
...
VMProtectEnd;

MASM

include VMProtectSDK.inc
invoke VMProtectBegin,SADD(MARKER_TITLE)
...
invoke VMProtectEnd

Visual Basic

VMProtectBegin (StrPtr(MARKER_TITLE))
...
VMProtectEnd

Instead of VMProtectBegin, you can also use markers with predefined compilation types:

  • VMProtectBeginVirtualization — uses the “Virtualization” compilation type.
  • VMProtectBeginMutation — uses the “Mutation” compilation type.
  • VMProtectBeginUltra — uses the “Ultra” compilation type.

Markers are processed as follows: when VMProtect analyzes the code of the protected application, it locates all calls to VMProtectSDK procedures and functions. The boundaries of protected blocks are determined by pairs of markers such as VMProtectBegin / VMProtectBeginVirtualization / VMProtectBeginMutation / VMProtectBeginUltra and VMProtectEnd. During code processing, VMProtect removes both the markers themselves and all references to VMProtectSDK, so there is no need to include these libraries in your application setup package. Markers are removed regardless of whether they are included in the compilation or not. When named markers are used, their names are also removed.

If a marker title is specified, the marker receives a name in the form “VMProtectMarker MARKER_TITLE”. If no title is specified, a unique name is generated automatically in the form “VMProtectMarker” + marker serial number. However, unnamed markers have a significant disadvantage: if a new marker is inserted into the program code, the numbering of all unnamed markers changes. Therefore, we strongly recommend always using named markers.

A particularly important consideration when working with markers is that jumps from unprotected code areas into protected marker regions must not be allowed. For example, this may happen if only part of a loop is enclosed within markers. If an application that uses markers stops functioning correctly after protection is applied, you can detect jumps from unprotected areas by enabling the “Debug mode” option. In this mode, when the protected application is executed under a debugger, execution will be interrupted whenever a jump from an unprotected area into protected code is detected. After all such jumps are identified, you should either adjust the marker placement or, if this is impossible, mark the corresponding addresses as external using the GUI version of VMProtect.

To protect individual code fragments and string constants, you can insert special markers into the source code of your application. Markers are implemented as calls to functions imported from the SDK library:

For .NET

  • VMProtect.SDK.dll

For Windows

  • 32-bit user-mode applications — VMProtectSDK32.dll
  • 32-bit kernel drivers — VMProtectDDK32.sys
  • 64-bit user-mode applications — VMProtectSDK64.dll
  • 64-bit kernel drivers — VMProtectDDK64.sys

For Linux

  • 32-bit applications — libVMProtectSDK32.so
  • 64-bit applications — libVMProtectSDK64.so

For macOS

  • libVMProtectSDK.dylib

The procedures and functions provided by the SDK do not perform any actions and serve only as labels used by VMProtect to determine the boundaries of protected code blocks. The beginning and end of a protected block are marked as follows:

C/C++

#include "VMProtectSDK.h"
VMProtectBegin(MARKER_TITLE);
...
VMProtectEnd();

C#

using System.Reflection;
class Foo
{
	[Obfuscation(Feature = "virtualization", Exclude = false)]
	// Feature = "virtualization", "ultra", "mutation",
	// "virtualizationlockbykey", "ultralockbykey"
	public Foo()
	{
...

Pascal

uses VMProtectSDK;
VMProtectBegin(MARKER_TITLE);
...
VMProtectEnd;

MASM

include VMProtectSDK.inc
invoke VMProtectBegin,SADD(MARKER_TITLE)
...
invoke VMProtectEnd

Visual Basic

VMProtectBegin (StrPtr(MARKER_TITLE))
...
VMProtectEnd

Instead of VMProtectBegin, you can also use markers with predefined compilation types:

  • VMProtectBeginVirtualization — uses the “Virtualization” compilation type.
  • VMProtectBeginMutation — uses the “Mutation” compilation type.
  • VMProtectBeginUltra — uses the “Ultra” compilation type.

Markers are processed as follows: when VMProtect analyzes the code of the protected application, it locates all calls to VMProtectSDK procedures and functions. The boundaries of protected blocks are determined by pairs of markers such as VMProtectBegin / VMProtectBeginVirtualization / VMProtectBeginMutation / VMProtectBeginUltra and VMProtectEnd. During code processing, VMProtect removes both the markers themselves and all references to VMProtectSDK, so there is no need to include these libraries in your application setup package. Markers are removed regardless of whether they are included in the compilation or not. When named markers are used, their names are also removed.

If a marker title is specified, the marker receives a name in the form “VMProtectMarker MARKER_TITLE”. If no title is specified, a unique name is generated automatically in the form “VMProtectMarker” + marker serial number. However, unnamed markers have a significant disadvantage: if a new marker is inserted into the program code, the numbering of all unnamed markers changes. Therefore, we strongly recommend always using named markers.

A particularly important consideration when working with markers is that jumps from unprotected code areas into protected marker regions must not be allowed. For example, this may happen if only part of a loop is enclosed within markers. If an application that uses markers stops functioning correctly after protection is applied, you can detect jumps from unprotected areas by enabling the “Debug mode” option. In this mode, when the protected application is executed under a debugger, execution will be interrupted whenever a jump from an unprotected area into protected code is detected. After all such jumps are identified, you should either adjust the marker placement or, if this is impossible, mark the corresponding addresses as external using the GUI version of VMProtect.

Last updated 10 days ago

Using a PDB/MAP file

To create a MAP file, you need to enable the corresponding option in the compiler settings.

Visual Studio

If you develop your application in Visual Studio, this can be done as follows: in the main menu of the IDE, open the project properties (Project → Properties), then on the “Linker → Debugging” tab, set the “Generate MAP File” option to “Yes (/MAP)”:

Borland Delphi

If you develop the application using Borland Delphi, you can enable MAP file generation as follows: in the main menu of the Delphi IDE, open the project options (Project → Options), then on the “Linker” tab, set the “MAP file” option to “Detailed”:

After enabling MAP file generation, the project must be rebuilt.

When loading a MAP file, VMProtect compares the modification date and time of the MAP file with those of the protected file. If they do not match, the MAP file will not be loaded.

Last updated 10 days ago

Preparing a project

Let us take a look at a very simple application consisting of a single form (Form1), a text input field (Edit1), and a button (Button1). The application works as follows: when Button1 is clicked, the application checks whether the entered password is correct and displays the corresponding message.

The password is verified using a very simple algorithm: first, it is converted into a numeric value, then the remainder of division by 17 is calculated. The password is considered correct if the remainder of dividing the numeric representation of the entered password by 17 equals 13. The implementation of the password verification procedure in Delphi looks as follows:

function TForm1.CheckPassword: Boolean;
begin
  Result:=(StrToIntDef(Edit1.Text, 0) mod 17=13);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  if CheckPassword then
   MessageDlg('Correct password', mtInformation, [mbOK], 0)
  else
   begin
    MessageDlg('Incorrect password', mtError, [mbOK], 0);
    Edit1.SetFocus;
   end;
end;

Procedures and functions to protect can be selected in three different ways:

  • Using a PDB/MAP file generated by the compiler together with the executable file of the application. The MAP file contains all necessary information about the names and addresses of all procedures and functions in the application. When a MAP file is used, procedures and functions can be selected for protection by name. In addition, whenever the project is recompiled, VMProtect automatically determines the new addresses of procedures and functions.
  • Using markers inserted directly into the application source code. Markers are special labels used by VMProtect to determine the boundaries of protected code fragments. VMProtect also supports markers with predefined compilation types. Using markers is useful when you want to protect only a specific part of a function or procedure. Markers also allow you to define code regions where protected string constants will later be placed.
  • By specifying the addresses of protected procedures directly in the executable file. Compared to the previous two methods, this approach is less convenient. Every time the application is modified and recompiled, all addresses must be specified again. This type of protection is mainly recommended for applications where the source code is unavailable.

Using a MAP file to define the boundaries of protected code provides another important advantage that deserves closer attention. Almost any procedure or function that contains local variables or uses the stack to save registers and/or intermediate calculation results includes a so-called prologue and epilogue located respectively at the beginning and the end of the compiled procedure or function:

push ebp      \
mov ebp, esp   \ prologue
push 00        / 
push ebx      /
...
pop ebx       \
pop ecx        \ epilogue
pop ebp        /
ret           /

Due to the way modern compilers work, code markers never include the prologue and epilogue of a function, even if the entire body of the CheckPassword function between begin and end is enclosed within markers. In this case, it would be enough for a hacker to modify the function prologue so that the virtualized code is never executed. For the CheckPassword function, this can be done as follows:

mov eax, 1
ret

!Important

If a PDB/MAP file is used to select code fragments for virtualization, the function prologue and epilogue are virtualized as well, significantly improving the tamper resistance of the protected application. Furthermore, if one virtualized function calls another virtualized function, control is transferred between them without actually jumping to the address of the called function. In this case, the call becomes a simple jump to another address within the bytecode of the virtual machine interpreter. This further strengthens application protection because any modifications made by a hacker to the function entry point become ineffective. When working with virtualized functions, control is transferred to the entry point of a virtualized function only when it is called from an unprotected or mutated code fragment.

Last updated 10 days ago

Working with VMProtect

Before you start working with VMProtect, please review the following sections of the manual:

Last updated Today