Skip to content

Commit 8f985af

Browse files
authored
Merge pull request #51 from wondercrash/feat/more-options
Add options to manually specify tokens for processors
2 parents 66ea2ce + f6a1b55 commit 8f985af

7 files changed

Lines changed: 135 additions & 35 deletions

File tree

EazFixer/Flags.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1+
using dnlib.DotNet;
2+
13
namespace EazFixer {
24
internal class Flags
35
{
4-
public static string InFile;
5-
public static string OutFile;
6+
public static string InFile;
7+
public static string OutFile;
68

7-
public static bool KeepTypes;
8-
public static bool VirtFix;
9+
public static bool KeepTypes;
10+
public static bool VirtFix;
11+
public static bool PreserveAll;
12+
13+
public static MDToken StrDecTok;
14+
public static MDToken ResResolverTok;
15+
public static MDToken ResInitTok;
16+
public static MDToken AsmResTypeTok;
17+
public static MDToken AsmResMoveNextTok;
18+
public static MDToken AsmResDecompressTok;
19+
public static MDToken AsmResDecryptTok;
920
}
1021
}

EazFixer/Options.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,34 @@ class Options
1212
[Option("out")]
1313
public string OutFile { get; set; }
1414

15-
[Option("keep-types")]
15+
[Option("keep-types", HelpText = "Don't cleanup/remove obfuscator types")]
1616
public bool KeepTypes { get; set; }
1717

18-
[Option("virt-fix")]
18+
[Option("virt-fix", HelpText = "Don't process obfuscated parts necessary for the code virtualization to work")]
1919
public bool VirtFix { get; set; }
20+
21+
[Option("preserve-all", HelpText = "Preserve all metadata")]
22+
public bool PreserveAll { get; set; }
23+
24+
[Option("str-decrypt-tok", Default = "0", HelpText = "Manually specify string decryptor method token for if detection fails (Format: 0x<token>) ")]
25+
public string StrDecTok { get; set; }
26+
27+
[Option("res-resolver-tok", Default = "0", HelpText = "Manually specify resource resolver type token for if detection fails (Format: 0x<token>) ")]
28+
public string ResResolverTok { get; set; }
29+
30+
[Option("res-init-tok", Default = "0", HelpText = "Manually specify resource init method token for if detection fails (Format: 0x<token>) ")]
31+
public string ResInitTok { get; set; }
32+
33+
[Option("asmres-type-tok", Default = "0", HelpText = "Manually specify assembly decryptor type token for if detection fails (Format: 0x<token>) ")]
34+
public string AsmResTypeTok { get; set; }
35+
36+
[Option("asmres-movenext-tok", Default = "0", HelpText = "Manually specify assembly decryptor MoveNext token for if detection fails (Format: 0x<token>) ")]
37+
public string AsmResMoveNextTok { get; set; }
38+
39+
[Option("asmres-decompress-tok", Default = "0", HelpText = "Manually specify assembly decompressor method token for if detection fails (Format: 0x<token>) ")]
40+
public string AsmResDecompressTok { get; set; }
41+
42+
[Option("asmres-decrypt-tok", Default = "0", HelpText = "Manually specify assembly decryptor method token for if detection fails (Format: 0x<token>) ")]
43+
public string AsmResDecryptTok { get; set; }
2044
}
2145
}

