Jump to content
Tuts 4 You

VMProtect 3.4 & Custom OB

Go to solution Solved by Washi,

Recommended Posts

  • Solution







Code is hidden behind a VM, but that does not matter if the serial is still constructed in the clear :) :

  • Run app.
  • Attach dnSpy.
  • Set breakpoint on 0x06000287 (call handler of VMP's virtual machine), preferably somewhere after the MethodBase.Invoke call (after offset IL_0B3E).
  • Enter garbage and press Validate
  • Spam F5 around metric tonne of times (You can speed it up by adding a condition checking whether the return value is a string or not).
  • Observe correct password being constructed in the local variables.
  • derp.gif.296f475b08f1b216db1ea87190c6a0dd.gif


  • Like 3
Link to comment
Share on other sites

Methodology -


  • Remove Anti-Tamper (if Exist) - The File will not run after Removing Anti-Tamper as the method is virtualized and still being called by the File. You must need to devirt and nop the call from Module.cctor in order to Run the File if the Anti Tamper is present in your Target. 

In the above given Target only the Main Method to check the Key and its associated one are protected with VMProtect VM but anyways You can use the above described stuff if It is Packed completely.

Our Given Target is not Protected with Anti-Debug from VMP but the Author applied his Custom Anti-Debugger but What is the Target is applied with Anti-Debug from VMP ?

  • Anti-Debug of VMP - 

1. PEB Structure - Process Environment Block (PEB) is populated by the OS Loader.

  • IsDebuggerPresent() - Access PEB at gs: [60]+2. PEB is present as a debug member if set to 1. Just set this value to 0.
  • NtGlobalFlag - During Debugging, Your System set the FLAG_HEAP_VALIDATE_PARAMETERSFOR_HELP_ENABLE_TAIL_CHECK, and FLAG_HELP_ENABLE_FREE_CHECK flags in the NtGlobalFlag field, which is located in the PEB Structure. The debugger uses these flags to control heap destruction via overflow. Access it at  gs:[60] + bc

PEB is present as a debug member if set to 70. Just set this value to 0.

2. NtQueryInformationProcess, NtSetInformationThread, NtClose - Now to bypass Debug Check We need to Patch it and before doing this, We must need to fix CRC.

If you hook the necessary functions (NtProtectVirtualMemory) -

#include <Windows.h>
#include <iostream>
int main()
        BYTE jmp[] = { 0xEB, 0x00 };
        DWORD Address = 0x7FF76B961353;
        DWORD pid;
        std::cout << "Enter Process: ";
        std::cin >> pid;
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, true, pid);
            if (!hProcess)
        std::cout << "[-] OpenProcess failed!" << std::endl;
        std::cout << "[+] Process opened!" << std::endl;
        if (!WriteProcessMemory(hProcess, LPVOID(Address), &jmp, sizeof(jmp), 0))
            std::cout << "[-] WriteProcessMemory failed! GetLastError(): " << GetLastError() << std::endl;
            std::cout << "[+] Inline Patching Successful!" << std::endl;

or If NtProtectVirtualMemory Hook occurred, In Windows, when loading a DLL from the Import Table -

 uintptr_t patch_addr;
        FARPROC nt_protect = GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "NtProtectVirtualMemory" );
        while ( *(BYTE*)nt_protect == 0xE9 )
            Sleep( 100 );
        Sleep( 500 );
        unsigned char shell_syscall[] = {
            0xB8, 0x50, 0x00, 0x00, 0x00, // mov eax, number ($+0x00)
            0xBA, 0x40, 0x8D, 0x70, 0x77, // mov edx, Wow64Transition ($+0x05)
            0xFF, 0xD2,                      // call edx ($+0x0A)
            0xC2, 0x14, 0x00              // ret 0x14 ($+0x0C)
        uintptr_t shell_mem = (uintptr_t)VirtualAlloc( 0, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );
        memcpy( (void*)shell_mem, shell_syscall, sizeof( shell_syscall ) );
        *(uint32_t*)( shell_mem + 0x1 ) = GetSystemNumber( "NtProtectVirtualMemory" );
        *(uintptr_t*)( shell_mem + 0x6 ) = *(uintptr_t*)( GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "Wow64Transition" ) );
        t_NtProtectVirtualMemory m_NtProtectVirtualMemory = (t_NtProtectVirtualMemory)shell_mem;
        memset( (void*)patch_addr, 0x90, 1 ); //nop

