Home » Support » User Manual » Working with VMProtect » Preparing a project

Preparing a project

Let us take the simplest application as an example. It consists of one form (Form1), a text input field (Edit1) and a button (Button1). The application does the following: once Button1 is clicked, the application checks if the entered password is correct and shows the corresponding message.

The following simple algorithm is used to check the password: it is converted into a number first, then this number is divided by 17 for the remainder to be found. The password is considered correct if the remainder is 13, after dividing the numerical representation of the password by 17. The password check procedure is implemented in the Delphi programming language in the following way:

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;

There are three ways to select procedures and functions for protection:

  • Using the MAP file generated by the compiler when the executable module of the program is created. This MAP file contains all necessary information about names and addresses of all procedures and functions in the application. In cases where the MAP file is used in work with VMProtect, it is possible to select procedures and functions for protection by their names. Using the MAP file, VMProtect will automatically determine the new addresses of procedures and functions after recompilation.
  • It is possible to use markers inserted into the source code of the application. Markers are special marks that VMProtect uses to determine the borders of the protected block. In addition, VMProtect supports markers with the predefined type of compilation. It makes sense to use markers if only part of a procedure or function needs to be protected. If markers are used, parts of code can be specified where string constants will later be protected.
  • The addresses of procedures to be protected can be used in the executable file. When compared to others, this method is less convenient because all addresses have to be determined again after any program changes are made and recompilation has occurred. This method is recommended only for protecting software products that do not possess any source code.

Using the MAP file to determine the borders of protected code has a further advantage that should be highlighted. The prologue and epilogue are located at the beginning and end of the compiled procedure or function for almost any procedure or function with local variables or that employ the stack to store registers and/or intermediate calculation results:

push ebp      \
mov ebp, esp   \ prologue
push 00        /
push ebx      /

...

pop ebx       \
pop ecx        \ epilogue
pop ebp        /
ret           /

Due to the peculiarities of implementation in modern compilers, code markers never cover either prologue or epilogue (even if the markers cover the entire text of the CheckPassword function located in-between the beginning and end). To crack the program, it will be enough to edit the function prologue so that the virtualized code is not executed. It can be done for the CheckPassword function in the following way:

mov eax, 1
ret

Important:
If you use the MAP file to select the virtualized sections of the code, the prologue and epilogue will also be virtualized, which will enhance the protection of the program. Moreover, if one virtualized function is called from another virtualized function, control will be handed to the called function without going to its address (the call will be a simple jump to another address in the bytecode inside the virtual machine interpreter). This will also increase the level of program protection since corrections the cracker will make in the entry point will be useless. In case of virtualized functions, control will be handed over to the entry point of the virtualized function only when the protected function is called from an unprotected or mutated section of the code.