EazFixer/Processors/AssemblyResolver.cs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,50 @@ protected override void InitializeInternal()
2222
{
2323
//try to find the embedded assemblies string, which is located in
2424
//the iterator in the EnumerateEmbeddedAssemblies function
25-
_assemblyResolver = Ctx.Module.Types.SingleOrDefault(CanBeAssemblyResolver)
26-
?? throw new Exception("Could not find resolver type");
27-
var extractionApi = _assemblyResolver.NestedTypes.SingleOrDefault(CanBeExtractionApi)
28-
?? throw new Exception("Could not find assembly extraction helper");
29-
var enumerable = extractionApi.NestedTypes.SingleOrDefault(CanBeEnumerable)
30-
?? throw new Exception("Could not find EnumerateEmbeddedAssemblies iterator");
31-
_moveNext = enumerable.Methods.SingleOrDefault(CanBeMoveNext)
32-
?? throw new Exception("Could not find EnumerateEmbeddedAssemblies's MoveNext");
25+
if (!Flags.AsmResTypeTok.IsNull)
26+
_assemblyResolver = Ctx.Module.ResolveToken(Flags.AsmResTypeTok) as TypeDef
27+
?? throw new Exception("AssemblyResolver token set but type not found");
28+
else
29+
_assemblyResolver = Ctx.Module.Types.SingleOrDefault(CanBeAssemblyResolver)
30+
?? throw new Exception("Could not find resolver type");
31+
32+
if (!Flags.AsmResMoveNextTok.IsNull)
33+
_moveNext = Ctx.Module.ResolveToken(Flags.AsmResMoveNextTok) as MethodDef
34+
?? throw new Exception("MoveNext token set but type not found");
35+
else
36+
{
37+
var extractionApi = _assemblyResolver.NestedTypes.SingleOrDefault(CanBeExtractionApi)
38+
?? throw new Exception("Could not find assembly extraction helper");
39+
var enumerable = extractionApi.NestedTypes.SingleOrDefault(CanBeEnumerable)
40+
?? throw new Exception("Could not find EnumerateEmbeddedAssemblies iterator");
41+
_moveNext = enumerable.Methods.SingleOrDefault(CanBeMoveNext)
42+
?? throw new Exception("Could not find EnumerateEmbeddedAssemblies's MoveNext");
43+
}
3344

3445
//find the decryption methods
35-
var dec1 = _assemblyResolver.Methods.SingleOrDefault(CanBeDecryptionMethod)
36-
?? throw new Exception("Could not find decryption method");
37-
_decrypter = Utils.FindMethod(Ctx.Assembly, dec1, new[] {typeof(byte[])})
38-
?? throw new Exception("Couldn't find decrypter through reflection");
3946

40-
var dec2 = _assemblyResolver.Methods.SingleOrDefault(CanBeDecompressionMethod); //this one may be null
47+
MethodDef dec1;
48+
if (!Flags.AsmResDecryptTok.IsNull)
49+
dec1 = Ctx.Module.ResolveToken(Flags.AsmResDecryptTok) as MethodDef
50+
?? throw new Exception("Decrypter token set but method not found");
51+
else
52+
dec1 = _assemblyResolver.Methods.SingleOrDefault(CanBeDecryptionMethod)
53+
?? throw new Exception("Could not find decryption method");
54+
55+
_decrypter = Utils.FindMethod(Ctx.Assembly, dec1, new[] { typeof(byte[]) })
56+
?? throw new Exception("Couldn't find decrypter through reflection");
57+
58+
MethodDef dec2;
59+
if (!Flags.AsmResDecompressTok.IsNull)
60+
dec2 = Ctx.Module.ResolveToken(Flags.AsmResDecompressTok) as MethodDef
61+
?? throw new Exception("Decompressor token set but method not found");
62+
else
63+
dec2 = _assemblyResolver.Methods.SingleOrDefault(CanBeDecompressionMethod);
64+
65+
//this one may be null
4166
if (dec2 != null)
4267
_decompressor = Utils.FindMethod(Ctx.Assembly, dec2, new[] {typeof(byte[])})
43-
?? throw new Exception("Couldn't find prefix remover through reflection");
68+
?? throw new Exception("Couldn't find prefix remover through reflection");
4469
}
4570

4671
protected override void ProcessInternal()

