├── .gitattributes ├── Deps ├── Echo.dll ├── shield.png ├── Echo.ControlFlow.dll └── Echo.Platforms.AsmResolver.dll ├── VirtualGuard.Tests ├── Program.cs ├── VirtualGuard.Tests.csproj └── CRC.cs ├── VirtualGuard.SDK ├── ExcludeAttribute.cs ├── VirtualizationAttribute.cs ├── Test.cs └── VirtualGuard.SDK.csproj ├── global.json ├── VirtualGuard.CLI ├── LicenseType.cs ├── Processors │ ├── IProcessor.cs │ └── impl │ │ ├── Watermark.cs │ │ ├── FieldVirtualization.cs │ │ ├── Virtualization.cs │ │ ├── FreeLimitations.cs │ │ ├── PostDataEncryption.cs │ │ ├── Renamer.cs │ │ └── ImportProtection.cs ├── ConsoleLogger.cs ├── VirtualGuard.CLI.csproj ├── Config │ ├── SerializedConfig.cs │ ├── SerializedMember.cs │ └── ConfigGenerator.cs ├── Context.cs ├── MultiProcessorVirtualizer.cs └── Program.cs ├── VirtualGuard ├── AST │ ├── IL │ │ ├── MarkerType.cs │ │ └── Marker.cs │ ├── AstBlock.cs │ ├── AstMarker.cs │ ├── AstExpression.cs │ └── AstBuilder.cs ├── RT │ ├── Dynamic │ │ ├── Operation.cs │ │ ├── MutationStep.cs │ │ ├── OperationHelper.cs │ │ └── MutationExpression.cs │ ├── Chunk │ │ ├── IChunk.cs │ │ └── BinaryChunk.cs │ ├── VmElements.cs │ ├── Mutators │ │ ├── impl │ │ │ ├── ChunkShuffler.cs │ │ │ ├── EncodeStrings.cs │ │ │ ├── TokenAllocator.cs │ │ │ ├── FinalizeMutations.cs │ │ │ ├── BuildChunkKeys.cs │ │ │ ├── VmCalls.cs │ │ │ ├── Runtime │ │ │ │ ├── LocMutation.cs │ │ │ │ ├── EncryptExceptions.cs │ │ │ │ └── Renamer.cs │ │ │ ├── BranchMutator.cs │ │ │ ├── VirtualOpCodes.cs │ │ │ └── HandlerMutator.cs │ │ ├── IRuntimeMutator.cs │ │ └── MutationOperation.cs │ ├── Descriptor │ │ ├── ComparisonDescriptor.cs │ │ ├── VMDescriptor.cs │ │ ├── HashDescriptor.cs │ │ ├── CorLibTypeDescriptor.cs │ │ ├── ExceptionHandlerDescriptor.cs │ │ ├── DataDescriptor.cs │ │ └── Handler │ │ │ ├── VmHandler.cs │ │ │ └── HandlerResolver.cs │ └── RuntimeConfig.cs ├── ILogger.cs ├── VMIL │ ├── VM │ │ ├── VmVariable.cs │ │ ├── DynamicStartKeyReference.cs │ │ ├── VmCode.cs │ │ ├── VmInstruction.cs │ │ └── VmBlock.cs │ └── Translation │ │ ├── impl │ │ ├── RetTranslator.cs │ │ ├── MemberOpTranslator.cs │ │ ├── UnconditionalTranslator.cs │ │ ├── ExceptionTranslator.cs │ │ ├── LocalTranslator.cs │ │ ├── ArgumentTranslator.cs │ │ ├── FieldTranslator.cs │ │ ├── BitwiseTranslator.cs │ │ ├── ArithmeticTranslator.cs │ │ ├── MarkerTranslator.cs │ │ ├── CallTranslator.cs │ │ ├── ConstantTranslator.cs │ │ ├── MiscTranslator.cs │ │ ├── ComparisonTranslator.cs │ │ ├── ConvTranslator.cs │ │ └── ArrayTranslator.cs │ │ └── ITranslator.cs ├── VirtualGuardContext.cs ├── Transform │ └── IL │ │ ├── impl │ │ ├── Nullifier.cs │ │ ├── BlockConnector.cs │ │ └── ConditionalSimplifier.cs │ │ └── IIlTransformer.cs ├── VirtualGuard.csproj └── Virtualizer.cs ├── VirtualGuard.Runtime ├── IElement.cs ├── Execution │ ├── ExecutionState.cs │ └── ExceptionHandler.cs ├── OpCodes │ ├── IOpCode.cs │ ├── impl │ │ ├── Flow │ │ │ ├── Ret.cs │ │ │ ├── Jmp.cs │ │ │ ├── Vmcall.cs │ │ │ └── Call.cs │ │ ├── Constant │ │ │ ├── Ldc_R4.cs │ │ │ ├── Ldc_R8.cs │ │ │ ├── Ldc_I4.cs │ │ │ ├── Ldc_I8.cs │ │ │ └── Ldstr.cs │ │ ├── Custom │ │ │ ├── Hash.cs │ │ │ ├── GetKey.cs │ │ │ └── Cmp.cs │ │ ├── Array │ │ │ ├── Ldlen.cs │ │ │ ├── Stelem.cs │ │ │ ├── Newarr.cs │ │ │ ├── Ldelem.cs │ │ │ └── Ldelema.cs │ │ ├── Stack │ │ │ ├── Dup.cs │ │ │ └── Pop.cs │ │ ├── Bitwise │ │ │ ├── Not.cs │ │ │ ├── Shl.cs │ │ │ ├── Shr.cs │ │ │ ├── And.cs │ │ │ ├── Or.cs │ │ │ └── Xor.cs │ │ ├── Local │ │ │ ├── Stloc.cs │ │ │ ├── Ldloc.cs │ │ │ └── Ldloca.cs │ │ ├── Conversion │ │ │ ├── Box.cs │ │ │ ├── Unboxany.cs │ │ │ ├── Castclass.cs │ │ │ ├── Unbox.cs │ │ │ └── Conv.cs │ │ ├── Exception │ │ │ ├── Throw.cs │ │ │ ├── Entertry.cs │ │ │ └── Leave.cs │ │ ├── Pointer │ │ │ ├── Ldftn.cs │ │ │ ├── Ldind.cs │ │ │ └── Stind.cs │ │ ├── Arithmetic │ │ │ ├── Div.cs │ │ │ ├── Mul.cs │ │ │ ├── Rem.cs │ │ │ ├── Add.cs │ │ │ └── Sub.cs │ │ ├── Field │ │ │ ├── Stfld.cs │ │ │ ├── Ldflda.cs │ │ │ └── Ldfld.cs │ │ └── Misc │ │ │ ├── Ldtoken.cs │ │ │ └── Sizeof.cs │ └── CodeMap.cs ├── Variant │ ├── Reference │ │ ├── BaseReferenceVariant.cs │ │ └── impl │ │ │ ├── BoxedReferenceVariant.cs │ │ │ ├── LocalReferenceVariant.cs │ │ │ ├── FieldReferenceVariant.cs │ │ │ ├── PointerReferenceVariant.cs │ │ │ └── ArrayReferenceVariant.cs │ ├── Object │ │ ├── NullVariant.cs │ │ ├── ObjectVariant.cs │ │ └── ArrayVariant.cs │ └── ValueType │ │ ├── StringVariant.cs │ │ └── Numeric │ │ ├── NumeralVariant.cs │ │ ├── LongVariant.cs │ │ ├── UIntVariant.cs │ │ └── ULongVariant.cs ├── Dynamic │ ├── Routines.cs │ └── Constants.cs ├── VirtualGuard.Runtime.csproj ├── Util.cs ├── Entry.cs ├── Junk │ └── HandlerJunkCode.cs ├── LocalStorage.cs ├── VMStack.cs └── VMContext.cs ├── .idea └── .idea.VirtualGuard │ └── .idea │ ├── encodings.xml │ ├── vcs.xml │ ├── indexLayout.xml │ └── .gitignore ├── VirtualGuard.Stubs ├── VirtualGuard.Stubs.csproj ├── ProxyFieldBase.cs ├── ProxyFieldChild.cs └── Limiter.cs ├── VirtualGuard.sln.DotSettings ├── README.md └── VirtualGuard.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Deps/Echo.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitoiscool/VirtualGuard/HEAD/Deps/Echo.dll -------------------------------------------------------------------------------- /Deps/shield.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitoiscool/VirtualGuard/HEAD/Deps/shield.png -------------------------------------------------------------------------------- /Deps/Echo.ControlFlow.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitoiscool/VirtualGuard/HEAD/Deps/Echo.ControlFlow.dll -------------------------------------------------------------------------------- /VirtualGuard.Tests/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | Console.WriteLine("test"); -------------------------------------------------------------------------------- /Deps/Echo.Platforms.AsmResolver.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitoiscool/VirtualGuard/HEAD/Deps/Echo.Platforms.AsmResolver.dll -------------------------------------------------------------------------------- /VirtualGuard.SDK/ExcludeAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.SDK; 2 | 3 | public class ExcludeAttribute : Attribute 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.0", 4 | "rollForward": "latestMajor", 5 | "allowPrerelease": true 6 | } 7 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/LicenseType.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.CLI; 2 | 3 | public enum LicenseType 4 | { 5 | Free, 6 | Lite, 7 | Plus 8 | } -------------------------------------------------------------------------------- /VirtualGuard.SDK/VirtualizationAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.SDK; 2 | 3 | public class VirtualizationAttribute : Attribute 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /VirtualGuard/AST/IL/MarkerType.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.AST.IL; 2 | 3 | internal enum MarkerType 4 | { 5 | TryStart, 6 | HandlerStart, 7 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Dynamic/Operation.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.RT.Dynamic; 2 | 3 | internal enum Operation 4 | { 5 | Add, 6 | Sub, 7 | Xor, 8 | } -------------------------------------------------------------------------------- /VirtualGuard/AST/AstBlock.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | using Echo.ControlFlow; 3 | 4 | namespace VirtualGuard.AST; 5 | 6 | internal class AstBlock : List 7 | { 8 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/IElement.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime 2 | { 3 | 4 | public interface IElement 5 | { 6 | void SetValue(int i); 7 | int GetValue(); 8 | } 9 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Processors/IProcessor.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.CLI.Processors; 2 | 3 | public interface IProcessor 4 | { 5 | public string Identifier { get; } 6 | public void Process(Context ctx); 7 | 8 | } -------------------------------------------------------------------------------- /.idea/.idea.VirtualGuard/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/.idea.VirtualGuard/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Execution/ExecutionState.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.Execution 2 | { 3 | 4 | public enum ExecutionState 5 | { 6 | Next, 7 | Exit, 8 | Catch, 9 | Finally 10 | } 11 | } -------------------------------------------------------------------------------- /VirtualGuard/ILogger.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard; 2 | 3 | public interface ILogger 4 | { 5 | public void Info(string msg); 6 | public void Success(string msg); 7 | public void Warning(string msg); 8 | public void Fatal(string msg); 9 | } -------------------------------------------------------------------------------- /VirtualGuard.Stubs/VirtualGuard.Stubs.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | disable 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /VirtualGuard/RT/Chunk/IChunk.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.RT.Chunk; 2 | 3 | internal interface IChunk 4 | { 5 | public int Length { get; } 6 | public void OnOffsetComputed(int offset); 7 | public void WriteBytes(BinaryWriter writer, VirtualGuardRT rt); 8 | } -------------------------------------------------------------------------------- /.idea/.idea.VirtualGuard/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/IOpCode.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Execution; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes 4 | { 5 | 6 | public interface IOpCode 7 | { 8 | void Execute(VMContext ctx); 9 | byte GetCode(); 10 | } 11 | } -------------------------------------------------------------------------------- /VirtualGuard.SDK/Test.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.SDK; 2 | 3 | public class Test 4 | { 5 | void Main() 6 | { 7 | int i = int.Parse(Console.ReadLine()); 8 | 9 | if (i == 12) 10 | { 11 | Console.WriteLine("i was 12"); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Processors/impl/Watermark.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.CLI.Processors.impl; 2 | 3 | public class Watermark : IProcessor 4 | { 5 | public string Identifier => "Watermark"; 6 | public void Process(Context ctx) 7 | { 8 | ctx.Module.Name = "virtualguard.io"; 9 | } 10 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Dynamic/MutationStep.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.RT.Dynamic; 2 | 3 | internal class MutationStep 4 | { 5 | public MutationStep(int mod, Operation op) 6 | { 7 | Modifier = mod; 8 | Operation = op; 9 | } 10 | public int Modifier; 11 | public Operation Operation; 12 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/VmElements.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | 3 | namespace VirtualGuard.RT; 4 | 5 | public struct VmElements 6 | { 7 | public MethodDefinition VmEntry; 8 | public MethodDefinition VmEntryInst; 9 | public MethodDefinition VmEntryNoArgs; 10 | 11 | public TypeDefinition[] VmTypes; 12 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/VM/VmVariable.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.VMIL.VM; 2 | 3 | internal class VmVariable 4 | { 5 | public VmVariable(short id) 6 | { 7 | Id = id; 8 | } 9 | 10 | public short Id; 11 | 12 | public override string ToString() 13 | { 14 | return ""; 15 | } 16 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Flow/Ret.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Flow 2 | { 3 | 4 | public class Ret : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | // lol probably a better way to do this 9 | } 10 | 11 | public byte GetCode() => 0; 12 | } 13 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/Reference/BaseReferenceVariant.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace VirtualGuard.Runtime.Variant.Reference 4 | { 5 | 6 | public abstract class BaseReferenceVariant : BaseVariant 7 | { 8 | public override bool IsReference() 9 | { 10 | return true; 11 | } 12 | 13 | } 14 | } -------------------------------------------------------------------------------- /VirtualGuard.Tests/VirtualGuard.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /VirtualGuard.SDK/VirtualGuard.SDK.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | enable 6 | disable 7 | 10 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Constant/Ldc_R4.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Constant 2 | { 3 | 4 | public class Ldc_R4 : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | throw new NotImplementedException(); 9 | } 10 | 11 | public byte GetCode() => 0; 12 | } 13 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Constant/Ldc_R8.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Constant 2 | { 3 | 4 | public class Ldc_R8 : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | throw new NotImplementedException(); 9 | } 10 | 11 | public byte GetCode() => 0; 12 | } 13 | } -------------------------------------------------------------------------------- /VirtualGuard/AST/AstMarker.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | using VirtualGuard.AST.IL; 3 | 4 | namespace VirtualGuard.AST; 5 | 6 | 7 | internal class AstMarker : AstExpression 8 | { 9 | public AstMarker(CilOpCode opCode, object operand, AstExpression[] exprs) : base(opCode, operand, exprs) 10 | { 11 | } 12 | 13 | public MarkerType Type; 14 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Chunk/BinaryChunk.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.RT.Chunk; 2 | 3 | internal class BinaryChunk : IChunk 4 | { 5 | public int Length => 0; // todo 6 | public void OnOffsetComputed(int offset) 7 | { 8 | 9 | } 10 | 11 | public void WriteBytes(BinaryWriter writer, VirtualGuardRT rt) 12 | { 13 | 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /.idea/.idea.VirtualGuard/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /contentModel.xml 6 | /modules.xml 7 | /.idea.VirtualGuard.iml 8 | /projectSettingsUpdater.xml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/ChunkShuffler.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.RT.Mutators.impl; 2 | 3 | internal class ChunkShuffler : IRuntimeMutator 4 | { 5 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 6 | { 7 | if(rt.isDebug) 8 | return; 9 | 10 | rt.GetChunkList().Shuffle(); 11 | 12 | rt.UpdateOffsets(); 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /VirtualGuard.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | False -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Custom/Hash.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Custom; 2 | 3 | public class Hash : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | ctx.Stack.Push(ctx.Stack.Pop().Hash()); 8 | 9 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 10 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 11 | } 12 | 13 | public byte GetCode() => 0; 14 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Execution/ExceptionHandler.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.Execution; 2 | 3 | public class ExceptionHandler 4 | { 5 | public ExceptionHandler(byte t, byte start, int handlerPos) 6 | { 7 | Type = t; 8 | HandlerStartKey = start; 9 | HandlerPos = handlerPos; 10 | } 11 | 12 | public byte Type; 13 | 14 | public byte HandlerStartKey; 15 | public int HandlerPos; 16 | } -------------------------------------------------------------------------------- /VirtualGuard.Stubs/ProxyFieldBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace VirtualGuard.Stubs 5 | { 6 | public abstract class ProxyFieldBase 7 | { 8 | public virtual object GetValue() 9 | { 10 | return "via https://virtualguard.io/"; 11 | } 12 | 13 | public virtual void SetValue(object obj) 14 | { 15 | Environment.Exit(-186414); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Array/Ldlen.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Array; 2 | 3 | public class Ldlen : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | ctx.Stack.Push(ctx.Stack.Pop().ToArray().GetLength()); 8 | 9 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 10 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 11 | } 12 | 13 | public byte GetCode() => 0; 14 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Descriptor/ComparisonDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.RT.Descriptor; 2 | 3 | internal class ComparisonDescriptor 4 | { 5 | public ComparisonDescriptor(Random rnd) 6 | { 7 | GtFlag = (byte)rnd.Next(byte.MaxValue); 8 | LtFlag = (byte)rnd.Next(byte.MaxValue); 9 | EqFlag = (byte)rnd.Next(byte.MaxValue); 10 | } 11 | 12 | 13 | public byte GtFlag; 14 | public byte LtFlag; 15 | public byte EqFlag; 16 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Descriptor/VMDescriptor.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.RT.Descriptor.Handler; 2 | 3 | namespace VirtualGuard.RT.Descriptor; 4 | 5 | internal class VMDescriptor 6 | { 7 | public HandlerResolver OpCodes; 8 | public DataDescriptor Data; 9 | public ComparisonDescriptor ComparisonFlags; 10 | public CorLibTypeDescriptor CorLibTypeDescriptor; 11 | public ExceptionHandlerDescriptor ExceptionHandlers; 12 | public HashDescriptor HashDescriptor; 13 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Stack/Dup.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Stack 2 | { 3 | 4 | public class Dup : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | ctx.Stack.Push(ctx.Stack.Peek().Clone()); 9 | 10 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 11 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 12 | } 13 | 14 | public byte GetCode() => 0; 15 | } 16 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Stack/Pop.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Stack 2 | { 3 | 4 | public class Pop : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | ctx.Stack.Pop(); 9 | 10 | 11 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 12 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 13 | } 14 | 15 | public byte GetCode() => 0; 16 | } 17 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Bitwise/Not.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Bitwise 2 | { 3 | public class Not : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | ctx.Stack.Push(ctx.Stack.Pop().ToNumeral().Not()); 8 | 9 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 10 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 11 | } 12 | 13 | public byte GetCode() => 0; 14 | } 15 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Local/Stloc.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Local 2 | { 3 | 4 | public class Stloc : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | ctx.Locals.SetLocal(ctx.Reader.ReadShort(), ctx.Stack.Pop()); 9 | 10 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 11 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 12 | } 13 | 14 | public byte GetCode() => 0; 15 | } 16 | } -------------------------------------------------------------------------------- /VirtualGuard.Stubs/ProxyFieldChild.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace VirtualGuard.Stubs 3 | { 4 | public class ProxyFieldChild : ProxyFieldBase 5 | { 6 | private object _obj; 7 | 8 | void InitializeValue() 9 | { 10 | 11 | } 12 | 13 | public override object GetValue() 14 | { 15 | return _obj; 16 | } 17 | 18 | public override void SetValue(object obj) 19 | { 20 | _obj = obj; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Conversion/Box.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Conversion; 2 | 3 | public class Box : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | var type = ctx.ResolveType(ctx.Reader.ReadInt()); 8 | 9 | ctx.Stack.Push(ctx.Stack.Pop().Cast(type).Box()); 10 | 11 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 12 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 13 | } 14 | 15 | public byte GetCode() => 0; 16 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Custom/GetKey.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Custom; 4 | 5 | public class GetKey : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | ctx.Stack.Push(new UIntVariant(ctx.Reader.GetKey())); 10 | 11 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 12 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 13 | } 14 | 15 | public byte GetCode() => 0; 16 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Local/Ldloc.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Local 2 | { 3 | 4 | public class Ldloc : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | ctx.Stack.Push(ctx.Locals.GetLocal(ctx.Reader.ReadShort())); 9 | 10 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 11 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 12 | } 13 | 14 | public byte GetCode() => 0; 15 | 16 | } 17 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Conversion/Unboxany.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Conversion; 2 | 3 | public class Unboxany : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | var type = ctx.ResolveType(ctx.Reader.ReadInt()); 8 | 9 | ctx.Stack.Push(ctx.Stack.Pop().Unbox().Cast(type)); 10 | 11 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 12 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 13 | } 14 | 15 | public byte GetCode() => 0; 16 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Bitwise/Shl.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Bitwise; 2 | 3 | public class Shl : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | var factor = ctx.Stack.Pop(); 8 | var num = ctx.Stack.Pop(); 9 | 10 | ctx.Stack.Push(num.ToNumeral().Shl(factor.ToNumeral())); 11 | 12 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 13 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 14 | } 15 | 16 | public byte GetCode() => 0; 17 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Bitwise/Shr.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Bitwise; 2 | 3 | public class Shr : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | var factor = ctx.Stack.Pop(); 8 | var num = ctx.Stack.Pop(); 9 | 10 | ctx.Stack.Push(num.ToNumeral().Shr(factor.ToNumeral())); 11 | 12 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 13 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 14 | } 15 | 16 | public byte GetCode() => 0; 17 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Array/Stelem.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Array 2 | { 3 | public class Stelem : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | var arr = ctx.Stack.Pop().ToArray(); 8 | 9 | arr.SetDelimeter(ctx.Stack.Pop(), ctx.Stack.Pop()); 10 | 11 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 12 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 13 | } 14 | 15 | public byte GetCode() => 0; 16 | } 17 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Exception/Throw.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Dynamic; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Exception; 4 | 5 | public class Throw : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | var exc = ctx.Stack.Pop().GetObject(); 10 | 11 | if (exc is System.Exception ex) 12 | throw ex; 13 | 14 | throw new InvalidOperationException(Routines.EncryptDebugMessage("Popped exception could not be thrown.")); 15 | } 16 | 17 | public byte GetCode() => 0; 18 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Pointer/Ldftn.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.Object; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Pointer; 4 | 5 | public class Ldftn : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | ctx.Stack.Push(new ObjectVariant(ctx.ResolveMethod(ctx.Reader.ReadInt()).MethodHandle.GetFunctionPointer())); 10 | 11 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 12 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 13 | } 14 | 15 | public byte GetCode() => 0; 16 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Array/Newarr.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.Object; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Array; 4 | 5 | public class Newarr : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | ctx.Stack.Push(new ArrayVariant(System.Array.CreateInstance(ctx.ResolveType(ctx.Reader.ReadInt()), ctx.Stack.Pop().I4()))); 10 | 11 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 12 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 13 | } 14 | 15 | public byte GetCode() => 0; 16 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Constant/Ldc_I4.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Constant 4 | { 5 | 6 | public class Ldc_I4 : IOpCode 7 | { 8 | public void Execute(VMContext ctx) 9 | { 10 | ctx.Stack.Push(new IntVariant(ctx.Reader.ReadInt())); 11 | 12 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 13 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 14 | } 15 | 16 | public byte GetCode() => 0; 17 | } 18 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Constant/Ldc_I8.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Constant 4 | { 5 | 6 | public class Ldc_I8 : IOpCode 7 | { 8 | public void Execute(VMContext ctx) 9 | { 10 | ctx.Stack.Push(new LongVariant(ctx.Reader.ReadLong())); 11 | 12 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 13 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 14 | } 15 | 16 | public byte GetCode() => 0; 17 | } 18 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Bitwise/And.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Bitwise 2 | { 3 | public class And : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | var i2 = ctx.Stack.Pop().ToNumeral(); 8 | var i1 = ctx.Stack.Pop().ToNumeral(); 9 | 10 | ctx.Stack.Push(i1.And(i2)); 11 | 12 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 13 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 14 | } 15 | 16 | public byte GetCode() => 0; 17 | } 18 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Bitwise/Or.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Bitwise 2 | { 3 | public class Or : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | var i2 = ctx.Stack.Pop().ToNumeral(); 8 | var i1 = ctx.Stack.Pop().ToNumeral(); 9 | 10 | ctx.Stack.Push(i1.Or(i2)); 11 | 12 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 13 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 14 | } 15 | 16 | public byte GetCode() => 0; 17 | } 18 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/Object/NullVariant.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace VirtualGuard.Runtime.Variant.Object 4 | { 5 | 6 | public class NullVariant : BaseVariant 7 | { 8 | public override object GetObject() 9 | { 10 | return null; 11 | } 12 | 13 | public override void SetVariantValue(object obj) 14 | { 15 | throw new InvalidOperationException(); 16 | } 17 | 18 | public override BaseVariant Clone() 19 | { 20 | return new NullVariant(); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Arithmetic/Div.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Arithmetic 2 | { 3 | 4 | public class Div : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | var i2 = ctx.Stack.Pop().ToNumeral(); 9 | var i1 = ctx.Stack.Pop().ToNumeral(); 10 | 11 | ctx.Stack.Push(i1.Div(i2)); 12 | 13 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 14 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 15 | } 16 | 17 | public byte GetCode() => 0; 18 | } 19 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Arithmetic/Mul.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Arithmetic 2 | { 3 | 4 | public class Mul : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | var i2 = ctx.Stack.Pop().ToNumeral(); 9 | var i1 = ctx.Stack.Pop().ToNumeral(); 10 | 11 | ctx.Stack.Push(i1.Mul(i2)); 12 | 13 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 14 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 15 | } 16 | 17 | public byte GetCode() => 0; 18 | } 19 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/VM/DynamicStartKeyReference.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | using Echo.ControlFlow; 3 | using VirtualGuard.RT.Chunk; 4 | 5 | namespace VirtualGuard.VMIL.VM; 6 | 7 | internal class DynamicStartKeyReference 8 | { 9 | public DynamicStartKeyReference(ControlFlowNode node, bool isConditional) 10 | { 11 | Node = node; 12 | IsConditional = isConditional; 13 | } 14 | 15 | public bool IsConditional; 16 | 17 | public VmBlock VmBlock; 18 | public VmChunk Chunk; 19 | public ControlFlowNode Node; 20 | } -------------------------------------------------------------------------------- /VirtualGuard/VirtualGuardContext.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | using VirtualGuard.RT; 3 | 4 | namespace VirtualGuard; 5 | 6 | public class VirtualGuardContext 7 | { 8 | public VirtualGuardContext(ModuleDefinition mod, ILogger logger) 9 | { 10 | Module = mod; 11 | Logger = logger; 12 | } 13 | 14 | internal VirtualGuardRT Runtime; 15 | public ILogger Logger; 16 | public ModuleDefinition Module; 17 | public Dictionary VirtualizedMethods = new Dictionary(); // populated once methods added 18 | 19 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Arithmetic/Rem.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Arithmetic 2 | { 3 | public class Rem : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | var i2 = ctx.Stack.Pop().ToNumeral(); 8 | var i1 = ctx.Stack.Pop().ToNumeral(); 9 | 10 | ctx.Stack.Push(i1.Rem(i2)); 11 | 12 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 13 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 14 | } 15 | 16 | public byte GetCode() => 0; 17 | } 18 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Array/Ldelem.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Array 2 | { 3 | public class Ldelem : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | var delem = ctx.Stack.Pop(); 8 | var arr = ctx.Stack.Pop().ToArray(); 9 | 10 | ctx.Stack.Push(arr.LoadDelimeter(delem)); 11 | 12 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 13 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 14 | } 15 | 16 | public byte GetCode() => 0; 17 | } 18 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Flow/Jmp.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Flow 2 | { 3 | 4 | public class Jmp : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | var key = ctx.Stack.Pop().U1(); 9 | 10 | ctx.Reader.SetKey(key); 11 | ctx.Reader.SetValue(ctx.Stack.Pop().I4()); 12 | 13 | ctx.CurrentCode = ctx.Reader.ReadFixupValue(); 14 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 15 | } 16 | 17 | public byte GetCode() => 0; 18 | } 19 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Arithmetic/Add.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Arithmetic 2 | { 3 | 4 | public class Add : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | var i2 = ctx.Stack.Pop().ToNumeral(); 9 | var i1 = ctx.Stack.Pop().ToNumeral(); 10 | 11 | ctx.Stack.Push(i1.Add(i2)); 12 | 13 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 14 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 15 | } 16 | 17 | public byte GetCode() => 0; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/EncodeStrings.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.RT.Mutators.impl; 2 | 3 | internal class EncodeStrings : IRuntimeMutator 4 | { 5 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 6 | { 7 | 8 | 9 | foreach (var instr in rt.VmChunks.SelectMany(x => x.Content)) 10 | { 11 | if (instr.Operand is string str) 12 | { 13 | instr.Operand = rt.Descriptor.Data.AddString(str); 14 | } 15 | 16 | 17 | } 18 | 19 | 20 | 21 | } 22 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Processors/impl/FieldVirtualization.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | 3 | namespace VirtualGuard.CLI.Processors.impl; 4 | 5 | public class FieldVirtualization : IProcessor 6 | { 7 | public string Identifier => "Field Virtualization"; 8 | public void Process(Context ctx) 9 | { 10 | foreach (var type in ctx.Module.GetAllTypes()) 11 | foreach (var field in type.Fields) 12 | { 13 | 14 | 15 | 16 | } 17 | 18 | } 19 | 20 | /*TypeDefinition BuildHolderField() 21 | { 22 | 23 | }*/ 24 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Arithmetic/Sub.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Arithmetic 2 | { 3 | 4 | public class Sub : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | var i2 = ctx.Stack.Pop().ToNumeral(); 9 | var i1 = ctx.Stack.Pop().ToNumeral(); 10 | 11 | ctx.Stack.Push(i1.Sub(i2)); 12 | 13 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 14 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 15 | } 16 | 17 | public byte GetCode() => 0; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Bitwise/Xor.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Bitwise 2 | { 3 | public class Xor : IOpCode 4 | { 5 | public void Execute(VMContext ctx) 6 | { 7 | var i2 = ctx.Stack.Pop().ToNumeral(); 8 | var i1 = ctx.Stack.Pop().ToNumeral(); 9 | 10 | ctx.Stack.Push(i1.Xor(i2)); 11 | 12 | // basic jmp routine 13 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 14 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 15 | } 16 | 17 | public byte GetCode() => 0; 18 | } 19 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Dynamic/Routines.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.Dynamic 2 | { 3 | 4 | public static class Routines 5 | { 6 | public static void Exit(string msg) 7 | { 8 | // dynamically replaced 9 | } 10 | 11 | public static string EncryptDebugMessage(string message) 12 | { // this will just mark a string for encryption 13 | return null; 14 | } 15 | 16 | public static void PrintDebug(string message) 17 | { // this will be removed if built in release 18 | Console.WriteLine(message); 19 | } 20 | 21 | } 22 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Conversion/Castclass.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.Object; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Conversion; 4 | 5 | public class Castclass : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | var type = ctx.ResolveType(ctx.Reader.ReadInt()); 10 | 11 | ctx.Stack.Push(new ObjectVariant(Convert.ChangeType(ctx.Stack.Pop().GetObject(), type))); 12 | 13 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 14 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 15 | } 16 | 17 | public byte GetCode() => 0; 18 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Local/Ldloca.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.Reference.impl; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Local 4 | { 5 | public class Ldloca : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | var local = ctx.Locals.GetLocal(ctx.Reader.ReadShort()); 10 | 11 | ctx.Stack.Push(new LocalReferenceVariant(local)); 12 | 13 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 14 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 15 | } 16 | 17 | public byte GetCode() => 0; 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Exception/Entertry.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Execution; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Exception; 4 | 5 | public class Entertry : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | 10 | var loc = ctx.Stack.Pop(); 11 | var type = ctx.Stack.Pop(); 12 | var entry = ctx.Reader.ReadByte(); 13 | 14 | ctx.HandlerStack.Push(new ExceptionHandler(type.U1(), entry, loc.I4())); 15 | 16 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 17 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 18 | } 19 | 20 | public byte GetCode() => 0; 21 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/Object/ObjectVariant.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.Variant.Object 2 | { 3 | 4 | public class ObjectVariant : BaseVariant 5 | { 6 | public ObjectVariant(object obj) 7 | { 8 | _obj = obj; 9 | } 10 | 11 | private object _obj; 12 | 13 | public override object GetObject() 14 | { 15 | return _obj; 16 | } 17 | 18 | public override void SetVariantValue(object obj) 19 | { 20 | _obj = obj; 21 | } 22 | 23 | public override BaseVariant Clone() 24 | { 25 | return new ObjectVariant(_obj); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Field/Stfld.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.OpCodes.impl.Field 2 | { 3 | 4 | public class Stfld : IOpCode 5 | { 6 | public void Execute(VMContext ctx) 7 | { 8 | var field = ctx.ResolveField(ctx.Stack.Pop().I4()); 9 | 10 | object inst = null; 11 | 12 | if (!field.IsStatic) 13 | inst = ctx.Stack.Pop(); 14 | 15 | field.SetValue(inst, ctx.Stack.Pop().GetObject()); 16 | 17 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 18 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 19 | } 20 | 21 | public byte GetCode() => 0; 22 | } 23 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/Reference/impl/BoxedReferenceVariant.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.Variant.Reference.impl; 2 | 3 | public class BoxedReferenceVariant : BaseReferenceVariant 4 | { 5 | private BaseVariant _var; 6 | public BoxedReferenceVariant(BaseVariant var) 7 | { 8 | _var = var; 9 | } 10 | 11 | public override object GetObject() 12 | { 13 | return _var.GetObject(); 14 | } 15 | 16 | public override void SetVariantValue(object obj) 17 | { 18 | _var.SetVariantValue(obj); 19 | } 20 | 21 | public override BaseVariant Clone() 22 | { 23 | return new BoxedReferenceVariant(_var); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/ConsoleLogger.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.CLI; 2 | 3 | public class ConsoleLogger : ILogger 4 | { 5 | public void Info(string msg) 6 | { 7 | Console.WriteLine("[i] " + msg); 8 | } 9 | 10 | public void Success(string msg) 11 | { 12 | Console.WriteLine("[+] " + msg); 13 | } 14 | 15 | public void Warning(string msg) 16 | { 17 | Console.WriteLine("[!] " + msg); 18 | } 19 | 20 | public void Fatal(string msg) 21 | { 22 | Console.WriteLine("[FATAL] " + msg); 23 | Environment.Exit(-1); 24 | } 25 | 26 | public void Verbose(string msg) 27 | { 28 | Console.WriteLine("[v] " + msg); 29 | } 30 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Array/Ldelema.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.Reference.impl; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Array 4 | { 5 | public class Ldelema : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { // need to make arrayreferencevariant 9 | 10 | var delem = ctx.Stack.Pop(); 11 | var arr = ctx.Stack.Pop().ToArray(); 12 | 13 | ctx.Stack.Push(new ArrayReferenceVariant(arr, delem)); 14 | 15 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 16 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 17 | } 18 | 19 | public byte GetCode() => 0; 20 | } 21 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Processors/impl/Virtualization.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.CLI.Processors.impl; 2 | 3 | public class Virtualization : IProcessor 4 | { 5 | public string Identifier => "Virtualization"; 6 | 7 | public void Process(Context ctx) 8 | { 9 | // mark methods 10 | 11 | if (ctx.License != LicenseType.Free) 12 | { 13 | foreach (var virtualizedMethod in ctx.Configuration.ResolveVirtualizedMethods(ctx)) 14 | { 15 | ctx.Virtualizer.AddMethod(virtualizedMethod, true); 16 | } 17 | } 18 | 19 | // still commit because other methods could be virtualized 20 | ctx.Virtualizer.Commit(); 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Descriptor/HashDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.RT.Descriptor; 2 | 3 | internal class HashDescriptor 4 | { 5 | public HashDescriptor(Random rnd) 6 | { 7 | NKey = (byte)rnd.Next(255); 8 | 9 | NSalt1 = (byte)rnd.Next(255); 10 | NSalt2 = (byte)rnd.Next(255); 11 | NSalt3 = (byte)rnd.Next(255); 12 | 13 | SPolynomial = (uint)rnd.Next(); 14 | SSeed = (uint)rnd.Next(); 15 | SXorMask = (uint)rnd.Next(); 16 | 17 | 18 | } 19 | 20 | public byte NKey; 21 | 22 | public byte NSalt1; 23 | public byte NSalt2; 24 | public byte NSalt3; 25 | 26 | public uint SPolynomial; 27 | public uint SSeed; 28 | public uint SXorMask; 29 | } -------------------------------------------------------------------------------- /VirtualGuard/Transform/IL/impl/Nullifier.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | using Echo.ControlFlow; 3 | using VirtualGuard.AST.IL; 4 | 5 | namespace VirtualGuard.Transform.IL.impl; 6 | 7 | internal class Nullifier : IILTransformer 8 | { 9 | public void Transform(ControlFlowNode node, ControlFlowGraph ctx) 10 | { 11 | var instructions = node.Contents.Instructions; 12 | 13 | for (int i = instructions.Count - 1; i >= 0; i--) 14 | { 15 | var instruction = instructions[i]; 16 | if (instruction.OpCode.Code == CilCode.Nop && instruction is not Marker) 17 | { 18 | instructions.RemoveAt(i); 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Descriptor/CorLibTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.RT.Descriptor; 2 | 3 | internal class CorLibTypeDescriptor 4 | { 5 | public CorLibTypeDescriptor(Random rnd) 6 | { 7 | I = rnd.Next(); 8 | I1 = rnd.Next(); 9 | I2 = rnd.Next(); 10 | I4 = rnd.Next(); 11 | I8 = rnd.Next(); 12 | 13 | U = rnd.Next(); 14 | U1 = rnd.Next(); 15 | U2 = rnd.Next(); 16 | U4 = rnd.Next(); 17 | U8 = rnd.Next(); 18 | } 19 | 20 | public int I; 21 | public int I1; 22 | public int I2; 23 | public int I4; 24 | public int I8; 25 | 26 | public int U; 27 | public int U1; 28 | public int U2; 29 | public int U4; 30 | public int U8; 31 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/RuntimeConfig.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.RT; 2 | 3 | internal static class RuntimeConfig 4 | { 5 | public const string RuntimePath = "VirtualGuard.Runtime.dll"; 6 | 7 | public const string Constants = "VirtualGuard.Runtime.Dynamic.Constants"; 8 | public const string Routines = "VirtualGuard.Runtime.Dynamic.Routines"; 9 | 10 | public const string BaseHandler = "VirtualGuard.Runtime.OpCodes.impl"; 11 | 12 | public const string VmEntry = "VirtualGuard.Runtime.Entry:VMEntryBasic"; 13 | public const string VmEntryInst = "VirtualGuard.Runtime.Entry:VMEntryInst"; 14 | public const string VmEntryNoArgs = "VirtualGuard.Runtime.Entry:VMEntryNoArgs"; 15 | 16 | public const string JunkCode = "VirtualGuard.Runtime.Junk.HandlerJunkCode"; 17 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Constant/Ldstr.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.Object; 2 | using VirtualGuard.Runtime.Variant.ValueType; 3 | 4 | namespace VirtualGuard.Runtime.OpCodes.impl.Constant 5 | { 6 | 7 | public class Ldstr : IOpCode 8 | { 9 | public void Execute(VMContext ctx) 10 | { 11 | var res = ctx.Reader.ReadString((uint)ctx.Reader.ReadInt()); 12 | 13 | if(res == null) 14 | ctx.Stack.Push(new NullVariant()); 15 | else 16 | ctx.Stack.Push(new StringVariant(res)); 17 | 18 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 19 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 20 | } 21 | 22 | public byte GetCode() => 0; 23 | } 24 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Field/Ldflda.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.Reference.impl; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Field 4 | { 5 | public class Ldflda : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | var field = ctx.ResolveField(ctx.Stack.Pop().I4()); 10 | 11 | object inst = null; 12 | 13 | if (!field.IsStatic) 14 | inst = ctx.Stack.Pop(); 15 | 16 | ctx.Stack.Push(new FieldReferenceVariant(field, inst)); // no value here, interesting 17 | 18 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 19 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 20 | } 21 | 22 | public byte GetCode() => 0; 23 | } 24 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/TokenAllocator.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | 3 | namespace VirtualGuard.RT.Mutators.impl; 4 | 5 | internal class TokenAllocator : IRuntimeMutator 6 | { 7 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 8 | { 9 | var importedMembers = new List(); 10 | 11 | foreach (var member in rt.VmChunks.SelectMany(x => x.Content).Where(x => x.Operand is MetadataMember).Select(x => x.Operand).Cast().Where(x => x.MetadataToken.Rid == 0)) 12 | { // unassigned 13 | if(importedMembers.Contains(member)) 14 | continue; 15 | 16 | ctx.Module.TokenAllocator.AssignNextAvailableToken(member); 17 | importedMembers.Add(member); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/RetTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using Echo.ControlFlow; 4 | using VirtualGuard.AST; 5 | using VirtualGuard.VMIL.VM; 6 | 7 | namespace VirtualGuard.VMIL.Translation.impl; 8 | 9 | internal class RetTranslator : ITranslator 10 | { 11 | [Obfuscation(Feature = "virtualization")] 12 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 13 | VirtualGuardContext ctx) 14 | { 15 | block.WithContent( 16 | new VmInstruction(VmCode.Ret)); 17 | } 18 | 19 | [Obfuscation(Feature = "virtualization")] 20 | public bool Supports(AstExpression instr) 21 | { 22 | return instr.OpCode.Code == CilCode.Ret; 23 | } 24 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Pointer/Ldind.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.Reference.impl; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Pointer; 4 | 5 | public class Ldind : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | var type = ctx.ResolveType(ctx.Reader.ReadInt()); 10 | var v = ctx.Stack.Pop(); 11 | 12 | if (!v.IsReference()) 13 | unsafe 14 | { 15 | v = new PointerReferenceVariant(new IntPtr(System.Reflection.Pointer.Unbox(v.GetObject())), type); 16 | } 17 | 18 | ctx.Stack.Push(v); 19 | 20 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 21 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 22 | } 23 | 24 | public byte GetCode() => 0; 25 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Field/Ldfld.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Field 4 | { 5 | 6 | public class Ldfld : IOpCode 7 | { 8 | public void Execute(VMContext ctx) 9 | { 10 | var field = ctx.ResolveField(ctx.Stack.Pop().I4()); 11 | 12 | object inst = null; 13 | 14 | if (!field.IsStatic) // ldsfld 15 | inst = ctx.Stack.Pop().GetObject(); 16 | 17 | var value = BaseVariant.CreateVariant(field.GetValue(inst)); 18 | 19 | ctx.Stack.Push(value); 20 | 21 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 22 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 23 | } 24 | 25 | public byte GetCode() => 0; 26 | } 27 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/FinalizeMutations.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.RT.Chunk; 2 | using VirtualGuard.VMIL.VM; 3 | 4 | namespace VirtualGuard.RT.Mutators.impl; 5 | 6 | internal class FinalizeMutations : IRuntimeMutator 7 | { 8 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 9 | { 10 | rt.UpdateOffsets(); // shouldn't need to do this again 11 | 12 | foreach (var chunk in rt.VmChunks) 13 | foreach (var instr in chunk.Content) 14 | { 15 | if(instr.OpCode != VmCode.Ldc_I4) 16 | continue; 17 | 18 | if(instr.Operand is not MutationOperation mutationOperation) 19 | continue; 20 | 21 | instr.Operand = mutationOperation.Emulate(); 22 | } 23 | 24 | } 25 | 26 | 27 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/VirtualGuard.Runtime.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | enable 6 | disable 7 | 10 8 | true 9 | 10 | 11 | 12 | false 13 | none 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/Reference/impl/LocalReferenceVariant.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace VirtualGuard.Runtime.Variant.Reference.impl 4 | { 5 | public class LocalReferenceVariant : BaseReferenceVariant 6 | { 7 | private BaseVariant _variant; 8 | 9 | public LocalReferenceVariant(BaseVariant var) 10 | { 11 | _variant = var; 12 | } 13 | 14 | public override object GetObject() 15 | { 16 | return _variant.GetObject(); 17 | } 18 | 19 | public override void SetVariantValue(object obj) 20 | { 21 | _variant.SetVariantValue(obj); 22 | } 23 | 24 | public override BaseVariant Clone() 25 | { 26 | return new LocalReferenceVariant(_variant); 27 | } 28 | 29 | 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Custom/Cmp.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant; 2 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 3 | 4 | namespace VirtualGuard.Runtime.OpCodes.impl.Misc 5 | { 6 | 7 | public class Cmp : IOpCode 8 | { 9 | public void Execute(VMContext ctx) 10 | { 11 | var v2 = ctx.Stack.Pop(); 12 | var v1 = ctx.Stack.Pop(); 13 | 14 | // could do something cool where we have a custom conditional branch based off of a flag 15 | // flag type would be onstack followed by the actual flag 16 | 17 | ctx.Stack.Push(new IntVariant(BaseVariant.Compare(v1, v2))); 18 | 19 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 20 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 21 | } 22 | 23 | public byte GetCode() => 0; 24 | } 25 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/Reference/impl/FieldReferenceVariant.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace VirtualGuard.Runtime.Variant.Reference.impl 4 | { 5 | public class FieldReferenceVariant : BaseReferenceVariant 6 | { 7 | private FieldInfo _field; 8 | private object _inst; 9 | 10 | public FieldReferenceVariant(FieldInfo info, object inst) 11 | { 12 | _field = info; 13 | _inst = inst; 14 | } 15 | 16 | public override object GetObject() 17 | { 18 | return _field.GetValue(_inst); 19 | } 20 | 21 | public override void SetVariantValue(object obj) 22 | { 23 | _field.SetValue(_inst, obj); 24 | } 25 | 26 | public override BaseVariant Clone() 27 | { 28 | return new FieldReferenceVariant(_field, _inst); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/Reference/impl/PointerReferenceVariant.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace VirtualGuard.Runtime.Variant.Reference.impl; 4 | 5 | public class PointerReferenceVariant : BaseReferenceVariant 6 | { 7 | private IntPtr _ptr; 8 | private Type _t; 9 | 10 | public PointerReferenceVariant(IntPtr ptr, Type t) 11 | { 12 | _ptr = ptr; 13 | _t = t; 14 | } 15 | 16 | public override object GetObject() 17 | { 18 | return Marshal.PtrToStructure(_ptr, _t); 19 | } 20 | 21 | public override void SetVariantValue(object obj) 22 | { 23 | if (obj == null) 24 | throw new InvalidOperationException(); 25 | 26 | Marshal.StructureToPtr(obj, _ptr, true); 27 | } 28 | 29 | public override BaseVariant Clone() 30 | { 31 | return new PointerReferenceVariant(_ptr, _t); 32 | } 33 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Misc/Ldtoken.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using VirtualGuard.Runtime.Variant.Object; 3 | 4 | namespace VirtualGuard.Runtime.OpCodes.impl.Misc; 5 | 6 | public class Ldtoken : IOpCode 7 | { 8 | public void Execute(VMContext ctx) 9 | { 10 | var member = ctx.ResolveMember(ctx.Reader.ReadInt()); 11 | 12 | if (member is TypeInfo t) 13 | { 14 | ctx.Stack.Push(new ObjectVariant(t.TypeHandle)); 15 | } 16 | 17 | if (member is MethodInfo m) 18 | { 19 | ctx.Stack.Push(new ObjectVariant(m.MethodHandle)); 20 | } 21 | 22 | if (member is FieldInfo f) 23 | { 24 | ctx.Stack.Push(new ObjectVariant(f.FieldHandle)); 25 | } 26 | 27 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 28 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 29 | } 30 | 31 | public byte GetCode() => 0; 32 | } -------------------------------------------------------------------------------- /VirtualGuard/Transform/IL/impl/BlockConnector.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection.Emit; 2 | using AsmResolver.DotNet.Code.Cil; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using Echo.ControlFlow; 5 | 6 | namespace VirtualGuard.Transform.IL.impl; 7 | 8 | internal class BlockConnector : IILTransformer 9 | { 10 | public void Transform(ControlFlowNode input, ControlFlowGraph ctx) 11 | { 12 | if (input.UnconditionalEdge != null && 13 | input.Contents.Instructions.Last().OpCode != CilOpCodes.Br && input.Contents.Instructions.Last().OpCode != CilOpCodes.Leave) // if it's br it doesn't matter anyway bc control is given up 14 | // connect to next block through jmp 15 | input.Contents.Instructions.Add( 16 | new CilInstruction( 17 | CilOpCodes.Br, 18 | input.UnconditionalEdge.Target 19 | ) 20 | ); 21 | } 22 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/VirtualGuard.CLI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | TRACE, DEBUG 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/MemberOpTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using Echo.ControlFlow; 4 | using VirtualGuard.AST; 5 | using VirtualGuard.VMIL.VM; 6 | 7 | namespace VirtualGuard.VMIL.Translation.impl; 8 | 9 | internal class MemberOpTranslator : ITranslator 10 | { 11 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 12 | VirtualGuardContext ctx) 13 | { 14 | switch (instr.OpCode.Code) 15 | { 16 | case CilCode.Ldtoken: 17 | block.WithContent(new VmInstruction(VmCode.Ldtoken, instr.Operand)); 18 | break; 19 | } 20 | } 21 | 22 | [Obfuscation(Feature = "virtualization")] 23 | public bool Supports(AstExpression instr) 24 | { 25 | return new[] 26 | { 27 | CilCode.Ldtoken 28 | }.Contains(instr.OpCode.Code); 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Util.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using VirtualGuard.Runtime.Dynamic; 3 | 4 | namespace VirtualGuard.Runtime; 5 | 6 | public class Util 7 | { 8 | public static long Hash(byte[] buffer) 9 | { 10 | uint[] table = new uint[256]; 11 | 12 | for (uint i = 0; i < 256; i++) 13 | { 14 | uint entry = i; 15 | for (int j = 0; j < 8; j++) 16 | { 17 | entry = (entry & 1) == 1 18 | ? (entry >> 1) ^ Constants.SPolynomial 19 | : entry >> 1; 20 | 21 | entry ^= (entry >> 12) ^ (entry >> 24); 22 | } 23 | 24 | table[i] = entry; 25 | } 26 | 27 | uint hash = Constants.SSeed; 28 | 29 | for (int i = 0; i < buffer.Length; i++) 30 | { 31 | hash = (hash >> 8) ^ table[buffer[i] ^ hash & 0xff]; 32 | } 33 | 34 | return ~hash ^ Constants.SXorMask; 35 | } 36 | } -------------------------------------------------------------------------------- /VirtualGuard.Tests/CRC.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Tests; 2 | 3 | public class CRC32 4 | { 5 | public static uint ComputeHash(byte[] buffer, uint polynomial, uint seed, uint xorMask) 6 | { 7 | uint[] table = new uint[256]; 8 | 9 | for (uint i = 0; i < 256; i++) 10 | { 11 | uint entry = i; 12 | for (int j = 0; j < 8; j++) 13 | { 14 | entry = (entry & 1) == 1 15 | ? (entry >> 1) ^ polynomial 16 | : entry >> 1; 17 | 18 | // Additional XOR to make the algorithm more unique 19 | entry ^= (entry >> 12) ^ (entry >> 24); 20 | } 21 | 22 | table[i] = entry; 23 | } 24 | 25 | uint hash = seed; 26 | 27 | for (int i = 0; i < buffer.Length; i++) 28 | { 29 | hash = (hash >> 8) ^ table[buffer[i] ^ hash & 0xff]; 30 | } 31 | 32 | return ~hash ^ xorMask; 33 | } 34 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/ValueType/StringVariant.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using VirtualGuard.Runtime.Dynamic; 3 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 4 | 5 | namespace VirtualGuard.Runtime.Variant.ValueType 6 | { 7 | 8 | public class StringVariant : BaseVariant 9 | { 10 | private string _str; 11 | 12 | public StringVariant(string str) 13 | { 14 | _str = str; 15 | } 16 | 17 | public override object GetObject() 18 | { 19 | return _str; 20 | } 21 | 22 | public override void SetVariantValue(object obj) 23 | { 24 | _str = (string)obj; 25 | } 26 | 27 | public override BaseVariant Clone() 28 | { 29 | return new StringVariant(_str); 30 | } 31 | 32 | public override BaseVariant Hash() 33 | { 34 | return new LongVariant(Util.Hash(Encoding.ASCII.GetBytes(_str))); 35 | } 36 | 37 | } 38 | } -------------------------------------------------------------------------------- /VirtualGuard/AST/IL/Marker.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | namespace VirtualGuard.AST.IL; 3 | 4 | internal class Marker : CilInstruction 5 | { 6 | 7 | public Marker(CilOpCode opCode, MarkerType t) : base(opCode) 8 | { 9 | Type = t; 10 | } 11 | 12 | public Marker(int offset, CilOpCode opCode) : base(offset, opCode) 13 | { 14 | } 15 | 16 | public Marker(CilOpCode opCode, object? operand) : base(opCode, operand) 17 | { 18 | } 19 | 20 | public Marker(int offset, CilOpCode opCode, object? operand) : base(offset, opCode, operand) 21 | { 22 | } 23 | 24 | public MarkerType Type; 25 | 26 | public override string ToString() 27 | { 28 | switch (Type) 29 | { 30 | case MarkerType.TryStart: 31 | return ""; 32 | 33 | case MarkerType.HandlerStart: 34 | return ""; 35 | 36 | default: 37 | return ""; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /VirtualGuard/AST/AstExpression.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | using VirtualGuard.AST.IL; 3 | 4 | namespace VirtualGuard.AST; 5 | 6 | internal class AstExpression 7 | { 8 | public static AstExpression Create(CilInstruction instr, AstExpression[] args) 9 | { 10 | if (instr is Marker m) 11 | return new AstMarker(CilOpCodes.Nop, null, args) 12 | { 13 | Type = m.Type 14 | }; 15 | 16 | // if not marker 17 | return new AstExpression(instr.OpCode, instr.Operand, args); 18 | } 19 | 20 | public AstExpression(CilOpCode opCode, object operand, AstExpression[] exprs) 21 | { 22 | OpCode = opCode; 23 | Operand = operand; 24 | Arguments = exprs; 25 | } 26 | 27 | public AstExpression[] Arguments; 28 | 29 | public CilOpCode OpCode; 30 | public object Operand; 31 | 32 | public override string ToString() 33 | { 34 | return OpCode + " " + (Operand == null ? "" : Operand.ToString()); 35 | } 36 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Entry.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant; 2 | using VirtualGuard.Runtime.Variant.Object; 3 | 4 | namespace VirtualGuard.Runtime 5 | { 6 | 7 | public class Entry 8 | { 9 | public static object VMEntryBasic(int loc, object[] args) 10 | { 11 | return VMEntry(loc, VMReader.GetEntryKey(loc), args); 12 | } 13 | 14 | public static object VMEntryNoArgs(int loc) 15 | { 16 | return VMEntryBasic(loc, Array.Empty()); 17 | } 18 | 19 | public static object VMEntry(int loc, byte entryKey, object[] args) 20 | { 21 | return new VMContext(entryKey).Dispatch(loc, args); 22 | } 23 | 24 | public static object VMEntryInst(int loc, object[] args, object explicitInst) 25 | { 26 | var ctx = new VMContext(VMReader.GetEntryKey(loc)); 27 | 28 | ctx.Stack.Push(new ObjectVariant(explicitInst)); 29 | 30 | return ctx.Dispatch(loc, args); 31 | } 32 | 33 | } 34 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Junk/HandlerJunkCode.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.OpCodes; 2 | using VirtualGuard.Runtime.Variant; 3 | using VirtualGuard.Runtime.Variant.Object; 4 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 5 | 6 | namespace VirtualGuard.Runtime.Junk; 7 | 8 | public class HandlerJunkCode 9 | { 10 | /*public void _OpaqueBranchReadInt(VMContext ctx) 11 | { 12 | ctx.Stack.Push(new NullVariant()); 13 | if (ctx.Stack.Pop().IsNumeral()) 14 | { 15 | ctx.Stack.Push(new IntVariant(ctx.Reader.ReadInt())); 16 | } 17 | 18 | } 19 | 20 | public void _OpaqueBranchReadLong(VMContext ctx) 21 | { 22 | ctx.Stack.Push(new NullVariant()); 23 | if (ctx.Stack.Pop().IsReference()) 24 | { 25 | ctx.Stack.Push(new LongVariant(ctx.Reader.ReadLong())); 26 | } 27 | 28 | }*/ 29 | 30 | public BaseVariant _StackPushPop(VMContext ctx) 31 | { 32 | ctx.Stack.Push(null); 33 | return ctx.Stack.Pop(); 34 | } 35 | 36 | 37 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Config/SerializedConfig.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | 3 | namespace VirtualGuard.CLI.Config; 4 | 5 | [Serializable] 6 | public class SerializedConfig 7 | { 8 | public SerializedMember[] Members; 9 | 10 | public bool RenameDebugSymbols; 11 | public bool UseDataEncryption; 12 | public bool UseImportProtection; 13 | 14 | public int ProcessorCount; 15 | 16 | public MethodDefinition[] ResolveVirtualizedMethods(Context ctx) 17 | { 18 | return Members 19 | .Where(x => x is { Virtualize: true, Exclude: false }) 20 | .Select(x => x.Resolve(ctx)).Cast().ToArray(); 21 | } 22 | 23 | public bool IsMemberExcluded(IMemberDefinition def, Context ctx) 24 | { 25 | return Members.Where(x => x.Exclude).Select(x => x.Resolve(ctx)).Contains(def); 26 | } 27 | 28 | public bool IsMemberVirtualized(IMemberDefinition def, Context ctx) 29 | { 30 | return Members.Where(x => x.Virtualize).Select(x => x.Resolve(ctx)).Contains(def); 31 | } 32 | 33 | 34 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Conversion/Unbox.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Dynamic; 2 | using VirtualGuard.Runtime.Variant.Reference.impl; 3 | 4 | namespace VirtualGuard.Runtime.OpCodes.impl.Conversion; 5 | 6 | public class Unbox : IOpCode 7 | { 8 | public void Execute(VMContext ctx) 9 | { 10 | unsafe 11 | { 12 | var type = ctx.ResolveType(ctx.Reader.ReadInt()); 13 | 14 | var boxedObject = ctx.Stack.Pop(); 15 | 16 | if (boxedObject is not BoxedReferenceVariant) 17 | throw new InvalidOperationException( 18 | Routines.EncryptDebugMessage("Trying to unbox a non boxed variant.")); 19 | 20 | var asPtr = new PointerReferenceVariant( 21 | new IntPtr(System.Reflection.Pointer.Unbox(boxedObject.GetObject())), type); 22 | 23 | ctx.Stack.Push(asPtr); 24 | } 25 | 26 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 27 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 28 | } 29 | 30 | public byte GetCode() => 0; 31 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/ValueType/Numeric/NumeralVariant.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.Variant.ValueType.Numeric 2 | { 3 | 4 | public abstract class NumeralVariant : BaseVariant 5 | { 6 | public override bool IsNumeral() 7 | { 8 | return true; 9 | } 10 | 11 | public abstract NumeralVariant Add(NumeralVariant addend); 12 | public abstract NumeralVariant Sub(NumeralVariant subtraend); 13 | public abstract NumeralVariant Mul(NumeralVariant factor); 14 | public abstract NumeralVariant Div(NumeralVariant divisor); 15 | 16 | public abstract NumeralVariant Xor(NumeralVariant xorfactor); 17 | public abstract NumeralVariant Rem(NumeralVariant remfactor); 18 | public abstract NumeralVariant Or(NumeralVariant or); 19 | public abstract NumeralVariant Not(); 20 | public abstract NumeralVariant And(NumeralVariant and); 21 | 22 | public abstract NumeralVariant Shl(NumeralVariant factor); 23 | public abstract NumeralVariant Shr(NumeralVariant factor); 24 | } 25 | } -------------------------------------------------------------------------------- /VirtualGuard/VirtualGuard.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | disable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ..\Deps\Echo.dll 21 | 22 | 23 | ..\Deps\Echo.ControlFlow.dll 24 | 25 | 26 | ..\Deps\Echo.Platforms.AsmResolver.dll 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /VirtualGuard.CLI/Config/SerializedMember.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | 3 | namespace VirtualGuard.CLI.Config; 4 | 5 | [Serializable] 6 | public class SerializedMember 7 | { 8 | public string Member; 9 | 10 | public bool Virtualize; 11 | public bool VirtualInlining; 12 | public bool Exclude; 13 | 14 | public IMemberDefinition Resolve(Context ctx) 15 | { 16 | if (ctx.ResolutionCache.TryGetValue(this, out IMemberDefinition def)) 17 | return def; 18 | 19 | try 20 | { 21 | if (!Member.Contains(":")) 22 | { 23 | var type = ctx.Module.LookupType(Member); 24 | 25 | ctx.ResolutionCache.Add(this, type); 26 | return type; 27 | } 28 | 29 | var member = ctx.Module.LookupMember(Member); 30 | 31 | ctx.ResolutionCache.Add(this, member); 32 | return member; 33 | } 34 | catch 35 | { 36 | ctx.Logger.Fatal("Could not resolve member " + Member); 37 | return null; 38 | } 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/BuildChunkKeys.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.RT.Chunk; 2 | using VirtualGuard.VMIL.VM; 3 | 4 | namespace VirtualGuard.RT.Mutators.impl; 5 | 6 | internal class BuildChunkKeys : IRuntimeMutator 7 | { 8 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 9 | { 10 | foreach (var chunk in rt.VmChunks) 11 | { 12 | rt.Descriptor.Data.BuildStartKey(chunk); 13 | } 14 | 15 | foreach (var chunk in rt.VmChunks) 16 | { 17 | 18 | foreach (var instr in chunk.Content) 19 | { 20 | if (instr.Operand is DynamicStartKeyReference startKeyReference) 21 | { 22 | 23 | if (startKeyReference.Chunk == null) 24 | throw new Exception("Operand is not expected target chunk."); 25 | 26 | // set operand to key start 27 | 28 | instr.Operand = (int)rt.Descriptor.Data.GetStartKey(startKeyReference.Chunk); 29 | } 30 | 31 | } 32 | 33 | } 34 | 35 | 36 | } 37 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Exception/Leave.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Dynamic; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Exception; 4 | 5 | public class Leave : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | // we can check if there is a finally here and jmp 10 | 11 | var previousTry = ctx.HandlerStack.Pop(); // pop off stack 12 | 13 | var pos = ctx.Stack.Pop(); 14 | var key = ctx.Reader.ReadByte(); 15 | 16 | ctx.Stack.SetValue(0); // reset stack 17 | 18 | if (previousTry.Type == Constants.FinallyFL) 19 | { // do finally 20 | 21 | ctx.Reader.SetKey(previousTry.HandlerStartKey); 22 | ctx.Reader.SetValue(previousTry.HandlerPos); 23 | 24 | } 25 | else 26 | { 27 | ctx.Reader.SetKey(key); 28 | ctx.Reader.SetValue(pos.I4()); // is this correct? 29 | } 30 | 31 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 32 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 33 | } 34 | 35 | public byte GetCode() => 0; 36 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Flow/Vmcall.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Flow 4 | { 5 | public class Vmcall : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | var loc = ctx.Stack.Pop().I4(); 10 | var argCount = ctx.Stack.Pop().I4(); 11 | 12 | var entryKey = ctx.Reader.ReadByte(); 13 | 14 | var args = new List(); 15 | 16 | // need to add support for ref params 17 | 18 | for(int i = 0; i < argCount; i++) 19 | args.Add(ctx.Stack.Pop().GetObject()); 20 | 21 | // do i need to cast here? 22 | // it may be better to restructure so vm doesn't need to init args 23 | 24 | ctx.Stack.Push(BaseVariant.CreateVariant(Entry.VMEntry(loc, entryKey, args.ToArray()))); 25 | 26 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 27 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 28 | } 29 | 30 | public byte GetCode() => 0; 31 | } 32 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Pointer/Stind.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant.Reference.impl; 2 | 3 | namespace VirtualGuard.Runtime.OpCodes.impl.Pointer; 4 | 5 | public class Stind : IOpCode 6 | { 7 | public void Execute(VMContext ctx) 8 | { 9 | var type = ctx.ResolveType(ctx.Reader.ReadInt()); 10 | 11 | var v2 = ctx.Stack.Pop(); 12 | var v1 = ctx.Stack.Pop(); 13 | 14 | v2 = v2.Cast(type); 15 | 16 | if(v1.IsReference()) 17 | v2 = v2.Cast(v1.GetObject().GetType()); 18 | else 19 | { 20 | if(v1.GetObject() is System.Reflection.Pointer) 21 | unsafe 22 | { 23 | v1 = new PointerReferenceVariant(new IntPtr(System.Reflection.Pointer.Unbox(v1.GetObject())), type); 24 | } 25 | else 26 | { 27 | throw new ArgumentException(); 28 | } 29 | } 30 | 31 | v1.SetVariantValue(v2.GetObject()); 32 | 33 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 34 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 35 | } 36 | 37 | public byte GetCode() => 0; 38 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/LocalStorage.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Variant; 2 | 3 | namespace VirtualGuard.Runtime 4 | { 5 | public class LocalStorage 6 | { 7 | private BaseVariant[] _internal; 8 | 9 | public LocalStorage() 10 | { 11 | _internal = new BaseVariant[10]; // if there's more than 10 locals fml 12 | } 13 | 14 | public BaseVariant GetLocal(short index) 15 | { 16 | if (index > _internal.Length) 17 | { 18 | var v = _internal; 19 | _internal = new BaseVariant[v.Length * 2]; 20 | Array.Copy(v, _internal, v.Length); 21 | } 22 | 23 | return _internal[index]; 24 | } 25 | 26 | public void SetLocal(short index, BaseVariant value) 27 | { 28 | if (index > _internal.Length) 29 | { 30 | var v = _internal; 31 | _internal = new BaseVariant[v.Length * 2]; 32 | Array.Copy(v, _internal, v.Length); 33 | } 34 | 35 | _internal[index] = value; 36 | } 37 | 38 | } 39 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Misc/Sizeof.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection.Emit; 2 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 3 | 4 | namespace VirtualGuard.Runtime.OpCodes.impl.Misc; 5 | 6 | public class Sizeof : IOpCode 7 | { 8 | private static DynamicMethod _cachedFactory; 9 | public void Execute(VMContext ctx) 10 | { 11 | if (_cachedFactory == null) 12 | { 13 | _cachedFactory = new DynamicMethod("virtualguard", typeof(int), new[] { typeof(Type) }); 14 | var gen = _cachedFactory.GetILGenerator(); 15 | 16 | gen.Emit(System.Reflection.Emit.OpCodes.Ldarg_0); 17 | gen.Emit(System.Reflection.Emit.OpCodes.Sizeof); 18 | gen.Emit(System.Reflection.Emit.OpCodes.Ret); 19 | } 20 | 21 | var type = ctx.ResolveType(ctx.Reader.ReadInt()); 22 | 23 | var size = (int)_cachedFactory.Invoke(null, new[] { type }); 24 | 25 | ctx.Stack.Push(new IntVariant(size)); 26 | 27 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 28 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 29 | } 30 | 31 | public byte GetCode() => 0; 32 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Descriptor/ExceptionHandlerDescriptor.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet.Code.Cil; 2 | 3 | namespace VirtualGuard.RT.Descriptor; 4 | 5 | internal class ExceptionHandlerDescriptor 6 | { 7 | public ExceptionHandlerDescriptor(Random rnd) 8 | { 9 | CatchFL = (byte)rnd.Next(byte.MaxValue); 10 | FinallyFL = (byte)rnd.Next(byte.MaxValue); 11 | FilterFL = (byte)rnd.Next(byte.MaxValue); 12 | FaultFL = (byte)rnd.Next(byte.MaxValue); 13 | } 14 | 15 | public byte CatchFL; 16 | public byte FinallyFL; 17 | public byte FilterFL; 18 | public byte FaultFL; 19 | 20 | public byte GetFlag(CilExceptionHandlerType type) 21 | { 22 | switch (type) 23 | { 24 | case CilExceptionHandlerType.Exception: 25 | return CatchFL; 26 | 27 | case CilExceptionHandlerType.Fault: 28 | return FaultFL; 29 | 30 | case CilExceptionHandlerType.Filter: 31 | return FilterFL; 32 | 33 | case CilExceptionHandlerType.Finally: 34 | return FinallyFL; 35 | } 36 | 37 | throw new InvalidOperationException(type.ToString()); 38 | } 39 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/Reference/impl/ArrayReferenceVariant.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using VirtualGuard.Runtime.Variant.Object; 3 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 4 | 5 | namespace VirtualGuard.Runtime.Variant.Reference.impl 6 | { 7 | public class ArrayReferenceVariant : BaseReferenceVariant 8 | { 9 | private ArrayVariant _array; 10 | private BaseVariant _index; 11 | private Type _markedType = null; 12 | 13 | public ArrayReferenceVariant(ArrayVariant arr, BaseVariant index) 14 | { 15 | _array = arr; 16 | _index = index; 17 | 18 | if (index.GetType() != typeof(IntVariant)) 19 | throw new ArgumentException(); 20 | 21 | } 22 | 23 | public override object GetObject() 24 | { 25 | return _array.LoadDelimeter(_index); 26 | } 27 | 28 | public override void SetVariantValue(object obj) 29 | { 30 | _array.SetDelimeter(_index, CreateVariant(obj)); 31 | } 32 | 33 | public override BaseVariant Clone() 34 | { 35 | return new ArrayReferenceVariant(_array, _index); 36 | } 37 | 38 | } 39 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/ITranslator.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | using Echo.ControlFlow; 3 | using VirtualGuard.AST; 4 | using VirtualGuard.VMIL.VM; 5 | 6 | namespace VirtualGuard.VMIL.Translation; 7 | 8 | internal interface ITranslator 9 | { 10 | 11 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 12 | VirtualGuardContext ctx); 13 | public bool Supports(AstExpression instr); 14 | 15 | 16 | private static readonly List _translators; 17 | static ITranslator() 18 | { 19 | _translators = new List(); 20 | foreach (var type in typeof(ITranslator).Assembly.GetTypes()) { 21 | if (typeof(ITranslator).IsAssignableFrom(type) && !type.IsAbstract) { 22 | var handler = (ITranslator)Activator.CreateInstance(type); 23 | _translators.Add(handler); 24 | } 25 | } 26 | } 27 | 28 | public static ITranslator Lookup(AstExpression instr) 29 | { 30 | foreach (var translator in _translators) 31 | if (translator.Supports(instr)) 32 | return translator; 33 | 34 | return null; 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Context.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.DotNet; 3 | using VirtualGuard.CLI.Config; 4 | using VirtualGuard.RT; 5 | using VirtualGuard.Stubs; 6 | 7 | namespace VirtualGuard.CLI; 8 | 9 | public class Context 10 | { 11 | public Context(ModuleDefinition mod, SerializedConfig cfg, ILogger logger, LicenseType license) 12 | { 13 | Module = mod; 14 | Configuration = cfg; 15 | Logger = logger; 16 | License = license; 17 | 18 | RuntimeModule = ModuleDefinition.FromFile(typeof(Limiter).Assembly.Location); 19 | } 20 | 21 | public Dictionary ResolutionCache = 22 | new Dictionary(); 23 | 24 | public ILogger Logger; 25 | public ModuleDefinition Module; 26 | public MultiProcessorVirtualizer Virtualizer; 27 | public SerializedConfig Configuration; 28 | 29 | public ModuleDefinition RuntimeModule; 30 | 31 | public LicenseType License; 32 | 33 | public MethodDefinition LocateStub(string name) 34 | { 35 | // get this module 36 | return RuntimeModule.GetAllTypes().SelectMany(x => x.Methods).Single(x => x.Name == name); 37 | } 38 | 39 | 40 | 41 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/VM/VmCode.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.VMIL.VM; 2 | 3 | public enum VmCode : byte 4 | { 5 | Add, 6 | Sub, 7 | Mul, 8 | Div, 9 | 10 | Not, 11 | Rem, 12 | Xor, 13 | And, 14 | Or, 15 | 16 | Stloc, 17 | Ldloc, 18 | Ldloca, 19 | 20 | Ldc_I4, 21 | Ldc_I8, 22 | 23 | Ldstr, 24 | Ldtoken, 25 | 26 | Ldc_R4, 27 | Ldc_R8, 28 | 29 | Call, 30 | 31 | Pop, 32 | Ret, 33 | 34 | Stfld, 35 | Ldfld, 36 | Ldflda, 37 | 38 | Cmp, 39 | 40 | Jmp, 41 | 42 | Conv, 43 | 44 | Ldelem, // these will be vcalls in special region 45 | Ldelema, 46 | Newarr, 47 | Ldlen, 48 | 49 | GetKey, 50 | 51 | Stelem, // these will be vcalls 52 | 53 | Vmcall, // can be a sick ass vcall, jmp to region, push all args and relativize ctx 54 | 55 | Entertry, 56 | 57 | Leave, 58 | Hash, // could turn into an awesome vcode 59 | 60 | Ldftn, 61 | Dup, 62 | 63 | Stind, 64 | Ldind, 65 | 66 | Throw, 67 | 68 | Box, 69 | Unbox, 70 | Unboxany, 71 | 72 | Castclass, 73 | Sizeof, 74 | 75 | Shl, 76 | Shr, 77 | 78 | __nop, 79 | } -------------------------------------------------------------------------------- /VirtualGuard/Transform/IL/IIlTransformer.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet.Code.Cil; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using Echo.ControlFlow; 4 | using VirtualGuard.Transform.IL.impl; 5 | 6 | namespace VirtualGuard.Transform.IL; 7 | 8 | internal interface IILTransformer 9 | { 10 | public void Transform(ControlFlowNode node, ControlFlowGraph ctx); 11 | 12 | private static readonly IILTransformer[] _transformers = 13 | { 14 | new ConditionalSimplifier(), 15 | new BlockConnector(), 16 | //w BranchTargetUpdater(), 17 | new Nullifier() // needs to be last to not break branches targetting nop instrs 18 | }; 19 | 20 | /*static IILTransformer() 21 | { 22 | var visitors = new List(); 23 | foreach (var type in typeof(IILTransformer).Assembly.GetExportedTypes()) { 24 | if (typeof(IILTransformer).IsAssignableFrom(type) && !type.IsAbstract) { 25 | var handler = (IILTransformer)Activator.CreateInstance(type); 26 | visitors.Add(handler); 27 | } 28 | } 29 | 30 | _transformers = visitors.ToArray(); 31 | }*/ 32 | 33 | public static IILTransformer[] GetTransformers() => _transformers; 34 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/UnconditionalTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using Echo.ControlFlow; 4 | using VirtualGuard.AST; 5 | using VirtualGuard.Runtime.OpCodes.impl; 6 | using VirtualGuard.VMIL.VM; 7 | 8 | namespace VirtualGuard.VMIL.Translation.impl; 9 | 10 | internal class UnconditionalTranslator : ITranslator 11 | { 12 | [Obfuscation(Feature = "virtualization")] 13 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 14 | VirtualGuardContext ctx) 15 | { 16 | if(node.ConditionalEdges.Count > 0) 17 | return; // handled in a fallback branch 18 | 19 | block.WithContent( 20 | new VmInstruction( 21 | VmCode.Ldc_I4, 22 | node.UnconditionalEdge.Target), 23 | new VmInstruction(VmCode.Ldc_I4, new DynamicStartKeyReference(node.UnconditionalEdge.Target, false)), 24 | new VmInstruction( 25 | VmCode.Jmp 26 | ) 27 | ); 28 | } 29 | 30 | [Obfuscation(Feature = "virtualization")] 31 | public bool Supports(AstExpression instr) 32 | { 33 | return instr.OpCode.Code == CilCode.Br; 34 | } 35 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/Object/ArrayVariant.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 4 | 5 | namespace VirtualGuard.Runtime.Variant.Object 6 | { 7 | 8 | public class ArrayVariant : BaseVariant 9 | { 10 | private Array _array; 11 | 12 | public ArrayVariant(Array arr) 13 | { 14 | _array = arr; 15 | } 16 | 17 | public override object GetObject() 18 | { 19 | return _array; 20 | } 21 | 22 | public override void SetVariantValue(object obj) 23 | { 24 | _array = (Array)obj; 25 | } 26 | 27 | public override BaseVariant Clone() 28 | { 29 | return new ArrayVariant(_array); 30 | } 31 | 32 | public BaseVariant LoadDelimeter(BaseVariant index) 33 | { 34 | return CreateVariant(_array.GetValue(index.I4()), _array.GetType().GetElementType()); 35 | } 36 | 37 | public void SetDelimeter(BaseVariant index, BaseVariant obj) 38 | { 39 | _array.SetValue(obj.GetObject(), index.I4()); 40 | } 41 | 42 | public override BaseVariant GetLength() 43 | { 44 | return new IntVariant(_array.Length); 45 | } 46 | 47 | } 48 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/VmCalls.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | using VirtualGuard.RT.Chunk; 3 | using VirtualGuard.VMIL.VM; 4 | 5 | namespace VirtualGuard.RT.Mutators.impl; 6 | 7 | internal class VmCalls : IRuntimeMutator 8 | { 9 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 10 | { 11 | foreach (var chunk in rt.VmChunks) 12 | foreach (var vmInstruction in chunk.Content.ToArray()) 13 | { 14 | if (vmInstruction.OpCode != VmCode.Call) 15 | continue; 16 | 17 | // resolve method def 18 | 19 | var method = vmInstruction.Operand as IMethodDescriptor; 20 | 21 | var def = method.Resolve(); 22 | 23 | if(def == null) 24 | continue; 25 | 26 | if (rt.IsMethodVirtualized(def, out VmChunk inlineTarget)) 27 | { 28 | chunk.Content.ReplaceRange(vmInstruction, 29 | new VmInstruction(VmCode.Ldc_I4, def.Parameters.Count), 30 | new VmInstruction(VmCode.Ldc_I4, inlineTarget), 31 | new VmInstruction(VmCode.Vmcall, rt.Descriptor.Data.GetStartKey(inlineTarget)) 32 | ); 33 | } 34 | 35 | } 36 | } 37 | 38 | 39 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/ExceptionTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Reflection; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using Echo.ControlFlow; 5 | using VirtualGuard.AST; 6 | using VirtualGuard.VMIL.VM; 7 | 8 | namespace VirtualGuard.VMIL.Translation.impl; 9 | 10 | internal class ExceptionTranslator : ITranslator 11 | { 12 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 13 | VirtualGuardContext ctx) 14 | { 15 | switch (instr.OpCode.Code) 16 | { 17 | case CilCode.Leave: 18 | case CilCode.Leave_S: 19 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, instr.Operand), 20 | new VmInstruction(VmCode.Leave, new DynamicStartKeyReference((ControlFlowNode)instr.Operand, false)) 21 | ); 22 | break; 23 | 24 | case CilCode.Throw: 25 | block.WithContent(new VmInstruction(VmCode.Throw)); 26 | break; 27 | } 28 | } 29 | 30 | [Obfuscation(Feature = "virtualization")] 31 | public bool Supports(AstExpression instr) 32 | { 33 | return new[] 34 | { 35 | CilCode.Leave, 36 | CilCode.Leave_S, 37 | CilCode.Throw 38 | }.Contains(instr.OpCode.Code); 39 | } 40 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Processors/impl/FreeLimitations.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | using AsmResolver.DotNet.Cloning; 3 | using AsmResolver.DotNet.Code.Cil; 4 | using AsmResolver.PE.DotNet.Cil; 5 | 6 | namespace VirtualGuard.CLI.Processors.impl; 7 | 8 | public class FreeLimitations : IProcessor 9 | { 10 | public string Identifier => "Free Limitations"; 11 | 12 | public void Process(Context ctx) 13 | { 14 | // inject limiter stub, reference in random virtualized methods 15 | 16 | // thought is we just drop a simple console.writeline and i'd need to implement virtual fields but yea 17 | 18 | // now to remember how to use member cloner 19 | 20 | var cloner = new MemberCloner(ctx.Module); 21 | 22 | cloner.Include(ctx.LocateStub("Limit")); 23 | 24 | var res = cloner.Clone(); 25 | 26 | var clonedMethod = (MethodDefinition)res.ClonedMembers.Single(x => x.Name == "Limit"); 27 | 28 | clonedMethod.Name = new Random().Next().ToString("x"); 29 | 30 | // inject cloned method 31 | ctx.Module.ManagedEntryPointMethod.DeclaringType.Methods.Add(clonedMethod); 32 | 33 | // mark for virtualization 34 | ctx.Virtualizer.AddMethod(clonedMethod, true); 35 | 36 | var entry = ctx.Module.ManagedEntryPointMethod; 37 | 38 | entry.CilMethodBody.Instructions.Insert(0, CilOpCodes.Call, clonedMethod); 39 | } 40 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Conversion/Conv.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Dynamic; 2 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 3 | 4 | namespace VirtualGuard.Runtime.OpCodes.impl.Conversion; 5 | 6 | public class Conv : IOpCode 7 | { 8 | public void Execute(VMContext ctx) 9 | { 10 | 11 | // fml this code is absolute DOGSHIT 12 | 13 | var type = ctx.Stack.Pop().I4(); 14 | var obj = ctx.Stack.Pop(); 15 | 16 | if (type == Constants.CorlibID_I || type == Constants.CorlibID_U) 17 | throw new InvalidOperationException(Routines.EncryptDebugMessage("Ptr and UIntPtr not supported in conv.")); 18 | 19 | if(type == Constants.CorlibID_I1 || type == Constants.CorlibID_I2 || type == Constants.CorlibID_I4) 20 | ctx.Stack.Push(new IntVariant(obj.I4())); 21 | 22 | if(type == Constants.CorlibID_U1 || type == Constants.CorlibID_U2 || type == Constants.CorlibID_U4) 23 | ctx.Stack.Push(new UIntVariant(obj.U4())); 24 | 25 | if(type == Constants.CorlibID_I8) 26 | ctx.Stack.Push(new LongVariant(obj.I8())); 27 | 28 | if(type == Constants.CorlibID_U8) 29 | ctx.Stack.Push(new ULongVariant(obj.U8())); 30 | 31 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 32 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 33 | } 34 | 35 | public byte GetCode() => 0; 36 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Processors/impl/PostDataEncryption.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | 3 | namespace VirtualGuard.CLI.Processors.impl; 4 | 5 | public class PostDataEncryption : IProcessor 6 | { 7 | public string Identifier => "PostDataEncryption"; 8 | public void Process(Context ctx) 9 | { 10 | 11 | foreach (var method in DataEncryption.ScannedMethods) 12 | { 13 | if(method.CilMethodBody == null) 14 | continue; 15 | 16 | method.CilMethodBody.Instructions.ExpandMacros(); 17 | 18 | foreach (var instruction in method.CilMethodBody.Instructions.ToArray()) 19 | { 20 | 21 | if(instruction.OpCode != CilOpCodes.Ldstr && instruction.OpCode != CilOpCodes.Ldc_I4) 22 | continue; 23 | 24 | // replace w vm call 25 | 26 | method.CilMethodBody.Instructions.ReplaceRange(instruction, DataEncryption._constantCache[instruction.Operand].CilMethodBody.Instructions.SkipLast(1).ToArray()); 27 | } 28 | 29 | method.CilMethodBody.Instructions.CalculateOffsets(); 30 | method.CilMethodBody.Instructions.OptimizeMacros(); 31 | } 32 | 33 | foreach (var meth in DataEncryption._constantCache.Values) 34 | { 35 | meth.DeclaringType.Methods.Remove(meth); 36 | } 37 | 38 | } 39 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/CodeMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using VirtualGuard.Runtime.Dynamic; 5 | using VirtualGuard.Runtime.Variant; 6 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 7 | 8 | namespace VirtualGuard.Runtime.OpCodes 9 | { 10 | 11 | public class CodeMap 12 | { 13 | private static Dictionary _opCodes = new Dictionary(); 14 | 15 | static CodeMap() 16 | { 17 | _opCodes = new Dictionary(); 18 | var types = typeof(CodeMap).Assembly.GetTypes(); 19 | 20 | foreach (var type in types) 21 | { 22 | if (typeof(IOpCode).IsAssignableFrom(type) && !type.IsAbstract) 23 | { 24 | var opCode = (IOpCode)Activator.CreateInstance(type); 25 | _opCodes[opCode.GetCode()] = opCode; 26 | } 27 | } 28 | } 29 | 30 | public static IOpCode LookupCode(byte code) 31 | { 32 | 33 | if (!_opCodes.TryGetValue(code, out IOpCode codeobj)) 34 | throw new Exception(Routines.EncryptDebugMessage("Error resolving handler")); 35 | 36 | #if DEBUG 37 | Console.WriteLine(codeobj.GetType().Name); 38 | #endif 39 | 40 | return codeobj; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Dynamic/OperationHelper.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | 3 | namespace VirtualGuard.RT.Dynamic; 4 | 5 | internal static class OperationHelper 6 | { 7 | private static readonly Dictionary InverseOperations = new Dictionary() 8 | { 9 | { Operation.Add, Operation.Sub}, 10 | { Operation.Sub, Operation.Add }, 11 | { Operation.Xor, Operation.Xor }, 12 | }; 13 | 14 | private static readonly Dictionary OperationCodeMap = new Dictionary() 15 | { 16 | { Operation.Add, CilOpCodes.Add }, 17 | { Operation.Sub, CilOpCodes.Sub }, 18 | { Operation.Xor, CilOpCodes.Xor }, 19 | }; 20 | 21 | public static Operation Inverse(this Operation op) 22 | { 23 | return InverseOperations[op]; 24 | } 25 | 26 | public static CilOpCode ToCil(this Operation op) 27 | { 28 | return OperationCodeMap[op]; 29 | } 30 | 31 | public static int Operate(this Operation op, int operand1, int operand2) 32 | { 33 | switch (op) 34 | { 35 | case Operation.Add: 36 | return operand1 + operand2; 37 | 38 | case Operation.Sub: 39 | return operand1 - operand2; 40 | 41 | case Operation.Xor: 42 | return operand1 ^ operand2; 43 | 44 | 45 | default: 46 | throw new NotImplementedException(op.ToString()); 47 | } 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/Runtime/LocMutation.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet.Code.Cil; 2 | using AsmResolver.PE.DotNet.Cil; 3 | 4 | namespace VirtualGuard.RT.Mutators.impl.Runtime; 5 | 6 | internal class LocMutation : IRuntimeMutator 7 | { 8 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 9 | { 10 | var rnd = new Random(); 11 | 12 | foreach (var method in rt.RuntimeModule.GetAllTypes().SelectMany(x => x.Methods.Where(x => x.CilMethodBody != null && x.CilMethodBody.Instructions.Count > 0))) 13 | { 14 | method.CilMethodBody.Instructions.ExpandMacros(); 15 | 16 | foreach (var instr in method.CilMethodBody.Instructions.ToArray()) 17 | { 18 | //if (rnd.Next(2) != 0) // 1/3 19 | // continue; 20 | 21 | if (instr.OpCode == CilOpCodes.Stloc) 22 | { 23 | var loc = instr.Operand; 24 | 25 | method.CilMethodBody.Instructions.Insert(method.CilMethodBody.Instructions.IndexOf(instr), CilOpCodes.Ldnull); 26 | 27 | method.CilMethodBody.Instructions.InsertRange(method.CilMethodBody.Instructions.IndexOf(instr), new[] 28 | { 29 | new CilInstruction(CilOpCodes.Stloc, 30 | loc), 31 | }); 32 | } 33 | } 34 | 35 | method.CilMethodBody.Instructions.OptimizeMacros(); 36 | method.CilMethodBody.ComputeMaxStack(); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/VMStack.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using VirtualGuard.Runtime.Variant; 3 | using VirtualGuard.Runtime.Variant.Object; 4 | 5 | namespace VirtualGuard.Runtime 6 | { 7 | 8 | public class VMStack : IElement 9 | { 10 | BaseVariant[] _array; 11 | uint _index; 12 | 13 | internal VMStack() 14 | { 15 | _array = new BaseVariant[10]; 16 | _index = 0; 17 | } 18 | 19 | internal void Push(BaseVariant val) 20 | { 21 | //Console.WriteLine("push: " + val.STR()); 22 | 23 | if (_index == _array.Length) 24 | { 25 | var arr = new BaseVariant[2 * _array.Length]; 26 | Array.Copy(_array, 0, arr, 0, _index); 27 | _array = arr; 28 | } 29 | 30 | _array[_index++] = val; 31 | } 32 | 33 | internal BaseVariant Pop() 34 | { 35 | if (_index == 0) 36 | return new NullVariant(); 37 | 38 | var res = _array[--_index]; 39 | _array[_index] = null; 40 | 41 | //Console.WriteLine("pop: " + res.STR()); 42 | return res; 43 | } 44 | 45 | internal BaseVariant Peek() 46 | { 47 | //Console.WriteLine("peeked " + _array[_index - 1].STR()); 48 | return _array[_index - 1]; 49 | } 50 | 51 | public void SetValue(int i) 52 | { 53 | _index = (uint)i; 54 | } 55 | 56 | public int GetValue() 57 | { 58 | return (int)_index; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/LocalTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.DotNet.Code.Cil; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using Echo.ControlFlow; 5 | using VirtualGuard.AST; 6 | using VirtualGuard.VMIL.VM; 7 | 8 | namespace VirtualGuard.VMIL.Translation.impl; 9 | 10 | internal class LocalTranslator : ITranslator 11 | { 12 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 13 | VirtualGuardContext ctx) 14 | { 15 | var local = instr.Operand as CilLocalVariable; 16 | var vmLoc = meth.GetVariableFromLocal(local.Index); 17 | 18 | switch (instr.OpCode.Code) 19 | { 20 | case CilCode.Stloc: 21 | block.WithContent( 22 | new VmInstruction(VmCode.Stloc, vmLoc)); 23 | break; 24 | 25 | case CilCode.Ldloca: 26 | block.WithContent( 27 | new VmInstruction(VmCode.Ldloca, vmLoc)); 28 | break; 29 | 30 | case CilCode.Ldloc: 31 | block.WithContent( 32 | new VmInstruction(VmCode.Ldloc, vmLoc)); 33 | break; 34 | } 35 | } 36 | 37 | [Obfuscation(Feature = "virtualization")] 38 | public bool Supports(AstExpression instr) 39 | { 40 | if (instr.OpCode.Code == CilCode.Stloc) 41 | return true; 42 | 43 | if (instr.OpCode.Code == CilCode.Ldloc) 44 | return true; 45 | 46 | if (instr.OpCode.Code == CilCode.Ldloca) 47 | return true; 48 | 49 | return false; 50 | } 51 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/IRuntimeMutator.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.RT.Mutators.impl; 2 | using VirtualGuard.RT.Mutators.impl.Runtime; 3 | 4 | namespace VirtualGuard.RT.Mutators; 5 | 6 | internal interface IRuntimeMutator 7 | { 8 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx); 9 | 10 | static IRuntimeMutator() 11 | { 12 | /*var mutators = new List(); 13 | foreach (var type in typeof(IRuntimeMutator).Assembly.GetExportedTypes()) { 14 | if (typeof(IRuntimeMutator).IsAssignableFrom(type) && !type.IsAbstract) { 15 | var handler = (IRuntimeMutator)Activator.CreateInstance(type); 16 | mutators.Add(handler); 17 | } 18 | } 19 | 20 | _mutators = mutators.ToArray();*/ 21 | } 22 | 23 | private static readonly IRuntimeMutator[] _mutators = 24 | { // need to do it manually to preserve order 25 | 26 | // Runtime 27 | new InjectConstants(), 28 | new EncryptExceptions(), 29 | 30 | new HandlerMutator(), 31 | 32 | new Renamer(), 33 | //new ControlFlow(), 34 | //new LocMutation(), 35 | //new HiddenFields(), 36 | 37 | // vmcode 38 | new TokenAllocator(), 39 | new EncodeStrings(), 40 | new BuildChunkKeys(), 41 | //new VirtualOpCodes(), 42 | new VmCalls(), 43 | new ChunkShuffler(), 44 | 45 | 46 | //new PseudoRegions(), 47 | //new ConstantMutation() 48 | 49 | new BranchMutator(), 50 | 51 | new FinalizeMutations() 52 | }; 53 | 54 | public static IRuntimeMutator[] GetMutators() => _mutators; 55 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Dynamic/MutationExpression.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | using AsmResolver.PE.Exports; 3 | using Echo.Platforms.AsmResolver; 4 | 5 | namespace VirtualGuard.RT.Dynamic; 6 | 7 | internal class MutationExpression 8 | { 9 | public List Steps = new List(); 10 | 11 | 12 | static Random _rnd = new Random(); 13 | 14 | public static MutationExpression Random(int steps) 15 | { 16 | var expr = new MutationExpression(); 17 | 18 | for (int i = 0; i < steps; i++) 19 | { 20 | // get random operation and mod 21 | var modifier = _rnd.Next(1, 100000); 22 | var operation = (Operation)_rnd.Next(typeof(Operation).GetEnumNames().Length); 23 | //var operation = (Operation)_rnd.Next(3); // hardcode debug 24 | 25 | expr.Steps.Add(new MutationStep(modifier, operation)); 26 | } 27 | 28 | return expr; 29 | } 30 | 31 | public int Solve(int input) 32 | { 33 | foreach (var step in this.Steps.ToArray().Reverse()) 34 | { 35 | input = step.Operation.Operate(input, step.Modifier); 36 | } 37 | 38 | return input; 39 | } 40 | 41 | public CilInstruction[] ToCIL() 42 | { 43 | // fml this is a headache 44 | var instrs = new List(); 45 | 46 | foreach (var step in Steps) 47 | { 48 | instrs.Add(new CilInstruction(CilOpCodes.Ldc_I4, step.Modifier)); 49 | instrs.Add(new CilInstruction(step.Operation.Inverse().ToCil())); 50 | } 51 | 52 | instrs.Add(new CilInstruction(CilOpCodes.Conv_U1)); 53 | 54 | return instrs.ToArray(); 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/ArgumentTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.DotNet.Collections; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using Echo.ControlFlow; 5 | using VirtualGuard.AST; 6 | using VirtualGuard.VMIL.VM; 7 | 8 | namespace VirtualGuard.VMIL.Translation.impl; 9 | 10 | internal class ArgumentTranslator : ITranslator 11 | { 12 | [Obfuscation(Feature = "virtualization")] 13 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 14 | VirtualGuardContext ctx) 15 | { 16 | var param = instr.Operand as Parameter; 17 | var index = param.Index; 18 | 19 | var varFromArg = meth.GetVariableFromArg(index); 20 | 21 | switch (instr.OpCode.Code) 22 | { 23 | case CilCode.Ldarg: 24 | block.WithContent( 25 | new VmInstruction(VmCode.Ldloc, varFromArg)); 26 | break; 27 | 28 | case CilCode.Ldarga: 29 | block.WithContent( 30 | new VmInstruction(VmCode.Ldloca, varFromArg)); 31 | break; 32 | 33 | case CilCode.Starg: 34 | block.WithContent(new VmInstruction(VmCode.Stloc, varFromArg)); 35 | break; 36 | } 37 | 38 | } 39 | 40 | [Obfuscation(Feature = "virtualization")] 41 | public bool Supports(AstExpression instr) 42 | { 43 | if (instr.OpCode == CilOpCodes.Ldarg) 44 | return true; 45 | 46 | if (instr.OpCode == CilOpCodes.Ldarga) 47 | return true; 48 | 49 | if (instr.OpCode == CilOpCodes.Starg) 50 | return true; 51 | 52 | return false; 53 | } 54 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/FieldTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using Echo.ControlFlow; 4 | using VirtualGuard.AST; 5 | using VirtualGuard.VMIL.VM; 6 | 7 | namespace VirtualGuard.VMIL.Translation.impl; 8 | 9 | internal class FieldTranslator : ITranslator 10 | { 11 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 12 | VirtualGuardContext ctx) 13 | { 14 | switch (instr.OpCode.Code) 15 | { 16 | case CilCode.Stfld: 17 | case CilCode.Stsfld: 18 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, instr.Operand)); 19 | block.WithContent(new VmInstruction(VmCode.Stfld)); 20 | break; 21 | 22 | case CilCode.Ldfld: 23 | case CilCode.Ldsfld: 24 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, instr.Operand)); 25 | block.WithContent(new VmInstruction(VmCode.Ldfld)); 26 | break; 27 | 28 | case CilCode.Ldflda: 29 | case CilCode.Ldsflda: 30 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, instr.Operand)); 31 | block.WithContent(new VmInstruction(VmCode.Ldflda)); 32 | break; 33 | } 34 | } 35 | 36 | [Obfuscation(Feature = "virtualization")] 37 | public bool Supports(AstExpression instr) 38 | { 39 | return new[] 40 | { 41 | CilCode.Ldfld, 42 | CilCode.Ldsfld, 43 | CilCode.Ldflda, 44 | CilCode.Ldsflda, 45 | 46 | CilCode.Stfld, 47 | CilCode.Stsfld 48 | }.Contains(instr.OpCode.Code); 49 | } 50 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/BitwiseTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using Echo.ControlFlow; 4 | using VirtualGuard.AST; 5 | using VirtualGuard.VMIL.VM; 6 | 7 | namespace VirtualGuard.VMIL.Translation.impl; 8 | 9 | internal class BitwiseTranslator : ITranslator 10 | { 11 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 12 | VirtualGuardContext ctx) 13 | { 14 | switch (instr.OpCode.Code) 15 | { 16 | case CilCode.And: 17 | block.WithContent(new VmInstruction(VmCode.And)); 18 | break; 19 | 20 | case CilCode.Xor: 21 | block.WithContent(new VmInstruction(VmCode.Xor)); 22 | break; 23 | 24 | case CilCode.Or: 25 | block.WithContent(new VmInstruction(VmCode.Or)); 26 | break; 27 | 28 | case CilCode.Not: 29 | block.WithContent(new VmInstruction(VmCode.Not)); 30 | break; 31 | 32 | case CilCode.Shr: 33 | block.WithContent(new VmInstruction(VmCode.Shr)); 34 | break; 35 | 36 | case CilCode.Shl: 37 | block.WithContent(new VmInstruction(VmCode.Shl)); 38 | break; 39 | } 40 | } 41 | 42 | [Obfuscation(Feature = "virtualization")] 43 | public bool Supports(AstExpression instr) 44 | { 45 | return new[] 46 | { 47 | CilCode.Xor, 48 | CilCode.Or, 49 | CilCode.And, 50 | CilCode.Not, 51 | CilCode.Shr, 52 | CilCode.Shl 53 | }.Contains(instr.OpCode.Code); 54 | } 55 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/ArithmeticTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using AsmResolver.PE.DotNet.Metadata.Tables; 4 | using Echo.ControlFlow; 5 | using VirtualGuard.AST; 6 | using VirtualGuard.VMIL.VM; 7 | 8 | namespace VirtualGuard.VMIL.Translation.impl; 9 | 10 | internal class ArithmeticTranslator : ITranslator 11 | { 12 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 13 | VirtualGuardContext ctx) 14 | { 15 | switch (instr.OpCode.Code) 16 | { 17 | case CilCode.Add: 18 | block.WithContent(new VmInstruction(VmCode.Add)); 19 | break; 20 | 21 | case CilCode.Sub: 22 | block.WithContent(new VmInstruction(VmCode.Sub)); 23 | break; 24 | 25 | case CilCode.Mul: 26 | block.WithContent(new VmInstruction(VmCode.Mul)); 27 | break; 28 | 29 | case CilCode.Div: 30 | block.WithContent(new VmInstruction(VmCode.Div)); 31 | break; 32 | 33 | case CilCode.Rem: 34 | block.WithContent(new VmInstruction(VmCode.Rem)); 35 | break; 36 | } 37 | } 38 | 39 | [Obfuscation(Feature = "virtualization")] 40 | public bool Supports(AstExpression instr) 41 | { 42 | var supported = new CilOpCode[] 43 | { 44 | CilOpCodes.Add, 45 | CilOpCodes.Sub, 46 | CilOpCodes.Mul, 47 | CilOpCodes.Div, 48 | 49 | CilOpCodes.Rem 50 | }; 51 | 52 | return supported.Contains(instr.OpCode); 53 | } 54 | 55 | 56 | 57 | 58 | } -------------------------------------------------------------------------------- /VirtualGuard/AST/AstBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Reflection.Emit; 3 | using AsmResolver.DotNet.Code.Cil; 4 | using AsmResolver.PE.DotNet.Cil; 5 | using Echo.ControlFlow; 6 | 7 | namespace VirtualGuard.AST; 8 | 9 | internal class AstBuilder 10 | { 11 | public AstBuilder() 12 | { 13 | 14 | } 15 | 16 | private Stack _evalStack = new Stack(); 17 | 18 | public void Reset() 19 | { 20 | _evalStack.Clear(); 21 | } 22 | 23 | public AstBlock Analyze(ControlFlowNode node, bool returns) 24 | { 25 | var block = new AstBlock(); 26 | 27 | foreach (var instr in node.Contents.Instructions) 28 | { 29 | 30 | // pop 31 | var pops = instr.GetStackPopCount(returns); 32 | 33 | if (instr.OpCode == CilOpCodes.Ret) 34 | pops = 0; // bad fix 35 | 36 | var popped = new AstExpression[pops == -1 ? 0 : pops]; // leave likes to use -1 - wtf bro 37 | 38 | for (int i = 0; i < pops; i++) 39 | popped[i] = _evalStack.Pop(); 40 | 41 | // turn into expression 42 | var expr = AstExpression.Create(instr, popped); 43 | 44 | block.Add(expr); 45 | 46 | if(instr.OpCode == CilOpCodes.Dup) // repush original bc only peeked 47 | _evalStack.Push(popped[0]); // dup 48 | 49 | if(instr.GetStackPushCount() > 0) 50 | _evalStack.Push(expr); 51 | 52 | if(instr.OpCode == CilOpCodes.Leave) 53 | _evalStack.Clear(); // tbh if stack frame ends up not being cleared doesn't it mess it up anyways? 54 | 55 | } 56 | 57 | return block; 58 | } 59 | 60 | 61 | 62 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/MarkerTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Reflection; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using Echo.ControlFlow; 5 | using VirtualGuard.AST; 6 | using VirtualGuard.AST.IL; 7 | using VirtualGuard.VMIL.VM; 8 | 9 | namespace VirtualGuard.VMIL.Translation.impl; 10 | 11 | internal class MarkerTranslator : ITranslator 12 | { 13 | private Stack _exceptionHandlers = new Stack(); 14 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 15 | VirtualGuardContext ctx) 16 | { 17 | int i = 0; 18 | var marker = instr as AstMarker; 19 | 20 | switch (marker.Type) 21 | { 22 | case MarkerType.TryStart: 23 | var unknownLink = new UnknownBlockLink(i++); 24 | _exceptionHandlers.Push(unknownLink); 25 | block.WithContent( 26 | new VmInstruction(VmCode.Ldc_I4, unknownLink), 27 | new VmInstruction(VmCode.Entertry)); 28 | break; 29 | 30 | case MarkerType.HandlerStart: // we can resolve the block 31 | var reference = _exceptionHandlers.Pop(); 32 | reference.LinkedBlock = block; // link block 33 | break; 34 | 35 | 36 | } 37 | 38 | 39 | 40 | 41 | } 42 | 43 | [Obfuscation(Feature = "virtualization")] 44 | public bool Supports(AstExpression instr) 45 | { 46 | if (instr is AstMarker) 47 | return true; 48 | 49 | return false; 50 | } 51 | } 52 | 53 | internal class UnknownBlockLink 54 | { 55 | public UnknownBlockLink(int id) 56 | { 57 | LinkIdentifier = id; 58 | } 59 | 60 | public int LinkIdentifier; 61 | 62 | public bool Linked => LinkedBlock != null; 63 | 64 | public VmBlock LinkedBlock; 65 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/CallTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.DotNet; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using Echo.ControlFlow; 5 | using VirtualGuard.AST; 6 | using VirtualGuard.VMIL.VM; 7 | 8 | namespace VirtualGuard.VMIL.Translation.impl; 9 | 10 | #pragma warning disable CS8602 // Dereference of a possibly null reference. 11 | 12 | internal class CallTranslator : ITranslator 13 | { 14 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 15 | VirtualGuardContext ctx) 16 | { 17 | //if(method.Resolve()) 18 | 19 | 20 | switch (((IMethodDescriptor)instr.Operand).Name.ToString().ToLower()) 21 | { 22 | case "op_equality": // use our cmp instruction, we should see about hashing 23 | // edit: we don't even need to use our cmp instr, let them hook 24 | // op_equality and have them go "oh shit" when they realized virtualguard > 25 | 26 | // edit: nvm cuz i make them longs to cmp 27 | 28 | block.WithContent(Util.BuildHashInstructions(instr, meth, ctx.Runtime)); // use util 29 | 30 | block.WithContent(new VmInstruction(VmCode.Cmp), 31 | new VmInstruction(VmCode.Ldc_I4, (int)ctx.Runtime.Descriptor.ComparisonFlags.EqFlag), 32 | new VmInstruction(VmCode.Xor)); 33 | break; 34 | 35 | default: 36 | block.WithContent(new VmInstruction(VmCode.Call, instr.Operand)); 37 | break; 38 | } 39 | 40 | } 41 | 42 | [Obfuscation(Feature = "virtualization")] 43 | public bool Supports(AstExpression instr) 44 | { 45 | return new[] 46 | { 47 | CilCode.Newobj, 48 | CilCode.Call, 49 | CilCode.Callvirt, 50 | }.Contains(instr.OpCode.Code); 51 | 52 | } 53 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/ConstantTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using Echo.ControlFlow; 4 | using VirtualGuard.AST; 5 | using VirtualGuard.VMIL.VM; 6 | 7 | namespace VirtualGuard.VMIL.Translation.impl; 8 | 9 | internal class ConstantTranslator : ITranslator 10 | { 11 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 12 | VirtualGuardContext ctx) 13 | { 14 | switch (instr.OpCode.Code) 15 | { 16 | case CilCode.Ldc_I4: 17 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, instr.Operand)); 18 | break; 19 | 20 | case CilCode.Ldc_I8: 21 | block.WithContent(new VmInstruction(VmCode.Ldc_I8, instr.Operand)); 22 | break; 23 | 24 | case CilCode.Ldc_R4: 25 | block.WithContent(new VmInstruction(VmCode.Ldc_R4, instr.Operand)); 26 | break; 27 | 28 | case CilCode.Ldc_R8: 29 | block.WithContent(new VmInstruction(VmCode.Ldc_R8, instr.Operand)); 30 | break; 31 | 32 | case CilCode.Ldnull: 33 | block.WithContent(new VmInstruction(VmCode.Ldstr, 0)); // loads null 34 | break; 35 | 36 | case CilCode.Ldstr: 37 | block.WithContent(new VmInstruction(VmCode.Ldstr, instr.Operand)); // encoded later on 38 | break; 39 | } 40 | } 41 | 42 | [Obfuscation(Feature = "virtualization")] 43 | public bool Supports(AstExpression instr) 44 | { 45 | return new [] 46 | { 47 | CilCode.Ldc_I4, 48 | CilCode.Ldc_I8, 49 | 50 | CilCode.Ldc_R4, 51 | CilCode.Ldc_R8, 52 | 53 | CilCode.Ldstr, 54 | CilCode.Ldnull, 55 | }.Contains(instr.OpCode.Code); 56 | } 57 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/MiscTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using Echo.ControlFlow; 4 | using VirtualGuard.AST; 5 | using VirtualGuard.VMIL.VM; 6 | 7 | namespace VirtualGuard.VMIL.Translation.impl; 8 | 9 | internal class MiscTranslator : ITranslator 10 | { 11 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 12 | VirtualGuardContext ctx) 13 | { 14 | switch (instr.OpCode.Code) 15 | { 16 | case CilCode.Dup: 17 | block.WithContent(new VmInstruction(VmCode.Dup)); 18 | break; 19 | 20 | case CilCode.Pop: 21 | block.WithContent(new VmInstruction(VmCode.Pop)); 22 | break; 23 | 24 | case CilCode.Castclass: 25 | block.WithContent(new VmInstruction(VmCode.Castclass, instr.Operand)); 26 | break; 27 | 28 | case CilCode.Box: 29 | block.WithContent(new VmInstruction(VmCode.Box, instr.Operand)); 30 | break; 31 | 32 | case CilCode.Unbox_Any: 33 | block.WithContent(new VmInstruction(VmCode.Unboxany, instr.Operand)); 34 | break; 35 | 36 | case CilCode.Sizeof: 37 | block.WithContent(new VmInstruction(VmCode.Sizeof, instr.Operand)); 38 | break; 39 | 40 | case CilCode.Unbox: 41 | block.WithContent(new VmInstruction(VmCode.Unbox, instr.Operand)); 42 | break; 43 | } 44 | 45 | } 46 | 47 | [Obfuscation(Feature = "virtualization")] 48 | public bool Supports(AstExpression instr) 49 | { 50 | return instr.OpCode.Code == CilCode.Dup || instr.OpCode.Code == CilCode.Pop || instr.OpCode.Code == CilCode.Castclass || instr.OpCode.Code == CilCode.Box || instr.OpCode.Code == CilCode.Unbox_Any || instr.OpCode.Code == CilCode.Sizeof || instr.OpCode.Code == CilCode.Unbox; // lol 51 | } 52 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Dynamic/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace VirtualGuard.Runtime.Dynamic 2 | { 3 | 4 | public static class Constants 5 | { 6 | // reader 7 | public static byte HEADER_IV = 0; 8 | 9 | public static byte HEADER_ROTATION_FACTOR1 = 0; 10 | public static byte HEADER_ROTATION_FACTOR2 = 0; 11 | public static byte HEADER_ROTATION_FACTOR3 = 0; 12 | 13 | public static byte HANDLER_ROT1 = 0; 14 | public static byte BYTE_ROT1 = 0; 15 | 16 | public static byte HANDLER_ROT2 = 0; 17 | public static byte BYTE_ROT2 = 0; 18 | 19 | public static byte HANDLER_ROT3 = 0; 20 | public static byte BYTE_ROT3 = 0; 21 | 22 | public static byte HANDLER_ROT4 = 0; 23 | public static byte BYTE_ROT4 = 0; 24 | 25 | public static byte HANDLER_ROT5 = 0; 26 | public static byte BYTE_ROT5 = 0; 27 | 28 | // data 29 | public static string DT_WATERMARK; 30 | public static string DT_NAME; 31 | 32 | // flags 33 | 34 | public static byte CMP_GT; 35 | public static byte CMP_LT; 36 | public static byte CMP_EQ; 37 | 38 | public static int CorlibID_I; 39 | public static int CorlibID_I1; 40 | public static int CorlibID_I2; 41 | public static int CorlibID_I4; 42 | public static int CorlibID_I8; 43 | 44 | public static int CorlibID_U; 45 | public static int CorlibID_U1; 46 | public static int CorlibID_U2; 47 | public static int CorlibID_U4; 48 | public static int CorlibID_U8; 49 | 50 | public static byte CatchFL; 51 | public static byte FaultFL; 52 | public static byte FilterFL; 53 | public static byte FinallyFL; 54 | 55 | public static byte NKey; 56 | public static byte NSalt1; 57 | public static byte NSalt2; 58 | public static byte NSalt3; 59 | 60 | public static uint SPolynomial; 61 | public static uint SSeed; 62 | public static uint SXorMask; 63 | 64 | } 65 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Config/ConfigGenerator.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | using AsmResolver.DotNet; 4 | using Newtonsoft.Json; 5 | 6 | namespace VirtualGuard.CLI.Config; 7 | 8 | public class ConfigGenerator 9 | { 10 | private SerializedConfig _cfg; 11 | private ModuleDefinition _module; 12 | 13 | public ConfigGenerator(ModuleDefinition mod) 14 | { 15 | _cfg = new SerializedConfig(); 16 | } 17 | 18 | public void Populate() 19 | { 20 | 21 | // put default methods that people would most likely like to obfuscate in the config 22 | 23 | var methods = new List(); 24 | 25 | 26 | methods.Add(_module.ManagedEntryPointMethod); 27 | 28 | var largestSupportedMethods = _module.GetAllTypes() 29 | .SelectMany(x => x.Methods.Where(x => x.CilMethodBody != null)) 30 | .OrderBy(x => x.CilMethodBody.Instructions.Count) 31 | .Where(x => x.CilMethodBody.Instructions.Count(x2 => Virtualizer.Supports(x2.OpCode)) == x.CilMethodBody.Instructions.Count).ToList(); 32 | 33 | if(largestSupportedMethods.Count() > 10) 34 | largestSupportedMethods.RemoveRange(10, largestSupportedMethods.Count - 10); // remove all after that 35 | 36 | methods.AddRange(largestSupportedMethods); 37 | 38 | var serializedMethods = new SerializedMember[methods.Count]; 39 | 40 | for (int i = 0; i < methods.Count; i++) 41 | serializedMethods[i] = new SerializedMember() 42 | { 43 | Virtualize = true, 44 | Exclude = false, 45 | Member = methods[i].DeclaringType.Namespace + "." + methods[i].DeclaringType.Name + ":" + methods[i].Name 46 | }; 47 | 48 | _cfg = new SerializedConfig() 49 | { 50 | Members = serializedMethods, 51 | ProcessorCount = 2, 52 | RenameDebugSymbols = false, 53 | UseDataEncryption = true, 54 | }; 55 | 56 | } 57 | 58 | 59 | public string Serialize() 60 | { 61 | return JsonConvert.SerializeObject(_cfg); 62 | } 63 | 64 | 65 | 66 | 67 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/VM/VmInstruction.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using AsmResolver.DotNet; 3 | using AsmResolver.DotNet.Signatures.Types; 4 | using VirtualGuard.RT.Chunk; 5 | using VirtualGuard.RT.Mutators; 6 | using VirtualGuard.Runtime.OpCodes.impl; 7 | 8 | namespace VirtualGuard.VMIL.VM; 9 | 10 | internal class VmInstruction 11 | { 12 | public VmInstruction(VmCode code) 13 | { 14 | OpCode = code; 15 | } 16 | 17 | public VmInstruction(VmCode code, object operand) 18 | { 19 | OpCode = code; 20 | Operand = operand; 21 | } 22 | 23 | 24 | public int GetSize() 25 | { 26 | if (this.Operand == null) 27 | return sizeof(VmCode); // stop execution, length should not be updated and it should move to the next instr 28 | 29 | if (this.Operand is byte) 30 | return sizeof(VmCode) + sizeof(byte); 31 | 32 | if (this.Operand is short) 33 | return sizeof(VmCode) + sizeof(short); 34 | 35 | if (this.Operand is int) 36 | return sizeof(VmCode) + sizeof(int); 37 | 38 | if (this.Operand is long) 39 | return sizeof(VmCode) + sizeof(long); 40 | 41 | if (this.Operand is VmVariable) 42 | return sizeof(VmCode) + sizeof(short); 43 | 44 | if (this.Operand is VmChunk) 45 | return sizeof(VmCode) + sizeof(int); 46 | 47 | if (this.Operand is IMetadataMember) 48 | return sizeof(VmCode) + sizeof(int); 49 | 50 | if(this.Operand is TypeSignature) 51 | return sizeof(VmCode) + sizeof(int); 52 | 53 | if(this.Operand is MutationOperation) 54 | return sizeof(VmCode) + sizeof(int); 55 | 56 | if(this.Operand is VmInstruction) 57 | return sizeof(VmCode) + sizeof(int); 58 | 59 | throw new DataException(this.Operand.GetType().FullName); 60 | } 61 | 62 | public VmCode OpCode; 63 | public object Operand; 64 | 65 | public override string ToString() 66 | { 67 | if (Operand is VmInstruction vi) 68 | return "ref:{" + vi + "}"; 69 | 70 | return OpCode + " " + (Operand == null ? "" : Operand.GetType().Name + ":" + Operand.ToString()); 71 | } 72 | 73 | 74 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/ComparisonTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Reflection; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using Echo.ControlFlow; 5 | using VirtualGuard.AST; 6 | using VirtualGuard.VMIL.VM; 7 | 8 | namespace VirtualGuard.VMIL.Translation.impl; 9 | 10 | internal class ComparisonTranslator : ITranslator 11 | { 12 | 13 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 14 | VirtualGuardContext ctx) 15 | { 16 | // handle hashing of args 17 | 18 | 19 | if(instr.OpCode.Code == CilCode.Ceq) 20 | block.WithContent(Util.BuildHashInstructions(instr, meth, ctx.Runtime)); // see about hashing for equals operations 21 | 22 | // now we just need to push the branch condition, aka validating the output flag 23 | 24 | block.WithContent(new VmInstruction(VmCode.Cmp)); // main cmp 25 | 26 | switch (instr.OpCode.Code) 27 | { 28 | case CilCode.Ceq: 29 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, (int)meth.Runtime.Descriptor.ComparisonFlags.EqFlag)); 30 | break; 31 | 32 | case CilCode.Cgt: 33 | case CilCode.Cgt_Un: 34 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, (int)meth.Runtime.Descriptor.ComparisonFlags.GtFlag)); 35 | break; 36 | 37 | case CilCode.Clt: 38 | case CilCode.Clt_Un: 39 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, (int)meth.Runtime.Descriptor.ComparisonFlags.LtFlag)); 40 | break; 41 | } 42 | 43 | // now we need to determine if the values are the same to produce the 1 or 0 flag 44 | 45 | block.WithContent(new VmInstruction(VmCode.Xor)); // this will push 0 if they are equal 46 | } 47 | 48 | [Obfuscation(Feature = "virtualization")] 49 | public bool Supports(AstExpression instr) 50 | { 51 | return new[] 52 | { 53 | CilCode.Ceq, 54 | CilCode.Cgt, 55 | CilCode.Cgt_Un, 56 | CilCode.Clt, 57 | CilCode.Clt_Un, 58 | }.Contains(instr.OpCode.Code); 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | # VirtualGuard 6 | 7 | This is the obfuscation engine for a project I was developing called VirtualGuard. 8 | 9 | [Foreword](#foreword) • 10 | [Features](#features) • 11 | [Usage](#usage) • 12 | [License](#license) • 13 | [Credits](#credits) 14 | 15 | 16 | [![forthebadge](https://forthebadge.com/images/badges/license-mit.svg)](https://forthebadge.com) 17 | [![forthebadge](https://forthebadge.com/images/badges/powered-by-black-magic.svg)](https://forthebadge.com) 18 | [![forthebadge](https://forthebadge.com/images/badges/made-with-c-sharp.svg)](https://forthebadge.com) 19 | 20 |
21 | 22 | ## Foreword 23 | 24 | I once intended to sell VirtualGuard, however as soon as money gets involved with things I tend to lose interest. So here's the source code! 25 | 26 | I am open-sourcing this months after I originally wrote it, so I may have trouble providing support on much of it. With that said, I have comments all over the code. I hope people can learn off of this! ( and see in the end that VirtualGuard was not a confuserEx clone :( ) 27 | 28 | ## Features 29 | 30 | - Automatic hashing of constants in equality checks 31 | - No dispatcher - each handler has a unique offset which is then added to a fixup byte to overflow to the next handler. 32 | - No conditional jump opcodes through the use of arithmetic to calculate the proper jump address 33 | - Multi-VM Support 34 | - Unique virtual machines (huge list of constants is randomized on compile-time) 35 | - And probably a bunch more that I am forgetting. 36 | 37 | 38 | ## Usage 39 | 40 | - I believe that the CLI will work, and it has brief provided documentation within it. You will need to pass in the arguments to generate a configuration first, and then once you have a config file you should be able to virtualize your files with it. If worst comes to worse, just use the code in the CLI as reference for interacting with the proper engine. 41 | 42 | 43 | ## License 44 | 45 | This repository uses the MIT license. 46 | 47 | 48 | ## Credits 49 | 50 | - Washi for [AsmResolver](https://github.com/Washi1337/AsmResolver) 51 | - [KoiVM](https://github.com/yck1509/KoiVM). Love the way KoiVM is organized. Structurally very inspired by it. Not a KoiVM clone. (however impl of the abstracted handlers I will admit is a little silly) 52 | - Echo 53 | -------------------------------------------------------------------------------- /VirtualGuard.Stubs/Limiter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace VirtualGuard.Stubs 4 | { 5 | public class Limiter 6 | { 7 | public static void Limit() 8 | { 9 | Console.Title = "virtualguard.io"; 10 | 11 | string s = @" 12 | . . . . . . . . . . . . . . . . . . . . . . 13 | . . . . :: . . . 14 | . . . . . . t.SS88 . . . . . . . 15 | . . . .;@8 88888 88% . . 16 | . . 8 8 8S888S888888888SS 8 8 % 8. . . . 17 | . . tSX888888888888X8888888S888XX8888888@888Xt . 18 | . SSXX888888X888X88888%;:88888S8 8S8X8 8888%.. . 19 | . . S888S@88 88888. ;X%: .% :8@8888888XX@8t . . . 20 | . tS88@88XtXXt:: . ..%X@8St88XXSS 21 | . X8@@88 . . . . . ;888S8 .. . . 22 | . .tX888SX. . . . .;8888 @ . 23 | . . . 8 88:.. . . . . . ..@8 8 : 24 | ..888 88 . . . . S8:@8 ; . . . . 25 | . . .;@88:S t . . . . . . : .X:@ ; . 26 | . . ..@888:8S% . . . tS;X888; . . 27 | 888@ 8X; . . . . . .;S88%8. . . 28 | . . . . : 8:@8;888; . . :88:8@88@ . . . 29 | . . 888%8SX;S.. . .S;8t88%88t . . 30 | . . ;8888%@8S; . t:8@88888 : . . . 31 | . . . .:8S8888888 @.. .@ @88%@88@8S. . . 32 | . . .: %88888tX8@:;88@%888888:: . . . . . 33 | . . . . . ;t.88%888SX888888X8%:. .. . . 34 | . . .:.@@88888888 8t: .. . . . . 35 | . . . . . ;@X8@8S . . . . . . . 36 | . . . . . . .. %;; . . . . . 37 | . . . . . . . . . . . 38 | . . . . . . . . . . . . "; 39 | Console.WriteLine(s); 40 | Console.WriteLine( 41 | "This application is protected by a trial version of VirtualGuard. You can purchase a full license @ https://virtualguard.io/."); 42 | Console.WriteLine("Press any key to begin execution of the program."); 43 | Console.ReadKey(); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/MultiProcessorVirtualizer.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | 3 | namespace VirtualGuard.CLI; 4 | 5 | public class MultiProcessorVirtualizer 6 | { 7 | private MultiProcessorAllocationMode _mode; 8 | 9 | private readonly Virtualizer[] _virtualizers; 10 | 11 | public MultiProcessorVirtualizer(VirtualGuardContext ctx, bool debug, int debugKey, MultiProcessorAllocationMode mode, int processors) 12 | { 13 | _mode = mode; 14 | 15 | _virtualizers = new Virtualizer[processors]; 16 | 17 | for (int i = 0; i < processors; i++) 18 | _virtualizers[i] = new Virtualizer(new VirtualGuardContext(ctx.Module, ctx.Logger), debugKey, debug); 19 | } 20 | 21 | private readonly List _virtualizedMethods = new List(); 22 | 23 | private static readonly Random _rnd = new Random(); 24 | private int _index = 0; 25 | 26 | public bool IsMethodVirtualized(MethodDefinition def) 27 | { 28 | return _virtualizedMethods.Contains(def); 29 | } 30 | 31 | public void AddMethod(MethodDefinition def, bool export) 32 | { 33 | if (_virtualizedMethods.Contains(def)) 34 | throw new InvalidOperationException("Method already virtualized."); 35 | 36 | _virtualizedMethods.Add(def); 37 | 38 | switch (_mode) 39 | { 40 | case MultiProcessorAllocationMode.Random: 41 | _virtualizers[_rnd.Next(_virtualizers.Length - 1)].AddMethod(def, export); 42 | break; 43 | 44 | case MultiProcessorAllocationMode.Sequential: 45 | if (_index == _virtualizers.Length - 1) 46 | _index = 0; // reset to 0, at capacity 47 | else 48 | _index++; 49 | 50 | _virtualizers[_index].AddMethod(def, export); 51 | break; 52 | 53 | } 54 | } 55 | 56 | public TypeDefinition[] GetVmTypes() 57 | { 58 | return _virtualizers.SelectMany(x => x.GetVmElements().VmTypes).ToArray(); 59 | } 60 | 61 | public void Commit() 62 | { 63 | foreach (var virt in _virtualizers) 64 | virt.CommitRuntime(); 65 | } 66 | 67 | } 68 | 69 | public enum MultiProcessorAllocationMode 70 | { 71 | Random, 72 | Sequential 73 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/Runtime/EncryptExceptions.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using AsmResolver.DotNet; 3 | using AsmResolver.PE.DotNet.Cil; 4 | 5 | namespace VirtualGuard.RT.Mutators.impl.Runtime; 6 | 7 | internal class EncryptExceptions : IRuntimeMutator 8 | { 9 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 10 | { 11 | if(rt.isDebug) 12 | return; 13 | 14 | // locate routine type 15 | var routineType = rt.RuntimeModule.LookupType(RuntimeConfig.Routines); 16 | 17 | var encryptDebugSymbol = routineType.Methods.Single(x => x.Name == "EncryptDebugMessage"); 18 | 19 | foreach (var method in rt.RuntimeModule.TopLevelTypes.SelectMany(x => x.Methods) 20 | .Where(x => x.CilMethodBody != null && x.CilMethodBody.Instructions.Count > 0)) 21 | { 22 | 23 | bool foundInstance = false; 24 | 25 | foreach (var instr in method.CilMethodBody.Instructions.Reverse()) 26 | { 27 | if (foundInstance) 28 | { 29 | if(instr.OpCode.Code != CilCode.Ldstr) 30 | continue; 31 | 32 | var str = instr.Operand.ToString(); 33 | 34 | instr.Operand = Encrypt(str, rt.Descriptor.Data.DebugKey); 35 | 36 | foundInstance = false; // set to false again 37 | } 38 | 39 | if(instr.OpCode.Code != CilCode.Call) 40 | continue; 41 | 42 | if (instr.Operand is IMethodDescriptor mdesc && mdesc.FullName == encryptDebugSymbol.FullName) 43 | { 44 | instr.ReplaceWithNop(); 45 | foundInstance = true; 46 | } 47 | 48 | 49 | } 50 | 51 | routineType.Methods.Remove(encryptDebugSymbol); 52 | 53 | } 54 | 55 | // pray we don't need this again (probably not for a bit) 56 | 57 | ctx.Module.TopLevelTypes.Remove(routineType); 58 | } 59 | 60 | string Encrypt(string str, int key) 61 | { 62 | StringBuilder builder = new StringBuilder(); 63 | foreach (char c in str.ToCharArray()) 64 | builder.Append((char)(c - key)); 65 | 66 | return builder.ToString(); 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Descriptor/DataDescriptor.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.Patching; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using VirtualGuard.RT.Chunk; 5 | using VirtualGuard.RT.Descriptor.Handler; 6 | using VirtualGuard.RT.Dynamic; 7 | using VirtualGuard.VMIL.VM; 8 | 9 | namespace VirtualGuard.RT.Descriptor; 10 | 11 | internal class DataDescriptor 12 | { 13 | public DataDescriptor(Random rnd, int debugKey) 14 | { // debug 15 | byte[] randomBytes1 = new byte[5]; 16 | byte[] randomBytes2 = new byte[5]; 17 | byte[] randomBytes3 = new byte[5]; 18 | 19 | rnd.NextBytes(randomBytes1); 20 | HandlerShifts = randomBytes1; 21 | 22 | rnd.NextBytes(randomBytes2); 23 | ByteShifts = randomBytes2; 24 | 25 | rnd.NextBytes(randomBytes3); 26 | HeaderRotationFactors = randomBytes3; 27 | 28 | InitialHeaderKey = (byte)_rnd.Next(255); 29 | 30 | DebugKey = debugKey; 31 | } 32 | 33 | public byte InitialHeaderKey; 34 | public byte[] HeaderRotationFactors; 35 | 36 | public int DebugKey; 37 | 38 | private Dictionary _stringMap = new Dictionary(); 39 | 40 | private Dictionary _chunkKeyMap = new Dictionary(); 41 | 42 | public byte GetStartKey(VmChunk chunk) 43 | { 44 | //if(!_chunkKeyMap.ContainsKey(chunk)) 45 | // BuildStartKey(chunk); 46 | 47 | return _chunkKeyMap[chunk]; 48 | } 49 | 50 | public void SetStartKey(VmChunk chunk, byte b) 51 | { 52 | _chunkKeyMap[chunk] = b; // used for branch encryption 53 | } 54 | 55 | public void BuildStartKey(VmChunk chunk) 56 | { 57 | var startKey = (byte)_rnd.Next(255); 58 | _chunkKeyMap.Add(chunk, startKey); 59 | } 60 | 61 | public Dictionary GetExports() 62 | { 63 | return _chunkKeyMap; 64 | } 65 | 66 | public string StreamName; 67 | public string Watermark; 68 | 69 | public byte[] ByteShifts; 70 | public byte[] HandlerShifts; 71 | 72 | private static Random _rnd = new Random(); 73 | public int AddString(string s) 74 | { 75 | int id = _rnd.Next(int.MaxValue); 76 | 77 | while(_stringMap.ContainsKey(id)) 78 | id = _rnd.Next(int.MaxValue); 79 | 80 | _stringMap.Add(id, s); 81 | 82 | return id; 83 | } 84 | 85 | public Dictionary GetStrings() 86 | { 87 | return _stringMap; 88 | } 89 | 90 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Descriptor/Handler/VmHandler.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | using AsmResolver.DotNet.Code.Cil; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using VirtualGuard.RT.Dynamic; 5 | using VirtualGuard.VMIL.VM; 6 | 7 | namespace VirtualGuard.RT.Descriptor.Handler; 8 | 9 | internal class VmHandler 10 | { 11 | public VmHandler(VmCode code, TypeDefinition def, byte identifier) 12 | { 13 | OpCode = code; 14 | _internalDefinition = def; 15 | 16 | Identifier = identifier; 17 | FixupMutation = MutationExpression.Random(0); 18 | 19 | if(code == VmCode.__nop) 20 | return; 21 | 22 | var body = new CilMethodBody(_codeDefinition); 23 | _codeDefinition.CilMethodBody = body; 24 | 25 | body.Instructions.Add(CilOpCodes.Ldc_I4, identifier); 26 | body.Instructions.Add(CilOpCodes.Ret); 27 | 28 | if (OpCode == VmCode.Jmp) 29 | return; 30 | 31 | FixupMutation = MutationExpression.Random(1); 32 | 33 | // inline fixup mutation into the identifier body 34 | 35 | var fixupRefs = ExecuteDefinition.CilMethodBody.Instructions.Where(x => 36 | x.Operand is IMethodDescriptor fd && fd.Name == "ReadFixupValue"); 37 | 38 | if (!fixupRefs.Any()) 39 | return; 40 | 41 | var fixupRef = fixupRefs.First(); 42 | 43 | var mutationCil = this.FixupMutation.ToCIL(); 44 | 45 | // get index of fixupRef 46 | var index = ExecuteDefinition.CilMethodBody.Instructions.IndexOf(fixupRef) + 1; 47 | 48 | // insert all into target 49 | ExecuteDefinition.CilMethodBody.Instructions.InsertRange(index, mutationCil); 50 | 51 | ExecuteDefinition.CilMethodBody.Instructions.CalculateOffsets(); 52 | } 53 | 54 | public readonly VmCode OpCode; 55 | public byte Identifier; 56 | 57 | public TypeDefinition HandlerDefinition 58 | { 59 | get 60 | { 61 | if (_internalDefinition == null) 62 | throw new Exception("Handler Representation " + OpCode + " never initialized!"); 63 | 64 | return _internalDefinition; 65 | } 66 | } 67 | 68 | public byte EmulateFixupMutation(int fixup) 69 | { 70 | return (byte)FixupMutation.Solve(fixup); 71 | } 72 | 73 | public MutationExpression FixupMutation; 74 | public MethodDefinition ExecuteDefinition => HandlerDefinition.Methods.Single(x => x.Parameters.Count > 0); 75 | private MethodDefinition _codeDefinition => HandlerDefinition.Methods.Single(x => x.Parameters.Count == 0 && !x.IsConstructor); 76 | 77 | private byte? _internalIdentifier = null; 78 | private readonly TypeDefinition _internalDefinition = null; 79 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/VMContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using VirtualGuard.Runtime.Dynamic; 5 | using VirtualGuard.Runtime.Execution; 6 | using VirtualGuard.Runtime.OpCodes; 7 | using VirtualGuard.Runtime.Variant; 8 | using VirtualGuard.Runtime.Variant.Object; 9 | using VirtualGuard.Runtime.Variant.ValueType.Numeric; 10 | 11 | namespace VirtualGuard.Runtime 12 | { 13 | 14 | public class VMContext 15 | { 16 | public VMContext(byte entryKey) 17 | { 18 | Reader.SetKey(entryKey); 19 | } 20 | 21 | public readonly VMStack Stack = new(); 22 | public readonly LocalStorage Locals = new(); 23 | public readonly VMReader Reader = new(); 24 | 25 | public byte CurrentCode; 26 | 27 | public Exception Exception; 28 | 29 | public Stack HandlerStack = new Stack(); 30 | 31 | public object Dispatch(int loc, object[] args) 32 | { 33 | Reader.SetValue(loc); 34 | 35 | Stack.Push(new ArrayVariant(args)); 36 | 37 | CurrentCode = Reader.ReadFixupValue(); 38 | CodeMap.LookupCode(CurrentCode).Execute(this); 39 | 40 | return Stack.Pop().GetObject(); 41 | } 42 | 43 | 44 | void Unwind() 45 | { 46 | var handler = HandlerStack.Pop(); 47 | 48 | if (handler.Type != Constants.CatchFL) 49 | throw new InvalidOperationException( 50 | Routines.EncryptDebugMessage("Unwinding exception handler was not a catch")); 51 | 52 | Stack.SetValue(0); // reset stack ptr 53 | 54 | // handler needs to jump to finally if we want finally to work 55 | 56 | Reader.SetKey(handler.HandlerStartKey); 57 | Reader.SetValue(handler.HandlerPos); 58 | 59 | Stack.Push(new ObjectVariant(Exception)); 60 | } 61 | 62 | 63 | public MethodBase ResolveMethod(int i) 64 | { 65 | return (MethodBase)Assembly.GetExecutingAssembly().ManifestModule.ResolveMember(i); 66 | } 67 | 68 | public FieldInfo ResolveField(int i) 69 | { 70 | return (FieldInfo)Assembly.GetExecutingAssembly().ManifestModule.ResolveMember(i); 71 | } 72 | 73 | public Type ResolveType(int i) 74 | { 75 | return Assembly.GetExecutingAssembly().ManifestModule.ResolveType(i); 76 | } 77 | 78 | public MemberInfo ResolveMember(int i) 79 | { 80 | return Assembly.GetExecutingAssembly().ManifestModule.ResolveMember(i); 81 | } 82 | 83 | } 84 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Processors/impl/Renamer.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection.Metadata; 2 | using AsmResolver.DotNet.Signatures; 3 | 4 | namespace VirtualGuard.CLI.Processors.impl; 5 | 6 | public class Renamer : IProcessor 7 | { 8 | private Dictionary _sigMap = new Dictionary(); 9 | 10 | public string Identifier => "Renamer"; 11 | public void Process(Context ctx) 12 | { 13 | int typeIndex = 0; 14 | 15 | foreach (var type in ctx.Module.GetAllTypes().Except(ctx.Virtualizer.GetVmTypes())) 16 | { 17 | int methodIndex = 0; 18 | 19 | if (ctx.Module.ManagedEntryPointMethod == null && type.IsPublic) 20 | { // idk how to unfuck this but it should work 21 | 22 | } else if (!ctx.Configuration.IsMemberExcluded(type, ctx)) 23 | { // should rename 24 | type.Namespace = ""; 25 | 26 | if (!type.IsModuleType && !type.IsRuntimeSpecialName) 27 | { 28 | type.Name = "<." + typeIndex++ + ".>;"; 29 | } 30 | 31 | } 32 | 33 | foreach (var method in type.Methods) 34 | { 35 | 36 | if(ctx.Module.ManagedEntryPointMethod == null && type.IsPublic && (method.IsPublic || type.IsInterface)) 37 | continue; // shouldn't rename 38 | 39 | if (!ctx.Configuration.IsMemberExcluded(method, ctx) && !method.IsRuntimeSpecialName) 40 | { 41 | // handle abstract 42 | 43 | if(method.IsConstructor) 44 | continue; 45 | 46 | if(method.IsAbstract || method.IsVirtual || (type.BaseType != null && type.BaseType.Resolve() != null && type.BaseType.Resolve().IsInterface && type.BaseType.Resolve().Methods.Select(x => x.Name).Contains(method.Name))) 47 | continue; // fml 48 | 49 | method.Name = "<." + methodIndex++ + ".>;"; 50 | } 51 | 52 | foreach (var arg in method.ParameterDefinitions) 53 | { 54 | arg.Name = "<.vg.>;"; 55 | } 56 | 57 | } 58 | 59 | foreach (var field in type.Fields) 60 | { 61 | if(ctx.Module.ManagedEntryPointMethod == null && field.IsPublic && type.IsPublic) 62 | continue; // shouldn't rename 63 | 64 | if (!ctx.Configuration.IsMemberExcluded(field, ctx) && !field.IsRuntimeSpecialName) 65 | field.Name = "<.vg.>;"; 66 | } 67 | 68 | } 69 | 70 | } 71 | } -------------------------------------------------------------------------------- /VirtualGuard/Virtualizer.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Reflection; 3 | using AsmResolver.DotNet; 4 | using AsmResolver.DotNet.Cloning; 5 | using AsmResolver.PE.DotNet.Cil; 6 | using VirtualGuard.AST; 7 | using VirtualGuard.RT; 8 | using VirtualGuard.RT.Chunk; 9 | using VirtualGuard.VMIL.Translation; 10 | 11 | namespace VirtualGuard; 12 | 13 | public class Virtualizer 14 | { 15 | private VirtualGuardContext _ctx; 16 | 17 | private MethodVirtualizer _methodVirtualizer; 18 | private VirtualGuardRT _rt; 19 | 20 | private bool _rtCommitted = false; 21 | 22 | public Virtualizer(VirtualGuardContext ctx, int debugKey, bool debug) 23 | { 24 | _ctx = ctx; 25 | _rt = new VirtualGuardRT(ModuleDefinition.FromFile(RuntimeConfig.RuntimePath), debugKey, debug); 26 | _methodVirtualizer = new MethodVirtualizer(_rt, _ctx); 27 | _ctx.Runtime = _rt; 28 | } 29 | 30 | [Obfuscation(Feature = "virtualization")] 31 | public void AddMethod(MethodDefinition def, bool exportMethod) 32 | { 33 | var sw = new Stopwatch(); 34 | sw.Start(); 35 | 36 | _ctx.Logger.Info("Virtualizing " + def.FullName); 37 | 38 | _methodVirtualizer.Virtualize(def, exportMethod); 39 | _ctx.VirtualizedMethods.Add(def, exportMethod); 40 | 41 | sw.Stop(); 42 | 43 | Console.WriteLine("Finished in: " + sw.ElapsedMilliseconds + "ms"); 44 | } 45 | 46 | [Obfuscation(Feature = "virtualization")] 47 | public void CommitRuntime() 48 | { 49 | if (_ctx.VirtualizedMethods.Count == 0) 50 | { 51 | _ctx.Logger.Warning("Virtualizer had no methods virtualized, not injecting."); 52 | return; 53 | } 54 | 55 | _rt.BuildData(_ctx); 56 | 57 | // clone runtime module into target module 58 | _rt.Inject(_ctx.Module); 59 | 60 | var processor = new RuntimeProcessor(_rt, _ctx); 61 | processor.FinalizeMethods(); 62 | 63 | _rtCommitted = true; 64 | } 65 | 66 | [Obfuscation(Feature = "virtualization")] 67 | public VmElements GetVmElements() 68 | { 69 | if (_ctx.VirtualizedMethods.Count == 0) 70 | return new VmElements() 71 | { 72 | VmTypes = Array.Empty() 73 | }; // kinda scuffed but in the present usages it's fine 74 | 75 | if(!_rtCommitted) 76 | _ctx.Logger.Fatal("Runtime has not been committed before requesting VmElements."); 77 | 78 | return _rt.Elements; 79 | } 80 | 81 | public static bool Supports(CilOpCode code) 82 | { 83 | var newExpr = new AstExpression(code, null, null); 84 | 85 | if (ITranslator.Lookup(newExpr) == null) 86 | return false; 87 | 88 | return true; // has a translator, doesn't necessarily mean it'll work ;) 89 | } 90 | 91 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | using System.Net; 4 | using AsmResolver.DotNet; 5 | using AsmResolver.DotNet.Builder; 6 | using AsmResolver.PE.DotNet.Builder; 7 | using Newtonsoft.Json; 8 | using VirtualGuard; 9 | using VirtualGuard.CLI; 10 | using VirtualGuard.CLI.Config; 11 | using VirtualGuard.CLI.Processors; 12 | using VirtualGuard.CLI.Processors.impl; 13 | 14 | #if DEBUG 15 | var debug = true; 16 | #else 17 | var debug = false 18 | #endif 19 | 20 | /* 21 | cli.exe -genconfig 22 | returns: gonna edit an example here 23 | 24 | default cli: 25 | 26 | cli.exe -raw 27 | cli.exe */ 28 | 29 | if (args[0] == "-genconfig") 30 | { 31 | var gen = new ConfigGenerator(ModuleDefinition.FromFile(args[1])); 32 | gen.Populate(); 33 | 34 | Console.WriteLine(gen.Serialize()); 35 | return; 36 | } 37 | 38 | LicenseType license = (LicenseType)int.Parse(args[0]); // will throw error if not int 39 | string path = args[1]; 40 | string outputPath = args[2]; 41 | int debugKey = int.Parse(args[3]); 42 | 43 | string settings = args[4] == "-raw" ? args[5] : File.ReadAllText(args[4]); 44 | 45 | var logger = new ConsoleLogger(); 46 | 47 | var module = ModuleDefinition.FromFile(path); 48 | 49 | 50 | // note: license is not initialized as of 12/17/23 51 | var ctx = new Context(module, JsonConvert.DeserializeObject(settings), logger, license); 52 | 53 | var vgCtx = new VirtualGuardContext(module, logger); 54 | 55 | // init processors 56 | ctx.Virtualizer = new MultiProcessorVirtualizer(vgCtx, debug, debugKey, MultiProcessorAllocationMode.Sequential, ctx.Configuration.ProcessorCount); 57 | 58 | var pipeline = new Queue(); 59 | 60 | if (ctx.License == LicenseType.Free) 61 | { 62 | pipeline.Enqueue(new FreeLimitations()); 63 | ctx.Logger.Warning("License is free, therefore adding limitations."); 64 | } 65 | 66 | if (ctx.Configuration.UseDataEncryption) 67 | { 68 | pipeline.Enqueue(new DataEncryption()); 69 | } 70 | 71 | if (ctx.Configuration.UseImportProtection && license != LicenseType.Free) 72 | { 73 | pipeline.Enqueue(new ImportProtection()); 74 | } 75 | 76 | pipeline.Enqueue(new Virtualization()); 77 | 78 | if (ctx.Configuration.UseDataEncryption) 79 | { 80 | pipeline.Enqueue(new PostDataEncryption()); // fml 81 | } 82 | 83 | //pipeline.Enqueue(new PostImportProtection()); 84 | 85 | if(ctx.Configuration.RenameDebugSymbols) 86 | pipeline.Enqueue(new Renamer()); 87 | 88 | pipeline.Enqueue(new Watermark()); 89 | 90 | while(pipeline.TryDequeue(out IProcessor processor)) { 91 | processor.Process(ctx); 92 | logger.Success("Processed: " + processor.Identifier); 93 | } 94 | 95 | // save file 96 | ctx.Module.Write(outputPath, new ManagedPEImageBuilder(MetadataBuilderFlags.PreserveTableIndices)); 97 | 98 | ctx.Logger.Success("Wrote file at " + outputPath); 99 | -------------------------------------------------------------------------------- /VirtualGuard/Transform/IL/impl/ConditionalSimplifier.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.PE.DotNet.Cil; 2 | using Echo.ControlFlow; 3 | 4 | namespace VirtualGuard.Transform.IL.impl; 5 | 6 | internal class ConditionalSimplifier : IILTransformer 7 | { 8 | public void Transform(ControlFlowNode node, ControlFlowGraph ctx) 9 | { 10 | var oldInstrs = node.Contents.Instructions.ToArray(); 11 | 12 | node.Contents.Instructions.Clear(); 13 | 14 | 15 | foreach (var oldInstr in oldInstrs) 16 | { 17 | 18 | if (Simplify(oldInstr, out CilInstruction[] instrs)) 19 | { 20 | foreach (var instr in instrs) 21 | { 22 | node.Contents.Instructions.Add(instr); 23 | } 24 | 25 | } 26 | else 27 | { 28 | node.Contents.Instructions.Add(oldInstr); 29 | } 30 | } 31 | } 32 | 33 | bool Simplify(CilInstruction instr, out CilInstruction[] instrs) 34 | { 35 | var instructions = new List(); 36 | 37 | switch (instr.OpCode.Code) 38 | { 39 | case CilCode.Beq: 40 | instructions.Add(new CilInstruction(CilOpCodes.Ceq)); 41 | instructions.Add(new CilInstruction(CilOpCodes.Brtrue, instr.Operand)); 42 | break; 43 | 44 | case CilCode.Bne_Un: 45 | instructions.Add(new CilInstruction(CilOpCodes.Ceq)); 46 | instructions.Add(new CilInstruction(CilOpCodes.Brfalse, instr.Operand)); 47 | break; 48 | 49 | case CilCode.Bge: 50 | case CilCode.Bge_Un: 51 | instructions.Add(new CilInstruction(CilOpCodes.Clt)); 52 | instructions.Add(new CilInstruction(CilOpCodes.Brfalse, instr.Operand)); 53 | break; 54 | 55 | case CilCode.Bgt: 56 | case CilCode.Bgt_Un: 57 | instructions.Add(new CilInstruction(CilOpCodes.Cgt)); 58 | instructions.Add(new CilInstruction(CilOpCodes.Brtrue, instr.Operand)); 59 | break; 60 | 61 | case CilCode.Ble: 62 | case CilCode.Ble_Un: 63 | instructions.Add(new CilInstruction(CilOpCodes.Cgt)); 64 | instructions.Add(new CilInstruction(CilOpCodes.Brfalse, instr.Operand)); 65 | break; 66 | 67 | case CilCode.Blt: 68 | case CilCode.Blt_Un: 69 | instructions.Add(new CilInstruction(CilOpCodes.Clt)); 70 | instructions.Add(new CilInstruction(CilOpCodes.Brtrue, instr.Operand)); 71 | break; 72 | 73 | default: 74 | instrs = Array.Empty(); 75 | return false; 76 | } 77 | 78 | throw new InvalidOperationException(); 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/Runtime/Renamer.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet.Signatures; 2 | 3 | namespace VirtualGuard.RT.Mutators.impl; 4 | 5 | internal class Renamer : IRuntimeMutator 6 | { 7 | private Dictionary _abstractNameMap = new Dictionary(); 8 | 9 | private static int Vm = 0; // scuffed but easy 10 | 11 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 12 | { 13 | if(rt.isDebug) 14 | return; 15 | 16 | var random = new Random(); 17 | 18 | // establish names for all abstract methods 19 | foreach (var type in rt.RuntimeModule.GetAllTypes().Where(x => !x.IsModuleType && !x.IsRuntimeSpecialName)) 20 | { 21 | foreach (var method in type.Methods) 22 | { 23 | 24 | if (method.IsAbstract || method.IsVirtual || method.DeclaringType.IsInterface && method.CilMethodBody != null && method.CilMethodBody.Instructions.Count == 0) 25 | { 26 | if (!_abstractNameMap.ContainsKey(method.Name)) 27 | { 28 | string name = random.Next(int.MaxValue).ToString("x"); // Use a different prefix for abstract methods 29 | _abstractNameMap.Add(method.Name, name); 30 | method.Name = name; 31 | } 32 | } 33 | } 34 | } 35 | 36 | foreach (var type in rt.RuntimeModule.GetAllTypes().Where(x => !x.IsModuleType && !x.IsRuntimeSpecialName)) 37 | { 38 | type.Namespace = random.Next(int.MaxValue).ToString("x"); 39 | type.Name = "vg" + random.Next(int.MaxValue).ToString("x"); 40 | 41 | foreach (var method in type.Methods) 42 | { 43 | foreach (var def in method.ParameterDefinitions) 44 | def.Name = random.Next(int.MaxValue).ToString("x"); 45 | 46 | if (method.IsConstructor || method.IsRuntimeSpecialName) 47 | continue; 48 | 49 | if (_abstractNameMap.TryGetValue(method.Name, out string sharedName)) 50 | { 51 | // rename abstract shared 52 | method.Name = sharedName; 53 | } 54 | else 55 | { 56 | if(method.IsAbstract || method.IsVirtual) 57 | continue; 58 | 59 | // rename normally 60 | method.Name = 61 | random.Next(int.MaxValue) 62 | .ToString("x"); // Use a different prefix for non-abstract methods 63 | } 64 | } 65 | 66 | var fieldName = random.Next(int.MaxValue) 67 | .ToString("x"); 68 | 69 | foreach (var field in type.Fields) 70 | { 71 | field.Name = fieldName; // Use a different prefix for fields 72 | } 73 | } 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /VirtualGuard.Runtime/OpCodes/impl/Flow/Call.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using VirtualGuard.Runtime.Variant; 3 | 4 | namespace VirtualGuard.Runtime.OpCodes.impl.Flow 5 | { 6 | 7 | public class Call : IOpCode 8 | { 9 | public void Execute(VMContext ctx) 10 | { 11 | var methodBase = ctx.ResolveMethod(ctx.Reader.ReadInt()); 12 | 13 | var args = methodBase.GetParameters(); 14 | var vmVariantArgs = new BaseVariant[args.Length]; 15 | var argsCasted = new object[args.Length]; 16 | 17 | var refIndexes = new HashSet(); 18 | 19 | for (int i = args.Length - 1; i >= 0; i--) 20 | { 21 | vmVariantArgs[i] = ctx.Stack.Pop(); 22 | 23 | if (vmVariantArgs[i].IsReference()) 24 | refIndexes.Add(i); // mark as reference to set value to after 25 | 26 | if (vmVariantArgs[i].GetObject().GetType() is IConvertible conv) 27 | { 28 | argsCasted[i] = Convert.ChangeType(conv, args[i].ParameterType); 29 | } 30 | else 31 | { 32 | argsCasted[i] = vmVariantArgs[i].GetObject(); 33 | } 34 | } 35 | 36 | // calculate inst 37 | 38 | object inst = null; 39 | bool isInstReference = false; 40 | BaseVariant instVariant = null; 41 | 42 | if (!methodBase.IsStatic) 43 | { // if it is inst 44 | 45 | //if(methodBase is ConstructorInfo ci && ci.) need a check here 46 | 47 | instVariant = ctx.Stack.Pop(); 48 | 49 | if (instVariant.IsReference()) 50 | isInstReference = true; 51 | 52 | // get object for inst 53 | 54 | inst = instVariant.GetObject(); 55 | } 56 | 57 | object ret = null; 58 | 59 | if (methodBase is ConstructorInfo ci) 60 | { 61 | ret = ci.Invoke(argsCasted); // maybe error here 62 | } 63 | else 64 | { 65 | ret = methodBase.Invoke(inst, argsCasted); 66 | } 67 | 68 | // update ref vars 69 | foreach (var refIndex in refIndexes) 70 | vmVariantArgs[refIndex].SetVariantValue(argsCasted[refIndex]); // set value of associated reference variant to that of the new variable 71 | 72 | if(isInstReference) 73 | instVariant.SetVariantValue(inst); // update inst ref 74 | 75 | if(methodBase.IsConstructor || methodBase is MethodInfo mi && mi.ReturnType != typeof(void)) 76 | ctx.Stack.Push(BaseVariant.CreateVariant(ret)); 77 | 78 | ctx.CurrentCode += ctx.Reader.ReadFixupValue(); 79 | CodeMap.LookupCode(ctx.CurrentCode).Execute(ctx); 80 | } 81 | 82 | public byte GetCode() => 0; 83 | } 84 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/ConvTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using Echo.ControlFlow; 4 | using VirtualGuard.AST; 5 | using VirtualGuard.VMIL.VM; 6 | 7 | namespace VirtualGuard.VMIL.Translation.impl; 8 | 9 | internal class ConvTranslator : ITranslator 10 | { 11 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 12 | VirtualGuardContext ctx) 13 | { 14 | switch (instr.OpCode.Code) 15 | { 16 | case CilCode.Conv_I: 17 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.I)); 18 | break; 19 | 20 | case CilCode.Conv_I1: 21 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.I1)); 22 | break; 23 | 24 | case CilCode.Conv_I2: 25 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.I2)); 26 | break; 27 | 28 | case CilCode.Conv_I4: 29 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.I4)); 30 | break; 31 | 32 | case CilCode.Conv_I8: 33 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.I8)); 34 | break; 35 | 36 | case CilCode.Conv_U: 37 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.U)); 38 | break; 39 | 40 | case CilCode.Conv_U1: 41 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.U1)); 42 | break; 43 | 44 | case CilCode.Conv_U2: 45 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.U2)); 46 | break; 47 | 48 | case CilCode.Conv_U4: 49 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.U4)); 50 | break; 51 | 52 | case CilCode.Conv_U8: 53 | block.WithContent(new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.U8)); 54 | break; 55 | } 56 | 57 | block.WithContent(new VmInstruction(VmCode.Conv)); 58 | } 59 | 60 | [Obfuscation(Feature = "virtualization")] 61 | public bool Supports(AstExpression instr) 62 | { 63 | return new[] 64 | { 65 | CilCode.Conv_I, 66 | CilCode.Conv_I1, 67 | CilCode.Conv_I2, 68 | CilCode.Conv_I4, 69 | CilCode.Conv_I8, 70 | CilCode.Conv_U, 71 | CilCode.Conv_U1, 72 | CilCode.Conv_U2, 73 | CilCode.Conv_U4, 74 | CilCode.Conv_U8 75 | }.Contains(instr.OpCode.Code); 76 | } 77 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/VM/VmBlock.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Reflection; 3 | using VirtualGuard.AST; 4 | using VirtualGuard.RT; 5 | using VirtualGuard.RT.Chunk; 6 | using VirtualGuard.VMIL.Translation.impl; 7 | 8 | namespace VirtualGuard.VMIL.VM; 9 | 10 | internal class VmBlock 11 | { 12 | 13 | public List Content = new List(); 14 | public VmMethod Parent; 15 | 16 | [Obfuscation(Feature = "virtualization")] 17 | public VmBlock WithArtificialContent(params VmInstruction[] instrs) 18 | { 19 | Content.AddRange(instrs); 20 | return this; 21 | } 22 | 23 | [Obfuscation(Feature = "virtualization")] 24 | public VmBlock WithContent(params VmInstruction[] instrs) 25 | { 26 | Parent.MarkTranslatedInstructions(instrs); // this is kinda screwed in my mind 27 | 28 | return WithArtificialContent(instrs); 29 | } 30 | 31 | [Obfuscation(Feature = "virtualization")] 32 | public VmChunk BuildChunk(VmMethod parent, VirtualGuardRT rt) 33 | { 34 | // do some transforms, for ex remove the idea of the locals using the ctx 35 | 36 | var chunk = new VmChunk(this.Content); 37 | 38 | if (!parent.Entry.Equals(this)) 39 | { // not an entry chunk 40 | rt.AddChunk(chunk); 41 | return chunk; // not entry chunk 42 | } 43 | 44 | 45 | if (parent.isExport) 46 | { 47 | rt.AddExportChunk(chunk, parent.CilMethod); 48 | } 49 | else 50 | { 51 | rt.AddImportChunk(chunk, parent.CilMethod); 52 | } 53 | 54 | return chunk; 55 | } 56 | 57 | 58 | public void OnChunksBuilt(Dictionary chunkMap, VirtualGuardRT rt) 59 | { 60 | // do initial updating of offsets 61 | 62 | var thisChunk = chunkMap[this]; 63 | 64 | foreach (var content in thisChunk.Content) 65 | { // update jmps to use chunks; it's in ldc.i4 which is kinda ew edit: entertry contains block offset of handler 66 | 67 | if (content.OpCode != VmCode.Ldc_I4 && content.OpCode != VmCode.Entertry) // 68 | continue; 69 | 70 | if(content.Operand is UnknownBlockLink ubl) 71 | if (ubl.Linked == false) 72 | { 73 | throw new DataException("Provided block link is not linked."); 74 | } 75 | else 76 | { 77 | content.Operand = ubl.LinkedBlock; 78 | } 79 | 80 | if (content.Operand is DynamicStartKeyReference startKeyReference) 81 | { 82 | startKeyReference.Chunk = chunkMap[startKeyReference.VmBlock]; 83 | continue; 84 | } 85 | 86 | if(content.Operand is not VmBlock) 87 | continue; 88 | 89 | var oldBlock = (VmBlock)content.Operand; 90 | var equivalentChunk = chunkMap[oldBlock]; 91 | 92 | content.Operand = equivalentChunk; 93 | } 94 | 95 | } 96 | 97 | 98 | 99 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/ValueType/Numeric/LongVariant.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using VirtualGuard.Runtime.Dynamic; 4 | 5 | namespace VirtualGuard.Runtime.Variant.ValueType.Numeric 6 | { 7 | 8 | public class LongVariant : NumeralVariant 9 | { 10 | private long _value; 11 | 12 | public LongVariant(long l) 13 | { 14 | _value = l; 15 | } 16 | 17 | public override object GetObject() 18 | { 19 | return _value; 20 | } 21 | 22 | public override void SetVariantValue(object obj) 23 | { 24 | _value = (long)obj; 25 | } 26 | 27 | public override BaseVariant Clone() 28 | { 29 | return new LongVariant(_value); 30 | } 31 | 32 | public override NumeralVariant Add(NumeralVariant addend) 33 | { 34 | var sum = _value + addend.I8(); 35 | 36 | return new LongVariant(sum); 37 | } 38 | 39 | public override NumeralVariant Sub(NumeralVariant subtraend) 40 | { 41 | var diff = _value - subtraend.I8(); 42 | 43 | return new LongVariant(diff); 44 | } 45 | 46 | public override NumeralVariant Mul(NumeralVariant factor) 47 | { 48 | var product = _value * factor.I8(); 49 | 50 | return new LongVariant(product); 51 | } 52 | 53 | public override NumeralVariant Div(NumeralVariant divisor) 54 | { 55 | var quotient = _value / divisor.I8(); 56 | 57 | return new LongVariant(quotient); 58 | } 59 | 60 | public override NumeralVariant Xor(NumeralVariant xorfactor) 61 | { 62 | var result = _value ^ xorfactor.I8(); 63 | 64 | return new LongVariant(result); 65 | } 66 | 67 | public override NumeralVariant Rem(NumeralVariant remfactor) 68 | { 69 | var res = _value % remfactor.I8(); 70 | 71 | return new LongVariant(res); 72 | } 73 | 74 | public override NumeralVariant Or(NumeralVariant or) 75 | { 76 | var res = _value | or.I8(); 77 | 78 | return new LongVariant(res); 79 | } 80 | 81 | public override NumeralVariant Not() 82 | { 83 | return new LongVariant(~_value); 84 | } 85 | 86 | public override NumeralVariant And(NumeralVariant and) 87 | { 88 | return new LongVariant(_value & and.I8()); 89 | } 90 | 91 | public override NumeralVariant Shl(NumeralVariant factor) 92 | { 93 | return new LongVariant(this.I8() << factor.I4()); 94 | } 95 | 96 | public override NumeralVariant Shr(NumeralVariant factor) 97 | { 98 | return new LongVariant(this.I8() >> factor.I4()); 99 | } 100 | 101 | public override BaseVariant Hash() 102 | { 103 | return new LongVariant(Util.Hash(BitConverter.GetBytes(_value))); 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Descriptor/Handler/HandlerResolver.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | using AsmResolver.DotNet.Cloning; 3 | using AsmResolver.DotNet.Code.Cil; 4 | using AsmResolver.PE.DotNet.Cil; 5 | using AsmResolver.PE.DotNet.Metadata.Tables.Rows; 6 | using VirtualGuard.RT.Dynamic; 7 | using VirtualGuard.VMIL.VM; 8 | 9 | namespace VirtualGuard.RT.Descriptor.Handler; 10 | 11 | internal class HandlerResolver 12 | { 13 | private static Random _rnd = new Random(); 14 | 15 | private Dictionary _handlerDefinitions = new Dictionary(); 16 | 17 | private List _handlerCache = new List(); 18 | private ModuleDefinition _runtimeModule; 19 | 20 | public HandlerResolver(ModuleDefinition runtime) 21 | { 22 | _runtimeModule = runtime; 23 | 24 | // populate handler definitions 25 | 26 | var opcodes = typeof(VmCode).GetEnumNames().Where(x => x.Substring(0, 2) != "__").ToArray(); // eliminate transform instrs 27 | 28 | foreach (var name in opcodes) 29 | { 30 | try 31 | { 32 | var type = runtime.LookupType(RuntimeConfig.BaseHandler + "." + name); 33 | 34 | _handlerDefinitions.Add((VmCode)Array.IndexOf(opcodes, name), type); 35 | runtime.TopLevelTypes.Remove(type); // remove (will be added later) 36 | } 37 | catch(InvalidOperationException) 38 | { 39 | throw new KeyNotFoundException("Could not locate opcode: " + name + " in runtime!"); 40 | } 41 | } 42 | 43 | // build handler map (we will include all handlers for this basic impl) 44 | 45 | byte[] opCodeOrder = Enumerable.Range(0, byte.MaxValue).Select(x => (byte)x).ToArray(); 46 | _rnd.Shuffle(opCodeOrder); // make an array of random bytes 47 | 48 | int i = 0; 49 | 50 | do 51 | { 52 | foreach (var handlerDefKvp in _handlerDefinitions) 53 | { 54 | // add some extra randomness 55 | 56 | if(_handlerCache.Any(x => x.OpCode == handlerDefKvp.Key) && _rnd.Next(9) == 0) 57 | continue; // potentially randomly stop execution if the opcode has already been added (1/10) 58 | 59 | // clone type def 60 | 61 | var oldType = handlerDefKvp.Value; 62 | 63 | var newDefinition = oldType.Clone(_runtimeModule); 64 | 65 | _handlerCache.Add(new VmHandler(handlerDefKvp.Key, newDefinition, opCodeOrder[i++])); 66 | _runtimeModule.TopLevelTypes.Add(newDefinition); 67 | 68 | if(i == opCodeOrder.Length) 69 | break; // don't let it go over 70 | } 71 | 72 | } while (i != opCodeOrder.Length); 73 | 74 | // pray this works 75 | } 76 | 77 | public VmHandler GetHandler(VmCode code) 78 | { // get a random handler that for the opcode 79 | var handlersSupportingCode = _handlerCache.Where(x => x.OpCode == code).ToArray(); 80 | 81 | return handlersSupportingCode[_rnd.Next(handlersSupportingCode.Length)]; 82 | } 83 | 84 | 85 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/BranchMutator.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.RT.Chunk; 2 | using VirtualGuard.VMIL.VM; 3 | 4 | namespace VirtualGuard.RT.Mutators.impl; 5 | 6 | internal class BranchMutator : IRuntimeMutator 7 | { 8 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 9 | { 10 | if(rt.isDebug) 11 | return; 12 | 13 | 14 | var rnd = new Random(); 15 | 16 | foreach (var chunk in rt.VmChunks) 17 | foreach (var instr in chunk.Content.ToArray()) 18 | { 19 | if(instr.OpCode != VmCode.Ldc_I4) 20 | continue; 21 | 22 | if(instr.Operand is not VmChunk target) 23 | continue; 24 | 25 | 26 | // going to be silly and use cmp flags to mutate the target values 27 | 28 | var salt = rnd.Next(10000); 29 | // first alloc all instructions 30 | 31 | var cmpValue1 = new VmInstruction(VmCode.Ldc_I4, 0); 32 | var cmpValue2 = new VmInstruction(VmCode.Ldc_I4, 0); 33 | 34 | var cmpInstr = new VmInstruction(VmCode.Cmp); 35 | 36 | var missingValueInstr = new VmInstruction(VmCode.Ldc_I4, 0); 37 | var addInstr = new VmInstruction(VmCode.Xor); 38 | 39 | chunk.Content.ReplaceRange(instr, 40 | cmpValue1, 41 | cmpValue2, 42 | 43 | cmpInstr, 44 | 45 | missingValueInstr, 46 | addInstr, 47 | new VmInstruction(VmCode.Ldc_I4, salt), 48 | new VmInstruction(VmCode.Sub) 49 | ); 50 | 51 | 52 | // we'll use eq flag to test 53 | 54 | byte flagValue = 0; 55 | 56 | int i1 = 0; 57 | int i2 = 0; 58 | 59 | switch (rnd.Next(2)) 60 | { 61 | case 0: // gt 62 | flagValue = rt.Descriptor.ComparisonFlags.GtFlag; 63 | i2 = rnd.Next(); 64 | i1 = rnd.Next(i2, int.MaxValue); 65 | break; 66 | 67 | case 1: // lt 68 | flagValue = rt.Descriptor.ComparisonFlags.LtFlag; 69 | i1 = rnd.Next(); 70 | i2 = rnd.Next(i1, int.MaxValue); 71 | break; 72 | 73 | case 2: // eq 74 | flagValue = rt.Descriptor.ComparisonFlags.LtFlag; 75 | i1 = rnd.Next(); 76 | i2 = i1; 77 | break; 78 | } 79 | 80 | // emulate eq by setting two of the same value 81 | cmpValue1.Operand = i1; 82 | cmpValue2.Operand = i2; 83 | 84 | var mutationExpression = new MutationOperation(target); 85 | 86 | mutationExpression.Steps.Add(new MutationStep() { Modifier = flagValue, Type = MutationType.Xor}); // xor 87 | mutationExpression.Steps.Add(new MutationStep() { Modifier = salt, Type = MutationType.Sub}); // salt 88 | 89 | missingValueInstr.Operand = mutationExpression; // pray this works edit: it works lfg 90 | } 91 | 92 | 93 | } 94 | 95 | 96 | 97 | } -------------------------------------------------------------------------------- /VirtualGuard.CLI/Processors/impl/ImportProtection.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | using AsmResolver.DotNet.Code.Cil; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using AsmResolver.PE.DotNet.Metadata.Tables.Rows; 5 | 6 | namespace VirtualGuard.CLI.Processors.impl; 7 | 8 | public class ImportProtection : IProcessor 9 | { 10 | public static readonly Dictionary ProxyMethodCache = 11 | new Dictionary(); 12 | 13 | public static List ScannedMethods = new List(); 14 | 15 | public string Identifier => "Import Protection"; 16 | public void Process(Context ctx) 17 | { 18 | 19 | foreach (var type in ctx.Module.GetAllTypes()) 20 | foreach (var method in type.Methods.Where(x => 21 | !ctx.Configuration.IsMemberExcluded(x, ctx) && !ctx.Configuration.IsMemberVirtualized(x, ctx) && 22 | !ctx.Virtualizer.IsMethodVirtualized(x)).ToArray()) 23 | { 24 | 25 | if(method.CilMethodBody == null) 26 | continue; 27 | 28 | foreach (var instr in method.CilMethodBody.Instructions) 29 | { 30 | 31 | if (instr.Operand is not IMethodDescriptor desc) 32 | continue; 33 | 34 | if(desc.Signature.HasThis) // impl later 35 | continue; 36 | 37 | var proxy = CreateProxyMethod(desc, instr.OpCode.Code, ctx.Module.GetOrCreateModuleType()); 38 | 39 | if(!ctx.Virtualizer.IsMethodVirtualized(proxy)) 40 | ctx.Virtualizer.AddMethod(proxy, true); 41 | 42 | instr.Operand = proxy; 43 | } 44 | 45 | ScannedMethods.Add(method); 46 | } 47 | 48 | 49 | } 50 | 51 | private static Random _rnd = new Random(); 52 | 53 | MethodDefinition CreateProxyMethod(IMethodDescriptor desc, CilCode code, TypeDefinition parent) 54 | { 55 | 56 | if (ProxyMethodCache.TryGetValue(desc, out MethodDefinition foundDef)) 57 | return foundDef; 58 | 59 | MethodDefinition def = new MethodDefinition(_rnd.Next().ToString("x"), 60 | MethodAttributes.Public | MethodAttributes.Static, desc.Signature); 61 | 62 | def.CilMethodBody = new CilMethodBody(def); 63 | 64 | var instrs = def.CilMethodBody.Instructions; 65 | 66 | foreach (var arg in def.Parameters) 67 | { 68 | instrs.Add(CilOpCodes.Ldarg, arg); 69 | } 70 | 71 | switch (code) 72 | { 73 | case CilCode.Call: 74 | instrs.Add(CilOpCodes.Call, desc); 75 | break; 76 | 77 | case CilCode.Callvirt: 78 | instrs.Add(CilOpCodes.Callvirt, desc); 79 | break; 80 | 81 | case CilCode.Newobj: 82 | instrs.Add(CilOpCodes.Newobj, desc); 83 | break; 84 | } 85 | 86 | instrs.Add(CilOpCodes.Ret); 87 | 88 | ProxyMethodCache.Add(desc, def); 89 | 90 | instrs.OptimizeMacros(); 91 | 92 | parent.Methods.Add(def); 93 | 94 | return def; 95 | } 96 | 97 | 98 | } -------------------------------------------------------------------------------- /VirtualGuard/VMIL/Translation/impl/ArrayTranslator.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AsmResolver.PE.DotNet.Cil; 3 | using Echo.ControlFlow; 4 | using VirtualGuard.AST; 5 | using VirtualGuard.VMIL.VM; 6 | 7 | namespace VirtualGuard.VMIL.Translation.impl; 8 | 9 | internal class ArrayTranslator : ITranslator 10 | { 11 | public void Translate(AstExpression instr, ControlFlowNode node, VmBlock block, VmMethod meth, 12 | VirtualGuardContext ctx) 13 | { 14 | switch (instr.OpCode.Code) 15 | { 16 | case CilCode.Stelem: 17 | case CilCode.Stelem_I: 18 | case CilCode.Stelem_I1: 19 | case CilCode.Stelem_I2: 20 | case CilCode.Stelem_I4: 21 | case CilCode.Stelem_I8: 22 | case CilCode.Stelem_R4: 23 | case CilCode.Stelem_R8: 24 | case CilCode.Stelem_Ref: 25 | block.WithContent(new VmInstruction(VmCode.Stelem)); 26 | break; 27 | 28 | case CilCode.Ldelem: 29 | case CilCode.Ldelem_I: 30 | case CilCode.Ldelem_I1: 31 | case CilCode.Ldelem_I2: 32 | case CilCode.Ldelem_I4: 33 | case CilCode.Ldelem_I8: 34 | case CilCode.Ldelem_U1: 35 | case CilCode.Ldelem_U2: 36 | case CilCode.Ldelem_U4: 37 | case CilCode.Ldelem_R4: 38 | case CilCode.Ldelem_R8: 39 | case CilCode.Ldelem_Ref: 40 | block.WithContent(new VmInstruction(VmCode.Ldelem)); 41 | break; 42 | 43 | // this might be necessary, not sure yet 44 | block.WithContent(new VmInstruction(VmCode.Ldelem), 45 | new VmInstruction(VmCode.Ldc_I4, ctx.Runtime.Descriptor.CorLibTypeDescriptor.U2), 46 | new VmInstruction(VmCode.Conv)); 47 | break; 48 | 49 | case CilCode.Ldelema: 50 | block.WithContent(new VmInstruction(VmCode.Ldelema)); 51 | break; 52 | 53 | case CilCode.Newarr: 54 | block.WithContent(new VmInstruction(VmCode.Newarr, instr.Operand)); 55 | break; 56 | 57 | case CilCode.Ldlen: 58 | block.WithContent(new VmInstruction(VmCode.Ldlen)); 59 | break; 60 | } 61 | 62 | 63 | } 64 | 65 | [Obfuscation(Feature = "virtualization")] 66 | public bool Supports(AstExpression instr) 67 | { 68 | return new[] 69 | { 70 | CilCode.Stelem, 71 | CilCode.Stelem_I, 72 | CilCode.Stelem_I1, 73 | CilCode.Stelem_I2, 74 | CilCode.Stelem_I4, 75 | CilCode.Stelem_I8, 76 | CilCode.Stelem_R4, 77 | CilCode.Stelem_R8, 78 | CilCode.Stelem_Ref, 79 | 80 | CilCode.Ldelem, 81 | CilCode.Ldelem_I, 82 | CilCode.Ldelem_I1, 83 | CilCode.Ldelem_I2, 84 | CilCode.Ldelem_I4, 85 | CilCode.Ldelem_I8, 86 | CilCode.Ldelem_U1, 87 | CilCode.Ldelem_U2, 88 | CilCode.Ldelem_U4, 89 | CilCode.Ldelem_R4, 90 | CilCode.Ldelem_R8, 91 | CilCode.Ldelema, 92 | 93 | CilCode.Newarr, 94 | CilCode.Ldlen 95 | }.Contains(instr.OpCode.Code); 96 | } 97 | } -------------------------------------------------------------------------------- /VirtualGuard.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualGuard.Runtime", "VirtualGuard.Runtime\VirtualGuard.Runtime.csproj", "{306D13A9-9B8B-4D39-8AE8-2870EC0C23A6}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualGuard.CLI", "VirtualGuard.CLI\VirtualGuard.CLI.csproj", "{8F2BA234-6441-4F04-9A33-F626D14BE084}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualGuard", "VirtualGuard\VirtualGuard.csproj", "{0034D005-420A-4ACE-8086-F02B17C6C670}" 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualGuard.SDK", "VirtualGuard.SDK\VirtualGuard.SDK.csproj", "{0887E1C7-C674-4F8D-BAFE-756A17E6290B}" 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualGuard.Tests", "VirtualGuard.Tests\VirtualGuard.Tests.csproj", "{C9E9D7C1-9634-4403-B2A9-3E2A2E0FA1FD}" 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualGuard.Stubs", "VirtualGuard.Stubs\VirtualGuard.Stubs.csproj", "{921C850C-0D2B-4D02-B1C6-56DDCFF660BA}" 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {306D13A9-9B8B-4D39-8AE8-2870EC0C23A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {306D13A9-9B8B-4D39-8AE8-2870EC0C23A6}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {306D13A9-9B8B-4D39-8AE8-2870EC0C23A6}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {306D13A9-9B8B-4D39-8AE8-2870EC0C23A6}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {8F2BA234-6441-4F04-9A33-F626D14BE084}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {8F2BA234-6441-4F04-9A33-F626D14BE084}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {8F2BA234-6441-4F04-9A33-F626D14BE084}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {8F2BA234-6441-4F04-9A33-F626D14BE084}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {0034D005-420A-4ACE-8086-F02B17C6C670}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {0034D005-420A-4ACE-8086-F02B17C6C670}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {0034D005-420A-4ACE-8086-F02B17C6C670}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {0034D005-420A-4ACE-8086-F02B17C6C670}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {0887E1C7-C674-4F8D-BAFE-756A17E6290B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {0887E1C7-C674-4F8D-BAFE-756A17E6290B}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {0887E1C7-C674-4F8D-BAFE-756A17E6290B}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {0887E1C7-C674-4F8D-BAFE-756A17E6290B}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {C9E9D7C1-9634-4403-B2A9-3E2A2E0FA1FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {C9E9D7C1-9634-4403-B2A9-3E2A2E0FA1FD}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {C9E9D7C1-9634-4403-B2A9-3E2A2E0FA1FD}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {C9E9D7C1-9634-4403-B2A9-3E2A2E0FA1FD}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {921C850C-0D2B-4D02-B1C6-56DDCFF660BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {921C850C-0D2B-4D02-B1C6-56DDCFF660BA}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {921C850C-0D2B-4D02-B1C6-56DDCFF660BA}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {921C850C-0D2B-4D02-B1C6-56DDCFF660BA}.Release|Any CPU.Build.0 = Release|Any CPU 45 | EndGlobalSection 46 | GlobalSection(NestedProjects) = preSolution 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/VirtualOpCodes.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.RT.Chunk; 2 | using VirtualGuard.VMIL.VM; 3 | 4 | namespace VirtualGuard.RT.Mutators.impl; 5 | 6 | internal class VirtualOpCodes : IRuntimeMutator 7 | { 8 | 9 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 10 | { 11 | // issue at hand : we have no way of calculating the start key 12 | 13 | foreach (var chunk in rt.VmChunks.ToArray()) 14 | foreach (var instr in chunk.Content.ToArray()) 15 | { 16 | 17 | switch (instr.OpCode) 18 | { 19 | case VmCode.Dup: 20 | 21 | var endJmpLoc = new VmInstruction(VmCode.Ldc_I4); 22 | var endJmpKey = new VmInstruction(VmCode.Ldc_I4); 23 | 24 | var endJmp = new VmInstruction(VmCode.Jmp); 25 | 26 | var region = GetOrCreateHandlerRegion(instr.OpCode, rt); 27 | 28 | chunk.Content.ReplaceRange(instr, // push current location 29 | endJmpLoc, 30 | endJmpKey, 31 | 32 | new VmInstruction(VmCode.Ldc_I4, region), // push region loc 33 | new VmInstruction(VmCode.Ldc_I4, rt.Descriptor.Data.GetStartKey(chunk)), 34 | endJmp 35 | ); 36 | 37 | // now split 38 | 39 | var newChunk = chunk.Split(rt, chunk.Content.IndexOf(endJmp)); 40 | 41 | endJmpLoc.Operand = newChunk; 42 | endJmpKey.Operand = rt.Descriptor.Data.GetStartKey(newChunk); 43 | 44 | break; 45 | 46 | default: // not a pseudocode 47 | continue; 48 | } 49 | 50 | } 51 | 52 | 53 | } 54 | 55 | private VmChunk GetOrCreateHandlerRegion(VmCode code, VirtualGuardRT rt) 56 | { 57 | if (!_handlers.TryGetValue(code, out VmInstruction[] value)) 58 | throw new InvalidOperationException("No virtual handler for pseudocode " + code); 59 | 60 | if (_codeChunkMap.TryGetValue(code, out VmChunk chunk)) 61 | return chunk; 62 | 63 | // make new chunk 64 | 65 | var newChunk = new VmChunk(value.ToList()); 66 | _codeChunkMap.Add(code, newChunk); 67 | 68 | // add to runtime 69 | rt.AddChunk(newChunk); 70 | 71 | return newChunk; 72 | } 73 | 74 | private Dictionary _codeChunkMap = new Dictionary(); 75 | 76 | private Dictionary _handlers = new Dictionary() 77 | { 78 | { 79 | VmCode.Dup, 80 | new[] 81 | { 82 | new VmInstruction(VmCode.Stloc, (short)-3), // store return key 83 | new VmInstruction(VmCode.Stloc, (short)-2), // store return addr 84 | new VmInstruction(VmCode.Stloc, (short)-1), 85 | new VmInstruction(VmCode.Ldloc, (short)-1), 86 | new VmInstruction(VmCode.Ldloc, (short)-1), 87 | new VmInstruction(VmCode.Ldloc, (short)-2), // push return addr 88 | new VmInstruction(VmCode.Ldloc, (short)-3), // push return key 89 | new VmInstruction(VmCode.Jmp) 90 | } 91 | } 92 | }; 93 | 94 | } -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/ValueType/Numeric/UIntVariant.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Dynamic; 2 | 3 | namespace VirtualGuard.Runtime.Variant.ValueType.Numeric; 4 | 5 | public class UIntVariant : NumeralVariant 6 | { 7 | private uint _value; 8 | 9 | public UIntVariant(uint i) 10 | { 11 | _value = i; 12 | } 13 | 14 | public override object GetObject() 15 | { 16 | return _value; 17 | } 18 | 19 | public override void SetVariantValue(object obj) 20 | { 21 | _value = (uint)obj; 22 | } 23 | 24 | public override BaseVariant Clone() 25 | { 26 | return new UIntVariant(_value); 27 | } 28 | 29 | public override NumeralVariant Add(NumeralVariant addend) 30 | { 31 | // result should always be int operating under realm of int 32 | var sum = _value + addend.U4(); 33 | 34 | // do something with flags???? 35 | 36 | return new UIntVariant(sum); 37 | } 38 | 39 | public override NumeralVariant Sub(NumeralVariant subtraend) 40 | { 41 | // result should always be int operating under realm of int 42 | var diff = _value - subtraend.U4(); 43 | 44 | // do something with flags???? 45 | 46 | return new UIntVariant(diff); 47 | } 48 | 49 | public override NumeralVariant Mul(NumeralVariant factor) 50 | { 51 | // result should always be int operating under realm of int 52 | var sum = _value * factor.U4(); 53 | 54 | // do something with flags???? 55 | 56 | return new UIntVariant(sum); 57 | } 58 | 59 | public override NumeralVariant Div(NumeralVariant divisor) 60 | { 61 | // result should always be int operating under realm of int 62 | var sum = _value / divisor.U4(); 63 | 64 | // do something with flags???? 65 | 66 | return new UIntVariant(sum); 67 | } 68 | 69 | public override NumeralVariant Xor(NumeralVariant xorfactor) 70 | { 71 | // result should always be int operating under realm of int 72 | var sum = _value ^ xorfactor.U4(); 73 | 74 | // do something with flags???? 75 | 76 | return new UIntVariant(sum); 77 | } 78 | 79 | public override NumeralVariant Rem(NumeralVariant remfactor) 80 | { 81 | // result should always be int operating under realm of int 82 | var sum = _value % remfactor.U4(); 83 | 84 | // do something with flags???? 85 | 86 | return new UIntVariant(sum); 87 | } 88 | 89 | public override NumeralVariant Or(NumeralVariant or) 90 | { 91 | // result should always be int operating under realm of int 92 | var sum = this.U4() | or.U4(); 93 | 94 | // do something with flags???? 95 | 96 | return new UIntVariant(sum); 97 | } 98 | 99 | public override NumeralVariant Not() 100 | { 101 | return new UIntVariant(~_value); 102 | } 103 | 104 | public override NumeralVariant And(NumeralVariant and) 105 | { 106 | return new UIntVariant((uint)(_value & and.U4())); 107 | } 108 | 109 | public override NumeralVariant Shl(NumeralVariant factor) 110 | { 111 | return new UIntVariant(this.U4() << factor.I4()); 112 | } 113 | 114 | public override NumeralVariant Shr(NumeralVariant factor) 115 | { 116 | return new UIntVariant(this.U4() >> factor.I4()); 117 | } 118 | 119 | public override BaseVariant Hash() 120 | { 121 | return new LongVariant(Util.Hash(BitConverter.GetBytes(_value))); 122 | } 123 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/MutationOperation.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.RT.Chunk; 2 | using VirtualGuard.VMIL.VM; 3 | 4 | namespace VirtualGuard.RT.Mutators; 5 | 6 | internal class MutationOperation 7 | { 8 | public static VmCode ToOpCode(MutationType t) 9 | { 10 | switch (t) 11 | { 12 | case MutationType.Add: 13 | return VmCode.Add; 14 | 15 | case MutationType.Sub: 16 | return VmCode.Sub; 17 | 18 | case MutationType.Xor: 19 | return VmCode.Xor; 20 | 21 | default: 22 | throw new NotImplementedException(t.ToString()); 23 | } 24 | } 25 | 26 | private static Random _rnd = new Random(); 27 | 28 | public static VmInstruction[] MutateConstant(VmInstruction instr) 29 | { 30 | 31 | var mutations = _rnd.Next(4); 32 | var instrs = new List(); 33 | 34 | var mutationOp = new MutationOperation(instr.Operand); 35 | 36 | // add initial 37 | instrs.Add(new VmInstruction(VmCode.Ldc_I4, mutationOp)); 38 | 39 | for (int i = 0; i < mutations; i++) 40 | { 41 | 42 | 43 | } 44 | 45 | 46 | throw new NotImplementedException(); 47 | } 48 | 49 | private object _iv; 50 | public MutationOperation(object obj) 51 | { 52 | _iv = obj; 53 | } 54 | 55 | int GetIV() 56 | { 57 | if (_iv is VmChunk chunk) 58 | return chunk.Offset; 59 | 60 | if (_iv is int i) 61 | return i; 62 | 63 | throw new InvalidOperationException(_iv.GetType().FullName); 64 | } 65 | 66 | public int Emulate() 67 | { 68 | Steps.Reverse(); // make the steps happen in the reverse order they execute in 69 | 70 | int initialValue = GetIV(); 71 | 72 | foreach (var step in Steps) 73 | { 74 | initialValue = EmulateOp(initialValue, step); 75 | } 76 | 77 | return initialValue; 78 | } 79 | 80 | 81 | public List Steps = new List(); 82 | 83 | MutationType InverseOp(MutationType type) 84 | { 85 | switch (type) 86 | { 87 | case MutationType.Add: 88 | return MutationType.Sub; 89 | 90 | case MutationType.Sub: 91 | return MutationType.Add; 92 | 93 | case MutationType.Xor: 94 | return MutationType.Xor; 95 | 96 | default: 97 | throw new NotImplementedException(type.ToString()); 98 | } 99 | 100 | } 101 | 102 | int EmulateOp(int i1, MutationStep step) 103 | { 104 | var type = InverseOp(step.Type); 105 | switch (type) 106 | { 107 | case MutationType.Add: 108 | return i1 + step.Modifier; 109 | 110 | case MutationType.Sub: 111 | return i1 - step.Modifier; 112 | 113 | case MutationType.Xor: 114 | return i1 ^ step.Modifier; 115 | 116 | default: 117 | throw new NotImplementedException(type.ToString()); 118 | } 119 | } 120 | 121 | } 122 | 123 | internal struct MutationStep 124 | { 125 | public int Modifier; 126 | public MutationType Type; 127 | } 128 | 129 | internal enum MutationType 130 | { 131 | Add, 132 | Sub, 133 | Xor 134 | } 135 | -------------------------------------------------------------------------------- /VirtualGuard.Runtime/Variant/ValueType/Numeric/ULongVariant.cs: -------------------------------------------------------------------------------- 1 | using VirtualGuard.Runtime.Dynamic; 2 | 3 | namespace VirtualGuard.Runtime.Variant.ValueType.Numeric; 4 | 5 | public class ULongVariant : NumeralVariant 6 | { 7 | private ulong _value; 8 | 9 | public ULongVariant(ulong i) 10 | { 11 | _value = i; 12 | } 13 | 14 | public override object GetObject() 15 | { 16 | return _value; 17 | } 18 | 19 | public override void SetVariantValue(object obj) 20 | { 21 | _value = (ulong)obj; 22 | } 23 | 24 | public override BaseVariant Clone() 25 | { 26 | return new ULongVariant(_value); 27 | } 28 | 29 | public override NumeralVariant Add(NumeralVariant addend) 30 | { 31 | // result should always be int operating under realm of int 32 | var sum = _value + addend.U8(); 33 | 34 | // do something with flags???? 35 | 36 | return new ULongVariant(sum); 37 | } 38 | 39 | public override NumeralVariant Sub(NumeralVariant subtraend) 40 | { 41 | // result should always be int operating under realm of int 42 | var diff = _value - subtraend.U8(); 43 | 44 | // do something with flags???? 45 | 46 | return new ULongVariant(diff); 47 | } 48 | 49 | public override NumeralVariant Mul(NumeralVariant factor) 50 | { 51 | // result should always be int operating under realm of int 52 | var sum = _value * factor.U8(); 53 | 54 | // do something with flags???? 55 | 56 | return new ULongVariant(sum); 57 | } 58 | 59 | public override NumeralVariant Div(NumeralVariant divisor) 60 | { 61 | // result should always be int operating under realm of int 62 | var sum = _value + divisor.U8(); 63 | 64 | // do something with flags???? 65 | 66 | return new ULongVariant(sum); 67 | } 68 | 69 | public override NumeralVariant Xor(NumeralVariant xorfactor) 70 | { 71 | // result should always be int operating under realm of int 72 | var sum = _value ^ xorfactor.U8(); 73 | 74 | // do something with flags???? 75 | 76 | return new ULongVariant(sum); 77 | } 78 | 79 | public override NumeralVariant Rem(NumeralVariant remfactor) 80 | { 81 | // result should always be int operating under realm of int 82 | var sum = _value % remfactor.U8(); 83 | 84 | // do something with flags???? 85 | 86 | return new ULongVariant(sum); 87 | } 88 | 89 | public override NumeralVariant Or(NumeralVariant or) 90 | { 91 | // result should always be int operating under realm of int 92 | var sum = this.U8() | or.U8(); 93 | 94 | // do something with flags???? 95 | 96 | return new ULongVariant(sum); 97 | } 98 | 99 | public override NumeralVariant Not() 100 | { 101 | return new ULongVariant(~_value); 102 | } 103 | 104 | public override NumeralVariant And(NumeralVariant and) 105 | { 106 | return new ULongVariant((ulong)(_value & and.U8())); 107 | } 108 | 109 | public override NumeralVariant Shl(NumeralVariant factor) 110 | { 111 | return new ULongVariant(this.U8() << factor.I4()); 112 | } 113 | 114 | public override NumeralVariant Shr(NumeralVariant factor) 115 | { 116 | return new ULongVariant(this.U8() >> factor.I4()); 117 | } 118 | 119 | public override BaseVariant Hash() 120 | { 121 | return new LongVariant(Util.Hash(BitConverter.GetBytes(_value))); 122 | } 123 | } -------------------------------------------------------------------------------- /VirtualGuard/RT/Mutators/impl/HandlerMutator.cs: -------------------------------------------------------------------------------- 1 | using AsmResolver.DotNet; 2 | using AsmResolver.DotNet.Code.Cil; 3 | using AsmResolver.PE.DotNet.Cil; 4 | using AsmResolver.PE.DotNet.Metadata.Tables.Rows; 5 | 6 | namespace VirtualGuard.RT.Mutators.impl; 7 | 8 | internal class HandlerMutator : IRuntimeMutator 9 | { 10 | public void Mutate(VirtualGuardRT rt, VirtualGuardContext ctx) 11 | { 12 | var rnd = new Random(); 13 | 14 | foreach (var handler in rt.RuntimeModule.TopLevelTypes.Where(x => x.Interfaces.Any(x => x.Interface != null && x.Interface.Name == "IOpCode"))) 15 | { 16 | // find random instruction to insert on 17 | var executeMethod = handler.Methods.Single(x => x.Name == "Execute"); 18 | 19 | var instrs = executeMethod.CilMethodBody.Instructions; 20 | 21 | // random l2f 22 | 23 | Dictionary map = new Dictionary(); 24 | 25 | foreach (var localVar in executeMethod.CilMethodBody.LocalVariables) 26 | { 27 | if(rnd.Next(2) != 0) 28 | continue; 29 | 30 | var field = new FieldDefinition("vg", FieldAttributes.Private, localVar.VariableType); 31 | 32 | map.Add(localVar, field); 33 | handler.Fields.Add(field); 34 | } 35 | 36 | instrs.ExpandMacros(); 37 | foreach (var instr in instrs.ToArray()) 38 | { 39 | if(instr.OpCode == CilOpCodes.Ldloc && map.TryGetValue((CilLocalVariable)instr.Operand, out FieldDefinition fd)) 40 | instrs.ReplaceRange(instr, new CilInstruction(CilOpCodes.Ldarg_0), new CilInstruction(CilOpCodes.Ldfld, fd)); 41 | 42 | if(instr.OpCode == CilOpCodes.Ldloca && map.TryGetValue((CilLocalVariable)instr.Operand, out FieldDefinition fd2)) 43 | instrs.ReplaceRange(instr, new CilInstruction(CilOpCodes.Ldarg_0), new CilInstruction(CilOpCodes.Ldflda, fd2)); 44 | 45 | if (instr.OpCode == CilOpCodes.Stloc && 46 | map.TryGetValue((CilLocalVariable)instr.Operand, out FieldDefinition fd1)) 47 | { // slightly more complicated bc we need to set to the local 48 | 49 | instrs.ReplaceRange(instr, new CilInstruction(CilOpCodes.Stloc, instr.Operand), new CilInstruction(CilOpCodes.Ldarg_0), new CilInstruction(CilOpCodes.Ldloc, instr.Operand), new CilInstruction(CilOpCodes.Stfld, fd1)); 50 | } 51 | 52 | } 53 | 54 | instrs.OptimizeMacros(); 55 | 56 | 57 | } 58 | 59 | 60 | 61 | 62 | } 63 | 64 | private List _cachedMutators; 65 | List GetMutators(ModuleDefinition rt) 66 | { 67 | if (_cachedMutators != null) 68 | return _cachedMutators; 69 | 70 | _cachedMutators = new List(); 71 | 72 | // locate junk type 73 | var junkType = rt.LookupType(RuntimeConfig.JunkCode); 74 | 75 | foreach (var method in junkType.Methods) 76 | { 77 | if(method.Name[0] != '_') 78 | continue; 79 | 80 | if(method.Signature.ReturnsValue) 81 | method.CilMethodBody.Instructions.Last().ReplaceWith(CilOpCodes.Pop); 82 | 83 | _cachedMutators.Add(method.CilMethodBody.Instructions.ToArray()); // NOTE: WILL NOT PRESERVE EXCEPTION HANDLERS OR LOCALS 84 | } 85 | 86 | return _cachedMutators; 87 | } 88 | } --------------------------------------------------------------------------------