diff --git a/.vs/de4dot/v15/Server/sqlite3/db.lock b/.vs/de4dot/v15/Server/sqlite3/db.lock
new file mode 100644
index 00000000..e69de29b
diff --git a/.vs/de4dot/v15/Server/sqlite3/storage.ide b/.vs/de4dot/v15/Server/sqlite3/storage.ide
new file mode 100644
index 00000000..57a761ee
Binary files /dev/null and b/.vs/de4dot/v15/Server/sqlite3/storage.ide differ
diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index 3f660a8f..ea058209 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -166,6 +166,7 @@
+
diff --git a/de4dot.code/deobfuscators/ConfuserEx/ConstantDecrypter.cs b/de4dot.code/deobfuscators/ConfuserEx/ConstantDecrypter.cs
index 69441811..e722dcf1 100644
--- a/de4dot.code/deobfuscators/ConfuserEx/ConstantDecrypter.cs
+++ b/de4dot.code/deobfuscators/ConfuserEx/ConstantDecrypter.cs
@@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
using System.Text;
using de4dot.blocks;
using de4dot.blocks.cflow;
-using de4dot.code.deobfuscators.ConfuserEx.x86;
+//using de4dot.code.deobfuscators.ConfuserEx.x86;
using dnlib.DotNet;
using dnlib.DotNet.Writer;
using FieldAttributes = dnlib.DotNet.FieldAttributes;
@@ -20,7 +20,8 @@ namespace de4dot.code.deobfuscators.ConfuserEx
public class ConstantDecrypterBase
{
private readonly InstructionEmulator _instructionEmulator = new InstructionEmulator();
- private X86Method _nativeMethod;
+ private x86Emulator _nativeEmulator;
+ //private X86Method _nativeMethod;
public MethodDef Method { get; set; }
public byte[] Decrypted { get; set; }
@@ -28,6 +29,11 @@ namespace de4dot.code.deobfuscators.ConfuserEx
public uint Magic2 { get; set; }
public bool CanRemove { get; set; } = true;
+ public ConstantDecrypterBase(x86Emulator nativeEmulator)
+ {
+ _nativeEmulator = nativeEmulator;
+ }
+
// native mode
public MethodDef NativeMethod { get; internal set; }
@@ -43,7 +49,8 @@ namespace de4dot.code.deobfuscators.ConfuserEx
return null;
_instructionEmulator.Pop();
- var result = _nativeMethod.Execute(((Int32Value) popValue).Value);
+ // var result = _nativeMethod.Execute(((Int32Value) popValue).Value);
+ var result = (int?)_nativeEmulator.Emulate(NativeMethod, ((Int32Value)popValue).Value);
return result;
}
@@ -53,7 +60,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
if (NativeMethod != null)
{
_instructionEmulator.Push(new Int32Value((int)index));
- _nativeMethod = new X86Method(NativeMethod, Method.Module as ModuleDefMD); //TODO: Possible null
+ //_nativeMethod = new X86Method(NativeMethod, Method.Module as ModuleDefMD); //TODO: Possible null
var key = CalculateKey();
uint_0 = (uint)key.Value;
@@ -115,12 +122,14 @@ namespace de4dot.code.deobfuscators.ConfuserEx
private byte[] _decryptedBytes;
private FieldDef _decryptedField, _arrayField;
internal TypeDef ArrayType;
+ private x86Emulator _nativeEmulator;
- public ConstantsDecrypter(ModuleDef module, MethodDef lzmaMethod, ISimpleDeobfuscator deobfsucator)
+ public ConstantsDecrypter(ModuleDef module, MethodDef lzmaMethod, ISimpleDeobfuscator deobfsucator, x86Emulator nativeEmulator)
{
_module = module;
_lzmaMethod = lzmaMethod;
_deobfuscator = deobfsucator;
+ _nativeEmulator = nativeEmulator;
}
public bool CanRemoveLzma { get; private set; }
@@ -295,7 +304,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
if (IsNativeStringDecrypter(method, out MethodDef nativeMethod))
{
- yield return new ConstantDecrypterBase
+ yield return new ConstantDecrypterBase(_nativeEmulator)
{
Decrypted = _decryptedBytes,
Method = method,
@@ -304,7 +313,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
}
if (IsNormalStringDecrypter(method, out int num1, out int num2))
{
- yield return new ConstantDecrypterBase
+ yield return new ConstantDecrypterBase(_nativeEmulator)
{
Decrypted = _decryptedBytes,
Method = method,
diff --git a/de4dot.code/deobfuscators/ConfuserEx/ControlFlowFixer.cs b/de4dot.code/deobfuscators/ConfuserEx/ControlFlowFixer.cs
index 8dcc6265..aff82be5 100644
--- a/de4dot.code/deobfuscators/ConfuserEx/ControlFlowFixer.cs
+++ b/de4dot.code/deobfuscators/ConfuserEx/ControlFlowFixer.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using de4dot.blocks;
using de4dot.blocks.cflow;
-using de4dot.code.deobfuscators.ConfuserEx.x86;
+//using de4dot.code.deobfuscators.ConfuserEx.x86;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
@@ -15,10 +15,16 @@ namespace de4dot.code.deobfuscators.ConfuserEx
public List NativeMethods = new List();
private readonly InstructionEmulator _instructionEmulator = new InstructionEmulator();
+ private x86Emulator _nativeEmulator;
private Blocks _blocks;
private Local _switchKey;
+ public ControlFlowFixer(x86Emulator nativeEmulator)
+ {
+ _nativeEmulator = nativeEmulator;
+ }
+
private int? CalculateKey(SwitchData switchData)
{
var popValue = _instructionEmulator.Peek();
@@ -31,8 +37,9 @@ namespace de4dot.code.deobfuscators.ConfuserEx
if (switchData is NativeSwitchData)
{
var nativeSwitchData = (NativeSwitchData)switchData;
- var nativeMethod = new X86Method(nativeSwitchData.NativeMethodDef, _blocks.Method.Module as ModuleDefMD); //TODO: Possible null
- return nativeMethod.Execute(num);
+ //var nativeMethod = new X86Method(nativeSwitchData.NativeMethodDef, _blocks.Method.Module as ModuleDefMD); //TODO: Possible null
+ //return nativeMethod.Execute(num);
+ return (int?)_nativeEmulator.Emulate(nativeSwitchData.NativeMethodDef, num);
}
if (switchData is NormalSwitchData)
{
diff --git a/de4dot.code/deobfuscators/ConfuserEx/Deobfuscator.cs b/de4dot.code/deobfuscators/ConfuserEx/Deobfuscator.cs
index a0e11c5b..8fcf7d0d 100644
--- a/de4dot.code/deobfuscators/ConfuserEx/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/ConfuserEx/Deobfuscator.cs
@@ -50,7 +50,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
private class Deobfuscator : DeobfuscatorBase
{
- private readonly ControlFlowFixer _controlFlowFixer = new ControlFlowFixer();
+ private ControlFlowFixer _controlFlowFixer;
private bool _canRemoveLzma = true;
private ConstantsDecrypter _constantDecrypter;
@@ -58,6 +58,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
private LzmaFinder _lzmaFinder;
private ProxyCallFixer _proxyCallFixer;
private ResourceDecrypter _resourceDecrypter;
+ private x86Emulator _nativeEmulator;
private string _version = "";
public Deobfuscator(Options options)
@@ -103,10 +104,13 @@ namespace de4dot.code.deobfuscators.ConfuserEx
protected override void ScanForObfuscator()
{
+ _nativeEmulator = new x86Emulator(DeobUtils.ReadModule(module));
+
+ _controlFlowFixer = new ControlFlowFixer(_nativeEmulator);
_lzmaFinder = new LzmaFinder(module, DeobfuscatedFile);
_lzmaFinder.Find();
- _constantDecrypter = new ConstantsDecrypter(module, _lzmaFinder.Method, DeobfuscatedFile);
+ _constantDecrypter = new ConstantsDecrypter(module, _lzmaFinder.Method, DeobfuscatedFile, _nativeEmulator);
_resourceDecrypter = new ResourceDecrypter(module, _lzmaFinder.Method, DeobfuscatedFile);
if (_lzmaFinder.FoundLzma)
@@ -115,7 +119,7 @@ namespace de4dot.code.deobfuscators.ConfuserEx
_resourceDecrypter.Find();
}
- _proxyCallFixer = new ProxyCallFixer(module, DeobfuscatedFile);
+ _proxyCallFixer = new ProxyCallFixer(module, DeobfuscatedFile, _nativeEmulator);
_proxyCallFixer.FindDelegateCreatorMethod();
_proxyCallFixer.Find();
diff --git a/de4dot.code/deobfuscators/ConfuserEx/ProxyCallFixer.cs b/de4dot.code/deobfuscators/ConfuserEx/ProxyCallFixer.cs
index 6a8e4611..2466ae27 100644
--- a/de4dot.code/deobfuscators/ConfuserEx/ProxyCallFixer.cs
+++ b/de4dot.code/deobfuscators/ConfuserEx/ProxyCallFixer.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using de4dot.blocks;
using de4dot.blocks.cflow;
-using de4dot.code.deobfuscators.ConfuserEx.x86;
+//using de4dot.code.deobfuscators.ConfuserEx.x86;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
@@ -31,10 +31,12 @@ namespace de4dot.code.deobfuscators.ConfuserEx
public List AttributeTypes = new List();
public List DelegateCreatorMethods = new List();
public List NativeMethods = new List();
+ private x86Emulator _nativeEmulator;
- public ProxyCallFixer(ModuleDefMD module, ISimpleDeobfuscator simpleDeobfuscator) : base(module)
+ public ProxyCallFixer(ModuleDefMD module, ISimpleDeobfuscator simpleDeobfuscator, x86Emulator nativeEmulator) : base(module)
{
_simpleDeobfuscator = simpleDeobfuscator;
+ _nativeEmulator = nativeEmulator;
}
public ProxyCallFixer(ModuleDefMD module, ProxyCallFixer4 oldOne) : base(module, oldOne)
@@ -167,8 +169,9 @@ namespace de4dot.code.deobfuscators.ConfuserEx
private int EmulateNativeMethod(MethodDef externalMethod, int parameter)
{
- var nativeMethod = new X86Method(externalMethod, module); //TODO: Possible null
- return nativeMethod.Execute(parameter);
+ //var nativeMethod = new X86Method(externalMethod, module); //TODO: Possible null
+ //return nativeMethod.Execute(parameter);
+ return (int)_nativeEmulator.Emulate(externalMethod, parameter);
}
private int EmulateManagedMethod(MethodDef method, int startIndex, int endIndex,
diff --git a/de4dot.code/deobfuscators/ConfuserEx/x86Emulator.cs b/de4dot.code/deobfuscators/ConfuserEx/x86Emulator.cs
new file mode 100644
index 00000000..6fbf0dc0
--- /dev/null
+++ b/de4dot.code/deobfuscators/ConfuserEx/x86Emulator.cs
@@ -0,0 +1,282 @@
+using System;
+using System.Collections.Generic;
+using dnlib.DotNet;
+using dnlib.IO;
+
+namespace de4dot.code.deobfuscators.ConfuserEx
+{
+ public class x86Emulator : IDisposable {
+
+ static readonly byte[] prolog2 = new byte[] {
+ 0x89, 0xE0, 0x53, 0x57, 0x56, 0x29, 0xe0,
+ 0x83, 0xf8, 0x18, 0x74, 0x07, 0x8b, 0x44,
+ 0x24, 0x10, 0x50, 0xeb, 0x01, 0x51
+ };
+ static readonly byte[] epilog2 = new byte[] {
+ 0x5E, 0x5F, 0x5B, 0xC3,
+ };
+
+ MyPEImage peImage;
+ IBinaryReader reader;
+ uint[] args;
+ int nextArgIndex;
+ uint[] regs = new uint[8];
+ byte modRM, mod, reg, rm;
+ enum OpCode {
+ Add_RI,
+ Add_RR,
+ Mov_RI,
+ Mov_RR,
+ IMul_RI,
+ IMul_RR,
+ Neg_R,
+ Not_R,
+ Pop_R,
+ Sub_RI,
+ Sub_RR,
+ Xor_RI,
+ Xor_RR,
+ }
+ interface IOperand {}
+ class RegOperand : IOperand {
+ static readonly string[] names = new string[8] { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", };
+ public readonly int reg;
+ public RegOperand(int reg) { this.reg = reg; }
+ public override string ToString() { return names[reg]; }
+ }
+
+ class ImmOperand : IOperand {
+ public readonly int imm;
+
+ public ImmOperand(int imm) {
+ this.imm = imm;
+ }
+
+ public override string ToString() {
+ return string.Format("{0:X2}h", imm);
+ }
+ }
+
+ class Instruction {
+ public readonly OpCode opCode;
+ public IOperand op1;
+ public IOperand op2;
+
+ public Instruction(OpCode opCode) : this(opCode, null, null) { }
+ public Instruction(OpCode opCode, IOperand op1) : this(opCode, op1, null) { }
+
+ public Instruction(OpCode opCode, IOperand op1, IOperand op2) {
+ this.opCode = opCode;
+ this.op1 = op1;
+ this.op2 = op2;
+ }
+
+ public override string ToString() {
+ if (op1 != null && op2 != null)
+ return string.Format("{0} {1},{2}", opCode, op1, op2);
+ if (op1 != null)
+ return string.Format("{0} {1}", opCode, op1);
+ return string.Format("{0}", opCode);
+ }
+ }
+
+ public x86Emulator(byte[] fileData) {
+ peImage = new MyPEImage(fileData);
+ reader = peImage.Reader;
+ }
+
+ public uint Emulate(MethodDef method, int arg)
+ {
+ return Emulate((uint)method.RVA, new uint[] { (uint)arg });
+ }
+
+ public uint Emulate(uint rva, uint arg) {
+ return Emulate(rva, new uint[] { arg });
+ }
+
+ public uint Emulate(uint rva, uint[] args) {
+ Initialize(args);
+ reader.Position = peImage.RvaToOffset(rva);
+ byte[] prolog, epilog;
+ if (IsBytes(prolog2)) {
+ prolog = prolog2;
+ epilog = epilog2;
+ }else
+ throw new ApplicationException(string.Format("Missing prolog @ RVA {0:X8}", rva));
+ reader.Position += prolog.Length;
+ while (!IsBytes(epilog))
+ Emulate();
+
+ return regs[0];
+ }
+
+ void Initialize(uint[] args) {
+ this.args = args;
+ nextArgIndex = 0;
+ for (int i = 0; i < regs.Length; i++)
+ regs[i] = 0;
+ }
+
+ bool IsBytes(IList bytes) {
+ long oldPos = reader.Position;
+ bool result = true;
+ for (int i = 0; i < bytes.Count; i++) {
+ if (bytes[i] != reader.ReadByte()) {
+ result = false;
+ break;
+ }
+ }
+ reader.Position = oldPos;
+ return result;
+ }
+
+ void Emulate() {
+ var instr = Decode();
+ switch (instr.opCode)
+ {
+ case OpCode.Add_RI:
+ case OpCode.Add_RR:
+ WriteReg(instr.op1, ReadOp(instr.op1) + ReadOp(instr.op2));
+ break;
+
+ case OpCode.Mov_RI:
+ case OpCode.Mov_RR:
+ WriteReg(instr.op1, ReadOp(instr.op2));
+ break;
+ case OpCode.IMul_RI:
+ case OpCode.IMul_RR:
+ WriteReg(instr.op1, ReadOp(instr.op1) * ReadOp(instr.op2));
+ break;
+ case OpCode.Neg_R:
+ WriteReg(instr.op1, (uint)-(int)ReadOp(instr.op1));
+ break;
+
+ case OpCode.Not_R:
+ WriteReg(instr.op1, ~ReadOp(instr.op1));
+ break;
+
+ case OpCode.Pop_R:
+ WriteReg(instr.op1, GetNextArg());
+ break;
+
+ case OpCode.Sub_RI:
+ case OpCode.Sub_RR:
+ WriteReg(instr.op1, ReadOp(instr.op1) - ReadOp(instr.op2));
+ break;
+
+ case OpCode.Xor_RI:
+ case OpCode.Xor_RR:
+ WriteReg(instr.op1, ReadOp(instr.op1) ^ ReadOp(instr.op2));
+ break;
+
+ default: throw new NotSupportedException();
+ }
+ }
+
+ uint GetNextArg() {
+ if (nextArgIndex >= args.Length)
+ throw new ApplicationException("No more args");
+ return args[nextArgIndex++];
+ }
+
+ void WriteReg(IOperand op, uint val) {
+ regs[((RegOperand)op).reg] = val;
+ }
+
+ uint ReadOp(IOperand op) {
+ if (op is RegOperand regOp)
+ return regs[regOp.reg];
+ if (op is ImmOperand immOp)
+ return (uint)immOp.imm;
+ throw new NotSupportedException();
+ }
+
+ Instruction Decode()
+ {
+ byte opc = reader.ReadByte();
+ switch (opc)
+ {
+ case 0x01: // ADD Ed,Gd
+ ParseModRM();
+ return new Instruction(OpCode.Add_RR, new RegOperand(rm), new RegOperand(reg));
+
+ case 0x0F: // IMUL Ed,Gd
+ ParseModRM();
+ return new Instruction(OpCode.IMul_RR, new RegOperand(rm), new RegOperand(reg));
+
+ case 0x29: // SUB Ed,Gd
+ ParseModRM();
+ return new Instruction(OpCode.Sub_RR, new RegOperand(rm), new RegOperand(reg));
+
+ case 0x31: // XOR Ed,Gd
+ ParseModRM();
+ return new Instruction(OpCode.Xor_RR, new RegOperand(rm), new RegOperand(reg));
+
+ case 0x58: // POP EAX
+ case 0x59: // POP ECX
+ case 0x5A: // POP EDX
+ case 0x5B: // POP EBX
+ case 0x5C: // POP ESP
+ case 0x5D: // POP EBP
+ case 0x5E: // POP ESI
+ case 0x5F: // POP EDI
+ return new Instruction(OpCode.Pop_R, new RegOperand(opc - 0x58));
+
+ case 0x69: // Imul Ed, Id
+ ParseModRM();
+ return new Instruction(OpCode.IMul_RI, new RegOperand(rm), new ImmOperand(reader.ReadInt32()));
+
+ case 0x81: // Grp1 Ed,Id
+ ParseModRM();
+ switch (reg)
+ {
+ case 0: return new Instruction(OpCode.Add_RI, new RegOperand(rm), new ImmOperand(reader.ReadInt32()));
+ case 5: return new Instruction(OpCode.Sub_RI, new RegOperand(rm), new ImmOperand(reader.ReadInt32()));
+ case 6: return new Instruction(OpCode.Xor_RI, new RegOperand(rm), new ImmOperand(reader.ReadInt32()));
+ default: throw new NotSupportedException();
+ }
+
+ case 0x89: // MOV Ed,Gd
+ ParseModRM();
+ return new Instruction(OpCode.Mov_RR, new RegOperand(rm), new RegOperand(reg));
+
+ case 0xB8: // MOV EAX,Id
+ case 0xB9: // MOV ECX,Id
+ case 0xBA: // MOV EDX,Id
+ case 0xBB: // MOV EBX,Id
+ case 0xBC: // MOV ESP,Id
+ case 0xBD: // MOV EBP,Id
+ case 0xBE: // MOV ESI,Id
+ case 0xBF: // MOV EDI,Id
+ return new Instruction(OpCode.Mov_RI, new RegOperand(opc - 0xB8), new ImmOperand(reader.ReadInt32()));
+
+ case 0xF7: // Grp3 Ev
+ ParseModRM();
+ switch (reg)
+ {
+ case 2: return new Instruction(OpCode.Not_R, new RegOperand(rm));
+ case 3: return new Instruction(OpCode.Neg_R, new RegOperand(rm));
+ default: throw new NotSupportedException();
+ }
+
+ default: throw new NotSupportedException(string.Format("Invalid opcode: {0:X2}", opc));
+ }
+ }
+
+ void ParseModRM() {
+ modRM = reader.ReadByte();
+ mod = (byte)((modRM >> 6) & 7);
+ reg = (byte)((modRM >> 3) & 7);
+ rm = (byte)(modRM & 7);
+ if (mod != 3)
+ throw new ApplicationException("Memory operand");
+ }
+
+ public void Dispose() {
+ if (peImage != null)
+ peImage.Dispose();
+ peImage = null;
+ reader = null;
+ }
+ }
+}