EazFixer/Processors/ResourceResolver.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,19 @@ internal class ResourceResolver : ProcessorBase
1818
protected override void InitializeInternal()
1919
{
2020
//find all "Resources" classes, and store them for later use
21-
_resourceResolver = Ctx.Module.Types.SingleOrDefault(CanBeResourceResolver)
22-
?? throw new Exception("Could not find resolver type");
23-
_initMethod = _resourceResolver.Methods.SingleOrDefault(CanBeInitMethod)
24-
?? throw new Exception("Could not find init method");
21+
if (!Flags.ResResolverTok.IsNull)
22+
_resourceResolver = Ctx.Module.ResolveToken(Flags.ResResolverTok) as TypeDef
23+
?? throw new Exception("ResourceResolver token set but token not found");
24+
else
25+
_resourceResolver = Ctx.Module.Types.SingleOrDefault(CanBeResourceResolver)
26+
?? throw new Exception("Could not find resolver type");
27+
28+
if (!Flags.ResInitTok.IsNull)
29+
_initMethod = Ctx.Module.ResolveToken(Flags.ResInitTok) as MethodDef
30+
?? throw new Exception("InitMethod token set but method not found");
31+
else
32+
_initMethod = _resourceResolver.Methods.SingleOrDefault(CanBeInitMethod)
33+
?? throw new Exception("Could not find init method");
2534
}
2635

2736
protected override void ProcessInternal()

EazFixer/Processors/StringFixer.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ internal class StringFixer : ProcessorBase
1313
protected override void InitializeInternal()
1414
{
1515
//find method
16-
_decrypterMethod = StringFixUtils.FindStringDecryptMethod(Ctx.Module) ??
16+
if (!Flags.StrDecTok.IsNull)
17+
_decrypterMethod = Ctx.Module.ResolveToken(Flags.StrDecTok) as MethodDef
18+
?? throw new Exception("StringDecrypter token set but method not found");
19+
else
20+
_decrypterMethod = StringFixUtils.FindStringDecryptMethod(Ctx.Module) ??
1721
throw new Exception("Could not find decrypter method");
1822
}
1923

EazFixer/Program.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using System.IO;
44
using System.Linq;
55
using CommandLine;
6+
using dnlib.DotNet;
7+
using dnlib.DotNet.Writer;
68
using EazFixer.Processors;
79

810
namespace EazFixer
@@ -19,7 +21,7 @@ private static int Main(string[] args)
1921

2022
//order is important! AssemblyResolver has to be after StringFixer and ResourceResolver
2123
var ctx = new EazContext(!string.IsNullOrEmpty(Flags.InFile) ? Flags.InFile : throw new Exception("Filepath not defined!"),
22-
new ProcessorBase[] {new StringFixer(), new ResourceResolver(), new AssemblyResolver()});
24+
new ProcessorBase[] {new StringFixer(), new ResourceResolver(), new Processors.AssemblyResolver()});
2325

2426
Console.WriteLine("Executing memory patches...");
2527
StacktracePatcher.Patch();
@@ -61,7 +63,7 @@ private static int Main(string[] args)
6163
Console.WriteLine();
6264

6365
Console.WriteLine("Writing new assembly...");
64-
ctx.Module.Write(Flags.OutFile);
66+
ctx.Module.Write(Flags.OutFile, new ModuleWriterOptions(ctx.Module) { MetadataOptions= new MetadataOptions(Flags.PreserveAll ? MetadataFlags.PreserveAll : 0) });
6567

