├── ILUnpacker ├── Properties │ └── AssemblyInfo.cs ├── ILReader.cs ├── AssemblyWriter.cs ├── Memory.cs ├── ILUnpacker.csproj ├── StringDecrypter.cs └── Program.cs ├── LICENSE └── ILUnpacker.sln /ILUnpacker/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | -------------------------------------------------------------------------------- /ILUnpacker/ILReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using dnlib.DotNet.Emit; 3 | 4 | namespace ILUnpacker 5 | { 6 | internal class IlReader 7 | { 8 | private readonly AssemblyWriter _assemblyWriter; 9 | 10 | internal IlReader(AssemblyWriter assemblyWriter) 11 | { 12 | _assemblyWriter = assemblyWriter; 13 | } 14 | 15 | internal void ReadMethod(object method) 16 | { 17 | try 18 | { 19 | var methodBodyReader = new DynamicMethodBodyReader(_assemblyWriter.ModuleDef, method); 20 | methodBodyReader.Read(); 21 | 22 | var methodDef = methodBodyReader.GetMethod(); 23 | 24 | _assemblyWriter.WriteMethod(methodDef); 25 | } 26 | catch (Exception e) 27 | { 28 | Console.WriteLine("Error in ReadMethod(): " + e.Message); 29 | throw; 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Michidu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ILUnpacker.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27004.2002 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILUnpacker", "ILUnpacker\ILUnpacker.csproj", "{4EDA515D-55B6-4DE5-88BD-46C5E4D31A69}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {4EDA515D-55B6-4DE5-88BD-46C5E4D31A69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {4EDA515D-55B6-4DE5-88BD-46C5E4D31A69}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {4EDA515D-55B6-4DE5-88BD-46C5E4D31A69}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {4EDA515D-55B6-4DE5-88BD-46C5E4D31A69}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {14DF1014-90EC-4EA6-8B44-D5FCA981469C} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /ILUnpacker/AssemblyWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using dnlib.DotNet; 4 | using dnlib.DotNet.Writer; 5 | 6 | namespace ILUnpacker 7 | { 8 | internal class AssemblyWriter 9 | { 10 | private readonly string _assemblyPath; 11 | 12 | internal ModuleDefMD ModuleDef; 13 | 14 | internal AssemblyWriter(string assemblyPath) 15 | { 16 | _assemblyPath = assemblyPath; 17 | 18 | AssemblyResolver asmResolver = new AssemblyResolver(); 19 | ModuleContext modCtx = new ModuleContext(asmResolver); 20 | 21 | asmResolver.EnableTypeDefCache = true; 22 | asmResolver.DefaultModuleContext = modCtx; 23 | 24 | ModuleDef = ModuleDefMD.Load(assemblyPath, modCtx); 25 | 26 | ModuleDef.Context = modCtx; 27 | ModuleDef.Context.AssemblyResolver.AddToCache(ModuleDef); 28 | } 29 | 30 | internal void WriteMethod(MethodDef methodDef) 31 | { 32 | MethodDef method = Program._executingMethod; 33 | if (method == null) 34 | { 35 | Console.WriteLine("Failed to write " + methodDef); 36 | return; 37 | } 38 | 39 | Program._executingMethod = null; 40 | 41 | method.FreeMethodBody(); 42 | method.Body = methodDef.Body; 43 | } 44 | 45 | internal void Save() 46 | { 47 | string file = Path.GetFileNameWithoutExtension(_assemblyPath); 48 | string newPath = _assemblyPath.Replace(file, file + "_unpacked"); 49 | 50 | var wOpts = new ModuleWriterOptions(ModuleDef); 51 | ModuleDef.Write(newPath, wOpts); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /ILUnpacker/Memory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace ILUnpacker 7 | { 8 | internal static class Memory 9 | { 10 | [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 11 | private static extern bool VirtualProtect( 12 | IntPtr lpAddress, 13 | IntPtr dwSize, 14 | uint flNewProtect, 15 | out uint lpflOldProtect 16 | ); 17 | 18 | internal static unsafe void Hook(MethodBase from, MethodBase to) 19 | { 20 | IntPtr intPtr = GetAddress(from); 21 | IntPtr intPtr2 = GetAddress(to); 22 | 23 | VirtualProtect(intPtr, (IntPtr) 5, 0x40, out var lpflOldProtect); 24 | 25 | if (IntPtr.Size == 8) 26 | { 27 | byte* ptr = (byte*) intPtr.ToPointer(); 28 | *ptr = 0x49; 29 | ptr[1] = 0xbb; 30 | *(long*) (ptr + 0x2) = intPtr2.ToInt64(); 31 | ptr[10] = 0x41; 32 | ptr[11] = 0xff; 33 | ptr[12] = 0xe3; 34 | } 35 | else if (IntPtr.Size == 4) 36 | { 37 | byte* ptr = (byte*) intPtr.ToPointer(); 38 | *ptr = 0xe9; 39 | *(long*) (ptr + 0x1) = intPtr2.ToInt32() - intPtr.ToInt32() - 5; 40 | ptr[5] = 0xc3; 41 | } 42 | 43 | VirtualProtect(intPtr, (IntPtr) 5, lpflOldProtect, out var _); 44 | } 45 | 46 | private static IntPtr GetAddress(MethodBase methodBase) 47 | { 48 | RuntimeHelpers.PrepareMethod(methodBase.MethodHandle); 49 | return methodBase.MethodHandle.GetFunctionPointer(); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /ILUnpacker/ILUnpacker.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {4EDA515D-55B6-4DE5-88BD-46C5E4D31A69} 8 | Exe 9 | Properties 10 | ILUnpacker 11 | ILUnpacker 12 | v4.6.1 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | true 32 | 33 | 34 | ILUnpacker.Program 35 | 36 | 37 | 38 | False 39 | bin\Release\dnlib.dll 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /ILUnpacker/StringDecrypter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Reflection; 4 | using dnlib.DotNet; 5 | using dnlib.DotNet.Emit; 6 | 7 | namespace ILUnpacker 8 | { 9 | internal class StringDecrypter 10 | { 11 | private readonly Assembly _assembly; 12 | 13 | private object _decryptField; 14 | private MethodInfo _decryptMethod; 15 | 16 | internal StringDecrypter(Assembly assembly) 17 | { 18 | _assembly = assembly; 19 | } 20 | 21 | internal void ReplaceStrings(IList typeDefs) 22 | { 23 | foreach (TypeDef typeDef in typeDefs) 24 | { 25 | foreach (MethodDef methodDef in typeDef.Methods) 26 | { 27 | if (!methodDef.HasBody) 28 | continue; 29 | 30 | var instructions = methodDef.Body.Instructions; 31 | for (var i = 0; i < instructions.Count; i++) 32 | { 33 | Instruction instruction = instructions[i]; 34 | 35 | if (instruction.OpCode == OpCodes.Ldsfld && 36 | instruction.Operand.ToString().Contains("::String") && 37 | instructions[i + 1].IsLdcI4() && 38 | instructions[i + 2].OpCode == OpCodes.Callvirt && 39 | instructions[i + 2].Operand.ToString().Contains("Invoke")) 40 | { 41 | if (_decryptField == null) 42 | { 43 | FieldDef fieldDef = (FieldDef) instruction.Operand; 44 | InitDecryptor(fieldDef); 45 | } 46 | 47 | int stringIdx = (int) instructions[i + 1].Operand; 48 | 49 | instructions[i].OpCode = OpCodes.Ldstr; 50 | instructions[i].Operand = GetString(stringIdx); 51 | 52 | instructions[i + 1].OpCode = OpCodes.Nop; 53 | instructions[i + 2].OpCode = OpCodes.Nop; 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | private void InitDecryptor(FieldDef fieldDef) 61 | { 62 | FieldInfo field = _assembly.Modules.FirstOrDefault() 63 | .ResolveField(fieldDef.MDToken.ToInt32()); 64 | _decryptField = field.GetValue(null); 65 | 66 | _decryptMethod = _decryptField.GetType().GetMethod("Invoke"); 67 | } 68 | 69 | private string GetString(int idx) 70 | { 71 | string res = (string) _decryptMethod.Invoke(_decryptField, new object[] {idx}); 72 | return res; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /ILUnpacker/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Reflection; 6 | using dnlib.DotNet; 7 | using dnlib.DotNet.Emit; 8 | 9 | namespace ILUnpacker 10 | { 11 | internal class Program 12 | { 13 | private static AssemblyWriter _assemblyWriter; 14 | 15 | private static Assembly _assembly; 16 | 17 | internal static MethodDef _executingMethod; 18 | 19 | public static void Main(string[] args) 20 | { 21 | if (args.Length < 1) 22 | return; 23 | 24 | string path = args[0]; 25 | 26 | _assemblyWriter = new AssemblyWriter(path); 27 | 28 | _assembly = Assembly.LoadFrom(path); 29 | 30 | Console.WriteLine("Unpacking.."); 31 | 32 | var stringDecrypter = new StringDecrypter(_assembly); 33 | 34 | Memory.Hook(typeof(StackFrame).GetMethod("GetMethod", BindingFlags.Instance | BindingFlags.Public), 35 | typeof(Program).GetMethod("HookGetMethod", BindingFlags.Instance | BindingFlags.Public)); 36 | 37 | int invokeToken = 0; 38 | 39 | var types = _assemblyWriter.ModuleDef.GetTypes(); 40 | var typeDefs = types as IList ?? types.ToList(); 41 | 42 | foreach (TypeDef typeDef in typeDefs) 43 | { 44 | if (typeDef.Name == "") 45 | { 46 | foreach (FieldDef fieldDef in typeDef.Fields) 47 | { 48 | if (fieldDef.FullName.Contains("::Invoke")) 49 | { 50 | invokeToken = fieldDef.MDToken.ToInt32(); 51 | 52 | goto exitLoop; 53 | } 54 | } 55 | } 56 | } 57 | 58 | exitLoop: 59 | 60 | if (invokeToken == 0) 61 | throw new Exception("Couldn't find Invoke"); 62 | 63 | FieldInfo field = _assembly.Modules.FirstOrDefault().ResolveField(invokeToken); 64 | var invokeField = field.GetValue(null); 65 | MethodInfo invokeMethod = invokeField.GetType().GetMethod("Invoke"); 66 | if (invokeMethod == null) 67 | throw new NullReferenceException("Couldn't find InvokeMethod"); 68 | 69 | InvokeDelegates(typeDefs, invokeMethod, invokeField); 70 | 71 | stringDecrypter.ReplaceStrings(typeDefs); 72 | 73 | CleanCctor(typeDefs); 74 | 75 | _assemblyWriter.Save(); 76 | 77 | Console.WriteLine("Unpacked file!"); 78 | 79 | Console.Read(); 80 | } 81 | 82 | private static void InvokeDelegates(IList typeDefs, MethodInfo invokeMethod, object invokeField) 83 | { 84 | string moduleName = _assembly.Modules.FirstOrDefault().Name; 85 | 86 | IlReader ilReader = new IlReader(_assemblyWriter); 87 | 88 | foreach (TypeDef typeDef in typeDefs) 89 | { 90 | foreach (MethodDef methodDef in typeDef.Methods) 91 | { 92 | if (methodDef.Module.Name != moduleName) 93 | continue; 94 | 95 | if (methodDef.HasBody && 96 | methodDef.Body.Instructions.Count > 2 && 97 | methodDef.Body.Instructions[0].OpCode == OpCodes.Ldsfld && 98 | methodDef.Body.Instructions[0].Operand.ToString().Contains("Invoke") && 99 | methodDef.Body.Instructions[1].IsLdcI4()) 100 | { 101 | int methodIdx = (int) methodDef.Body.Instructions[1].Operand; 102 | 103 | _executingMethod = methodDef; 104 | 105 | var methodDelegate = invokeMethod.Invoke(invokeField, new object[] {methodIdx}); 106 | 107 | ilReader.ReadMethod(methodDelegate); 108 | } 109 | } 110 | } 111 | } 112 | 113 | public MethodBase HookGetMethod() 114 | { 115 | var method = (MethodBase) GetType().GetField("method", BindingFlags.Instance | BindingFlags.NonPublic) 116 | .GetValue(this); 117 | 118 | if (method.DeclaringType?.Namespace == "ILUnpacker" && _executingMethod != null) 119 | { 120 | method = _assembly.Modules.FirstOrDefault().ResolveMethod(_executingMethod.MDToken.ToInt32()); 121 | } 122 | 123 | return method; 124 | } 125 | 126 | private static void CleanCctor(IList typeDefs) 127 | { 128 | foreach (TypeDef typeDef in typeDefs) 129 | { 130 | if (typeDef.Name == "") 131 | { 132 | MethodDef cctor = typeDef.FindStaticConstructor(); 133 | 134 | if (cctor.HasBody) 135 | { 136 | cctor.Body.Instructions.Clear(); 137 | cctor.Body.ExceptionHandlers.Clear(); 138 | 139 | cctor.Body.Instructions.Add(new Instruction(OpCodes.Ret)); 140 | } 141 | 142 | break; 143 | } 144 | } 145 | } 146 | } 147 | } --------------------------------------------------------------------------------