Skip to content

Commit b117960

Browse files
committed
Added VMProtect Anti Debug Bypass
1 parent 3ad8c76 commit b117960

13 files changed

+129
-96
lines changed

README.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,24 @@
1919
VMUnprotect.exe
2020
-f, --file Required. Path to file.
2121
--usetranspiler (Default: false) Use an older method that makes use of Transpiler (not recommended).
22-
--enableharmonylogs (Default: true) Enable logs from Harmony.
22+
--enableharmonylogs (Default: false) Disable or Enable logs from Harmony.
23+
--bypassantidebug (Default: false) Bypass VMProtect Anti Debug.
2324
--help Display this help screen.
2425
--version Display version information.
2526
```
2627

2728
# Supported Protections
2829
Note: ***All Supported Protections are working combined***
2930

30-
Protection Name | Is supported |
31-
------------- | :----:
32-
Memory Protection | Yes
33-
Import Protection | Yes
34-
Resource Protection | Yes
35-
Debugger Detection | Yes
36-
Virtualization Tools | Yes
37-
Strip Debug Information | Yes
38-
Pack the Output File | No
31+
Protection Name | Is supported
32+
------------------------|--------------
33+
Memory Protection | ✓
34+
Import Protection | ✓
35+
Resource Protection | ✓
36+
Debugger Detection | ✓
37+
Virtualization Tools | ✓
38+
Strip Debug Information |
39+
Pack the Output File | ✓
3940

4041
# Usage can be found in ```MiddleMan```
4142
```csharp
@@ -91,11 +92,13 @@ namespace VMUnprotect.Core.MiddleMan {
9192
## Current Features
9293
- Tracing invokes in virtualized methods.
9394
- Manipulating parameters and return values.
95+
- Bypass NtQueryInformationProcess, IsLogging, get_IsAttached
96+
9497

9598
## Todo
9699
- Change this to support more VM's
97100
- VMP Stack tracing
98-
- Bypass VMP Debugger Detection
101+
- Bypass VMP Debugger Detection
99102
- Bypass VMP CRC Check
100103
- Nice WPF GUI
101104

VMUP/VMUnprotect.Core/CommandLineOptions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ public class CommandLineOptions {
88
[Option(Default = false, HelpText = "Use an older method that makes use of Transpiler (not recommended).", Required = false)]
99
public bool UseTranspiler { get; set; }
1010

11-
[Option(Default = true, HelpText = "Enable logs from Harmony.", Required = false)]
11+
[Option(Default = false, HelpText = "Disable or Enable logs from Harmony.", Required = false)]
1212
public bool EnableHarmonyLogs { get; set; }
13+
14+
[Option(Default = false, HelpText = "Bypass VMProtect Anti Debug.", Required = false)]
15+
public bool BypassAntiDebug { get; set; }
1316
}
1417
}