6668
#if DEBUG
6769
return Exit("DONE", true);
@@ -93,7 +95,15 @@ private static void handleOptions(Options args)
9395
Flags.InFile = args.InFile;
9496
Flags.KeepTypes = args.KeepTypes;
9597
Flags.VirtFix = args.VirtFix;
96-
98+
Flags.PreserveAll = args.PreserveAll;
99+
Flags.StrDecTok = new MDToken(Convert.ToUInt32(args.StrDecTok, 16));
100+
Flags.ResResolverTok = new MDToken(Convert.ToUInt32(args.ResResolverTok, 16));
101+
Flags.ResInitTok = new MDToken(Convert.ToUInt32(args.ResInitTok, 16));
102+
Flags.AsmResDecompressTok = new MDToken(Convert.ToUInt32(args.AsmResDecompressTok, 16));
103+
Flags.AsmResDecryptTok = new MDToken(Convert.ToUInt32(args.AsmResDecryptTok, 16));
104+
Flags.AsmResTypeTok = new MDToken(Convert.ToUInt32(args.AsmResTypeTok, 16));
105+
Flags.AsmResMoveNextTok = new MDToken(Convert.ToUInt32(args.AsmResMoveNextTok, 16));
106+
97107
if (args.OutFile != default)
98108
{
99109
Flags.OutFile = args.OutFile;

README.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,44 @@ EazFixer is a deobfuscation tool for [Eazfuscator](https://www.gapotchenko.com/e
2828
Call from the command line or drag and drop the file on and let it run or use the command line flag `--file`.
2929

3030
If your assembly is protected with control-flow obfuscation, run it through [de4dot](https://github.com/0xd4d/de4dot) with the
31-
`--only-cflow-deob` flag first.
31+
`--only-cflow-deob` flag first. This could break the AssemblyResolver processor's method detection, so you may need to manually find the AssemblyResolver tokens and use the `--asmres-decrypt-tok` and `--asmres-decompress-tok` flags.
3232

3333
* --file path
34+
* input file
3435
* --keep-types
36+
* similar to the de4dot flag, keeps obfuscator types and assemblies
3537
* --virt-fix
38+
* keeps certain parts obfuscated to stay working with [virtualized](https://help.gapotchenko.com/eazfuscator.net/30/virtualization) assemblies.
39+
* --preserve-all
40+
* preserves all metadata
3641

37-
The flag `--file` is used for the input file.
38-
The flag `--keep-types` is similar to the de4dot flag, Keeps obfuscator types and assemblies.
39-
The flag `--virt-fix` keeps certain parts obfuscated to stay working with [virtualized](https://help.gapotchenko.com/eazfuscator.net/30/virtualization) assemblies.
42+
The following flags are for manually specifying metadata tokens in the case EazFixer fails to find them. They accept the token in hex format. e.g. `--str-decrypt-tok 0x060002B7`
43+
* --str-decrypt-tok
44+
* string decryption method
45+
* --res-resolver-tok
46+
* resource resolver type
47+
* --res-init-tok
48+
* resource initialization method
49+
* --asmres-type-tok
50+
* assembly resolver type
51+
* --asmres-movenext-tok
52+
* assembly resolver's MoveNext implementation method token
53+
* --asmres-decrypt-tok
54+
* assembly resolver's decryption method
55+
* --asmres-decompress-tok
56+
* assembly resolver's decompression method
4057

4158
example: `EazFixer.exe --file test.exe --keep-types`
4259

4360
## Building
4461
Clone the repository and use the latest version of Visual Studio (2019, at the time of writing).
4562

4663
## Support
47-
EazFixer is (and will always be) targeted at the latest version of Eazfuscator. If your version is not supported, try a more universal
48-
deobfuscator like [de4dot](https://github.com/0xd4d/de4dot). If your version is newer than what this tool supports, create an issue only
64+
EazFixer is (and will always be) targeted at the latest version of Eazfuscator. If your version is not supported, try a more universal
65+
deobfuscator like [de4dot](https://github.com/0xd4d/de4dot). If your version is newer than what this tool supports, create an issue only
4966
**after** verifying with the latest version of Eazfuscator.
5067

51-
Also, I will not help you use this program. Consider it for advanced users only. If you do run into a problem and are sure it is a bug,
68+
Also, I will not help you use this program. Consider it for advanced users only. If you do run into a problem and are sure it is a bug,
5269
feel free to submit an issue but I cannot guarantee I will fix it.
5370

5471
## Related projects

0 commit comments

Comments
 (0)