or If You don't like these Manual Stuff, Use Ready Made Script for VMP Anti-Debugging Bypass -

// Disable all breakpoints
// Variables breakpoints
// Enable breakpoints
bph $NtProcAddr
bph $NtThreadAddr
bph $NtCloseAddr
// Add condition on breakpoints
bphwcond $NtProcAddr, "rdx=0x7 || rdx=0x1e"
bphwcond $NtThreadAddr, "rdx==0x11"
bphwcond $NtCloseAddr, "rcx==0xDEADC0DE"
// Run programm and the reset registers of the CPU on "zero"
// Disable breakpoints
bphd $NtProcAddr
bphd $NtThreadAddr
bphd $NtCloseAddr
msg "Success"


You can use these Steps to Bypass Anti-Debug Check of VMP in Native Files as well along with C# and can patch the file to bypass CRC Check.

Though the Given Target doesn't have any Anti-Debugging Check from VMP, So We don't need this.

So You can simply Dump the File with the Power of Kernel Driver and Fix the Mutations.

  • Devirtualization of VMP -

- The first approach to learn the CIL Basics in order to start Unpacking.
Learn about Your Assembly Writer/Reader and How it Works. You can choose anyone of your choice as long as it fulfill your need.
- Understand the basics of it & learn Eh/Inst. of VMP to figure out for restoration of method. If We just broaden our area and look, The unpacking of VM for .NET (no matter what is the nature of protection) looks almost same.

1. Identify all stub which are virtualized in your Target.
2. Understand the virtualized opcodes to devirtualize it.
3. List all virtualized opcodes and start resolving those to do unpacking. 
4. (How Streams are initiated, Location of Opcodes & How VMP VM Handlers connected to them) Understanding of all these can help to devirt the VM.

When the Tool is virtualized, It generates the signature. They trigger the WinAPI function which can be easily seen. for example,

  • CRC Check - use CreateFile WinAPI function to map.
  • VM Check - didn't exist in the target but call the CPUID so it can also be bypassed.
  • Mutations - loops are generated by dnSpy which are generated by VMP. the variable num in it execute an instruction and update itself once. Find the decryption of the constants and replace. This process is briefly explain at Here -


Now Let's see What is Customised in it ? To Bypass the Custom Anti-Debug, Simply go to EntryPoint and nop the Debug Checking Call and BOOM !!! Now You can use It and Debug it.

Since It is a CrackMe I won't bother myself to generate/find a Valid Serial by understanding the Algo. So I simply gonna patch it to accept any Key or show Valid Message from any of that.


Thanks to RCE Community Members from all those diff Forums who shared their Knowledge with Public.

Valid Key -



Steps -


  • Run the Software after Dumping and fixing CRC Check. (No Need to Devirtualize)
  • Open the Process Hacker.
  • Enter anything in the TextBox and It will show an Error.
  • Check for that in Memory Strings and You will find out the Correct Key just near to it.


Image -




Method 2 - 


Go to CrackMe.Form1 and Open XKNZJZ4AZWC2A and put a bp at return text

See the Magic.


Since it is a Crack Me so these method makes sense but in Real World App, these are not so useful. We must need to Devirt the App to fully Read the Code. So You can follow my 1st Comment regarding Complete Unpacking of Your Code.

Edited by BlackHat
spelling mistakes
  • Like 5
  • Thanks 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...