-
Notifications
You must be signed in to change notification settings - Fork 87
/
Program.cs
248 lines (218 loc) · 12.5 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using AssemblyUnhollower.Contexts;
using AssemblyUnhollower.Passes;
using Iced.Intel;
using UnhollowerBaseLib;
using UnhollowerRuntimeLib;
namespace AssemblyUnhollower
{
public class Program
{
private struct TimingCookie : IDisposable
{
private Stopwatch myStopwatch;
public TimingCookie(string message)
{
LogSupport.Info(message + "... ");
myStopwatch = Stopwatch.StartNew();
}
public void Dispose()
{
LogSupport.Info($"Done in {myStopwatch.Elapsed}");
}
}
public static void AnalyzeDeobfuscationParams(UnhollowerOptions options)
{
RewriteGlobalContext rewriteContext;
using(new TimingCookie("Reading assemblies"))
rewriteContext = new RewriteGlobalContext(options, Directory.EnumerateFiles(options.SourceDir, "*.dll"));
for (var chars = 1; chars <= 3; chars++)
for (var uniq = 3; uniq <= 15; uniq++)
{
options.TypeDeobfuscationCharsPerUniquifier = chars;
options.TypeDeobfuscationMaxUniquifiers = uniq;
rewriteContext.RenamedTypes.Clear();
rewriteContext.RenameGroups.Clear();
Pass05CreateRenameGroups.DoPass(rewriteContext);
var uniqueTypes = rewriteContext.RenameGroups.Values.Count(it => it.Count == 1);
var nonUniqueTypes = rewriteContext.RenameGroups.Values.Count(it => it.Count > 1);
Console.WriteLine($"Chars=\t{chars}\tMaxU=\t{uniq}\tUniq=\t{uniqueTypes}\tNonUniq=\t{nonUniqueTypes}");
}
}
private const string ParamInputDir = "--input=";
private const string ParamOutputDir = "--output=";
private const string ParamMscorlibPath = "--mscorlib=";
private const string ParamUnityDir = "--unity=";
private const string ParamGameAssemblyPath = "--gameassembly=";
private const string ParamUniqChars = "--deobf-uniq-chars=";
private const string ParamUniqMax = "--deobf-uniq-max=";
private const string ParamAnalyze = "--deobf-analyze";
private const string ParamBlacklistAssembly = "--blacklist-assembly=";
private const string ParamNoXrefCache = "--no-xref-cache";
private const string ParamNoCopyUnhollowerLibs = "--no-copy-unhollower-libs";
private const string ParamVerbose = "--verbose";
private const string ParamHelp = "--help";
private const string ParamHelpShort = "-h";
private const string ParamHelpShortSlash = "/?";
private static void PrintUsage()
{
Console.WriteLine("Usage: AssemblyUnhollower [parameters]");
Console.WriteLine("Possible parameters:");
Console.WriteLine($"\t{ParamInputDir}<directory path> - Required. Directory with Il2CppDumper's dummy assemblies");
Console.WriteLine($"\t{ParamOutputDir}<directory path> - Required. Directory to put results into");
Console.WriteLine($"\t{ParamMscorlibPath}<file path> - Required. mscorlib.dll of target runtime system (typically loader's)");
Console.WriteLine($"\t{ParamUnityDir}<directory path> - Optional. Directory with original Unity assemblies for unstripping");
Console.WriteLine($"\t{ParamGameAssemblyPath}<file path> - Optional. Path to GameAssembly.dll. Used for certain analyses");
Console.WriteLine($"\t{ParamUniqChars}<number> - Optional. How many characters per unique token to use during deobfuscation");
Console.WriteLine($"\t{ParamUniqMax}<number> - Optional. How many maximum unique tokens per type are allowed during deobfuscation");
Console.WriteLine($"\t{ParamAnalyze} - Optional. Analyze deobfuscation performance with different parameter values. Will not generate assemblies.");
Console.WriteLine($"\t{ParamBlacklistAssembly}<assembly name> - Optional. Don't write specified assembly to output. Can be used multiple times");
Console.WriteLine($"\t{ParamNoXrefCache} - Optional. Don't generate xref scanning cache. All scanning will be done at runtime.");
Console.WriteLine($"\t{ParamNoCopyUnhollowerLibs} - Optional. Don't copy unhollower libraries to output directory");
Console.WriteLine($"\t{ParamVerbose} - Optional. Produce more console output");
Console.WriteLine($"\t{ParamHelp}, {ParamHelpShort}, {ParamHelpShortSlash} - Optional. Show this help");
}
public static void Main(string[] args)
{
LogSupport.InstallConsoleHandlers();
var options = new UnhollowerOptions();
var analyze = false;
foreach (var s in args)
{
if (s == ParamAnalyze)
analyze = true;
else if (s == ParamHelp || s == ParamHelpShort || s == ParamHelpShortSlash)
{
PrintUsage();
return;
} else if (s == ParamVerbose)
{
LogSupport.TraceHandler += Console.WriteLine;
options.Verbose = true;
} else if (s == ParamNoXrefCache)
options.NoXrefCache = true;
else if (s == ParamNoCopyUnhollowerLibs)
options.NoCopyUnhollowerLibs = true;
else if (s.StartsWith(ParamInputDir))
options.SourceDir = s.Substring(ParamInputDir.Length);
else if (s.StartsWith(ParamOutputDir))
options.OutputDir = s.Substring(ParamOutputDir.Length);
else if (s.StartsWith(ParamMscorlibPath))
options.MscorlibPath = s.Substring(ParamMscorlibPath.Length);
else if (s.StartsWith(ParamUnityDir))
options.UnityBaseLibsDir = s.Substring(ParamUnityDir.Length);
else if (s.StartsWith(ParamGameAssemblyPath))
options.GameAssemblyPath = s.Substring(ParamGameAssemblyPath.Length);
else if(s.StartsWith(ParamUniqChars))
options.TypeDeobfuscationCharsPerUniquifier = Int32.Parse(s.Substring(ParamUniqChars.Length));
else if(s.StartsWith(ParamUniqMax))
options.TypeDeobfuscationMaxUniquifiers = Int32.Parse(s.Substring(ParamUniqMax.Length));
else if(s.StartsWith(ParamBlacklistAssembly))
options.AdditionalAssembliesBlacklist.Add(s.Substring(ParamBlacklistAssembly.Length));
else
{
Console.WriteLine($"Unrecognized option {s}; use -h for help");
return;
}
}
if (analyze)
AnalyzeDeobfuscationParams(options);
else
Main(options);
}
public static void Main(UnhollowerOptions options)
{
if (string.IsNullOrEmpty(options.SourceDir))
{
Console.WriteLine("No input dir specified; use -h for help");
return;
}
if (string.IsNullOrEmpty(options.OutputDir))
{
Console.WriteLine("No target dir specified; use -h for help");
return;
}
if (string.IsNullOrEmpty(options.MscorlibPath))
{
Console.WriteLine("No mscorlib specified; use -h for help");
return;
}
if (!Directory.Exists(options.OutputDir))
Directory.CreateDirectory(options.OutputDir);
RewriteGlobalContext rewriteContext;
using(new TimingCookie("Reading assemblies"))
rewriteContext = new RewriteGlobalContext(options, Directory.EnumerateFiles(options.SourceDir, "*.dll"));
using(new TimingCookie("Computing renames"))
Pass05CreateRenameGroups.DoPass(rewriteContext);
using(new TimingCookie("Creating typedefs"))
Pass10CreateTypedefs.DoPass(rewriteContext);
using(new TimingCookie("Computing struct blittability"))
Pass11ComputeTypeSpecifics.DoPass(rewriteContext);
using(new TimingCookie("Filling typedefs"))
Pass12FillTypedefs.DoPass(rewriteContext);
using(new TimingCookie("Filling generic constraints"))
Pass13FillGenericConstraints.DoPass(rewriteContext);
using(new TimingCookie("Creating members"))
Pass15GenerateMemberContexts.DoPass(rewriteContext);
using(new TimingCookie("Scanning method cross-references"))
Pass16ScanMethodRefs.DoPass(rewriteContext, options);
using(new TimingCookie("Finalizing method declarations"))
Pass18FinalizeMethodContexts.DoPass(rewriteContext);
LogSupport.Info($"{Pass18FinalizeMethodContexts.TotalPotentiallyDeadMethods} total potentially dead methods");
using(new TimingCookie("Filling method parameters"))
Pass19CopyMethodParameters.DoPass(rewriteContext);
using(new TimingCookie("Creating static constructors"))
Pass20GenerateStaticConstructors.DoPass(rewriteContext);
using(new TimingCookie("Creating value type fields"))
Pass21GenerateValueTypeFields.DoPass(rewriteContext);
using(new TimingCookie("Creating enums"))
Pass22GenerateEnums.DoPass(rewriteContext);
using(new TimingCookie("Creating IntPtr constructors"))
Pass23GeneratePointerConstructors.DoPass(rewriteContext);
using(new TimingCookie("Creating type getters"))
Pass24GenerateTypeStaticGetters.DoPass(rewriteContext);
using(new TimingCookie("Creating non-blittable struct constructors"))
Pass25GenerateNonBlittableValueTypeDefaultCtors.DoPass(rewriteContext);
using(new TimingCookie("Creating generic method static constructors"))
Pass30GenerateGenericMethodStoreConstructors.DoPass(rewriteContext);
using(new TimingCookie("Creating field accessors"))
Pass40GenerateFieldAccessors.DoPass(rewriteContext);
using(new TimingCookie("Filling methods"))
Pass50GenerateMethods.DoPass(rewriteContext);
using(new TimingCookie("Generating implicit conversions"))
Pass60AddImplicitConversions.DoPass(rewriteContext);
using(new TimingCookie("Creating properties"))
Pass70GenerateProperties.DoPass(rewriteContext);
if (options.UnityBaseLibsDir != null)
{
using (new TimingCookie("Unstripping types"))
Pass79UnstripTypes.DoPass(rewriteContext);
using (new TimingCookie("Unstripping methods"))
Pass80UnstripMethods.DoPass(rewriteContext);
using (new TimingCookie("Unstripping method bodies"))
Pass81FillUnstrippedMethodBodies.DoPass(rewriteContext);
}
else
LogSupport.Warning("Not performing unstripping as unity libs are not specified");
using(new TimingCookie("Generating forwarded types"))
Pass89GenerateForwarders.DoPass(rewriteContext);
using(new TimingCookie("Writing xref cache"))
Pass89GenerateMethodXrefCache.DoPass(rewriteContext, options);
using(new TimingCookie("Writing assemblies"))
Pass90WriteToDisk.DoPass(rewriteContext, options);
using(new TimingCookie("Writing method pointer map"))
Pass91GenerateMethodPointerMap.DoPass(rewriteContext, options);
if (!options.NoCopyUnhollowerLibs)
{
File.Copy(typeof(IL2CPP).Assembly.Location, Path.Combine(options.OutputDir, typeof(IL2CPP).Assembly.GetName().Name + ".dll"), true);
File.Copy(typeof(RuntimeLibMarker).Assembly.Location, Path.Combine(options.OutputDir, typeof(RuntimeLibMarker).Assembly.GetName().Name + ".dll"), true);
File.Copy(typeof(Decoder).Assembly.Location, Path.Combine(options.OutputDir, typeof(Decoder).Assembly.GetName().Name + ".dll"), true);
}
LogSupport.Info("Done!");
rewriteContext.Dispose();
}
}
}