VMUP/VMUnprotect.Core/Context.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace VMUnprotect.Core {
99
public class Context {
1010
public Context(ILogger logger, string vmpAssembly, CommandLineOptions options) {
1111
Harmony.DEBUG = options.EnableHarmonyLogs;
12-
12+
1313
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
1414
Options = options ?? throw new ArgumentNullException(nameof(options));
1515

VMUP/VMUnprotect.Core/Engine.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,8 @@ public Engine(Context context) {
1111
Ctx = context;
1212
Logger = context.Logger;
1313
}
14-
internal static Context Ctx
15-
{
16-
get;
17-
private set;
18-
} = null!;
19-
20-
public static ILogger Logger
21-
{
22-
get;
23-
private set;
24-
} = new EmptyLogger();
14+
internal static Context Ctx { get; private set; } = null!;
15+
public static ILogger Logger { get; private set; } = new EmptyLogger();
2516

2617
public void Start() {
2718
var fileEntryPoint = Ctx.VmpAssembly.EntryPoint;
@@ -41,7 +32,7 @@ public void Start() {
4132
RuntimeHelpers.RunModuleConstructor(moduleHandle);
4233

4334
Logger.Info("--- Invoking assembly.\n");
44-
fileEntryPoint.Invoke(null, parameters.Length == 0 ? null : new object[] {null!});
35+
fileEntryPoint.Invoke(null, parameters.Length == 0 ? null : new object[] {new[] {string.Empty}}); // parse arguments from commandlineoptions
4536
}
4637
private static void ApplyHooks() {
4738
try {

VMUP/VMUnprotect.Core/Helpers/Formatter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public static string FormatObject(object obj) {
1313
null => "null",
1414
string x => $"\"{x}\"",
1515
IEnumerable enumerable => $"{obj.GetType().Name} {{{string.Join(", ", enumerable.Cast<object>().Select(FormatObject))}}}",
16-
_ => obj.ToString()
16+
var _ => obj.ToString()
1717
};
1818
}
1919
catch (Exception) {

VMUP/VMUnprotect.Core/Hooks/Methods/GetCallingAssemblyPatch.cs

Lines changed: 0 additions & 24 deletions
This file was deleted.

VMUP/VMUnprotect.Core/Hooks/Methods/GetEntryAssemblyPatch.cs

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using HarmonyLib;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
5+
using System.Linq;
6+
using System.Reflection;
7+
8+
namespace VMUnprotect.Core.Hooks.Methods {
9+
/// <summary>
10+
/// Honestly, I Don't know about this, need better Idea
11+
/// </summary>
12+
public static class VmProtectBypassAntiDebug {
13+
public static bool Filter(out object __result, object obj, IList<object> arguments, MethodInfo? methodInfo) {
14+
if (!Engine.Ctx.Options.BypassAntiDebug) {
15+
__result = true; // dont skip original function
16+
return true;
17+
}
18+
19+
// GetExecutingAssembly.Get_Location() check
20+
if (methodInfo == GetExecutingAssembly) {
21+
__result = Engine.Ctx.VmpAssembly;
22+
return false;
23+
}
24+
25+
// Bypass IsLogging
26+
if (methodInfo == IsLogging) {
27+
__result = false;
28+
return false; // skip function and set __result to false
29+
}
30+
31+
// Bypass GetIsAttached
32+
if (methodInfo == GetIsAttached) {
33+
__result = false;
34+
return false; // skip function and set __result to false
35+
}
36+
37+
// Bypass NtQueryInformationProcess
38+
/*__kernel_entry NTSTATUS NtQueryInformationProcess(
39+
[in] HANDLE ProcessHandle,
40+
[in] PROCESSINFOCLASS ProcessInformationClass,
41+
[out] PVOID ProcessInformation,
42+
[in] ULONG ProcessInformationLength,
43+
[out, optional] PULONG ReturnLength
44+
);*/
45+
46+
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
47+
if (obj is not null && obj.Equals(NtQueryInformationProcessDelegate))
48+
arguments[2] = (IntPtr) 0x0; // [out] PVOID ProcessInformation = 0x0
49+
50+
__result = true; // dont skip original function
51+
return true;
52+
}
53+
54+
/// <summary>
55+
/// There's a function that takes "NtQueryInformationProcess" and converts it into IntPtr for
56+
/// GetDelegateForFunctionPointer.
57+
/// </summary>
58+
public static void FindNtQueryInformationProcessDelegate(object __result, object[] parameters) {
59+
if (!Engine.Ctx.Options.BypassAntiDebug)
60+
return;
61+
62+
// Steal IntPtr
63+
if (parameters.Any(x => x.Equals("NtQueryInformationProcess")))
64+
_ntQueryInformationProcessPtr = (IntPtr) __result;
65+
66+
// Steal Delegate
67+
if (parameters.Any(x => x.Equals(_ntQueryInformationProcessPtr)))
68+
NtQueryInformationProcessDelegate = (Delegate) __result;
69+
}
70+
71+
#region VMP_ANTIDEBUG_FUNCTIONS
72+
private static IntPtr _ntQueryInformationProcessPtr = new(0x0);
73+
private static Delegate? NtQueryInformationProcessDelegate { get; set; }
74+
private static MethodInfo? GetExecutingAssembly => AccessTools.Method(typeof(Assembly), nameof(Assembly.GetExecutingAssembly));
75+
private static MethodInfo? GetIsAttached => AccessTools.Method(typeof(Debugger), "get_IsAttached");
76+
private static MethodInfo? IsLogging => AccessTools.Method(typeof(Debugger), "IsLogging");
77+
#endregion
78+
}
79+
}

VMUP/VMUnprotect.Core/Hooks/Methods/VmProtectDumperTranspiler.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ namespace VMUnprotect.Core.Hooks.Methods {
1212
internal class Targets {
1313
private static readonly ILogger Logger = Engine.Logger;
1414

15-
1615
/// <summary>
1716
/// This function is used by current VMProtect version.
1817
/// </summary>
@@ -114,7 +113,6 @@ public object HookedInvokeOld(object obj, object[] parameters, MethodBase method
114113
public static class VmProtectDumperTranspiler {
115114
private static readonly ILogger Logger = Engine.Logger;
116115

117-
118116
/// <summary>A transpiler that replaces all occurrences of a given method with another with additional Ldarg_1 instruction</summary>
119117
/// <param name="instructions">The enumeration of <see cref="T:HarmonyLib.CodeInstruction" /> to act on</param>
120118
/// <param name="from">Method to search for</param>

VMUP/VMUnprotect.Core/Hooks/Methods/VmProtectDumperUnsafeInvoke.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics;
2+
using System.Reflection;
23
using VMUnprotect.Core.Abstraction;
34
using VMUnprotect.Core.MiddleMan;
45

@@ -13,20 +14,26 @@ public static class VmProtectDumperUnsafeInvoke {
1314
/// <summary>
1415
/// Prefix of UnsafeInvoke, this runs before.
1516
/// </summary>
16-
public static void InvokePrefix(ref object __instance, ref object obj, ref object[] parameters, ref object[] arguments) {
17+
public static bool InvokePrefix(ref object __result, ref object __instance, ref object obj, ref object[] parameters, ref object[] arguments) {
1718
// Check if this invoke is coming from VMP Handler
1819
var isVmpFunction = Engine.Ctx.RuntimeStructure?.FunctionHandler != null
1920
&& Engine.Ctx.RuntimeStructure != null
2021
&& new StackTrace().GetFrame(3).GetMethod().MetadataToken == Engine.Ctx.RuntimeStructure.FunctionHandler.MDToken.ToInt32();
21-
2222
if (!isVmpFunction)
23-
return;
23+
return true;
24+
25+
var methodInfo = (MethodInfo) __instance;
26+
27+
// Skip debugging functions
28+
if (!VmProtectBypassAntiDebug.Filter(out __result, obj, arguments, methodInfo))
29+
return false;
2430

2531
CtxLogger.Info("VmProtectDumperUnsafeInvoke Prefix:");
2632
CtxLogger.Warn("{");
27-
UnsafeInvokeMiddleMan.Prefix(ref __instance, ref obj, ref parameters, ref arguments);
33+
return UnsafeInvokeMiddleMan.Prefix(ref __result, ref __instance, ref obj, ref parameters, ref arguments);
2834
}
2935

36+
3037
/// <summary>
3138
/// Postfix of UnsafeInvoke, this runs after.
3239
/// </summary>
@@ -35,10 +42,12 @@ public static void InvokePostfix(ref object __instance, ref object __result, ref
3542
var isVmpFunction = Engine.Ctx.RuntimeStructure?.FunctionHandler != null
3643
&& Engine.Ctx.RuntimeStructure != null
3744
&& new StackTrace().GetFrame(3).GetMethod().MetadataToken == Engine.Ctx.RuntimeStructure.FunctionHandler.MDToken.ToInt32();
38-
3945
if (!isVmpFunction)
4046
return;
4147

48+
// Find NtQueryInformationProcessDelegate
49+
VmProtectBypassAntiDebug.FindNtQueryInformationProcessDelegate(__result, parameters);
50+
4251
// Log it
4352
CtxLogger.Info("VmProtectDumperUnsafeInvoke Result:");
4453
UnsafeInvokeMiddleMan.Postfix(ref __instance, ref __result, ref obj, ref parameters, ref arguments);

0 commit comments

Comments
 (0)