├── 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 | }
--------------------------------------------------------------------------------