├── .gitignore ├── Hex.VM.Runtime ├── Context.cs ├── Handler │ ├── HxOpCode.cs │ ├── HxOpCodes.cs │ └── Impl │ │ ├── Add.cs │ │ ├── And.cs │ │ ├── Box.cs │ │ ├── Brfalse.cs │ │ ├── Brtrue.cs │ │ ├── Castclass.cs │ │ ├── Ceq.cs │ │ ├── Constrained.cs │ │ ├── Custom │ │ ├── HxArg.cs │ │ ├── HxArray.cs │ │ ├── HxBeq.cs │ │ ├── HxBge.cs │ │ ├── HxBr.cs │ │ ├── HxCall.cs │ │ ├── HxCgt.cs │ │ ├── HxClt.cs │ │ ├── HxConv.cs │ │ ├── HxFld.cs │ │ ├── HxLdc.cs │ │ └── HxLoc.cs │ │ ├── Div.cs │ │ ├── Dup.cs │ │ ├── Endfinally.cs │ │ ├── Initobj.cs │ │ ├── Ldftn.cs │ │ ├── Ldlen.cs │ │ ├── Ldloca.cs │ │ ├── Ldtoken.cs │ │ ├── Mul.cs │ │ ├── Neg.cs │ │ ├── Newarr.cs │ │ ├── Newobj.cs │ │ ├── Nop.cs │ │ ├── Not.cs │ │ ├── Or.cs │ │ ├── Pop.cs │ │ ├── Rem.cs │ │ ├── Ret.cs │ │ ├── Shl.cs │ │ ├── Shr.cs │ │ ├── Sub.cs │ │ └── Xor.cs ├── Hex.VM.Runtime.csproj ├── Properties │ └── AssemblyInfo.cs ├── Util │ ├── Factory.cs │ ├── Helper.cs │ ├── HxInstruction.cs │ ├── Value.cs │ ├── VmArgs.cs │ ├── VmLocal.cs │ └── VmStack.cs ├── VirtualMachine.cs └── XXHash.cs ├── Hex.VM.Tests ├── Hex.VM.Tests.csproj ├── Maths.cs ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── Hex.VM.sln ├── Hex.VM ├── Core │ ├── Context.cs │ ├── Engine.cs │ ├── Helper │ │ ├── Compression.cs │ │ ├── Generator.cs │ │ └── InjectHelper.cs │ └── Protections │ │ ├── IProtection.cs │ │ ├── Impl │ │ ├── UStrings │ │ │ ├── Runtime.cs │ │ │ └── VStrings.cs │ │ └── Virtualization │ │ │ ├── Converter.cs │ │ │ ├── RuntimeProtections │ │ │ ├── CFlow.cs │ │ │ ├── CallToCalli.cs │ │ │ ├── ProxyInteger.cs │ │ │ ├── ProxyStrings.cs │ │ │ ├── Renamer.cs │ │ │ └── Strings.cs │ │ │ └── Virtualization.cs │ │ └── LoadDLLRuntime │ │ └── VMInitialize.cs ├── Hex.VM.csproj ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── app.config └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific files 2 | *.rsuser 3 | *.suo 4 | *.user 5 | *.userosscache 6 | *.sln.docstates 7 | *.suo 8 | *.user 9 | _ReSharper.* 10 | bin 11 | obj 12 | packages 13 | */**/bin/Debug 14 | */**/bin/Release 15 | */**/obj/Debug 16 | */**/obj/Release 17 | */bin/Debug 18 | */bin/Release 19 | */obj/Debug 20 | */obj/Release 21 | 22 | # User-specific files (MonoDevelop/Xamarin Studio) 23 | *.userprefs 24 | 25 | # Build results 26 | [Dd]ebug/ 27 | [Dd]ebugPublic/ 28 | [Rr]elease/ 29 | [Rr]eleases/ 30 | x64/ 31 | x86/ 32 | [Aa][Rr][Mm]/ 33 | [Aa][Rr][Mm]64/ 34 | bld/ 35 | [Bb]in/ 36 | [Oo]bj/ 37 | [Ll]og/ 38 | 39 | # Visual Studio 2015/2017 cache/options directory 40 | .vs/ 41 | # Uncomment if you have tasks that create the project's static files in wwwroot 42 | #wwwroot/ 43 | 44 | # Visual Studio 2017 auto generated files 45 | Generated\ Files/ 46 | 47 | # MSTest test Results 48 | [Tt]est[Rr]esult*/ 49 | [Bb]uild[Ll]og.* 50 | 51 | # NUNIT 52 | *.VisualState.xml 53 | TestResult.xml 54 | 55 | # Build Results of an ATL Project 56 | [Dd]ebugPS/ 57 | [Rr]eleasePS/ 58 | dlldata.c 59 | 60 | # Benchmark Results 61 | BenchmarkDotNet.Artifacts/ 62 | 63 | # .NET Core 64 | project.lock.json 65 | project.fragment.lock.json 66 | artifacts/ 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.svclog 98 | *.scc 99 | 100 | # Chutzpah Test files 101 | _Chutzpah* 102 | 103 | # Visual C++ cache files 104 | ipch/ 105 | *.aps 106 | *.ncb 107 | *.opendb 108 | *.opensdf 109 | *.sdf 110 | *.cachefile 111 | *.VC.db 112 | *.VC.VC.opendb 113 | 114 | # Visual Studio profiler 115 | *.psess 116 | *.vsp 117 | *.vspx 118 | *.sap 119 | 120 | # Visual Studio Trace Files 121 | *.e2e 122 | 123 | # TFS 2012 Local Workspace 124 | $tf/ 125 | 126 | # Guidance Automation Toolkit 127 | *.gpState 128 | 129 | # ReSharper is a .NET coding add-in 130 | _ReSharper*/ 131 | *.[Rr]e[Ss]harper 132 | *.DotSettings.user 133 | 134 | # JustCode is a .NET coding add-in 135 | .JustCode 136 | 137 | # TeamCity is a build add-in 138 | _TeamCity* 139 | 140 | # DotCover is a Code Coverage Tool 141 | *.dotCover 142 | 143 | # AxoCover is a Code Coverage Tool 144 | .axoCover/* 145 | !.axoCover/settings.json 146 | 147 | # Visual Studio code coverage results 148 | *.coverage 149 | *.coveragexml 150 | 151 | # NCrunch 152 | _NCrunch_* 153 | .*crunch*.local.xml 154 | nCrunchTemp_* 155 | 156 | # MightyMoose 157 | *.mm.* 158 | AutoTest.Net/ 159 | 160 | # Web workbench (sass) 161 | .sass-cache/ 162 | 163 | # Installshield output folder 164 | [Ee]xpress/ 165 | 166 | # DocProject is a documentation generator add-in 167 | DocProject/buildhelp/ 168 | DocProject/Help/*.HxT 169 | DocProject/Help/*.HxC 170 | DocProject/Help/*.hhc 171 | DocProject/Help/*.hhk 172 | DocProject/Help/*.hhp 173 | DocProject/Help/Html2 174 | DocProject/Help/html 175 | 176 | # Click-Once directory 177 | publish/ 178 | 179 | # Publish Web Output 180 | *.[Pp]ublish.xml 181 | *.azurePubxml 182 | # Note: Comment the next line if you want to checkin your web deploy settings, 183 | # but database connection strings (with potential passwords) will be unencrypted 184 | *.pubxml 185 | *.publishproj 186 | 187 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 188 | # checkin your Azure Web App publish settings, but sensitive information contained 189 | # in these scripts will be unencrypted 190 | PublishScripts/ 191 | 192 | # NuGet Packages 193 | *.nupkg 194 | # The packages folder can be ignored because of Package Restore 195 | **/[Pp]ackages/* 196 | # except build/, which is used as an MSBuild target. 197 | !**/[Pp]ackages/build/ 198 | # Uncomment if necessary however generally it will be regenerated when needed 199 | #!**/[Pp]ackages/repositories.config 200 | # NuGet v3's project.json files produces more ignorable files 201 | *.nuget.props 202 | *.nuget.targets 203 | 204 | # Microsoft Azure Build Output 205 | csx/ 206 | *.build.csdef 207 | 208 | # Microsoft Azure Emulator 209 | ecf/ 210 | rcf/ 211 | 212 | # Windows Store app package directories and files 213 | AppPackages/ 214 | BundleArtifacts/ 215 | Package.StoreAssociation.xml 216 | _pkginfo.txt 217 | *.appx 218 | 219 | # Visual Studio cache files 220 | # files ending in .cache can be ignored 221 | *.[Cc]ache 222 | # but keep track of directories ending in .cache 223 | !?*.[Cc]ache/ 224 | 225 | # Others 226 | ClientBin/ 227 | ~$* 228 | *~ 229 | *.dbmdl 230 | *.dbproj.schemaview 231 | *.jfm 232 | *.pfx 233 | *.publishsettings 234 | orleans.codegen.cs 235 | 236 | # Including strong name files can present a security risk 237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 238 | #*.snk 239 | 240 | # Since there are multiple workflows, uncomment next line to ignore bower_components 241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 242 | #bower_components/ 243 | 244 | # RIA/Silverlight projects 245 | Generated_Code/ 246 | 247 | # Backup & report files from converting an old project file 248 | # to a newer Visual Studio version. Backup files are not needed, 249 | # because we have git ;-) 250 | _UpgradeReport_Files/ 251 | Backup*/ 252 | UpgradeLog*.XML 253 | UpgradeLog*.htm 254 | ServiceFabricBackup/ 255 | *.rptproj.bak 256 | 257 | # SQL Server files 258 | *.mdf 259 | *.ldf 260 | *.ndf 261 | 262 | # Business Intelligence projects 263 | *.rdl.data 264 | *.bim.layout 265 | *.bim_*.settings 266 | *.rptproj.rsuser 267 | *- Backup*.rdl 268 | 269 | # Microsoft Fakes 270 | FakesAssemblies/ 271 | 272 | # GhostDoc plugin setting file 273 | *.GhostDoc.xml 274 | 275 | # Node.js Tools for Visual Studio 276 | .ntvs_analysis.dat 277 | node_modules/ 278 | 279 | # Visual Studio 6 build log 280 | *.plg 281 | 282 | # Visual Studio 6 workspace options file 283 | *.opt 284 | 285 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 286 | *.vbw 287 | 288 | # Visual Studio LightSwitch build output 289 | **/*.HTMLClient/GeneratedArtifacts 290 | **/*.DesktopClient/GeneratedArtifacts 291 | **/*.DesktopClient/ModelManifest.xml 292 | **/*.Server/GeneratedArtifacts 293 | **/*.Server/ModelManifest.xml 294 | _Pvt_Extensions 295 | 296 | # Paket dependency manager 297 | .paket/paket.exe 298 | paket-files/ 299 | 300 | # FAKE - F# Make 301 | .fake/ 302 | 303 | # JetBrains Rider 304 | .idea/ 305 | *.sln.iml 306 | 307 | # CodeRush personal settings 308 | .cr/personal 309 | 310 | # Python Tools for Visual Studio (PTVS) 311 | __pycache__/ 312 | *.pyc 313 | 314 | # Cake - Uncomment if you are using it 315 | # tools/** 316 | # !tools/packages.config 317 | 318 | # Tabs Studio 319 | *.tss 320 | 321 | # Telerik's JustMock configuration file 322 | *.jmconfig 323 | 324 | # BizTalk build output 325 | *.btp.cs 326 | *.btm.cs 327 | *.odx.cs 328 | *.xsd.cs 329 | 330 | # OpenCover UI analysis results 331 | OpenCover/ 332 | 333 | # Azure Stream Analytics local run output 334 | ASALocalRun/ 335 | 336 | # MSBuild Binary and Structured Log 337 | *.binlog 338 | 339 | # NVidia Nsight GPU debugger configuration file 340 | *.nvuser 341 | 342 | # MFractors (Xamarin productivity tool) working folder 343 | .mfractor/ 344 | 345 | # Local History for Visual Studio 346 | .localhistory/ 347 | 348 | # BeatPulse healthcheck temp database 349 | healthchecksdb 350 | -------------------------------------------------------------------------------- /Hex.VM.Runtime/Context.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Handler; 2 | using Hex.VM.Runtime.Handler.Impl; 3 | using Hex.VM.Runtime.Handler.Impl.Custom; 4 | using Hex.VM.Runtime.Util; 5 | using System.Collections.Generic; 6 | 7 | namespace Hex.VM.Runtime 8 | { 9 | public class Context 10 | { 11 | public List Instructions { get; } 12 | public Dictionary Handlers; 13 | public VmStack Stack; 14 | public VmLocal Locals; 15 | public VmArgs Args; 16 | 17 | public int Index { get; set; } 18 | 19 | public Context(List instrs, object[] args) 20 | { 21 | Index = 0; 22 | Instructions = instrs; 23 | Stack = new VmStack(); 24 | Locals = new VmLocal(); 25 | Args = new VmArgs(args); 26 | 27 | Handlers = new Dictionary 28 | { 29 | // custom 30 | {HxOpCodes.HxCall, new HxCall()}, // universal call 31 | {HxOpCodes.HxLdc, new HxLdc()}, // universal ldc] 32 | {HxOpCodes.HxArray, new HxArray()}, // array stuff 33 | {HxOpCodes.HxLoc, new HxLoc()}, // stloc, ldloc 34 | {HxOpCodes.HxArg, new HxArg()}, // starg, ldarg 35 | {HxOpCodes.HxFld, new HxFld()}, // fld 36 | {HxOpCodes.HxConv, new HxConv()}, // conv 37 | 38 | // stuff where operand is null 39 | {HxOpCodes.HxClt, new HxClt()}, // y x (first value compare first) 41 | 42 | {HxOpCodes.ANeg, new Neg()}, // -val 43 | {HxOpCodes.ANot, new Not()}, // ˜val 44 | {HxOpCodes.AAnd, new And()}, // true and true 45 | 46 | {HxOpCodes.AShr, new Shr()}, // >> 47 | {HxOpCodes.AShl, new Shl()}, // << 48 | {HxOpCodes.AXor, new Xor()}, // y^x 49 | 50 | {HxOpCodes.ARem, new Rem()}, // module y % x 51 | {HxOpCodes.ACeq, new Ceq()}, // x == y 52 | {HxOpCodes.AMul, new Mul()}, // y * x 53 | {HxOpCodes.ANop, new Nop()}, // nop do nothing 54 | 55 | {HxOpCodes.AAdd, new Add()}, // y+x 56 | {HxOpCodes.ASub, new Sub()}, // y-x 57 | {HxOpCodes.ARet, new Ret()}, // return 58 | {HxOpCodes.APop, new Pop()}, // pop val on top of stack 59 | {HxOpCodes.ALdlen, new Ldlen()}, // length of array 60 | {HxOpCodes.ADup, new Dup()}, // dup on top of stack 61 | {HxOpCodes.ADiv, new Div()}, // divide 62 | 63 | // not custom & not null operand 64 | {HxOpCodes.Ldtoken, new Ldtoken()}, 65 | {HxOpCodes.HxBr, new HxBr()}, 66 | {HxOpCodes.Brtrue, new Brtrue()}, 67 | {HxOpCodes.Brfalse, new Brfalse()}, 68 | {HxOpCodes.Box, new Box()}, 69 | {HxOpCodes.Newobj, new Newobj()}, 70 | 71 | {HxOpCodes.Ldloca, new Ldloca()}, 72 | {HxOpCodes.Ldftn, new Ldftn()}, 73 | {HxOpCodes.Newarr, new Newarr()}, 74 | {HxOpCodes.Castclass, new Castclass()}, 75 | {HxOpCodes.AOr, new Or()}, 76 | {HxOpCodes.Initobj, new Initobj()}, 77 | {HxOpCodes.Constrained, new Constrained()}, 78 | {HxOpCodes.HxCgt, new HxCgt()}, 79 | {HxOpCodes.Endfinally, new Endfinally()}, 80 | {HxOpCodes.HxBeq, new HxBeq()}, 81 | {HxOpCodes.HxBge, new HxBge()}, 82 | }; 83 | } 84 | 85 | public Value Run() 86 | { 87 | do 88 | { 89 | var instruction = Instructions[Index]; 90 | Handlers[instruction.OpCode].Execute(this, instruction); 91 | } while (Instructions.Count > Index); 92 | return Stack.Pop(); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/HxOpCode.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | // github.com/hexck 4 | namespace Hex.VM.Runtime.Handler 5 | { 6 | public abstract class HxOpCode 7 | { 8 | public abstract void Execute(Context vmContext, HxInstruction instruction); 9 | } 10 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/HxOpCodes.cs: -------------------------------------------------------------------------------- 1 | namespace Hex.VM.Runtime.Handler 2 | { 3 | public enum HxOpCodes 4 | { 5 | // custom 6 | HxCall, // universal call 7 | HxLdc, // universal ldc] 8 | HxArray, // array stuff 9 | HxLoc, 10 | HxArg, 11 | HxFld, 12 | HxConv, 13 | HxBeq, 14 | HxBge, 15 | 16 | // stuff where operand is null 17 | //AClt, // y> 22 | AShl, // << 23 | ARem, // module y % x 24 | ARem_Un, // module y % x 25 | ACeq, // x == y 26 | AMul, // y * x 27 | AMul_Ovf, // checked(y * x) 28 | AMul_Ovf_Un, // checked(y * x) 29 | ANop, // nop do nothing 30 | //ACgt, // y > x (first value compare first) 31 | AAdd, // y+x 32 | AAdd_Ovf, // checked(y+x) 33 | AAdd_Ovf_Un, // checked(y+x) 34 | ASub, // y-x 35 | ASub_Ovf, // checked(y-x) 36 | ASub_Ovf_Un, // checked(y-x) 37 | ARet ,// return 38 | AXor, // y^x 39 | APop, // pop value on top of stack 40 | ALdlen, // get len of array 41 | ADup, // dup on top of stack 42 | ADiv, // y / x 43 | ADiv_Un, // y / x 44 | 45 | // not custom & not null 46 | Ldtoken, // ldtoken 47 | Brfalse, // if == 0, transfer 48 | Brtrue, // if == 1, transfer 49 | //Br, // unconditional transfer 50 | Box, 51 | Newobj, 52 | 53 | Ldloca, 54 | Ldftn, 55 | Newarr, 56 | Castclass, 57 | Initobj, 58 | Constrained, 59 | AOr, 60 | HxCgt, 61 | HxClt, 62 | HxBr, 63 | Endfinally 64 | } 65 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Add.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Add : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.AAdd, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/And.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class And : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.AAnd, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Box.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Box : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | Value val = vmContext.Stack.Pop(); 10 | var type = Helper.ResolveType((int)instruction.Operand.GetObject()); 11 | vmContext.Stack.Push(vmContext.Stack.Cast(val, type)); 12 | vmContext.Index++; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Brfalse.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Brfalse : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | /*var v = vmContext.Stack.Pop(); 10 | object val = v.GetObject(); 11 | 12 | if (v.IsBool()) 13 | val = (bool)v.GetObject() ? 1 : 0; 14 | else 15 | val = (int)v.GetObject(); 16 | 17 | if (val == null || Convert.ToInt32(val) == 0) 18 | { 19 | vmContext.Index = (int)instruction.Operand.GetObject(); 20 | } 21 | else 22 | { 23 | vmContext.Index++; 24 | }*/ 25 | var val = vmContext.Stack.Pop().GetObject(); 26 | if (val is int Integer && Integer == 0) 27 | vmContext.Index = (int)instruction.Operand.GetObject(); 28 | else if (val is bool Boolean && Boolean == false) 29 | vmContext.Index = (int)instruction.Operand.GetObject(); 30 | else 31 | vmContext.Index++; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Brtrue.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Brtrue : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | /*var v = vmContext.Stack.Pop(); 10 | object val = v.GetObject(); 11 | 12 | if (v.IsBool()) 13 | val = (bool)v.GetObject() ? 1 : 0; 14 | else 15 | val = (int)v.GetObject(); 16 | 17 | if (val == null || Convert.ToInt32(val) == 1) 18 | { 19 | vmContext.Index = (int)instruction.Operand.GetObject(); 20 | } 21 | else 22 | { 23 | vmContext.Index++; 24 | }*/ 25 | var val = vmContext.Stack.Pop().GetObject(); 26 | if (val is int Integer && Integer == 1) 27 | vmContext.Index = (int)instruction.Operand.GetObject(); 28 | else if (val is bool Boolean && Boolean == true) 29 | vmContext.Index = (int)instruction.Operand.GetObject(); 30 | else 31 | vmContext.Index++; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Castclass.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System; 3 | using System.Reflection; 4 | 5 | namespace Hex.VM.Runtime.Handler.Impl 6 | { 7 | public class Castclass : HxOpCode 8 | { 9 | public override void Execute(Context vmContext, HxInstruction instruction) 10 | { 11 | TypeInfo conversionType = Helper.ResolveType((int)instruction.Operand.GetObject()); 12 | object o = vmContext.Stack.Pop().GetObject(); 13 | object newo = Convert.ChangeType(o, conversionType); 14 | vmContext.Stack.Push(newo); 15 | vmContext.Index++; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Ceq.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Ceq : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = (bool)Factory.CreateArithmethicFactory(HxOpCodes.ACeq, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result ? 1 : 0); 14 | 15 | vmContext.Index++; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Constrained.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Constrained : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | //Need to be implemented for Callvirt case. 10 | vmContext.Index++; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxArg.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl.Custom 4 | { 5 | public class HxArg : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | var str = (string) instruction.Operand.GetObject(); 10 | var prefix = Helper.ReadPrefix(str); 11 | var idx = int.Parse(str.Substring(1)); 12 | 13 | if (prefix == 0) 14 | { 15 | //vmContext.Stack.Push(vmContext.Args.Get(idx)); 16 | vmContext.Stack.Push(vmContext.Args.Get(idx).GetObject()); 17 | } 18 | else 19 | { 20 | var item = vmContext.Stack.Pop(); 21 | vmContext.Args.Update(idx, item); 22 | } 23 | 24 | vmContext.Index++; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxArray.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl.Custom 5 | { 6 | public class HxArray : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var prefix = (int) instruction.Operand.GetObject(); 11 | 12 | if (prefix == 0) 13 | { 14 | var idx = (int)vmContext.Stack.Pop().GetObject(); 15 | var arr = (Array)vmContext.Stack.Pop().GetObject(); 16 | 17 | vmContext.Stack.Push(arr.GetValue(idx)); 18 | 19 | /*var castType = Helper.ResolveType((int)instruction.Operand.GetObject()); 20 | vmContext.Stack.Push(Convert.ChangeType((Array)arr.GetValue(idx), castType));*/ 21 | } 22 | else if (prefix == 1) 23 | { 24 | var obj = vmContext.Stack.Pop().GetObject(); 25 | var idx = (int)vmContext.Stack.Pop().GetObject(); 26 | var arr = (Array)vmContext.Stack.Pop().GetObject(); 27 | 28 | arr.SetValue(Convert.ChangeType(obj, arr.GetType().GetElementType()), idx); 29 | 30 | /*arr.SetValue(obj, idx);*/ 31 | } 32 | 33 | vmContext.Index++; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxBeq.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl.Custom 5 | { 6 | public class HxBeq : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }.Reverse().ToArray(); 11 | if (values[0].Equals(values[1])) 12 | { 13 | vmContext.Index = (int)instruction.Operand.GetObject(); 14 | } 15 | else 16 | { 17 | vmContext.Index++; 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxBge.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl.Custom 5 | { 6 | public class HxBge : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var obj = (string)instruction.Operand.GetObject(); 11 | 12 | var prefix = Helper.ReadPrefix(obj); 13 | 14 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }.Reverse().ToArray(); 15 | 16 | bool res = prefix == 0 ? (int)values[0] >= (int)values[1] : unchecked((uint)values[0]) >= unchecked((uint)values[1]); 17 | /*bool res = false; 18 | if(prefix == 0) 19 | { 20 | res = (int)values[0] >= (int)values[1]; 21 | } else if(prefix == 1) 22 | { 23 | res = unchecked((uint)values[0]) >= unchecked((uint)values[1]); 24 | }*/ 25 | 26 | if (res) 27 | { 28 | vmContext.Index = (int)instruction.Operand.GetObject(); 29 | } 30 | else 31 | { 32 | vmContext.Index++; 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxBr.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl.Custom 4 | { 5 | public class HxBr : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) => vmContext.Index = (int)instruction.Operand.GetObject(); 8 | } 9 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxCall.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl.Custom 4 | { 5 | public class HxCall : HxOpCode 6 | { 7 | public override void Execute(Context ctx, HxInstruction instruction) 8 | { 9 | var obj = (string)instruction.Operand.GetObject(); 10 | 11 | var type = Helper.ReadPrefix(obj); 12 | var prefix = Helper.ReadPrefix(obj, 1); 13 | var mdtoken = int.Parse(obj.Substring(2)); 14 | 15 | switch (prefix) 16 | { 17 | // Constructor 18 | case 0: 19 | { 20 | var constructor = Helper.ResolveConstructor(mdtoken); 21 | var parameters = Helper.GetMethodParameters(ctx, constructor); 22 | var owner = constructor.IsStatic ? null : ctx.Stack.Pop()?.GetObject(); 23 | 24 | object instance; 25 | 26 | if (type == 0) 27 | { 28 | instance = constructor.Invoke(owner, parameters.ToArray()); 29 | } 30 | else 31 | { 32 | var proxy = Helper.CreateProxyMethodCall(constructor); 33 | 34 | if (!constructor.IsStatic) 35 | parameters.Insert(0, owner); 36 | 37 | instance = proxy.DynamicInvoke(parameters.ToArray()); 38 | } 39 | 40 | if (instance != null) 41 | ctx.Stack.Push(instance); 42 | } 43 | break; 44 | // Method 45 | case 1: 46 | { 47 | var method = Helper.ResolveMethod(mdtoken); 48 | var parameters = Helper.GetMethodParameters(ctx, method); 49 | var owner = method.IsStatic ? null : ctx.Stack.Pop()?.GetObject(); 50 | 51 | object result; 52 | 53 | if (type == 0) 54 | { 55 | result = method.Invoke(owner, parameters.ToArray()); 56 | } 57 | else 58 | { 59 | var proxy = Helper.CreateProxyMethodCall(method); 60 | 61 | if (!method.IsStatic) 62 | parameters.Insert(0, owner); 63 | 64 | result = proxy.DynamicInvoke(parameters.ToArray()); 65 | } 66 | 67 | if (result != null) 68 | ctx.Stack.Push(result); 69 | break; 70 | } 71 | // MemberRef 72 | case 2: 73 | { 74 | var member = Helper.ResolveMember(mdtoken); 75 | var parameters = Helper.GetMethodParameters(ctx, member); 76 | var owner = member.IsStatic ? null : ctx.Stack.Pop()?.GetObject(); 77 | 78 | object result; 79 | 80 | if (type == 0) 81 | { 82 | result = member.Invoke(owner, parameters.ToArray()); 83 | } 84 | else 85 | { 86 | try 87 | { 88 | var proxy = Helper.CreateProxyMethodCall(member); 89 | 90 | if (!member.IsStatic) 91 | parameters.Insert(0, owner); 92 | 93 | result = proxy.DynamicInvoke(parameters.ToArray()); 94 | } catch 95 | { 96 | result = member.Invoke(owner, parameters.ToArray()); 97 | } 98 | } 99 | 100 | if (result != null) 101 | ctx.Stack.Push(result); 102 | } 103 | break; 104 | } 105 | ctx.Index++; 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxCgt.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | 5 | namespace Hex.VM.Runtime.Handler.Impl.Custom 6 | { 7 | public class HxCgt : HxOpCode 8 | { 9 | public override void Execute(Context vmContext, HxInstruction instruction) 10 | { 11 | var obj = (string)instruction.Operand.GetObject(); 12 | var prefix = Helper.ReadPrefix(obj); 13 | 14 | ExpressionType ET = prefix == 1 ? ExpressionType.NotEqual : ExpressionType.GreaterThan; 15 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 16 | var result = (bool)Factory.CreateArithmethicFactoryM(values.Reverse().ToArray(), ET); 17 | vmContext.Stack.Push(result ? 1 : 0); 18 | 19 | vmContext.Index++; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxClt.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl.Custom 5 | { 6 | public class HxClt : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = (bool)Factory.CreateArithmethicFactory(HxOpCodes.HxClt, values.Reverse().ToArray()); 12 | vmContext.Stack.Push(result ? 1 : 0); 13 | 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxConv.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl.Custom 5 | { 6 | public class HxConv : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var id = (int)instruction.Operand.GetObject(); 11 | object item = vmContext.Stack.Pop().GetObject(); 12 | 13 | vmContext.Stack.Push(id switch 14 | { 15 | 0 => (object)(Convert.ToSingle(item)), // convert to "float". Conv_R4 16 | 1 => (object)(Convert.ToDouble(item)), // convert to "double". Conv_R8 17 | 2 => (object)(Convert.ToInt32(item)), // convert to "int32". Conv_I4 18 | 3 => (object)(Convert.ToInt64(item)), // convert to "int64". Conv_I8 19 | 4 => (object)((Int32)Convert.ToByte(item)), // convert to "unsigned int8" then extends to "int32". Conv_U1 20 | 5 => (object)((Int64)Convert.ToUInt64(item)), // convert to "unsigned int64" then extends to "int64". Conv_U8 21 | 6 => (object)((Int32)Convert.ToUInt16(item)), // convert to "unsigned int16", then extends to "int32". Conv_U2 22 | 7 => (object)((Int32)Convert.ToUInt32(item)), // converts to "unsigned int32", then extends to "int32". Conv_U4 23 | _ => item //Should not happen, otherwise I or YOU messed up in the converter.. And yes this is a useless comment. 24 | }); 25 | 26 | vmContext.Index++; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxFld.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl.Custom 5 | { 6 | public class HxFld : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | /*var str = (string) instruction.Operand.GetObject(); 11 | 12 | var id = Helper.ReadPrefix(str); 13 | var mdtoken = int.Parse(str.Substring(1)); 14 | 15 | var fi = Helper.ResolveField(mdtoken); 16 | if (id == 0) 17 | { 18 | vmContext.Stack.Push(fi.GetValue(vmContext.Stack.Pop().GetObject())); 19 | } else if(id == 1) 20 | { 21 | vmContext.Stack.Push(fi.GetValue(null)); 22 | } else if(id == 2) 23 | { 24 | var item = vmContext.Stack.Pop().GetObject(); 25 | fi.SetValue(fi.IsStatic ? null : vmContext.Stack.Pop().GetObject(), item); 26 | }*/ 27 | var str = (string)instruction.Operand.GetObject(); 28 | 29 | var prefix = Helper.ReadPrefix(str); 30 | var mdtoken = int.Parse(str.Substring(1)); 31 | var field = Helper.ResolveField(mdtoken); 32 | 33 | if (prefix == 0) 34 | { 35 | var owner = field.IsStatic ? null : vmContext.Stack.Pop().GetObject(); 36 | vmContext.Stack.Push(field.GetValue(owner)); 37 | } 38 | else if (prefix == 1) 39 | { 40 | var obj = vmContext.Stack.Pop().GetObject(); 41 | var owner = field.IsStatic ? null : vmContext.Stack.Pop().GetObject(); 42 | 43 | try 44 | { 45 | field.SetValue(owner, Convert.ChangeType(obj, field.FieldType)); 46 | } 47 | catch 48 | { 49 | field.SetValue(owner, obj); 50 | } 51 | } 52 | vmContext.Index++; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxLdc.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl.Custom 4 | { 5 | public class HxLdc : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | vmContext.Stack.Push(instruction.Operand.GetObject()); 10 | vmContext.Index++; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Custom/HxLoc.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl.Custom 4 | { 5 | public class HxLoc : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | var str = (string) instruction.Operand.GetObject(); 10 | var prefix = Helper.ReadPrefix(str); 11 | var idx = int.Parse(str.Substring(1)); 12 | 13 | if (prefix == 0) 14 | { 15 | vmContext.Stack.Push(vmContext.Locals.Get(idx)); 16 | //vmContext.Stack.Push(vmContext.Locals.Get(idx).GetObject()); 17 | } 18 | else 19 | { 20 | var item = vmContext.Stack.Pop(); 21 | vmContext.Locals.Update(idx, item); 22 | } 23 | 24 | vmContext.Index++; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Div.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Div : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.ADiv, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Dup.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Dup : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | vmContext.Stack.Push(vmContext.Stack.Peek()); 10 | vmContext.Index++; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Endfinally.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Endfinally : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) => vmContext.Index = (int)instruction.Operand.GetObject(); 8 | } 9 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Initobj.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System; 3 | using System.Runtime.Serialization; 4 | 5 | namespace Hex.VM.Runtime.Handler.Impl 6 | { 7 | public class Initobj : HxOpCode 8 | { 9 | public override void Execute(Context vmContext, HxInstruction instruction) { 10 | 11 | Value val = vmContext.Stack.Pop(); 12 | var type = Helper.ResolveType((int)instruction.Operand.GetObject()); 13 | object obj = null; 14 | 15 | if (type.IsValueType) 16 | if (Nullable.GetUnderlyingType(type) == null) 17 | obj = FormatterServices.GetUninitializedObject(type); 18 | 19 | vmContext.Stack.Push(obj); 20 | vmContext.Index++; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Ldftn.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Ldftn : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | var method = Helper.ResolveMethod((int)instruction.Operand.GetObject()); 10 | vmContext.Stack.Push(method.MethodHandle.GetFunctionPointer()); 11 | vmContext.Index++; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Ldlen.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Ldlen : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | Array arr = (Array)vmContext.Stack.Pop().GetObject(); 11 | vmContext.Stack.Push(arr.Length); 12 | 13 | vmContext.Index++; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Ldloca.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Ldloca : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | var local = vmContext.Locals.Get((int)instruction.Operand.GetObject()); 10 | vmContext.Stack.Push(local); 11 | vmContext.Index++; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Ldtoken.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Ldtoken : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | var str = (string)instruction.Operand.GetObject(); 10 | 11 | var prefix = Helper.ReadPrefix(str); 12 | var mdtoken = int.Parse(str.Substring(1)); 13 | 14 | vmContext.Stack.Push(prefix switch 15 | { 16 | 0 => Helper.ResolveMethod(mdtoken).MethodHandle, // Method 17 | 1 => Helper.ResolveMember(mdtoken).MethodHandle, // MemberRef 18 | 2 => Helper.ResolveField(mdtoken).FieldHandle, // IField 19 | 3 => Helper.ResolveType(mdtoken).TypeHandle, // ITypeOrDef 20 | }); 21 | 22 | vmContext.Index++; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Mul.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Mul : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.AMul, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Neg.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Neg : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.ANeg, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Newarr.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Newarr : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var mdtoken = (int)instruction.Operand.GetObject(); 11 | 12 | var length = (int)vmContext.Stack.Pop().GetObject(); 13 | var type = Helper.ResolveType(mdtoken).MakeArrayType().GetElementType(); 14 | //var type = Helper.ResolveType(mdtoken).GetType(); 15 | 16 | vmContext.Stack.Push(Array.CreateInstance(type, length)); 17 | vmContext.Index++; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Newobj.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Newobj : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | var mdtoken = instruction.Operand.GetObject(); 10 | var constructor = Helper.ResolveConstructor((int)mdtoken); 11 | var parameters = Helper.GetMethodParameters(vmContext, constructor); 12 | 13 | var inst = constructor.Invoke(parameters.ToArray()); 14 | 15 | if (inst != null) 16 | vmContext.Stack.Push(inst); 17 | 18 | vmContext.Index++; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Nop.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Nop : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) => vmContext.Index++; 8 | } 9 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Not.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Not : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.ANot, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Or.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Or : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.AOr, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Pop.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Pop : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | vmContext.Stack.Pop(); 10 | vmContext.Index++; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Rem.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Rem : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.ARem, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Ret.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | 3 | namespace Hex.VM.Runtime.Handler.Impl 4 | { 5 | public class Ret : HxOpCode 6 | { 7 | public override void Execute(Context vmContext, HxInstruction instruction) 8 | { 9 | //vmContext.Stack.Push(vmContext.Stack.Count == 0 ? new Value(null) : vmContext.Stack.Pop().GetObject()); 10 | vmContext.Stack.Push(vmContext.Stack.Count == 0 ? new Value(null) : vmContext.Stack.Pop()); 11 | vmContext.Index++; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Shl.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Shl : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.AShl, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Shr.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Shr : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.AShr, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Sub.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Sub : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.ASub, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Handler/Impl/Xor.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Util; 2 | using System.Linq; 3 | 4 | namespace Hex.VM.Runtime.Handler.Impl 5 | { 6 | public class Xor : HxOpCode 7 | { 8 | public override void Execute(Context vmContext, HxInstruction instruction) 9 | { 10 | var values = new object[] { vmContext.Stack.Pop().GetObject(), vmContext.Stack.Pop().GetObject() }; 11 | var result = Factory.CreateArithmethicFactory(HxOpCodes.AXor, values.Reverse().ToArray()); //Not Sure 12 | 13 | vmContext.Stack.Push(result); 14 | vmContext.Index++; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Hex.VM.Runtime.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {CE5E6BBE-61D5-4594-BFCA-7B3305A98F57} 8 | Library 9 | Properties 10 | Hex.VM.Runtime 11 | Hex.VM.Runtime 12 | v4.7.2 13 | 512 14 | 8.0 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | ..\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | true 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 109 | -------------------------------------------------------------------------------- /Hex.VM.Runtime/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Hex.VM.Runtime")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("Hex.VM.Runtime")] 12 | [assembly: AssemblyCopyright("Copyright © 2020")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("CE5E6BBE-61D5-4594-BFCA-7B3305A98F57")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /Hex.VM.Runtime/Util/Factory.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Handler; 2 | using Microsoft.CSharp.RuntimeBinder; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq.Expressions; 6 | using System.Reflection.Emit; 7 | using System.Runtime.CompilerServices; 8 | 9 | namespace Hex.VM.Runtime.Util 10 | { 11 | public delegate int SizeOfFactory(); 12 | public static class Factory 13 | { 14 | private static Dictionary _sizeofFactories = 15 | new Dictionary(); 16 | 17 | #region Dynamic Arithmetics 18 | private static CallSite> CreateBinaryBinder(ExpressionType expressionType) 19 | { 20 | return CallSite>.Create( 21 | Binder.BinaryOperation(CSharpBinderFlags.None, 22 | expressionType, 23 | typeof(Factory), new CSharpArgumentInfo[] { 24 | CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 25 | CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 26 | }) 27 | ); 28 | } 29 | 30 | private static CallSite> CreateUnaryBinder(ExpressionType expressionType) 31 | { 32 | return CallSite>.Create( 33 | Binder.UnaryOperation(CSharpBinderFlags.None, 34 | expressionType, 35 | typeof(Factory), new CSharpArgumentInfo[] { 36 | CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 37 | }) 38 | ); 39 | } 40 | private static Dictionary _arithmeticFactories = 41 | new Dictionary() 42 | { 43 | { HxOpCodes.AAdd, CreateBinaryBinder(ExpressionType.Add) }, 44 | { HxOpCodes.AAnd, CreateBinaryBinder(ExpressionType.And) }, 45 | { HxOpCodes.ADiv, CreateBinaryBinder(ExpressionType.Divide) }, 46 | { HxOpCodes.AMul, CreateBinaryBinder(ExpressionType.Multiply) }, 47 | { HxOpCodes.ANeg, CreateUnaryBinder(ExpressionType.Negate) }, 48 | { HxOpCodes.ANot, CreateUnaryBinder(ExpressionType.OnesComplement) }, 49 | { HxOpCodes.AOr, CreateBinaryBinder(ExpressionType.Or) }, 50 | { HxOpCodes.ARem, CreateBinaryBinder(ExpressionType.Modulo) }, 51 | { HxOpCodes.AShl, CreateBinaryBinder(ExpressionType.LeftShift) }, 52 | { HxOpCodes.AShr, CreateBinaryBinder(ExpressionType.RightShift) }, 53 | { HxOpCodes.ASub, CreateBinaryBinder(ExpressionType.Subtract) }, 54 | { HxOpCodes.AXor, CreateBinaryBinder(ExpressionType.ExclusiveOr) }, 55 | { HxOpCodes.HxClt, CreateBinaryBinder(ExpressionType.LessThan) }, 56 | { HxOpCodes.ACeq, CreateBinaryBinder(ExpressionType.Equal) } 57 | }; 58 | #endregion 59 | 60 | public static int CreateSizeOfFactory(Type sizeType) 61 | { 62 | if (_sizeofFactories.ContainsKey(sizeType)) 63 | { 64 | return _sizeofFactories[sizeType](); 65 | } 66 | else 67 | { 68 | var dynamicMethod = new DynamicMethod(string.Empty, 69 | typeof(int), Type.EmptyTypes, 70 | typeof(Factory).Module, true); 71 | var ilGen = dynamicMethod.GetILGenerator(); 72 | ilGen.Emit(OpCodes.Sizeof, sizeType); 73 | ilGen.Emit(OpCodes.Ret); 74 | var sizeDelegate = (SizeOfFactory)dynamicMethod.CreateDelegate(typeof(SizeOfFactory)); 75 | _sizeofFactories[sizeType] = sizeDelegate; 76 | return sizeDelegate(); 77 | } 78 | throw new ArgumentOutOfRangeException(); 79 | } 80 | 81 | public static object CreateBoxFactory(object obj, Type boxType) 82 | { 83 | var dyn = new DynamicMethod(string.Empty, boxType, new[] { typeof(object) }, typeof(Factory).Module, true); 84 | var ilgen = dyn.GetILGenerator(); 85 | ilgen.Emit(OpCodes.Ldarg_0); 86 | ilgen.Emit(OpCodes.Box, boxType); 87 | ilgen.Emit(OpCodes.Ret); 88 | return dyn.Invoke(null, new[] { obj }); 89 | } 90 | 91 | public static object CreateArithmethicFactory(HxOpCodes key, object[] reversedPops) 92 | { 93 | dynamic result = null; 94 | switch (key) 95 | { 96 | case HxOpCodes.ANeg: 97 | case HxOpCodes.ANot: 98 | var unaryFactory = (CallSite>)_arithmeticFactories[key]; 99 | result = unaryFactory.Target(unaryFactory, reversedPops[0]); 100 | break; 101 | default: 102 | var firstValue = reversedPops[0]; 103 | var secondValue = reversedPops[1]; 104 | var realKey = _arithmeticFactories[key]; 105 | var arithmeticFactory = (CallSite>)realKey; 106 | result = arithmeticFactory.Target(arithmeticFactory, firstValue, secondValue); 107 | break; 108 | } 109 | return result; 110 | } 111 | 112 | public static object CreateArithmethicFactoryM(object[] reversedPops, ExpressionType ET) 113 | { 114 | dynamic result = null; 115 | var firstValue = reversedPops[0]; 116 | var secondValue = reversedPops[1]; 117 | var realKey = CreateBinaryBinder(ET); 118 | var arithmeticFactory = (CallSite>)realKey; 119 | result = arithmeticFactory.Target(arithmeticFactory, firstValue, secondValue); 120 | return result; 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Util/Helper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | using System.Reflection.Emit; 7 | 8 | namespace Hex.VM.Runtime.Util 9 | { 10 | public class Helper 11 | { 12 | internal static byte[] Extract(string resourceName) 13 | { 14 | using (var stream = Assembly.GetEntryAssembly().GetManifestResourceStream(resourceName)) 15 | { 16 | var bytes = new byte[stream.Length]; 17 | stream.Read(bytes, 0, bytes.Length); 18 | 19 | int n = bytes.Length - 1; 20 | int[] key = resourceName.Select(c => int.Parse(c.ToString())).ToArray(); 21 | 22 | // XOR Cipher decryption with array reversal and key rotation 23 | for (int i = 0; i < n; i++, n--) 24 | { 25 | // Reverse the array 26 | Array.Reverse(bytes); 27 | 28 | bytes[i] ^= bytes[n]; 29 | bytes[n] ^= (byte)(bytes[i] ^ key[i % key.Length]); 30 | bytes[i] ^= bytes[n]; 31 | 32 | // Rotate the key 33 | RotateKey(ref key); 34 | } 35 | 36 | if (bytes.Length % 2 != 0) 37 | bytes[bytes.Length >> 1] ^= (byte)key[key.Length - 1]; 38 | 39 | return bytes; 40 | } 41 | } 42 | 43 | private static void RotateKey(ref int[] key) 44 | { 45 | int rotationFactor = key.Length % 5 + 1; 46 | // Automatically decide the multiplier based on key characteristics 47 | int multiplier = (key.Sum() + key.Aggregate(1, (current, val) => current * val)) % (int.MaxValue / key.Length); 48 | int preDivide = multiplier != 0 ? int.MaxValue / multiplier : int.MaxValue / 1337; 49 | 50 | for (int rotationCount = 0; rotationCount < rotationFactor; rotationCount++) 51 | { 52 | int lastElement = key[key.Length - 1]; 53 | 54 | for (int i = key.Length - 1; i > 0; i--) 55 | { 56 | key[i] = (key[i - 1] * multiplier + key.Length) % preDivide; 57 | } 58 | 59 | key[0] = (lastElement * multiplier + key.Length) % preDivide; 60 | } 61 | } 62 | 63 | internal static TypeInfo ResolveType(int mdtoken) 64 | { 65 | foreach (var module in Assembly.GetEntryAssembly().Modules) 66 | { 67 | try 68 | { 69 | return (TypeInfo)module.ResolveType(mdtoken); 70 | } 71 | catch 72 | { 73 | // ignored 74 | } 75 | } 76 | 77 | return null; 78 | } 79 | 80 | internal static FieldInfo ResolveField(int mdtoken) 81 | { 82 | foreach (var module in Assembly.GetEntryAssembly().Modules) 83 | { 84 | try 85 | { 86 | return module.ResolveField(mdtoken); 87 | } 88 | catch 89 | { 90 | // ignored 91 | } 92 | } 93 | 94 | return null; 95 | } 96 | 97 | internal static ConstructorInfo ResolveConstructor(int mdtoken) 98 | { 99 | foreach (var module in Assembly.GetEntryAssembly().Modules) 100 | { 101 | try 102 | { 103 | return (ConstructorInfo)module.ResolveMethod(mdtoken); 104 | } 105 | catch 106 | { 107 | // ignored 108 | } 109 | } 110 | 111 | return null; 112 | } 113 | 114 | internal static MethodInfo ResolveMethod(int mdtoken) 115 | { 116 | foreach (var module in Assembly.GetEntryAssembly().Modules) 117 | { 118 | try 119 | { 120 | return (MethodInfo)module.ResolveMethod(mdtoken); 121 | } 122 | catch 123 | { 124 | // ignored 125 | } 126 | } 127 | 128 | return null; 129 | } 130 | internal static MethodInfo ResolveMember(int mdtoken) 131 | { 132 | foreach (var module in Assembly.GetEntryAssembly().Modules) 133 | { 134 | try 135 | { 136 | return (MethodInfo)module.ResolveMember(mdtoken); 137 | } 138 | catch 139 | { 140 | // ignored 141 | } 142 | } 143 | 144 | return null; 145 | } 146 | 147 | public static int ReadPrefix(string txt, int idx = 0) => int.Parse(txt[idx].ToString()); 148 | public static List GetMethodParameters(Context ctx, MethodBase method) 149 | { 150 | var parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray(); 151 | var parameters = new object[parameterTypes.Length]; 152 | 153 | Dictionary> conversionMap = new Dictionary> 154 | { 155 | { TypeCode.Empty, obj => obj }, 156 | { TypeCode.Object, obj => obj }, 157 | { TypeCode.DBNull, obj => DBNull.Value }, 158 | { TypeCode.Boolean, obj => obj is int I32B ? Convert.ToBoolean(I32B) : Convert.ToBoolean(obj) }, 159 | { TypeCode.Char, obj => Convert.ToChar(obj) }, 160 | { TypeCode.SByte, obj => Convert.ToSByte(obj) }, 161 | { TypeCode.Byte, obj => Convert.ToByte(obj) }, 162 | { TypeCode.Int16, obj => Convert.ToInt16(obj) }, 163 | { TypeCode.UInt16, obj => Convert.ToUInt16(obj) }, 164 | { TypeCode.Int32, obj => Convert.ToInt32(obj) }, 165 | { TypeCode.UInt32, obj => Convert.ToUInt32(obj) }, 166 | { TypeCode.Int64, obj => Convert.ToInt64(obj) }, 167 | { TypeCode.UInt64, obj => Convert.ToUInt64(obj) }, 168 | { TypeCode.Single, obj => Convert.ToSingle(obj) }, 169 | { TypeCode.Double, obj => Convert.ToDouble(obj) }, 170 | { TypeCode.Decimal, obj => Convert.ToDecimal(obj) }, 171 | { TypeCode.DateTime, obj => Convert.ToDateTime(obj) }, 172 | { TypeCode.String, obj => Convert.ToString(obj) }, 173 | }; 174 | 175 | for (int i = parameterTypes.Length - 1; i >= 0; i--) 176 | { 177 | var type = parameterTypes[i]; 178 | var pop = ctx.Stack.Pop(); 179 | var obj = pop?.GetObject(); 180 | 181 | if (type.IsByRef) 182 | throw new NotSupportedException(); 183 | 184 | if (conversionMap.TryGetValue(Type.GetTypeCode(type), out var conversion)) 185 | { 186 | parameters[i] = conversion(obj); 187 | } 188 | else 189 | { 190 | parameters[i] = obj; 191 | } 192 | } 193 | 194 | return parameters.ToList(); 195 | } 196 | public static Type[] GetParameterTypes(MethodInfo method) 197 | { 198 | var parameters = method.GetParameters(); 199 | var parameterTypes = new Type[parameters.Length + (method.IsStatic ? 0 : 1)]; 200 | 201 | for (var i = 0; i < parameterTypes.Length; i++) 202 | { 203 | if (method.IsStatic) 204 | { 205 | parameterTypes[i] = parameters[i].ParameterType; 206 | } 207 | else 208 | { 209 | if (i == 0) 210 | { 211 | parameterTypes[0] = method.IsVirtual ? method.DeclaringType.BaseType : method.DeclaringType; 212 | } 213 | else 214 | { 215 | parameterTypes[i] = parameters[i - 1].ParameterType; 216 | } 217 | } 218 | } 219 | return parameterTypes; 220 | } 221 | 222 | public static Delegate CreateProxyMethodCall(MethodBase method) 223 | { 224 | List parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToList(); 225 | 226 | if (!method.IsStatic) parameterTypes.Insert(0, method.DeclaringType); 227 | 228 | var returnType = method is MethodInfo ? ((MethodInfo)method).ReturnType : typeof(void); 229 | var dm = new DynamicMethod(method.Name, returnType, parameterTypes.ToArray(), method.DeclaringType.Module, true); 230 | var gen = dm.GetILGenerator(); 231 | 232 | for (var i = 0; i < parameterTypes.Count; i++) 233 | { 234 | if (!method.IsStatic && i == 0 && parameterTypes[0].IsValueType) 235 | { 236 | gen.Emit(OpCodes.Ldarga_S, i); 237 | } 238 | else 239 | { 240 | gen.Emit(OpCodes.Ldarg, i); 241 | } 242 | } 243 | 244 | if (method is MethodInfo) 245 | { 246 | gen.Emit(OpCodes.Call, (MethodInfo)method); 247 | } 248 | else 249 | { 250 | gen.Emit(OpCodes.Call, (ConstructorInfo)method); 251 | } 252 | gen.Emit(OpCodes.Ret); 253 | 254 | return dm.CreateDelegate(Expression.GetDelegateType(parameterTypes.Concat(new Type[] { returnType }).ToArray())); 255 | } 256 | } 257 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Util/HxInstruction.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Handler; 2 | 3 | namespace Hex.VM.Runtime.Util 4 | { 5 | public class HxInstruction 6 | { 7 | public HxOpCodes OpCode { get; } 8 | public Value Operand { get; } 9 | 10 | public HxInstruction(HxOpCodes opcode, Value value = null) 11 | { 12 | OpCode = opcode; 13 | Operand = value ?? null; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Util/Value.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Hex.VM.Runtime.Util 4 | { 5 | public class Value 6 | { 7 | private object _obj; 8 | public object GetObject() => _obj; 9 | 10 | public Value(object obj) => _obj = obj; 11 | 12 | public bool IsByte() 13 | { 14 | if (_obj == null) return false; 15 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.Byte; 16 | } 17 | 18 | public bool IsSByte() 19 | { 20 | if (_obj == null) return false; 21 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.SByte; 22 | } 23 | 24 | public bool IsUInt16() 25 | { 26 | if (_obj == null) return false; 27 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.UInt16; 28 | } 29 | 30 | public bool IsUInt32() 31 | { 32 | if (_obj == null) return false; 33 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.UInt32; 34 | } 35 | 36 | public bool IsUInt64() 37 | { 38 | if (_obj == null) return false; 39 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.UInt64; 40 | } 41 | 42 | public bool IsInt16() 43 | { 44 | if (_obj == null) return false; 45 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.Int16; 46 | } 47 | 48 | public bool Same(Value other) 49 | { 50 | if (_obj == null) return false; 51 | return Type.GetTypeCode(_obj.GetType()) == Type.GetTypeCode(other.GetObject().GetType()); 52 | } 53 | 54 | public bool IsInt32() 55 | { 56 | if (_obj == null) return false; 57 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.Int32; 58 | } 59 | 60 | public bool IsInt64() 61 | { 62 | if (_obj == null) return false; 63 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.Int64; 64 | } 65 | 66 | public bool IsDecimal() 67 | { 68 | if (_obj == null) return false; 69 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.Decimal; 70 | } 71 | 72 | public bool IsDouble() 73 | { 74 | if (_obj == null) return false; 75 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.Double; 76 | } 77 | 78 | public bool IsBool() 79 | { 80 | if (_obj == null) return false; 81 | try 82 | { 83 | var b = (bool)_obj; 84 | return true; 85 | } 86 | catch 87 | { 88 | // ignored 89 | } 90 | 91 | return false; 92 | } 93 | 94 | public bool IsString() 95 | { 96 | if (_obj == null) return false; 97 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.String; 98 | } 99 | 100 | public bool IsNull() 101 | { 102 | return _obj == null; 103 | } 104 | 105 | public bool IsFloat() 106 | { 107 | if (_obj == null) return false; 108 | return Type.GetTypeCode(_obj.GetType()) == TypeCode.Single; 109 | } 110 | 111 | public bool IsNumeric() 112 | { 113 | if (_obj == null) return false; 114 | switch (Type.GetTypeCode(_obj.GetType())) 115 | { 116 | case TypeCode.Byte: 117 | case TypeCode.SByte: 118 | case TypeCode.UInt16: 119 | case TypeCode.UInt32: 120 | case TypeCode.UInt64: 121 | case TypeCode.Int16: 122 | case TypeCode.Int32: 123 | case TypeCode.Int64: 124 | case TypeCode.Decimal: 125 | case TypeCode.Double: 126 | case TypeCode.Single: 127 | return true; 128 | default: 129 | return false; 130 | } 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Util/VmArgs.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Hex.VM.Runtime.Util 4 | { 5 | public class VmArgs 6 | { 7 | public Dictionary Args { get; } 8 | 9 | public VmArgs() => Args = new Dictionary(); 10 | 11 | public VmArgs(object[] pm) 12 | { 13 | Args = new Dictionary(); 14 | for (var i = 0; i < pm.Length; i++) 15 | Args[i] = new Value(pm[i]); 16 | } 17 | 18 | public void Update(int index, Value value) => Args[index] = value; 19 | 20 | public Value Get(int index) => Args[index]; 21 | } 22 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Util/VmLocal.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Hex.VM.Runtime.Util 4 | { 5 | public class VmLocal 6 | { 7 | public Dictionary Vars { get; } 8 | 9 | public VmLocal() 10 | { 11 | Vars = new Dictionary(); 12 | for(var i = 0;i<50; i++) 13 | Vars.Add(i, null); 14 | } 15 | 16 | public void Update(int index, Value value) => Vars[index] = value; 17 | 18 | public Value Get(int index) => !Vars.ContainsKey(index) ? null : Vars[index]; 19 | } 20 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/Util/VmStack.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Hex.VM.Runtime.Util 6 | { 7 | public class VmStack 8 | { 9 | public Stack Stack { get; } 10 | 11 | public int Count => Stack.Count; 12 | 13 | public VmStack() => Stack = new Stack(); 14 | 15 | public void Push(object obj) => Stack.Push(new Value(obj)); 16 | public void Push(Value value) => Stack.Push(value); 17 | public Value Get(int i) => Stack.ToList()[i]; 18 | public Value Peek() => Stack.Peek(); 19 | public Value Pop() => Stack.Pop(); 20 | 21 | public object Cast(Value value, Type castType) 22 | { 23 | object valueObject = value.GetObject(); 24 | if (valueObject is null || castType is null) return null; 25 | 26 | Dictionary> conversionMap = new Dictionary> 27 | { 28 | { TypeCode.Empty, obj => obj }, 29 | { TypeCode.Object, obj => obj }, 30 | { TypeCode.DBNull, obj => DBNull.Value }, 31 | { TypeCode.Boolean, obj => obj is int I32B ? Convert.ToBoolean(I32B) : Convert.ToBoolean(obj) }, 32 | { TypeCode.Char, obj => Convert.ToChar(obj) }, 33 | { TypeCode.SByte, obj => Convert.ToSByte(obj) }, 34 | { TypeCode.Byte, obj => Convert.ToByte(obj) }, 35 | { TypeCode.Int16, obj => Convert.ToInt16(obj) }, 36 | { TypeCode.UInt16, obj => Convert.ToUInt16(obj) }, 37 | { TypeCode.Int32, obj => Convert.ToInt32(obj) }, 38 | { TypeCode.UInt32, obj => Convert.ToUInt32(obj) }, 39 | { TypeCode.Int64, obj => Convert.ToInt64(obj) }, 40 | { TypeCode.UInt64, obj => Convert.ToUInt64(obj) }, 41 | { TypeCode.Single, obj => Convert.ToSingle(obj) }, 42 | { TypeCode.Double, obj => Convert.ToDouble(obj) }, 43 | { TypeCode.Decimal, obj => Convert.ToDecimal(obj) }, 44 | { TypeCode.DateTime, obj => Convert.ToDateTime(obj) }, 45 | { TypeCode.String, obj => Convert.ToString(obj) }, 46 | }; 47 | 48 | if (conversionMap.TryGetValue(Type.GetTypeCode(castType ?? typeof(object)), out var conversion)) 49 | return conversion(valueObject); 50 | 51 | try 52 | { 53 | return Convert.ChangeType(valueObject, castType); 54 | } 55 | catch 56 | { 57 | return Factory.CreateBoxFactory(valueObject, castType); 58 | } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/VirtualMachine.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Runtime.Handler; 2 | using Hex.VM.Runtime.Util; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Reflection; 7 | 8 | // github.com/hexck 9 | namespace Hex.VM.Runtime 10 | { 11 | public class VirtualMachine 12 | { 13 | public static object RunVM(object[] pm, string OriginalMethod) 14 | { 15 | if (Assembly.GetCallingAssembly().ToString() == "{{TExecutingHAssemblyT}}") 16 | { 17 | var code = Helper.Extract(XXHash.CalculateXXHash32(OriginalMethod).ToString()); 18 | 19 | var ms = new MemoryStream(code); 20 | var br = new BinaryReader(ms); 21 | var count = br.ReadInt32(); 22 | var instrs = new List(); 23 | 24 | for (var i = 0; i < count; i++) 25 | { 26 | var opcode = (HxOpCodes)br.ReadInt32(); 27 | Value operand = null; 28 | if (br.ReadBoolean()) // has operand 29 | { 30 | var type = br.ReadInt32(); 31 | operand = ReadValue(br, type); 32 | } 33 | //maybe is better to do this in real time as it may be a bad idea to store all of the instructions in an list like this because it would be easier to devirtualize 34 | instrs.Add(new HxInstruction(opcode, operand)); 35 | } 36 | 37 | var ctx = new Context(instrs, pm ?? new object[0]); 38 | return ctx.Run().GetObject(); 39 | } 40 | return new object[] { "https://github.com/TheHellTower/Hex-Virtualization" }; 41 | } 42 | 43 | public static Value ReadValue(BinaryReader br, int type) 44 | { 45 | Dictionary> valueReaders = new Dictionary> 46 | { 47 | { 0, () => new Value(br.ReadString()) }, 48 | { 1, () => new Value(br.ReadInt16()) }, 49 | { 2, () => new Value(br.ReadInt32()) }, 50 | { 3, () => new Value(br.ReadInt64()) }, 51 | { 4, () => new Value(br.ReadUInt16()) }, 52 | { 5, () => new Value(br.ReadUInt32()) }, 53 | { 6, () => new Value(br.ReadUInt64()) }, 54 | { 7, () => new Value(br.ReadDouble()) }, 55 | { 8, () => new Value(br.ReadDecimal()) }, 56 | { 9, () => new Value(br.ReadByte()) }, 57 | { 10, () => new Value(br.ReadSByte()) }, 58 | { 11, () => new Value(br.ReadSingle()) }, 59 | { 12, () => new Value(null) } 60 | }; 61 | 62 | return valueReaders.TryGetValue(type, out var valueReader) ? valueReader() : valueReaders[12](); // default case is null 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /Hex.VM.Runtime/XXHash.cs: -------------------------------------------------------------------------------- 1 | namespace Hex.VM.Runtime 2 | { 3 | internal static class XXHash 4 | { 5 | internal static uint CalculateXXHash32(string input) 6 | { 7 | const uint prime1 = 2654435761U; 8 | const uint prime2 = 2246822519U; 9 | const uint prime3 = 3266489917U; 10 | const uint prime4 = 668265263U; 11 | const uint prime5 = 374761393U; 12 | 13 | int len = input.Length; 14 | int index = 0; 15 | uint seed = 0; // You can change the seed value if needed 16 | 17 | uint h32; 18 | 19 | if (len >= 16) 20 | { 21 | int limit = len - 16; 22 | uint v1 = seed + prime1; 23 | uint v2 = seed + prime2; 24 | uint v3 = seed + prime3; 25 | uint v4 = seed + prime4; 26 | 27 | do 28 | { 29 | uint block1 = GetUInt32(input, index) * prime2; 30 | index += 4; 31 | uint block2 = GetUInt32(input, index) * prime2; 32 | index += 4; 33 | 34 | v1 = Rol(v1 + block1, 13) * prime1; 35 | v2 = Rol(v2 + block2, 13) * prime1; 36 | v1 = Rol(v1, 13); 37 | v2 = Rol(v2, 13); 38 | 39 | uint block3 = GetUInt32(input, index) * prime2; 40 | index += 4; 41 | uint block4 = GetUInt32(input, index) * prime2; 42 | index += 4; 43 | 44 | v3 = Rol(v3 + block3, 13) * prime1; 45 | v4 = Rol(v4 + block4, 13) * prime1; 46 | v3 = Rol(v3, 13); 47 | v4 = Rol(v4, 13); 48 | } while (index <= limit); 49 | 50 | h32 = Rol(v1, 1) + Rol(v2, 7) + Rol(v3, 12) + Rol(v4, 18); 51 | } 52 | else 53 | { 54 | h32 = seed + prime5; 55 | } 56 | 57 | h32 += (uint)len; 58 | 59 | while (index <= len - 4) 60 | { 61 | h32 += GetUInt32(input, index) * prime3; 62 | h32 = Rol(h32, 17) * prime4; 63 | index += 4; 64 | } 65 | 66 | while (index < len) 67 | { 68 | h32 += input[index] * prime5; 69 | h32 = Rol(h32, 11) * prime1; 70 | index++; 71 | } 72 | 73 | h32 ^= h32 >> 15; 74 | h32 *= prime2; 75 | h32 ^= h32 >> 13; 76 | h32 *= prime3; 77 | h32 ^= h32 >> 16; 78 | 79 | return h32; 80 | } 81 | 82 | private static uint GetUInt32(string input, int index) => (uint)input[index] | ((uint)input[index + 1] << 8) | ((uint)input[index + 2] << 16) | ((uint)input[index + 3] << 24); 83 | 84 | private static uint Rol(uint value, int count) => (value << count) | (value >> (32 - count)); 85 | } 86 | } -------------------------------------------------------------------------------- /Hex.VM.Tests/Hex.VM.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {DBC66F83-2BA3-4D69-8F1D-6344F61A093A} 8 | Exe 9 | Properties 10 | Hex.VM.Tests 11 | Hex.VM.Tests 12 | v4.7.2 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | ..\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 53 | -------------------------------------------------------------------------------- /Hex.VM.Tests/Maths.cs: -------------------------------------------------------------------------------- 1 | namespace Hex.VM.Tests 2 | { 3 | public class Maths 4 | { 5 | public int Sum { get; set; } 6 | private int _x, _y; 7 | 8 | public Maths(int x, int y) 9 | { 10 | _x = x; 11 | _y = y; 12 | Sum = _x + _y; 13 | } 14 | 15 | public int Add() => _x + _y; 16 | 17 | public int Subtract() => _x - _y; 18 | 19 | public int Multiply() => _x * _y; 20 | 21 | public int Divide() => _x / _y; 22 | } 23 | } -------------------------------------------------------------------------------- /Hex.VM.Tests/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Hex.VM.Tests 4 | { 5 | public class Program 6 | { 7 | public static void Main(string[] args) 8 | { 9 | Console.WriteLine("Hello, type anything."); 10 | while (true) 11 | { 12 | var line = Console.ReadLine(); 13 | Console.WriteLine($"You wrote: {line}"); 14 | 15 | if (line == "continue") 16 | break; 17 | } 18 | var maths = new Maths(10,10); 19 | /*Console.WriteLine($"Add {maths.Add()}"); 20 | Console.WriteLine($"Sub {maths.Subtract()}"); 21 | Console.WriteLine($"Mul {maths.Multiply()}"); 22 | Console.WriteLine($"Div {maths.Divide()}"); 23 | Console.WriteLine($"Cgt {(double)maths.Add() > maths.Subtract()}"); 24 | Console.WriteLine($"Clt {maths.Add() < (float)maths.Subtract()}"); 25 | Console.WriteLine($"Or {1337 | 7331}"); 26 | Console.WriteLine(maths.Sum);*/ 27 | Console.WriteLine($"Add {maths.Add()}\nSub {maths.Subtract()}\nMul {maths.Multiply()}\nDiv {maths.Divide()}\nCgt {(double)maths.Add() > maths.Subtract()}\nClt {maths.Add() < (float)maths.Subtract()}\nOr {1337 | 7331}\n{maths.Sum}"); 28 | double d = Convert.ToDouble(int.Parse(Console.ReadLine())); 29 | d += 0.5; 30 | Console.WriteLine(d); 31 | Console.ReadKey(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Hex.VM.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Hex.VM.Tests")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("Hex.VM.Tests")] 12 | [assembly: AssemblyCopyright("Copyright © 2020")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("DBC66F83-2BA3-4D69-8F1D-6344F61A093A")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /Hex.VM.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34212.112 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hex.VM", "Hex.VM\Hex.VM.csproj", "{40A83DD8-5878-4433-80DB-B80339E33A6C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hex.VM.Runtime", "Hex.VM.Runtime\Hex.VM.Runtime.csproj", "{CE5E6BBE-61D5-4594-BFCA-7B3305A98F57}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hex.VM.Tests", "Hex.VM.Tests\Hex.VM.Tests.csproj", "{DBC66F83-2BA3-4D69-8F1D-6344F61A093A}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {40A83DD8-5878-4433-80DB-B80339E33A6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {40A83DD8-5878-4433-80DB-B80339E33A6C}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {40A83DD8-5878-4433-80DB-B80339E33A6C}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {40A83DD8-5878-4433-80DB-B80339E33A6C}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {CE5E6BBE-61D5-4594-BFCA-7B3305A98F57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {CE5E6BBE-61D5-4594-BFCA-7B3305A98F57}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {CE5E6BBE-61D5-4594-BFCA-7B3305A98F57}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {CE5E6BBE-61D5-4594-BFCA-7B3305A98F57}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {DBC66F83-2BA3-4D69-8F1D-6344F61A093A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {DBC66F83-2BA3-4D69-8F1D-6344F61A093A}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {DBC66F83-2BA3-4D69-8F1D-6344F61A093A}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {DBC66F83-2BA3-4D69-8F1D-6344F61A093A}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {0685C025-317D-4738-AB25-CEA02D4C525D} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /Hex.VM/Core/Context.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using Hex.VM.Core.Protections; 3 | using Hex.VM.Core.Protections.Impl.UStrings; 4 | using Hex.VM.Core.Protections.Impl.Virtualization; 5 | using Serilog; 6 | using Serilog.Core; 7 | using Serilog.Sinks.SystemConsole.Themes; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | 11 | namespace Hex.VM.Core 12 | { 13 | public class Context 14 | { 15 | public static Context Instance { get; private set; } 16 | public ModuleDefMD Module { get; set; } 17 | public ModuleDefMD RTModule { get; } 18 | public ModuleContext ModuleContext { get; } 19 | public Importer Importer { get; } 20 | 21 | public TypeDef theType = null; 22 | public MethodDef theMethod = null; 23 | 24 | public List Protections { get; } 25 | public List VirtualizedMethods = new List(); 26 | 27 | public Logger Log { get; } 28 | 29 | public Context(string name) 30 | { 31 | Log = new LoggerConfiguration() 32 | .WriteTo.Console(theme: AnsiConsoleTheme.Code) 33 | .CreateLogger(); 34 | 35 | Instance = this; 36 | ModuleContext = ModuleDef.CreateModuleContext(); 37 | Module = ModuleDefMD.Load(name, ModuleContext); 38 | RTModule = ModuleDefMD.Load("Hex.VM.Runtime.dll"); 39 | Importer = new Importer(Module); 40 | Protections = new List() 41 | { 42 | new VStrings(), 43 | new Virtualization() 44 | }; 45 | 46 | this.theType = Instance.RTModule.Types.Where(t => t.FullName.Contains("VirtualMachine")).First(); //VirtualMachine 47 | this.theMethod = theType.Methods.Where(m => m.ReturnType.ToString().Contains("Object")).First(); //RunVM, in case other methods are added. 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Engine.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Writer; 3 | using Hex.VM.Core.Protections; 4 | using System; 5 | using System.IO; 6 | 7 | namespace Hex.VM.Core 8 | { 9 | public class Engine 10 | { 11 | private Context Context { get; set; } 12 | 13 | public void Run(string[] args) 14 | { 15 | string filePath = Path.GetFullPath(args[0]); 16 | Context = new Context(filePath); 17 | 18 | try 19 | { 20 | foreach (IProtection Protection in Context.Protections) 21 | { 22 | Context.Log.Information($"{Protection.Name()} phase.."); 23 | Protection.Execute(Context); 24 | } 25 | } 26 | catch (Exception exc) 27 | { 28 | Context.Log.Error($"Something went wrong while applying virtualization: {exc.Message}"); 29 | } 30 | 31 | string This = "[https://t.me/TheHellTower_Group]"; 32 | 33 | if (Context.Module.Kind == ModuleKind.Dll) 34 | Context.Instance.Module.GlobalType.Name = This; 35 | else if (Context.Module.Kind == ModuleKind.Windows || Context.Module.Kind == ModuleKind.Console) 36 | Context.Instance.Module.EntryPoint.Name = This; 37 | 38 | Save(filePath.Insert(filePath.Length - 4, "-HexVM")); 39 | } 40 | 41 | private void Save(string sp) 42 | { 43 | Console.WriteLine(); 44 | try 45 | { 46 | var opts = new ModuleWriterOptions(Context.Module) { Logger = DummyLogger.NoThrowInstance }; 47 | 48 | opts.MetadataOptions.Flags = MetadataFlags.PreserveAll; 49 | 50 | Context.Module.Write(sp, opts); 51 | 52 | if (File.Exists(sp)) 53 | Context.Log.Information($"Obfuscated file saved as {sp}"); 54 | } 55 | catch (Exception exc) 56 | { 57 | Context.Log.Fatal("Error, could not save: " + exc.Message); 58 | } 59 | 60 | Console.ReadKey(); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Helper/Compression.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Hex.VM.Core.Helper 4 | { 5 | //QuickLZ 6 | internal class Compression 7 | { 8 | public const int QLZ_VERSION_MAJOR = 1; 9 | public const int QLZ_VERSION_MINOR = 5; 10 | public const int QLZ_VERSION_REVISION = 0; 11 | 12 | public const int QLZ_STREAMING_BUFFER = 0; 13 | 14 | public const int QLZ_MEMORY_SAFE = 0; 15 | 16 | // Decrease QLZ_POINTERS_3 to increase level 3 compression speed 17 | private const int HASH_VALUES = 4096; 18 | private const int MINOFFSET = 2; 19 | private const int UNCONDITIONAL_MATCHLEN = 6; 20 | private const int UNCOMPRESSED_END = 4; 21 | private const int CWORD_LEN = 4; 22 | private const int DEFAULT_HEADERLEN = 9; 23 | private const int QLZ_POINTERS_1 = 1; 24 | private const int QLZ_POINTERS_3 = 16; 25 | 26 | private static int headerLen(byte[] source) 27 | { 28 | return ((source[0] & 2) == 2) ? 9 : 3; 29 | } 30 | 31 | public static int sizeDecompressed(byte[] source) 32 | { 33 | if (headerLen(source) == 9) 34 | return source[5] | (source[6] << 8) | (source[7] << 16) | (source[8] << 24); 35 | else 36 | return source[2]; 37 | } 38 | 39 | public static int sizeCompressed(byte[] source) 40 | { 41 | if (headerLen(source) == 9) 42 | return source[1] | (source[2] << 8) | (source[3] << 16) | (source[4] << 24); 43 | else 44 | return source[1]; 45 | } 46 | 47 | private static void write_header(byte[] dst, int level, bool compressible, int size_compressed, int size_decompressed) 48 | { 49 | dst[0] = (byte)(2 | (compressible ? 1 : 0)); 50 | dst[0] |= (byte)(level << 2); 51 | dst[0] |= (1 << 6); 52 | dst[0] |= (0 << 4); 53 | fast_write(dst, 1, size_decompressed, 4); 54 | fast_write(dst, 5, size_compressed, 4); 55 | } 56 | 57 | public static byte[] Compress(byte[] source, int level = 3) 58 | { 59 | int src = 0; 60 | int dst = DEFAULT_HEADERLEN + CWORD_LEN; 61 | uint cword_val = 0x80000000; 62 | int cword_ptr = DEFAULT_HEADERLEN; 63 | byte[] destination = new byte[source.Length + 400]; 64 | int[,] hashtable; 65 | int[] cachetable = new int[HASH_VALUES]; 66 | byte[] hash_counter = new byte[HASH_VALUES]; 67 | byte[] d2; 68 | int fetch = 0; 69 | int last_matchstart = (source.Length - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1); 70 | int lits = 0; 71 | 72 | if (level != 1 && level != 3) 73 | throw new ArgumentException("C# version only supports level 1 and 3"); 74 | 75 | if (level == 1) 76 | hashtable = new int[HASH_VALUES, QLZ_POINTERS_1]; 77 | else 78 | hashtable = new int[HASH_VALUES, QLZ_POINTERS_3]; 79 | 80 | if (source.Length == 0) 81 | return new byte[0]; 82 | 83 | if (src <= last_matchstart) 84 | fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16); 85 | 86 | while (src <= last_matchstart) 87 | { 88 | if ((cword_val & 1) == 1) 89 | { 90 | if (src > source.Length >> 1 && dst > src - (src >> 5)) 91 | { 92 | d2 = new byte[source.Length + DEFAULT_HEADERLEN]; 93 | write_header(d2, level, false, source.Length, source.Length + DEFAULT_HEADERLEN); 94 | System.Array.Copy(source, 0, d2, DEFAULT_HEADERLEN, source.Length); 95 | return d2; 96 | } 97 | 98 | fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4); 99 | cword_ptr = dst; 100 | dst += CWORD_LEN; 101 | cword_val = 0x80000000; 102 | } 103 | 104 | if (level == 1) 105 | { 106 | int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1); 107 | int o = hashtable[hash, 0]; 108 | int cache = cachetable[hash] ^ fetch; 109 | cachetable[hash] = fetch; 110 | hashtable[hash, 0] = src; 111 | 112 | if (cache == 0 && hash_counter[hash] != 0 && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > 3 && source[src] == source[src - 3] && source[src] == source[src - 2] && source[src] == source[src - 1] && source[src] == source[src + 1] && source[src] == source[src + 2]))) 113 | { 114 | cword_val = ((cword_val >> 1) | 0x80000000); 115 | if (source[o + 3] != source[src + 3]) 116 | { 117 | int f = 3 - 2 | (hash << 4); 118 | destination[dst + 0] = (byte)(f >> 0 * 8); 119 | destination[dst + 1] = (byte)(f >> 1 * 8); 120 | src += 3; 121 | dst += 2; 122 | } 123 | else 124 | { 125 | int old_src = src; 126 | int remaining = ((source.Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (source.Length - UNCOMPRESSED_END - src + 1 - 1)); 127 | 128 | src += 4; 129 | if (source[o + src - old_src] == source[src]) 130 | { 131 | src++; 132 | if (source[o + src - old_src] == source[src]) 133 | { 134 | src++; 135 | while (source[o + (src - old_src)] == source[src] && (src - old_src) < remaining) 136 | src++; 137 | } 138 | } 139 | 140 | int matchlen = src - old_src; 141 | 142 | hash <<= 4; 143 | if (matchlen < 18) 144 | { 145 | int f = (hash | (matchlen - 2)); 146 | destination[dst + 0] = (byte)(f >> 0 * 8); 147 | destination[dst + 1] = (byte)(f >> 1 * 8); 148 | dst += 2; 149 | } 150 | else 151 | { 152 | fast_write(destination, dst, hash | (matchlen << 16), 3); 153 | dst += 3; 154 | } 155 | } 156 | fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16); 157 | lits = 0; 158 | } 159 | else 160 | { 161 | lits++; 162 | hash_counter[hash] = 1; 163 | destination[dst] = source[src]; 164 | cword_val = (cword_val >> 1); 165 | src++; 166 | dst++; 167 | fetch = ((fetch >> 8) & 0xffff) | (source[src + 2] << 16); 168 | } 169 | 170 | } 171 | else 172 | { 173 | fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16); 174 | 175 | int o, offset2; 176 | int matchlen, k, m, best_k = 0; 177 | byte c; 178 | int remaining = ((source.Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (source.Length - UNCOMPRESSED_END - src + 1 - 1)); 179 | int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1); 180 | 181 | c = hash_counter[hash]; 182 | matchlen = 0; 183 | offset2 = 0; 184 | for (k = 0; k < QLZ_POINTERS_3 && c > k; k++) 185 | { 186 | o = hashtable[hash, k]; 187 | if ((byte)fetch == source[o] && (byte)(fetch >> 8) == source[o + 1] && (byte)(fetch >> 16) == source[o + 2] && o < src - MINOFFSET) 188 | { 189 | m = 3; 190 | while (source[o + m] == source[src + m] && m < remaining) 191 | m++; 192 | if ((m > matchlen) || (m == matchlen && o > offset2)) 193 | { 194 | offset2 = o; 195 | matchlen = m; 196 | best_k = k; 197 | } 198 | } 199 | } 200 | o = offset2; 201 | hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src; 202 | c++; 203 | hash_counter[hash] = c; 204 | 205 | if (matchlen >= 3 && src - o < 131071) 206 | { 207 | int offset = src - o; 208 | 209 | for (int u = 1; u < matchlen; u++) 210 | { 211 | fetch = source[src + u] | (source[src + u + 1] << 8) | (source[src + u + 2] << 16); 212 | hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1); 213 | c = hash_counter[hash]++; 214 | hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src + u; 215 | } 216 | 217 | src += matchlen; 218 | cword_val = ((cword_val >> 1) | 0x80000000); 219 | 220 | if (matchlen == 3 && offset <= 63) 221 | { 222 | fast_write(destination, dst, offset << 2, 1); 223 | dst++; 224 | } 225 | else if (matchlen == 3 && offset <= 16383) 226 | { 227 | fast_write(destination, dst, (offset << 2) | 1, 2); 228 | dst += 2; 229 | } 230 | else if (matchlen <= 18 && offset <= 1023) 231 | { 232 | fast_write(destination, dst, ((matchlen - 3) << 2) | (offset << 6) | 2, 2); 233 | dst += 2; 234 | } 235 | else if (matchlen <= 33) 236 | { 237 | fast_write(destination, dst, ((matchlen - 2) << 2) | (offset << 7) | 3, 3); 238 | dst += 3; 239 | } 240 | else 241 | { 242 | fast_write(destination, dst, ((matchlen - 3) << 7) | (offset << 15) | 3, 4); 243 | dst += 4; 244 | } 245 | lits = 0; 246 | } 247 | else 248 | { 249 | destination[dst] = source[src]; 250 | cword_val = (cword_val >> 1); 251 | src++; 252 | dst++; 253 | } 254 | } 255 | } 256 | while (src <= source.Length - 1) 257 | { 258 | if ((cword_val & 1) == 1) 259 | { 260 | fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4); 261 | cword_ptr = dst; 262 | dst += CWORD_LEN; 263 | cword_val = 0x80000000; 264 | } 265 | 266 | destination[dst] = source[src]; 267 | src++; 268 | dst++; 269 | cword_val = (cword_val >> 1); 270 | } 271 | while ((cword_val & 1) != 1) 272 | { 273 | cword_val = (cword_val >> 1); 274 | } 275 | fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), CWORD_LEN); 276 | write_header(destination, level, true, source.Length, dst); 277 | d2 = new byte[dst]; 278 | System.Array.Copy(destination, d2, dst); 279 | return d2; 280 | } 281 | 282 | 283 | private static void fast_write(byte[] a, int i, int value, int numbytes) 284 | { 285 | for (int j = 0; j < numbytes; j++) 286 | a[i + j] = (byte)(value >> (j * 8)); 287 | } 288 | 289 | public static byte[] Decompress(byte[] source) 290 | { 291 | int level; 292 | int size = sizeDecompressed(source); 293 | int src = headerLen(source); 294 | int dst = 0; 295 | uint cword_val = 1; 296 | byte[] destination = new byte[size]; 297 | int[] hashtable = new int[4096]; 298 | byte[] hash_counter = new byte[4096]; 299 | int last_matchstart = size - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1; 300 | int last_hashed = -1; 301 | int hash; 302 | uint fetch = 0; 303 | 304 | level = (source[0] >> 2) & 0x3; 305 | 306 | if (level != 1 && level != 3) 307 | throw new ArgumentException("C# version only supports level 1 and 3"); 308 | 309 | if ((source[0] & 1) != 1) 310 | { 311 | byte[] d2 = new byte[size]; 312 | System.Array.Copy(source, headerLen(source), d2, 0, size); 313 | return d2; 314 | } 315 | 316 | for (; ; ) 317 | { 318 | if (cword_val == 1) 319 | { 320 | cword_val = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24)); 321 | src += 4; 322 | if (dst <= last_matchstart) 323 | { 324 | if (level == 1) 325 | fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16)); 326 | else 327 | fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24)); 328 | } 329 | } 330 | 331 | if ((cword_val & 1) == 1) 332 | { 333 | uint matchlen; 334 | uint offset2; 335 | 336 | cword_val = cword_val >> 1; 337 | 338 | if (level == 1) 339 | { 340 | hash = ((int)fetch >> 4) & 0xfff; 341 | offset2 = (uint)hashtable[hash]; 342 | 343 | if ((fetch & 0xf) != 0) 344 | { 345 | matchlen = (fetch & 0xf) + 2; 346 | src += 2; 347 | } 348 | else 349 | { 350 | matchlen = source[src + 2]; 351 | src += 3; 352 | } 353 | } 354 | else 355 | { 356 | uint offset; 357 | if ((fetch & 3) == 0) 358 | { 359 | offset = (fetch & 0xff) >> 2; 360 | matchlen = 3; 361 | src++; 362 | } 363 | else if ((fetch & 2) == 0) 364 | { 365 | offset = (fetch & 0xffff) >> 2; 366 | matchlen = 3; 367 | src += 2; 368 | } 369 | else if ((fetch & 1) == 0) 370 | { 371 | offset = (fetch & 0xffff) >> 6; 372 | matchlen = ((fetch >> 2) & 15) + 3; 373 | src += 2; 374 | } 375 | else if ((fetch & 127) != 3) 376 | { 377 | offset = (fetch >> 7) & 0x1ffff; 378 | matchlen = ((fetch >> 2) & 0x1f) + 2; 379 | src += 3; 380 | } 381 | else 382 | { 383 | offset = (fetch >> 15); 384 | matchlen = ((fetch >> 7) & 255) + 3; 385 | src += 4; 386 | } 387 | offset2 = (uint)(dst - offset); 388 | } 389 | 390 | destination[dst + 0] = destination[offset2 + 0]; 391 | destination[dst + 1] = destination[offset2 + 1]; 392 | destination[dst + 2] = destination[offset2 + 2]; 393 | 394 | for (int i = 3; i < matchlen; i += 1) 395 | { 396 | destination[dst + i] = destination[offset2 + i]; 397 | } 398 | 399 | dst += (int)matchlen; 400 | 401 | if (level == 1) 402 | { 403 | fetch = (uint)(destination[last_hashed + 1] | (destination[last_hashed + 2] << 8) | (destination[last_hashed + 3] << 16)); 404 | while (last_hashed < dst - matchlen) 405 | { 406 | last_hashed++; 407 | hash = (int)(((fetch >> 12) ^ fetch) & (HASH_VALUES - 1)); 408 | hashtable[hash] = last_hashed; 409 | hash_counter[hash] = 1; 410 | fetch = (uint)(fetch >> 8 & 0xffff | destination[last_hashed + 3] << 16); 411 | } 412 | fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16)); 413 | } 414 | else 415 | { 416 | fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24)); 417 | } 418 | last_hashed = dst - 1; 419 | } 420 | else 421 | { 422 | if (dst <= last_matchstart) 423 | { 424 | destination[dst] = source[src]; 425 | dst += 1; 426 | src += 1; 427 | cword_val = cword_val >> 1; 428 | 429 | if (level == 1) 430 | { 431 | while (last_hashed < dst - 3) 432 | { 433 | last_hashed++; 434 | int fetch2 = destination[last_hashed] | (destination[last_hashed + 1] << 8) | (destination[last_hashed + 2] << 16); 435 | hash = ((fetch2 >> 12) ^ fetch2) & (HASH_VALUES - 1); 436 | hashtable[hash] = last_hashed; 437 | hash_counter[hash] = 1; 438 | } 439 | fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16); 440 | } 441 | else 442 | { 443 | fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16 | source[src + 3] << 24); 444 | } 445 | } 446 | else 447 | { 448 | while (dst <= size - 1) 449 | { 450 | if (cword_val == 1) 451 | { 452 | src += CWORD_LEN; 453 | cword_val = 0x80000000; 454 | } 455 | 456 | destination[dst] = source[src]; 457 | dst++; 458 | src++; 459 | cword_val = cword_val >> 1; 460 | } 461 | return destination; 462 | } 463 | } 464 | } 465 | } 466 | } 467 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Helper/Generator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Hex.VM.Core.Helper 4 | { 5 | public class Generator 6 | { 7 | public static Random Random = new Random(); 8 | public static string RandomName() => $"[{Guid.NewGuid().ToString().ToUpper()}]".Replace("[", "{").Replace("]", "}"); 9 | public static int NextInt(int min, int max) => new Random(Guid.NewGuid().GetHashCode()).Next(min, max + 1); 10 | } 11 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Helper/InjectHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using dnlib.DotNet; 5 | using dnlib.DotNet.Emit; 6 | using Hex.VM.Runtime; 7 | 8 | namespace Hex.VM.Core.Helper 9 | { 10 | public static class InjectHelper 11 | { 12 | /// 13 | /// Clones the specified origin TypeDef. 14 | /// 15 | /// The origin TypeDef. 16 | /// The cloned TypeDef. 17 | static TypeDefUser Clone(TypeDef origin) 18 | { 19 | var ret = new TypeDefUser(origin.Namespace, origin.Name); 20 | ret.Attributes = origin.Attributes; 21 | 22 | if (origin.ClassLayout != null) 23 | ret.ClassLayout = new ClassLayoutUser(origin.ClassLayout.PackingSize, origin.ClassSize); 24 | 25 | foreach (GenericParam genericParam in origin.GenericParameters) 26 | ret.GenericParameters.Add(new GenericParamUser(genericParam.Number, genericParam.Flags, "-")); 27 | 28 | return ret; 29 | } 30 | 31 | /// 32 | /// Clones the specified origin MethodDef. 33 | /// 34 | /// The origin MethodDef. 35 | /// The cloned MethodDef. 36 | static MethodDefUser Clone(MethodDef origin) 37 | { 38 | var ret = new MethodDefUser(origin.Name, null, origin.ImplAttributes, origin.Attributes); 39 | 40 | foreach (GenericParam genericParam in origin.GenericParameters) 41 | ret.GenericParameters.Add(new GenericParamUser(genericParam.Number, genericParam.Flags, "-")); 42 | 43 | return ret; 44 | } 45 | 46 | /// 47 | /// Clones the specified origin FieldDef. 48 | /// 49 | /// The origin FieldDef. 50 | /// The cloned FieldDef. 51 | static FieldDefUser Clone(FieldDef origin) 52 | { 53 | var ret = new FieldDefUser(origin.Name, null, origin.Attributes); 54 | return ret; 55 | } 56 | 57 | /// 58 | /// Populates the context mappings. 59 | /// 60 | /// The origin TypeDef. 61 | /// The injection context. 62 | /// The new TypeDef. 63 | static TypeDef PopulateContext(TypeDef typeDef, InjectContext ctx) 64 | { 65 | var ret = ctx.Map(typeDef)?.ResolveTypeDef(); 66 | if (ret is null) 67 | { 68 | ret = Clone(typeDef); 69 | ctx.DefMap[typeDef] = ret; 70 | } 71 | 72 | foreach (TypeDef nestedType in typeDef.NestedTypes) 73 | ret.NestedTypes.Add(PopulateContext(nestedType, ctx)); 74 | 75 | foreach (MethodDef method in typeDef.Methods) 76 | ret.Methods.Add((MethodDef)(ctx.DefMap[method] = Clone(method))); 77 | 78 | foreach (FieldDef field in typeDef.Fields) 79 | ret.Fields.Add((FieldDef)(ctx.DefMap[field] = Clone(field))); 80 | 81 | return ret; 82 | } 83 | 84 | /// 85 | /// Copies the information from the origin type to injected type. 86 | /// 87 | /// The origin TypeDef. 88 | /// The injection context. 89 | static void CopyTypeDef(TypeDef typeDef, InjectContext ctx) 90 | { 91 | var newTypeDef = ctx.Map(typeDef)?.ResolveTypeDefThrow(); 92 | newTypeDef.BaseType = ctx.Importer.Import(typeDef.BaseType); 93 | 94 | foreach (InterfaceImpl iface in typeDef.Interfaces) 95 | newTypeDef.Interfaces.Add(new InterfaceImplUser(ctx.Importer.Import(iface.Interface))); 96 | } 97 | 98 | /// 99 | /// Copies the information from the origin method to injected method. 100 | /// 101 | /// The origin MethodDef. 102 | /// The injection context. 103 | static void CopyMethodDef(MethodDef methodDef, InjectContext ctx) 104 | { 105 | var newMethodDef = ctx.Map(methodDef)?.ResolveMethodDefThrow(); 106 | 107 | newMethodDef.Signature = ctx.Importer.Import(methodDef.Signature); 108 | newMethodDef.Parameters.UpdateParameterTypes(); 109 | 110 | foreach (var paramDef in methodDef.ParamDefs) 111 | newMethodDef.ParamDefs.Add(new ParamDefUser(paramDef.Name, paramDef.Sequence, paramDef.Attributes)); 112 | 113 | if (methodDef.ImplMap != null) 114 | newMethodDef.ImplMap = new ImplMapUser(new ModuleRefUser(ctx.TargetModule, methodDef.ImplMap.Module.Name), methodDef.ImplMap.Name, methodDef.ImplMap.Attributes); 115 | 116 | foreach (CustomAttribute ca in methodDef.CustomAttributes) 117 | newMethodDef.CustomAttributes.Add(new CustomAttribute((ICustomAttributeType)ctx.Importer.Import(ca.Constructor))); 118 | 119 | if (methodDef.HasBody) 120 | CopyMethodBody(methodDef, ctx, newMethodDef); 121 | } 122 | 123 | static void CopyMethodBody(MethodDef methodDef, InjectContext ctx, MethodDef newMethodDef) 124 | { 125 | newMethodDef.Body = new CilBody(methodDef.Body.InitLocals, new List(), 126 | new List(), new List()) 127 | { MaxStack = methodDef.Body.MaxStack }; 128 | 129 | var bodyMap = new Dictionary(); 130 | 131 | foreach (Local local in methodDef.Body.Variables) 132 | { 133 | var newLocal = new Local(ctx.Importer.Import(local.Type)); 134 | newMethodDef.Body.Variables.Add(newLocal); 135 | newLocal.Name = local.Name; 136 | 137 | bodyMap[local] = newLocal; 138 | } 139 | 140 | foreach (Instruction instr in methodDef.Body.Instructions) 141 | { 142 | var newInstr = new Instruction(instr.OpCode, instr.Operand) 143 | { 144 | SequencePoint = instr.SequencePoint 145 | }; 146 | 147 | switch (newInstr.Operand) 148 | { 149 | case IType type: 150 | newInstr.Operand = ctx.Importer.Import(type); 151 | break; 152 | case IMethod method: 153 | newInstr.Operand = ctx.Importer.Import(method); 154 | break; 155 | case IField field: 156 | newInstr.Operand = ctx.Importer.Import(field); 157 | break; 158 | } 159 | 160 | newMethodDef.Body.Instructions.Add(newInstr); 161 | bodyMap[instr] = newInstr; 162 | } 163 | 164 | foreach (Instruction instr in newMethodDef.Body.Instructions) 165 | { 166 | if (instr.Operand != null && bodyMap.ContainsKey(instr.Operand)) 167 | instr.Operand = bodyMap[instr.Operand]; 168 | else if (instr.Operand is Instruction[] instructions) 169 | instr.Operand = instructions.Select(target => (Instruction)bodyMap[target]).ToArray(); 170 | } 171 | 172 | foreach (ExceptionHandler eh in methodDef.Body.ExceptionHandlers) 173 | newMethodDef.Body.ExceptionHandlers.Add(new ExceptionHandler(eh.HandlerType) 174 | { 175 | CatchType = eh.CatchType == null ? null : ctx.Importer.Import(eh.CatchType), 176 | TryStart = (Instruction)bodyMap[eh.TryStart], 177 | TryEnd = (Instruction)bodyMap[eh.TryEnd], 178 | HandlerStart = (Instruction)bodyMap[eh.HandlerStart], 179 | HandlerEnd = (Instruction)bodyMap[eh.HandlerEnd], 180 | FilterStart = eh.FilterStart == null ? null : (Instruction)bodyMap[eh.FilterStart] 181 | }); 182 | 183 | newMethodDef.Body.SimplifyMacros(newMethodDef.Parameters); 184 | } 185 | 186 | /// 187 | /// Copies the information from the origin field to injected field. 188 | /// 189 | /// The origin FieldDef. 190 | /// The injection context. 191 | static void CopyFieldDef(FieldDef fieldDef, InjectContext ctx) 192 | { 193 | var newFieldDef = ctx.Map(fieldDef).ResolveFieldDefThrow(); 194 | 195 | newFieldDef.Signature = ctx.Importer.Import(fieldDef.Signature); 196 | } 197 | 198 | /// 199 | /// Copies the information to the injected definitions. 200 | /// 201 | /// The origin TypeDef. 202 | /// The injection context. 203 | /// if set to true, copy information of . 204 | static void Copy(TypeDef typeDef, InjectContext ctx, bool copySelf) 205 | { 206 | if (copySelf) 207 | CopyTypeDef(typeDef, ctx); 208 | 209 | foreach (TypeDef nestedType in typeDef.NestedTypes) 210 | Copy(nestedType, ctx, true); 211 | 212 | foreach (MethodDef method in typeDef.Methods) 213 | CopyMethodDef(method, ctx); 214 | 215 | foreach (FieldDef field in typeDef.Fields) 216 | CopyFieldDef(field, ctx); 217 | } 218 | 219 | /// 220 | /// Injects the specified TypeDef to another module. 221 | /// 222 | /// The source TypeDef. 223 | /// The target module. 224 | /// The injected TypeDef. 225 | public static TypeDef Inject(TypeDef typeDef, ModuleDef target) 226 | { 227 | var ctx = new InjectContext(typeDef.Module, target); 228 | var result = PopulateContext(typeDef, ctx); 229 | Copy(typeDef, ctx, true); 230 | return result; 231 | } 232 | 233 | /// 234 | /// Injects the specified MethodDef to another module. 235 | /// 236 | /// The source MethodDef. 237 | /// The target module. 238 | /// The injected MethodDef. 239 | public static MethodDef Inject(MethodDef methodDef, ModuleDef target) 240 | { 241 | var ctx = new InjectContext(methodDef.Module, target); 242 | MethodDef result; 243 | ctx.DefMap[methodDef] = result = Clone(methodDef); 244 | CopyMethodDef(methodDef, ctx); 245 | return result; 246 | } 247 | 248 | /// 249 | /// Injects the members of specified TypeDef to another module. 250 | /// 251 | /// The source TypeDef. 252 | /// The new type. 253 | /// The target module. 254 | /// Injected members. 255 | public static IEnumerable Inject(TypeDef typeDef, TypeDef newType, ModuleDef target) 256 | { 257 | var ctx = new InjectContext(typeDef.Module, target); 258 | ctx.DefMap[typeDef] = newType; 259 | PopulateContext(typeDef, ctx); 260 | Copy(typeDef, ctx, false); 261 | return ctx.DefMap.Values.Except(new[] { newType }).OfType(); 262 | } 263 | 264 | 265 | // https://stackoverflow.com/questions/949246/how-can-i-get-all-classes-within-a-namespace 266 | public static Type[] GetTypesInNamespace(string nameSpace) 267 | { 268 | return 269 | typeof(VirtualMachine).Assembly.GetTypes() 270 | .Where(t => String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal)) 271 | .ToArray(); 272 | } 273 | 274 | public static List InjectNamespaces(string[] names) 275 | { 276 | var list = new List(); 277 | foreach (var ns in names) 278 | { 279 | foreach(var type in GetTypesInNamespace(ns)) 280 | { 281 | InjectType(type); 282 | list.Add(type.FullName); 283 | } 284 | } 285 | 286 | return list; 287 | } 288 | 289 | public static void InjectType(Type type) 290 | { 291 | var typeToInject = ModuleDefMD.Load(type.Module); 292 | var typeDef = typeToInject.ResolveTypeDef(MDToken.ToRID(type.MetadataToken)); // class 293 | var newTypeDef = new TypeDefUser(type.Namespace, type.Name, typeDef.BaseType); 294 | Context.Instance.Module.Types.Add(newTypeDef); // add class 295 | Inject(typeDef, newTypeDef, Context.Instance.Module); 296 | } 297 | 298 | /// 299 | /// Context of the injection process. 300 | /// 301 | private class InjectContext : ImportMapper 302 | { 303 | /// 304 | /// The mapping of origin definitions to injected definitions. 305 | /// 306 | public readonly Dictionary DefMap = new Dictionary(); 307 | 308 | /// 309 | /// The module which source type originated from. 310 | /// 311 | public readonly ModuleDef OriginModule; 312 | 313 | /// 314 | /// The module which source type is being injected to. 315 | /// 316 | public readonly ModuleDef TargetModule; 317 | 318 | /// 319 | /// Initializes a new instance of the class. 320 | /// 321 | /// The origin module. 322 | /// The target module. 323 | public InjectContext(ModuleDef module, ModuleDef target) 324 | { 325 | OriginModule = module; 326 | TargetModule = target; 327 | Importer = new Importer(target, ImporterOptions.TryToUseTypeDefs, new GenericParamContext(), this); 328 | } 329 | 330 | /// 331 | /// Gets the importer. 332 | /// 333 | /// The importer. 334 | public Importer Importer { get; } 335 | 336 | /// 337 | public override ITypeDefOrRef Map(ITypeDefOrRef source) 338 | { 339 | if (DefMap.TryGetValue(source, out var mappedRef)) 340 | return mappedRef as ITypeDefOrRef; 341 | 342 | // check if the assembly reference needs to be fixed. 343 | if (source is TypeRef sourceRef) 344 | { 345 | var targetAssemblyRef = TargetModule.GetAssemblyRef(sourceRef.DefinitionAssembly.Name); 346 | if (!(targetAssemblyRef is null) && !string.Equals(targetAssemblyRef.FullName, source.DefinitionAssembly.FullName, StringComparison.Ordinal)) 347 | { 348 | // We got a matching assembly by the simple name, but not by the full name. 349 | // This means the injected code uses a different assembly version than the target assembly. 350 | // We'll fix the assembly reference, to avoid breaking anything. 351 | var fixedTypeRef = new TypeRefUser(sourceRef.Module, sourceRef.Namespace, sourceRef.Name, targetAssemblyRef); 352 | return Importer.Import(fixedTypeRef); 353 | } 354 | } 355 | return null; 356 | } 357 | 358 | /// 359 | public override IMethod Map(MethodDef source) 360 | { 361 | if (DefMap.TryGetValue(source, out var mappedRef)) 362 | return mappedRef as IMethod; 363 | return null; 364 | } 365 | 366 | /// 367 | public override IField Map(FieldDef source) 368 | { 369 | if (DefMap.TryGetValue(source, out var mappedRef)) 370 | return mappedRef as IField; 371 | return null; 372 | } 373 | 374 | public override MemberRef Map(MemberRef source) 375 | { 376 | if (DefMap.TryGetValue(source, out var mappedRef)) 377 | return mappedRef as MemberRef; 378 | return null; 379 | } 380 | } 381 | } 382 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/IProtection.cs: -------------------------------------------------------------------------------- 1 | namespace Hex.VM.Core.Protections 2 | { 3 | public abstract class IProtection 4 | { 5 | public abstract string Name(); 6 | public abstract void Execute(Context context); 7 | } 8 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/Impl/UStrings/Runtime.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO.Compression; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Diagnostics; 9 | using dnlib.W32Resources; 10 | using Hex.VM.Runtime.Handler.Impl; 11 | 12 | public static class Runtime 13 | { 14 | 15 | public static string Recover(string processedStr) 16 | { 17 | /*var Method = new StackTrace().GetFrame(1)!.GetMethod(); 18 | int MDToken = Method.MetadataToken; 19 | int MaxStack = Method.GetMethodBody().MaxStackSize;*/ 20 | 21 | byte[] data = processedStr.Split('|').Select(s => byte.Parse(s)).ToArray(); 22 | 23 | using (MemoryStream input = new MemoryStream(data)) 24 | using (DeflateStream dstream = new DeflateStream(input, CompressionMode.Decompress)) 25 | using (MemoryStream output = new MemoryStream()) 26 | { 27 | dstream.CopyTo(output); 28 | 29 | data = output.ToArray(); 30 | /*for (var i = 0; i < data.Length; i++) 31 | { 32 | //data[i] = (byte)((byte)((BitConverter.GetBytes(MDToken ^ MaxStack)[i % sizeof(int)] ^ (data[i])))); 33 | data[i] = (byte)((byte)((BitConverter.GetBytes(test)[i % sizeof(int)] ^ (data[i])))); 34 | }*/ 35 | 36 | return Encoding.UTF8.GetString(data); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/Impl/UStrings/VStrings.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using Hex.VM.Core.Helper; 4 | using System; 5 | using System.IO.Compression; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Data; 10 | using Hex.VM.Runtime.Handler.Impl; 11 | using dnlib.DotNet.Writer; 12 | 13 | namespace Hex.VM.Core.Protections.Impl.UStrings 14 | { 15 | public class VStrings : IProtection 16 | { 17 | private static MethodDef StringRecover = null; 18 | 19 | public static string Process(string str, int MDToken, int MaxStack) 20 | { 21 | byte[] data = Encoding.UTF8.GetBytes(str); 22 | 23 | /*for (var i = 0; i < data.Length; i++) 24 | data[i] = (byte)((byte)((BitConverter.GetBytes(MDToken ^ MaxStack)[i % sizeof(int)] ^ (data[i]))));*/ 25 | 26 | MemoryStream output = new MemoryStream(); 27 | using (DeflateStream dstream = new DeflateStream(output, CompressionLevel.Optimal)) 28 | dstream.Write(data, 0, data.Length); 29 | 30 | return string.Join("|", output.ToArray().Select(b => b.ToString())); 31 | } 32 | 33 | private static int Processed = 0; 34 | 35 | public override string Name() => "Strings"; 36 | public override void Execute(Context context) 37 | { 38 | #region "Inject Runtime" 39 | var Self = ModuleDefMD.Load(typeof(VStrings).Module); 40 | 41 | TypeDef StrType = Self.ResolveTypeDef(MDToken.ToRID(typeof(global::Runtime).MetadataToken)); 42 | 43 | StringRecover = (MethodDef)InjectHelper.Inject(StrType, context.Module.GlobalType, context.Module).First(M => M.Name == "Recover"); 44 | 45 | StringRecover.Name = Generator.RandomName(); 46 | #endregion 47 | 48 | #region "Process Module" 49 | foreach (var Type in context.Module.Types.Where(t => t.Methods.Count > 0).ToArray()) 50 | { 51 | foreach (var Method in Type.Methods.Where(M => M.HasBody && M.Body.HasInstructions && M.Body.Instructions.Count() > 1).ToArray()) 52 | { 53 | Instruction[] Instructions = Method.Body.Instructions.ToArray(); 54 | for (int i = 0; i < Instructions.Count(); i++) 55 | { 56 | Instruction Instruction = Instructions[i]; 57 | if (Instruction.OpCode != OpCodes.Ldstr || Instruction.Operand == null) 58 | continue; 59 | 60 | if (Instruction.Operand.ToString().Length > 1) 61 | { 62 | Instruction.Operand = Process(Instruction.Operand.ToString(), Method.MDToken.ToInt32(), Method.Body.MaxStack); 63 | 64 | Method.Body.Instructions.Insert(Method.Body.Instructions.IndexOf(Instruction) + 1, new Instruction(OpCodes.Call, context.Module.Import(StringRecover))); 65 | 66 | Processed++; 67 | continue; 68 | } 69 | 70 | } 71 | 72 | Method.Body.Instructions.OptimizeMacros(); 73 | Method.Body.Instructions.SimplifyBranches(); 74 | } 75 | } 76 | #endregion 77 | 78 | context.Log.Information($"{Processed} Virtualized Strings"); 79 | 80 | MemoryStream MS = new MemoryStream(); 81 | ModuleWriterOptions ModuleWriterOptions = new ModuleWriterOptions(context.Module) { Logger = DummyLogger.NoThrowInstance }; 82 | ModuleWriterOptions.MetadataOptions.Flags = MetadataFlags.PreserveAll; 83 | context.Module.Write(MS, ModuleWriterOptions); 84 | context.Module = ModuleDefMD.Load(MS); 85 | MS.Dispose(); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/Impl/Virtualization/RuntimeProtections/CFlow.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace Hex.VM.Core.Protections.Impl.Virtualization.RuntimeProtections 8 | { 9 | internal static class CFlow 10 | { 11 | internal static void Execute(ModuleDefMD Module) 12 | { 13 | foreach (TypeDef Type in Module.GetTypes().Where(T => T.HasMethods).ToArray()) 14 | foreach (MethodDef Method in Type.Methods.Where(M => M.HasBody && M.Body.HasInstructions && M.Body.Instructions.Count() > 1 && !M.IsSetter && !M.IsGetter).ToArray()) 15 | { 16 | if (Method == Module.GlobalType.FindOrCreateStaticConstructor()) continue; 17 | //Method.Body.SimplifyBranches(); 18 | Method.Body.SimplifyMacros(Method.Parameters); 19 | List blocks = BlockParser.ParseMethod(Method); 20 | blocks = Randomize(blocks); 21 | Method.Body.Instructions.Clear(); 22 | Local local = new Local(Module.CorLibTypes.Int32); 23 | Method.Body.Variables.Add(local); 24 | Instruction target = Instruction.Create(OpCodes.Nop); 25 | Instruction instr = Instruction.Create(OpCodes.Br, target); 26 | foreach (Instruction instruction in Calc(0)) 27 | Method.Body.Instructions.Add(instruction); 28 | Method.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc, local)); 29 | Method.Body.Instructions.Add(Instruction.Create(OpCodes.Br, instr)); 30 | Method.Body.Instructions.Add(target); 31 | foreach (Block block in blocks) 32 | if (block != blocks.Single(x => x.Number == blocks.Count - 1)) 33 | { 34 | Method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc, local)); 35 | foreach (Instruction instruction in Calc(block.Number)) 36 | Method.Body.Instructions.Add(instruction); 37 | Method.Body.Instructions.Add(Instruction.Create(OpCodes.Ceq)); 38 | Instruction instruction4 = Instruction.Create(OpCodes.Nop); 39 | Method.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse, instruction4)); 40 | foreach (Instruction instruction in block.Instructions) 41 | Method.Body.Instructions.Add(instruction); 42 | foreach (Instruction instruction in Calc(block.Number + 1)) 43 | Method.Body.Instructions.Add(instruction); 44 | 45 | Method.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc, local)); 46 | Method.Body.Instructions.Add(instruction4); 47 | } 48 | 49 | Method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc, local)); 50 | foreach (Instruction instruction in Calc(blocks.Count - 1)) 51 | Method.Body.Instructions.Add(instruction); 52 | Method.Body.Instructions.Add(Instruction.Create(OpCodes.Ceq)); 53 | Method.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse, instr)); 54 | Method.Body.Instructions.Add(Instruction.Create(OpCodes.Br, blocks.Single(x => x.Number == blocks.Count - 1).Instructions[0])); 55 | Method.Body.Instructions.Add(instr); 56 | foreach (Instruction lastBlock in blocks.Single(x => x.Number == blocks.Count - 1).Instructions) 57 | Method.Body.Instructions.Add(lastBlock); 58 | } 59 | } 60 | 61 | public class Block 62 | { 63 | public Block() => Instructions = new List(); 64 | public List Instructions { get; set; } 65 | 66 | public int Number { get; set; } 67 | public int Next { get; set; } 68 | } 69 | public class BlockParser 70 | { 71 | public static List ParseMethod(MethodDef method) 72 | { 73 | List blocks = new List(); 74 | List body = new List(method.Body.Instructions); 75 | 76 | Block block = new Block(); 77 | int Id = 0; 78 | int usage = 0; 79 | block.Number = Id; 80 | block.Instructions.Add(Instruction.Create(OpCodes.Nop)); 81 | blocks.Add(block); 82 | block = new Block(); 83 | Stack handlers = new Stack(); 84 | foreach (Instruction instruction in method.Body.Instructions) 85 | { 86 | foreach (ExceptionHandler eh in method.Body.ExceptionHandlers) 87 | if (eh.HandlerStart == instruction || eh.TryStart == instruction || eh.FilterStart == instruction) 88 | handlers.Push(eh); 89 | 90 | foreach (ExceptionHandler eh in method.Body.ExceptionHandlers) 91 | if (eh.HandlerEnd == instruction || eh.TryEnd == instruction) 92 | handlers.Pop(); 93 | 94 | int stacks, pops; 95 | instruction.CalculateStackUsage(out stacks, out pops); 96 | block.Instructions.Add(instruction); 97 | usage += stacks - pops; 98 | if (stacks == 0) 99 | if (instruction.OpCode != OpCodes.Nop) 100 | if ((usage == 0 || instruction.OpCode == OpCodes.Ret) && handlers.Count == 0) 101 | { 102 | block.Number = ++Id; 103 | blocks.Add(block); 104 | block = new Block(); 105 | } 106 | } 107 | 108 | return blocks; 109 | } 110 | } 111 | public static List Randomize(List input) 112 | { 113 | List ret = new List(); 114 | foreach (Block group in input) 115 | ret.Insert(new Random().Next(0, ret.Count), group); 116 | return ret; 117 | } 118 | 119 | public static List Calc(int value) 120 | { 121 | List instructions = new List(); 122 | instructions.Add(Instruction.Create(OpCodes.Ldc_I4, value)); 123 | return instructions; 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/Impl/Virtualization/RuntimeProtections/CallToCalli.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace Hex.VM.Core.Protections.Impl.Virtualization.RuntimeProtections 7 | { 8 | internal static class CallToCalli 9 | { 10 | private static List Blacklist = new List() { "GetMethodParameters" }; //Issues when applied 11 | internal static void Execute(ModuleDefMD Module) 12 | { 13 | if(Module == Context.Instance.RTModule) 14 | { 15 | foreach (var Type in Module.GetTypes().Where(T => T.HasMethods && !T.IsGlobalModuleType && !T.Name.Contains("AssemblyLoader")).ToArray()) 16 | foreach (var Method in Type.Methods.Where(M => M.HasBody && M.Body.HasInstructions && !Blacklist.Contains(M.Name)).ToArray()) 17 | Process(Method); 18 | } else 19 | { 20 | foreach (var Method in Module.GlobalType.Methods.Where(M => M.HasBody && M.Body.HasInstructions).ToArray()) 21 | Process(Method); 22 | } 23 | } 24 | internal static void Process(MethodDef Method) 25 | { 26 | for (var i = 0; i < Method.Body.Instructions.Count; i++) 27 | { 28 | Instruction Instruction = Method.Body.Instructions[i]; 29 | if (Instruction.OpCode == OpCodes.Call) 30 | if (Instruction.Operand is MethodDef M) 31 | { 32 | Method.Body.Instructions[i] = new Instruction(OpCodes.Ldftn, M); 33 | Method.Body.Instructions.Insert(i + 1, new Instruction(OpCodes.Nop)); 34 | Method.Body.Instructions.Insert(i + 2, new Instruction(OpCodes.Calli, M.MethodSig)); 35 | } 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/Impl/Virtualization/RuntimeProtections/ProxyInteger.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using Hex.VM.Core.Helper; 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace Hex.VM.Core.Protections.Impl.Virtualization.RuntimeProtections 10 | { 11 | internal static class ProxyInteger 12 | { 13 | private static Hashtable HT = null; 14 | private static List BlacklistTypes = new List() { "<>c", "Ceq", "HxCgt", "Factory" }; //Issues when applied 15 | private static List BlacklistMethods = new List() { "RotateKey" }; //Issues when applied 16 | internal static void Execute(ModuleDef Module) 17 | { 18 | HT = new Hashtable(); 19 | MethodDef cctor = Module.GlobalType.FindOrCreateStaticConstructor(); 20 | foreach (var Type in Module.GetTypes().Where(T => T.HasMethods && !T.IsGlobalModuleType && !BlacklistTypes.Contains(T.Name) && !T.Name.Contains("AssemblyLoader")).ToArray()) 21 | foreach (var Method in Type.Methods.Where(M => M.HasBody && M.Body.HasInstructions && !BlacklistMethods.Contains(M.Name)).ToArray()) 22 | { 23 | if (Module == Context.Instance.Module && !Context.Instance.VirtualizedMethods.Contains(Method.FullName)) 24 | continue; 25 | try 26 | { 27 | for (var i = 0; i < Method.Body.Instructions.Count; i++) 28 | { 29 | Instruction Instruction = Method.Body.Instructions[i]; 30 | if (Instruction.IsLdcI4()) 31 | { 32 | FieldDef F = null; 33 | MethodDef M = null; 34 | if (!HT.ContainsKey(Instruction.Operand)) 35 | { 36 | FieldDefUser Field = new FieldDefUser(Generator.RandomName(), new FieldSig(Module.CorLibTypes.Int32), FieldAttributes.Assembly | FieldAttributes.Static); 37 | Field.IsStatic = true; 38 | Module.GlobalType.Fields.Add(Field); 39 | OpCode OpCode = null; 40 | switch (Instruction.OpCode.Code) 41 | { 42 | case Code.Ldloc: 43 | OpCode = OpCodes.Ldsfld; 44 | break; 45 | 46 | case Code.Ldloca: 47 | OpCode = OpCodes.Ldsflda; 48 | break; 49 | 50 | case Code.Stloc: 51 | OpCode = OpCodes.Stsfld; 52 | break; 53 | } 54 | HT[Instruction.Operand] = Field; 55 | F = (FieldDef)HT[Instruction.Operand]; 56 | cctor.Body.Variables.Add(new Local(Module.CorLibTypes.Int32)); 57 | cctor.Body.Instructions.Insert(0, new Instruction(OpCodes.Ldc_I4, Instruction.GetLdcI4Value())); 58 | cctor.Body.Instructions.Insert(1, new Instruction(OpCodes.Stsfld, F)); 59 | } 60 | else 61 | { 62 | F = (FieldDef)HT[Instruction.Operand]; 63 | } 64 | 65 | if (!HT.ContainsKey(F)) 66 | { 67 | var MMethod = new MethodDefUser(Generator.RandomName(), MethodSig.CreateStatic(Module.CorLibTypes.Int32), MethodImplAttributes.IL | MethodImplAttributes.Managed, MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot); 68 | Method.DeclaringType.Methods.Add(MMethod); 69 | MMethod.Body = new CilBody(); 70 | MMethod.Body.Variables.Add(new Local(Module.CorLibTypes.Int32)); 71 | MMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, F)); 72 | MMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); 73 | MMethod.Body.SimplifyBranches(); 74 | MMethod.Body.OptimizeBranches(); 75 | HT[F] = MMethod; 76 | M = (MethodDef)HT[F]; 77 | } 78 | else 79 | { 80 | M = (MethodDef)HT[F]; 81 | } 82 | 83 | Method.Body.Instructions[i] = new Instruction(OpCodes.Ldftn, M); 84 | Method.Body.Instructions.Insert(i + 1, new Instruction(OpCodes.Nop)); 85 | Method.Body.Instructions.Insert(i + 2, new Instruction(OpCodes.Calli, M.MethodSig)); 86 | } 87 | else if (Method.Body.Instructions[i].OpCode == OpCodes.Ldc_R4) 88 | { 89 | var MMethod = new MethodDefUser(Generator.RandomName(), MethodSig.CreateStatic(Module.CorLibTypes.Double), MethodImplAttributes.IL | MethodImplAttributes.Managed, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot); 90 | Module.GlobalType.Methods.Add(MMethod); 91 | MMethod.Body = new CilBody(); 92 | MMethod.Body.Variables.Add(new Local(Module.CorLibTypes.Double)); 93 | MMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_R4, (float)Instruction.Operand)); 94 | MMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); 95 | MMethod.Body.SimplifyBranches(); 96 | MMethod.Body.OptimizeBranches(); 97 | 98 | Method.Body.Instructions[i] = new Instruction(OpCodes.Ldftn, MMethod); 99 | Method.Body.Instructions.Insert(i + 1, new Instruction(OpCodes.Nop)); 100 | Method.Body.Instructions.Insert(i + 2, new Instruction(OpCodes.Calli, MMethod.MethodSig)); 101 | } 102 | } 103 | } 104 | catch (Exception ex) 105 | { 106 | //I'm not sure which one throw but whatever all of the visible ones in the assembly are handled. 107 | //Console.WriteLine(ex.ToString()); 108 | } 109 | } 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/Impl/Virtualization/RuntimeProtections/ProxyStrings.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using Hex.VM.Core.Helper; 4 | using System; 5 | using System.Collections; 6 | using System.Linq; 7 | 8 | namespace Hex.VM.Core.Protections.Impl.Virtualization.RuntimeProtections 9 | { 10 | internal static class ProxyStrings 11 | { 12 | private static Hashtable HT = null; 13 | internal static void Execute(ModuleDef Module) 14 | { 15 | HT = new Hashtable(); 16 | MethodDef cctor = Module.GlobalType.FindOrCreateStaticConstructor(); 17 | foreach (var Type in Module.GetTypes().Where(T => T.HasMethods && !T.IsGlobalModuleType && !T.Name.Contains("AssemblyLoader")).ToArray()) 18 | foreach (var Method in Type.Methods.Where(M => M.HasBody && M.Body.HasInstructions).ToArray()) 19 | { 20 | if (Module == Context.Instance.Module && !Context.Instance.VirtualizedMethods.Contains(Method.FullName)) 21 | continue; 22 | try 23 | { 24 | for (var i = 0; i < Method.Body.Instructions.Count; i++) 25 | { 26 | Instruction Instruction = Method.Body.Instructions[i]; 27 | if (Instruction.OpCode == OpCodes.Ldstr) 28 | { 29 | FieldDef F = null; 30 | MethodDef M = null; 31 | if (!HT.ContainsKey(Instruction.Operand)) 32 | { 33 | FieldDefUser Field = new FieldDefUser(Generator.RandomName(), new FieldSig(Module.CorLibTypes.String), FieldAttributes.Assembly | FieldAttributes.Static); 34 | Field.IsStatic = true; 35 | Module.GlobalType.Fields.Add(Field); 36 | OpCode OpCode = null; 37 | switch (Instruction.OpCode.Code) 38 | { 39 | case Code.Ldloc: 40 | OpCode = OpCodes.Ldsfld; 41 | break; 42 | 43 | case Code.Ldloca: 44 | OpCode = OpCodes.Ldsflda; 45 | break; 46 | 47 | case Code.Stloc: 48 | OpCode = OpCodes.Stsfld; 49 | break; 50 | } 51 | HT[Instruction.Operand] = Field; 52 | F = (FieldDef)HT[Instruction.Operand]; 53 | cctor.Body.Variables.Add(new Local(Module.CorLibTypes.String)); 54 | cctor.Body.Instructions.Insert(0, new Instruction(OpCodes.Ldstr, Instruction.Operand.ToString())); 55 | cctor.Body.Instructions.Insert(1, new Instruction(OpCodes.Stsfld, F)); 56 | } 57 | else 58 | { 59 | F = (FieldDef)HT[Instruction.Operand]; 60 | } 61 | 62 | if (!HT.ContainsKey(F)) 63 | { 64 | var MMethod = new MethodDefUser(Generator.RandomName(), MethodSig.CreateStatic(Module.CorLibTypes.String), MethodImplAttributes.IL | MethodImplAttributes.Managed, MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot); 65 | Method.DeclaringType.Methods.Add(MMethod); 66 | MMethod.Body = new CilBody(); 67 | MMethod.Body.Variables.Add(new Local(Module.CorLibTypes.String)); 68 | MMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, F)); 69 | MMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); 70 | MMethod.Body.SimplifyBranches(); 71 | MMethod.Body.OptimizeBranches(); 72 | HT[F] = MMethod; 73 | M = (MethodDef)HT[F]; 74 | } 75 | else 76 | { 77 | M = (MethodDef)HT[F]; 78 | } 79 | 80 | Method.Body.Instructions[i] = new Instruction(OpCodes.Ldftn, M); 81 | Method.Body.Instructions.Insert(i + 1, new Instruction(OpCodes.Nop)); 82 | Method.Body.Instructions.Insert(i + 2, new Instruction(OpCodes.Calli, M.MethodSig)); 83 | } 84 | } 85 | } 86 | catch (Exception ex) 87 | { 88 | //I'm not sure which one throw but whatever all of the visible ones in the assembly are handled. 89 | //Console.WriteLine(ex.ToString()); 90 | } 91 | } 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/Impl/Virtualization/RuntimeProtections/Renamer.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using Hex.VM.Core.Helper; 3 | using System.Linq; 4 | 5 | namespace Hex.VM.Core.Protections.Impl.Virtualization.RuntimeProtections 6 | { 7 | internal static class Renamer 8 | { 9 | public static void Execute(ModuleDefMD mod) 10 | { 11 | foreach (var type in mod.GetTypes().Where(t => !t.IsGlobalModuleType).ToArray()) 12 | { 13 | type.Namespace = string.Empty; 14 | type.Name = Generator.RandomName(); 15 | 16 | foreach (MethodDef method in type.Methods.Where(m => !m.IsConstructor).ToArray()) 17 | if (method.Name != Context.Instance.theMethod.Name) 18 | { 19 | foreach (var param in method.Parameters) 20 | param.Name = Generator.RandomName(); 21 | 22 | if (!method.IsVirtual) 23 | method.Name = Generator.RandomName(); 24 | 25 | if (method.IsAbstract) 26 | { 27 | var oldName = method.Name; 28 | var oldParam1 = method.Parameters[0].Name; 29 | var oldParam2 = method.Parameters[1].Name; 30 | method.Name = Generator.RandomName(); 31 | method.Parameters[0].Name = Generator.RandomName(); 32 | method.Parameters[1].Name = Generator.RandomName(); 33 | foreach (var t in mod.Types.Where(t => !t.IsGlobalModuleType)) 34 | foreach (var m in t.Methods.Where(m => m.IsVirtual)) 35 | if (m.Name == oldName) 36 | { 37 | m.Name = method.Name; 38 | m.Parameters[0].Name = method.Parameters[0].Name; 39 | m.Parameters[1].Name = method.Parameters[1].Name; 40 | } 41 | } 42 | } 43 | 44 | foreach (PropertyDef property in type.Properties) 45 | property.Name = Generator.RandomName(); 46 | 47 | foreach (FieldDef field in type.Fields) 48 | field.Name = Generator.RandomName(); 49 | 50 | foreach (EventDef thisEvent in type.Events) 51 | thisEvent.Name = Generator.RandomName(); 52 | 53 | foreach (var x in type.Interfaces) 54 | x.Interface.Name = Generator.RandomName(); 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/Impl/Virtualization/RuntimeProtections/Strings.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using Hex.VM.Core.Helper; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Runtime.CompilerServices; 8 | using System.Text; 9 | 10 | namespace Hex.VM.Core.Protections.Impl.Virtualization.RuntimeProtections 11 | { 12 | internal static class Strings 13 | { 14 | internal static void Execute(ModuleDefMD Module) 15 | { 16 | foreach (TypeDef Type in Module.GetTypes().Where(T => T.HasMethods).ToArray()) 17 | { 18 | ITypeDefOrRef valueTypeRef = Context.Instance.Module.Import(typeof(ValueType)); 19 | foreach (MethodDef Method in Type.Methods.Where(m => m.HasBody && m.Body.HasInstructions).ToArray()) 20 | { 21 | if (Module == Context.Instance.Module && Method.IsConstructor) 22 | continue; 23 | //IsConstructor avoid virtualized constructors strings to be processed, on a sample it fail so I need to fix it later.. 24 | 25 | if (Module == Context.Instance.Module && !Context.Instance.VirtualizedMethods.Contains(Method.FullName)) 26 | continue; 27 | try 28 | { 29 | for (int i = 0; i < Method.Body.Instructions.ToArray().Count(); i++) 30 | { 31 | if (Method.Body.Instructions[i].OpCode == OpCodes.Ldstr) 32 | { 33 | string str = Method.Body.Instructions[i].Operand.ToString(); 34 | if(str == string.Empty || str.Length == 0 || str == " ") 35 | continue; 36 | 37 | TypeDef classWithLayout = null; 38 | TypeDef ourType; 39 | try 40 | { 41 | ourType = (TypeDef)Module.Types.Single(t => t.Name == $"'__StaticArrayInitTypeSize={str.Length}'"); 42 | classWithLayout = ourType; 43 | } 44 | catch 45 | { 46 | ourType = new TypeDefUser($"'__StaticArrayInitTypeSize={str.Length}'", valueTypeRef); 47 | classWithLayout = ourType; 48 | classWithLayout.Attributes |= TypeAttributes.Sealed | TypeAttributes.ExplicitLayout; 49 | classWithLayout.ClassLayout = new ClassLayoutUser(1, (uint)str.Length); 50 | Module.Types.Add(classWithLayout); 51 | } 52 | FieldDef fieldWithRVA = new FieldDefUser($"'$$Method{Method.MDToken.ToString()}-{Generator.RandomName()}'", new FieldSig(classWithLayout.ToTypeSig()), FieldAttributes.Static | FieldAttributes.Assembly | FieldAttributes.HasFieldRVA); 53 | fieldWithRVA.InitialValue = Encoding.UTF8.GetBytes(str); 54 | Method.DeclaringType.Fields.Add(fieldWithRVA); 55 | FieldDef fieldInjectedArray = new FieldDefUser(Generator.RandomName(), new FieldSig(new SZArraySig(Module.CorLibTypes.Byte)), FieldAttributes.Static | FieldAttributes.Assembly); 56 | //Module.GlobalType.Fields.Add(fieldInjectedArray); 57 | Method.DeclaringType.Fields.Add(fieldInjectedArray); 58 | ITypeDefOrRef runtimeHelpers = Context.Instance.Module.Import(typeof(RuntimeHelpers)); 59 | IMethod initArray = Context.Instance.Module.Import(typeof(RuntimeHelpers).GetMethod("InitializeArray", new Type[] { typeof(Array), typeof(RuntimeFieldHandle) })); 60 | 61 | //MethodDef cctor = Module.GlobalType.FindOrCreateStaticConstructor(); 62 | MethodDef cctor = Method.DeclaringType.FindOrCreateStaticConstructor(); 63 | IList instrs = cctor.Body.Instructions; 64 | instrs.Insert(0, new Instruction(OpCodes.Ldc_I4, str.Length)); 65 | instrs.Insert(1, new Instruction(OpCodes.Newarr, Module.CorLibTypes.Byte.ToTypeDefOrRef())); 66 | instrs.Insert(2, new Instruction(OpCodes.Dup)); 67 | instrs.Insert(3, new Instruction(OpCodes.Ldtoken, fieldWithRVA)); 68 | instrs.Insert(4, new Instruction(OpCodes.Call, initArray)); 69 | instrs.Insert(5, new Instruction(OpCodes.Stsfld, fieldInjectedArray)); 70 | 71 | Method.Body.Instructions[i].OpCode = OpCodes.Ldfld; 72 | Method.Body.Instructions[i].Operand = fieldInjectedArray; 73 | 74 | Method.Body.Instructions.Insert(i, new Instruction(OpCodes.Call, Context.Instance.Module.Import(typeof(Encoding).GetMethod("get_UTF8", new Type[] { })))); 75 | Method.Body.Instructions.Insert(i + 1, new Instruction(OpCodes.Ldnull)); 76 | Method.Body.Instructions.Insert(i + 3, new Instruction(OpCodes.Callvirt, Context.Instance.Module.Import(typeof(Encoding).GetMethod("GetString", new Type[] { typeof(byte[]) })))); 77 | } 78 | } 79 | } catch (Exception ex) 80 | { 81 | Console.WriteLine(ex.ToString()); 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/Impl/Virtualization/Virtualization.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using dnlib.DotNet.Writer; 4 | using Hex.VM.Core.Helper; 5 | using Hex.VM.Core.Protections.Impl.Virtualization.RuntimeProtections; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.IO; 9 | using System.Linq; 10 | 11 | // github.com/hexck 12 | namespace Hex.VM.Core.Protections.Impl.Virtualization 13 | { 14 | public class Virtualization : IProtection 15 | { 16 | public override string Name() => "Virtualization"; 17 | public override void Execute(Context context) 18 | { 19 | protectRuntime(); 20 | IMethod runVm = context.Module.Import(Context.Instance.theMethod); 21 | foreach (var type in context.Module.GetTypes().ToArray()) 22 | { 23 | if (type.FullName.StartsWith(Context.Instance.RTModule.Assembly.Name)) 24 | continue; 25 | 26 | Context.Instance.Log.Information($"Processing type: {type.FullName}"); 27 | 28 | foreach (var method in type.Methods.Where(M => M.HasBody && M.Body.HasInstructions).ToArray()) 29 | { 30 | string methodName = method.MDToken.ToInt32().ToString(); 31 | 32 | if (method.IsRuntime) 33 | continue; 34 | 35 | Context.Instance.Log.Information($"Virtualizing method: {method.FullName}"); 36 | 37 | var name = Generator.RandomName(); 38 | 39 | var conv = new Converter(method, name); 40 | conv.Save(); 41 | 42 | if (!conv.Compatible) 43 | { 44 | Context.Instance.Log.Warning($"Skipped method because of incompatibilities: {method.FullName}"); 45 | continue; 46 | } 47 | 48 | method.Body = new CilBody(); 49 | 50 | if (method.Parameters.Count() == 0) 51 | { 52 | method.Body.Instructions.Add(new Instruction(OpCodes.Ldnull)); 53 | } else 54 | { 55 | method.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, method.Parameters.Count)); 56 | method.Body.Instructions.Add(OpCodes.Newarr.ToInstruction(context.Module.CorLibTypes.Object)); 57 | for (var i = 0; i < method.Parameters.Count; i++) 58 | { 59 | method.Body.Instructions.Add(new Instruction(OpCodes.Dup)); 60 | method.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4, i)); 61 | method.Body.Instructions.Add(new Instruction(OpCodes.Ldarg, method.Parameters[i])); 62 | method.Body.Instructions.Add(new Instruction(OpCodes.Box, method.Parameters[i].Type.ToTypeDefOrRef())); 63 | method.Body.Instructions.Add(new Instruction(OpCodes.Stelem_Ref)); 64 | } 65 | } 66 | method.Body.Instructions.Add(new Instruction(OpCodes.Ldstr, methodName)); 67 | method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldftn, runVm)); 68 | method.Body.Instructions.Add(Instruction.Create(OpCodes.Calli, runVm.MethodSig)); 69 | 70 | if (method.HasReturnType) 71 | method.Body.Instructions.Add(new Instruction(OpCodes.Unbox_Any, method.ReturnType.ToTypeDefOrRef())); 72 | else 73 | method.Body.Instructions.Add(OpCodes.Pop.ToInstruction()); 74 | 75 | method.Body.Instructions.Add(new Instruction(OpCodes.Ret)); 76 | 77 | method.Body.UpdateInstructionOffsets(); 78 | 79 | Context.Instance.VirtualizedMethods.Add(method.FullName); 80 | } 81 | } 82 | injectRuntime(); 83 | } 84 | 85 | private void injectRuntime() 86 | { 87 | var runtimeName = $"{Context.Instance.RTModule.Assembly.Name}.THT"; 88 | 89 | #region Inject Runtime DLL 90 | var opts = new ModuleWriterOptions(Context.Instance.RTModule) { Logger = DummyLogger.NoThrowInstance }; 91 | 92 | opts.MetadataOptions.Flags = MetadataFlags.PreserveAll; 93 | 94 | MemoryStream ms = new MemoryStream(); 95 | //... 96 | Context.Instance.RTModule.Write(ms, opts); 97 | 98 | byte[] array = ms.ToArray(); 99 | Context.Instance.Module.Resources.Add(new EmbeddedResource(runtimeName, Compression.Compress(array), ManifestResourceAttributes.Private)); 100 | #endregion 101 | #region Inject Runtime DLL Loader 102 | ModuleDefMD typeModule = ModuleDefMD.Load(typeof(LoadDLLRuntime.VMInitialize).Module); 103 | TypeDef typeDef = typeModule.ResolveTypeDef(MDToken.ToRID(typeof(LoadDLLRuntime.VMInitialize).MetadataToken)); 104 | IEnumerable members = InjectHelper.Inject(typeDef, Context.Instance.Module.GlobalType, Context.Instance.Module); 105 | MethodDef init = (MethodDef)members.Single(method => method.Name == "InitializeRuntime"); 106 | init.Name = Generator.RandomName(); 107 | 108 | Context.Instance.Module.GlobalType.FindOrCreateStaticConstructor().Body.Instructions.Insert(0, new Instruction(OpCodes.Calli, init.MethodSig)); 109 | Context.Instance.Module.GlobalType.FindOrCreateStaticConstructor().Body.Instructions.Insert(0, new Instruction(OpCodes.Ldftn, init)); 110 | #endregion 111 | 112 | #region Protect Virtualized Methods 113 | ProxyInteger.Execute(Context.Instance.Module); 114 | Strings.Execute(Context.Instance.Module); 115 | CallToCalli.Execute(Context.Instance.Module); 116 | #endregion 117 | } 118 | 119 | private void protectRuntime() 120 | { 121 | /*Patch RunVM GetCallingAssembly*/ 122 | foreach (var x in Context.Instance.theMethod.Body.Instructions) 123 | if (x.OpCode == OpCodes.Ldstr && x.Operand.ToString().Contains("{{TExecutingHAssemblyT}}")) 124 | x.Operand = Context.Instance.Module.Assembly.FullName; 125 | /*Patch RunVM GetCallingAssembly*/ 126 | 127 | #region Protect Runtime 128 | Strings.Execute(Context.Instance.RTModule); 129 | /*CFlow.Execute(Context.Instance.RTModule); 130 | ProxyInteger.Execute(Context.Instance.RTModule); 131 | CallToCalli.Execute(Context.Instance.RTModule);*/ 132 | Renamer.Execute(Context.Instance.RTModule); Context.Instance.theMethod.Name = Generator.RandomName(); 133 | #endregion 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /Hex.VM/Core/Protections/LoadDLLRuntime/VMInitialize.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | 5 | namespace Hex.VM.Core.Protections.LoadDLLRuntime 6 | { 7 | public static class VMInitialize 8 | { 9 | public static void InitializeRuntime() => AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler((object sender, ResolveEventArgs args) => 10 | { 11 | byte[] array = null; 12 | 13 | int HASH_VALUES = 4096; 14 | int UNCONDITIONAL_MATCHLEN = 6; 15 | int UNCOMPRESSED_END = 4; 16 | int CWORD_LEN = 4; 17 | 18 | Stream manifestResourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream("Hex.VM.Runtime.THT"); 19 | array = new byte[manifestResourceStream.Length]; 20 | manifestResourceStream.Read(array, 0, array.Length); 21 | byte[] source = array; 22 | int level; 23 | int size = 0; 24 | if ((((source[0] & 2) == 2) ? 9 : 3) == 9) 25 | size = source[5] | (source[6] << 8) | (source[7] << 16) | (source[8] << 24); 26 | else 27 | size = source[2]; 28 | int src = (((source[0] & 2) == 2) ? 9 : 3); 29 | int dst = 0; 30 | uint cword_val = 1; 31 | byte[] destination = new byte[size]; 32 | int[] hashtable = new int[4096]; 33 | byte[] hash_counter = new byte[4096]; 34 | int last_matchstart = size - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1; 35 | int last_hashed = -1; 36 | int hash; 37 | uint fetch = 0; 38 | 39 | level = (source[0] >> 2) & 0x3; 40 | 41 | if ((source[0] & 1) != 1) 42 | { 43 | byte[] d2 = new byte[size]; 44 | Array.Copy(source, (((source[0] & 2) == 2) ? 9 : 3), d2, 0, size); 45 | source = d2; 46 | goto Final; 47 | } 48 | 49 | for (; ; ) 50 | { 51 | if (cword_val == 1) 52 | { 53 | cword_val = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24)); 54 | src += 4; 55 | if (dst <= last_matchstart) 56 | { 57 | if (level == 1) 58 | fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16)); 59 | else 60 | fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24)); 61 | } 62 | } 63 | 64 | if ((cword_val & 1) == 1) 65 | { 66 | uint matchlen; 67 | uint offset2; 68 | 69 | cword_val = cword_val >> 1; 70 | 71 | if (level == 1) 72 | { 73 | hash = ((int)fetch >> 4) & 0xfff; 74 | offset2 = (uint)hashtable[hash]; 75 | 76 | if ((fetch & 0xf) != 0) 77 | { 78 | matchlen = (fetch & 0xf) + 2; 79 | src += 2; 80 | } 81 | else 82 | { 83 | matchlen = source[src + 2]; 84 | src += 3; 85 | } 86 | } 87 | else 88 | { 89 | uint offset; 90 | if ((fetch & 3) == 0) 91 | { 92 | offset = (fetch & 0xff) >> 2; 93 | matchlen = 3; 94 | src++; 95 | } 96 | else if ((fetch & 2) == 0) 97 | { 98 | offset = (fetch & 0xffff) >> 2; 99 | matchlen = 3; 100 | src += 2; 101 | } 102 | else if ((fetch & 1) == 0) 103 | { 104 | offset = (fetch & 0xffff) >> 6; 105 | matchlen = ((fetch >> 2) & 15) + 3; 106 | src += 2; 107 | } 108 | else if ((fetch & 127) != 3) 109 | { 110 | offset = (fetch >> 7) & 0x1ffff; 111 | matchlen = ((fetch >> 2) & 0x1f) + 2; 112 | src += 3; 113 | } 114 | else 115 | { 116 | offset = (fetch >> 15); 117 | matchlen = ((fetch >> 7) & 255) + 3; 118 | src += 4; 119 | } 120 | offset2 = (uint)(dst - offset); 121 | } 122 | 123 | destination[dst + 0] = destination[offset2 + 0]; 124 | destination[dst + 1] = destination[offset2 + 1]; 125 | destination[dst + 2] = destination[offset2 + 2]; 126 | 127 | for (int i = 3; i < matchlen; i += 1) 128 | destination[dst + i] = destination[offset2 + i]; 129 | 130 | dst += (int)matchlen; 131 | 132 | if (level == 1) 133 | { 134 | fetch = (uint)(destination[last_hashed + 1] | (destination[last_hashed + 2] << 8) | (destination[last_hashed + 3] << 16)); 135 | while (last_hashed < dst - matchlen) 136 | { 137 | last_hashed++; 138 | hash = (int)(((fetch >> 12) ^ fetch) & (HASH_VALUES - 1)); 139 | hashtable[hash] = last_hashed; 140 | hash_counter[hash] = 1; 141 | fetch = (uint)(fetch >> 8 & 0xffff | destination[last_hashed + 3] << 16); 142 | } 143 | fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16)); 144 | } 145 | else 146 | { 147 | fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24)); 148 | } 149 | last_hashed = dst - 1; 150 | } 151 | else 152 | { 153 | if (dst <= last_matchstart) 154 | { 155 | destination[dst] = source[src]; 156 | dst += 1; 157 | src += 1; 158 | cword_val = cword_val >> 1; 159 | 160 | if (level == 1) 161 | { 162 | while (last_hashed < dst - 3) 163 | { 164 | last_hashed++; 165 | int fetch2 = destination[last_hashed] | (destination[last_hashed + 1] << 8) | (destination[last_hashed + 2] << 16); 166 | hash = ((fetch2 >> 12) ^ fetch2) & (HASH_VALUES - 1); 167 | hashtable[hash] = last_hashed; 168 | hash_counter[hash] = 1; 169 | } 170 | fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16); 171 | } 172 | else 173 | { 174 | fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16 | source[src + 3] << 24); 175 | } 176 | } 177 | else 178 | { 179 | while (dst <= size - 1) 180 | { 181 | if (cword_val == 1) 182 | { 183 | src += CWORD_LEN; 184 | cword_val = 0x80000000; 185 | } 186 | 187 | destination[dst] = source[src]; 188 | dst++; 189 | src++; 190 | cword_val = cword_val >> 1; 191 | } 192 | source = destination; 193 | goto Final; 194 | } 195 | } 196 | } 197 | Final: 198 | return Assembly.Load(source); 199 | }); 200 | } 201 | } -------------------------------------------------------------------------------- /Hex.VM/Hex.VM.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {40A83DD8-5878-4433-80DB-B80339E33A6C} 8 | Exe 9 | Properties 10 | Hex.VM 11 | Hex.VM 12 | v4.7.2 13 | 512 14 | 15 | 8.0 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | true 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | ..\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | true 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {ce5e6bbe-61d5-4594-bfca-7b3305a98f57} 69 | Hex.VM.Runtime 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 4.3.0 78 | 79 | 80 | 2.10.0 81 | 82 | 83 | 4.0.0 84 | 85 | 86 | 87 | 94 | -------------------------------------------------------------------------------- /Hex.VM/Program.cs: -------------------------------------------------------------------------------- 1 | using Hex.VM.Core; 2 | 3 | namespace Hex.VM 4 | { 5 | class Program 6 | { 7 | static void Main(string[] args) => new Engine().Run(args); 8 | } 9 | } -------------------------------------------------------------------------------- /Hex.VM/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Hex.VM")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("Hex.VM")] 12 | [assembly: AssemblyCopyright("Copyright © 2020")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("40A83DD8-5878-4433-80DB-B80339E33A6C")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /Hex.VM/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Hex Virtualization](https://github.com/TheHellTower/Hex-Virtualization) [![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/) 2 | Developed by Hexk 3 |
4 | 5 | ## :guardsman: Why do you need Hex Virtualization ? 6 | 7 | Hex-Virtualization was built so that people can learn from it, for real-world use, other obfuscation techniques such as anti-tampering, mutations, controlflow, and renamer would bring this vm to its full potential. 8 | 9 | Eazfuscator describes perfectly what a vm does:
10 | _"Many of us consider particular pieces of code especially important. May it be a license code check algorithm implementation, an innovative optimization method, or anything else equally important so we would want to protect it by any means possible. As we know, the traditional obfuscation techniques basically do renaming of symbols and encryption, thus leaving the actual algorithms — cycles, conditional branches and arithmetics potentially naked to eye of the skilled intruder._ 11 | 12 | _Here a radical approach may be useful: to remove all the .NET bytecode instructions from an assembly, and replace it with something completely different and unknown to an external observer, but functionally equivalent to the original algorithm during runtime — this is what the code virtualization actually is."_ 13 | 14 |
15 | 16 | ## 💡 Features 17 | 18 | - [x] Virtualize Methods 19 | - [x] Virtualize Strings 20 | 21 | 22 | Note: Unchecked = future updates 23 |
24 | 25 | ## :bug: Known "issues" ? 26 | 27 | - Missing `ref/out` keyword support(`any method virtualized containing one will throw`) 28 | - Missing EH (`try{}catch{}finally{}`) support. 29 | - Handlers are not perfect. 30 | - Performances hits up to 1,5 seconds with Runtime obfuscation in a resource needy/intensive speed-test.(`not really noticiable in standard tested programs.`) 31 | - Xor 32 | - Using a whole thing(`XXHash`) just for naming. 33 |
34 | 35 | ## :star: How does it work ? 36 | 37 | - MSIL to VMIL 38 | - Methods are stored as resources 39 | - Bytes are encrypted with xor cipher 40 |
41 | 42 | ## :fire: What does it do ? 43 | 44 | - [x] Virtualize code into instructions which only Hex.VM can understand 45 | - [x] Support for a decent amount of opcodes, as said, this is made for educational purposes and as such I believe these opcodes are enough for people to learn and build on 46 | - [x] Easy to use, understand, and build on 47 | 48 |
49 | 50 | ## 🎥 Preview 51 | 52 | [View Video](https://youtu.be/hIUg9JYsdOk) 53 | [![](https://i.imgur.com/LO6m8Ge.jpeg)](https://youtu.be/hIUg9JYsdOk) 54 | 55 | ## :bookmark_tabs: Examples 56 | 57 |
58 | Before 59 | 60 | 61 | ```cs 62 | using System; 63 | using System.Runtime.CompilerServices; 64 | 65 | namespace Hex.VM.Tests 66 | { 67 | public class Maths 68 | { 69 | public int Sum { get; set; } 70 | 71 | public Maths(int x, int y) 72 | { 73 | this._x = x; 74 | this._y = y; 75 | this.Sum = this._x + this._y; 76 | } 77 | 78 | public int Add() 79 | { 80 | return this._x + this._y; 81 | } 82 | 83 | public int Subtract() 84 | { 85 | return this._x - this._y; 86 | } 87 | 88 | public int Multiply() 89 | { 90 | return this._x * this._y; 91 | } 92 | 93 | public int Divide() 94 | { 95 | return this._x / this._y; 96 | } 97 | 98 | private int k__BackingField; 99 | 100 | private int _x; 101 | 102 | private int _y; 103 | } 104 | } 105 | ``` 106 |
107 | 108 |
109 | After 110 | 111 | 112 | ```cs 113 | using System; 114 | using System.Runtime.CompilerServices; 115 | using System.Text; 116 | 117 | namespace Hex.VM.Tests 118 | { 119 | public class Maths 120 | { 121 | public int Sum 122 | { 123 | [CompilerGenerated] 124 | get 125 | { 126 | int num = calli(System.Int32(), ldftn({A586DBFE-F476-402B-B003-7E070D33AF8B})); 127 | object[] array = new object[calli(System.Int32(), ldftn({0BC6BDCA-B12C-431A-A06E-25AFD7485DD4}))]; 128 | array[calli(System.Int32(), ldftn({1ACC3772-1D8F-4338-A7EE-19E65A64615B}))] = this; 129 | return (int)calli(System.Object(System.Int32,System.Object[],System.String), num, array, Encoding.UTF8.GetString(null.{30332EE9-2ADA-43EF-8657-A9D0C4A731C8}), ldftn({84254139-6195-4422-967F-5A70E84992B3})); 130 | } 131 | [CompilerGenerated] 132 | set 133 | { 134 | int num = calli(System.Int32(), ldftn({66A3A30C-3172-41A1-AE2A-C95779761AD7})); 135 | object[] array = new object[calli(System.Int32(), ldftn({928EABDE-0520-47F9-908A-449B147E475E}))]; 136 | array[calli(System.Int32(), ldftn({1ACC3772-1D8F-4338-A7EE-19E65A64615B}))] = this; 137 | array[calli(System.Int32(), ldftn({0BC6BDCA-B12C-431A-A06E-25AFD7485DD4}))] = value; 138 | object obj = calli(System.Object(System.Int32,System.Object[],System.String), num, array, Encoding.UTF8.GetString(null.{EDF81B16-C478-45DD-B9F1-3563ABE3C2F5}), ldftn({84254139-6195-4422-967F-5A70E84992B3})); 139 | } 140 | } 141 | 142 | public Maths(int x, int y) 143 | { 144 | int num = calli(System.Int32(), ldftn({F40013D7-ECE4-4313-84D8-35C2147B46F3})); 145 | object[] array = new object[calli(System.Int32(), ldftn({E59CE633-867C-47F3-AC29-D82AC012BE94}))]; 146 | array[calli(System.Int32(), ldftn({1ACC3772-1D8F-4338-A7EE-19E65A64615B}))] = this; 147 | array[calli(System.Int32(), ldftn({0BC6BDCA-B12C-431A-A06E-25AFD7485DD4}))] = x; 148 | array[calli(System.Int32(), ldftn({928EABDE-0520-47F9-908A-449B147E475E}))] = y; 149 | object obj = calli(System.Object(System.Int32,System.Object[],System.String), num, array, "100663299", ldftn({84254139-6195-4422-967F-5A70E84992B3})); 150 | } 151 | 152 | public int Add() 153 | { 154 | int num = calli(System.Int32(), ldftn({7D87F09E-E20F-457B-AF56-73F9878E8130})); 155 | object[] array = new object[calli(System.Int32(), ldftn({0BC6BDCA-B12C-431A-A06E-25AFD7485DD4}))]; 156 | array[calli(System.Int32(), ldftn({1ACC3772-1D8F-4338-A7EE-19E65A64615B}))] = this; 157 | return (int)calli(System.Object(System.Int32,System.Object[],System.String), num, array, Encoding.UTF8.GetString(null.{2BD8B0CE-9AC1-4BB6-81EC-2828FC5D8C16}), ldftn({84254139-6195-4422-967F-5A70E84992B3})); 158 | } 159 | 160 | public int Subtract() 161 | { 162 | int num = calli(System.Int32(), ldftn({074AF9BD-EACA-443B-AC25-D36C361C9442})); 163 | object[] array = new object[calli(System.Int32(), ldftn({0BC6BDCA-B12C-431A-A06E-25AFD7485DD4}))]; 164 | array[calli(System.Int32(), ldftn({1ACC3772-1D8F-4338-A7EE-19E65A64615B}))] = this; 165 | return (int)calli(System.Object(System.Int32,System.Object[],System.String), num, array, Encoding.UTF8.GetString(null.{8F28EAA7-6D42-4026-AC72-F55842D07D28}), ldftn({84254139-6195-4422-967F-5A70E84992B3})); 166 | } 167 | 168 | public int Multiply() 169 | { 170 | int num = calli(System.Int32(), ldftn({DFBFEB9C-F74F-4961-B8F2-13E6342A02DA})); 171 | object[] array = new object[calli(System.Int32(), ldftn({0BC6BDCA-B12C-431A-A06E-25AFD7485DD4}))]; 172 | array[calli(System.Int32(), ldftn({1ACC3772-1D8F-4338-A7EE-19E65A64615B}))] = this; 173 | return (int)calli(System.Object(System.Int32,System.Object[],System.String), num, array, Encoding.UTF8.GetString(null.{49697F00-A6F0-414B-96DF-ABD6B3D7BCFF}), ldftn({84254139-6195-4422-967F-5A70E84992B3})); 174 | } 175 | 176 | public int Divide() 177 | { 178 | int num = calli(System.Int32(), ldftn({7887B604-26C8-46F1-9A31-076B3079417F})); 179 | object[] array = new object[calli(System.Int32(), ldftn({0BC6BDCA-B12C-431A-A06E-25AFD7485DD4}))]; 180 | array[calli(System.Int32(), ldftn({1ACC3772-1D8F-4338-A7EE-19E65A64615B}))] = this; 181 | return (int)calli(System.Object(System.Int32,System.Object[],System.String), num, array, Encoding.UTF8.GetString(null.{85D9BB1A-3C37-4BE6-8D18-EA58A244D39D}), ldftn({84254139-6195-4422-967F-5A70E84992B3})); 182 | } 183 | //.... 184 | } 185 | } 186 | 187 | ``` 188 |
189 | 190 | 191 | ## Resources 192 | https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-334.pdf
193 | 194 | https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=netframework-4.8 195 | 196 | ## Credits 197 | 198 | Hexk for HexVM(Hex-Virtualization) 199 |
200 | CursedLand for ILVirtualization | [Factory](https://github.com/CursedLand/ILVirtualization/blob/master/Runtime/Factory.cs) & [Cast](https://github.com/CursedLand/ILVirtualization/blob/master/Runtime/ILValue.cs#L27) 201 |
202 | Jonathan Peters --------------------------------------------------------------------------------