Merge branches 'ef', 'mc' and 'dr' into merged
Conflicts: de4dot.code/de4dot.code.csproj
This commit is contained in:
commit
ee370d6ffe
|
@ -159,7 +159,9 @@
|
||||||
<Compile Include="deobfuscators\DeobUtils.cs" />
|
<Compile Include="deobfuscators\DeobUtils.cs" />
|
||||||
<Compile Include="deobfuscators\Dotfuscator\Deobfuscator.cs" />
|
<Compile Include="deobfuscators\Dotfuscator\Deobfuscator.cs" />
|
||||||
<Compile Include="deobfuscators\Dotfuscator\StringDecrypter.cs" />
|
<Compile Include="deobfuscators\Dotfuscator\StringDecrypter.cs" />
|
||||||
<Compile Include="deobfuscators\Eazfuscator_NET\Dynocode.cs" />
|
<Compile Include="deobfuscators\Eazfuscator_NET\DynamicDynocodeIterator.cs" />
|
||||||
|
<Compile Include="deobfuscators\Eazfuscator_NET\DynocodeService.cs" />
|
||||||
|
<Compile Include="deobfuscators\dotNET_Reactor\v4\DnrMethodCallInliner.cs" />
|
||||||
<Compile Include="deobfuscators\MyPEImage.cs" />
|
<Compile Include="deobfuscators\MyPEImage.cs" />
|
||||||
<Compile Include="deobfuscators\dotNET_Reactor\v3\AntiStrongName.cs" />
|
<Compile Include="deobfuscators\dotNET_Reactor\v3\AntiStrongName.cs" />
|
||||||
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeDecrypter.cs" />
|
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeDecrypter.cs" />
|
||||||
|
|
|
@ -159,6 +159,8 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
||||||
AddTypesToBeRemoved(stringDecrypter.DynocodeTypes, "Dynocode type");
|
AddTypesToBeRemoved(stringDecrypter.DynocodeTypes, "Dynocode type");
|
||||||
AddResourceToBeRemoved(stringDecrypter.Resource, "Encrypted strings");
|
AddResourceToBeRemoved(stringDecrypter.Resource, "Encrypted strings");
|
||||||
}
|
}
|
||||||
|
stringDecrypter.CloseServer();
|
||||||
|
|
||||||
AddTypeToBeRemoved(assemblyResolver.Type, "Assembly resolver type");
|
AddTypeToBeRemoved(assemblyResolver.Type, "Assembly resolver type");
|
||||||
AddTypeToBeRemoved(assemblyResolver.OtherType, "Assembly resolver other type");
|
AddTypeToBeRemoved(assemblyResolver.OtherType, "Assembly resolver other type");
|
||||||
AddTypeToBeRemoved(resourceResolver.Type, "Resource resolver type");
|
AddTypeToBeRemoved(resourceResolver.Type, "Resource resolver type");
|
||||||
|
@ -214,6 +216,14 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
||||||
DotNetUtils.RestoreBody(cctor, allInstructions, allExceptionHandlers);
|
DotNetUtils.RestoreBody(cctor, allInstructions, allExceptionHandlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing) {
|
||||||
|
if (disposing) {
|
||||||
|
if (stringDecrypter != null)
|
||||||
|
stringDecrypter.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
public override IEnumerable<int> GetStringDecrypterMethods() {
|
public override IEnumerable<int> GetStringDecrypterMethods() {
|
||||||
var list = new List<int>();
|
var list = new List<int>();
|
||||||
if (stringDecrypter.Method != null)
|
if (stringDecrypter.Method != null)
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011-2013 de4dot@gmail.com
|
||||||
|
|
||||||
|
This file is part of de4dot.
|
||||||
|
|
||||||
|
de4dot is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
de4dot is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AssemblyData;
|
||||||
|
using de4dot.code.AssemblyClient;
|
||||||
|
using dnlib.DotNet;
|
||||||
|
|
||||||
|
namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
||||||
|
class DynamicDynocodeIterator : IDisposable, IEnumerable<int> {
|
||||||
|
IAssemblyClient assemblyClient;
|
||||||
|
List<TypeDef> dynocodeTypes = new List<TypeDef>();
|
||||||
|
|
||||||
|
public List<TypeDef> Types {
|
||||||
|
get { return dynocodeTypes; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyEnumerator : IEnumerator<int> {
|
||||||
|
DynamicDynocodeIterator ddi;
|
||||||
|
|
||||||
|
public MyEnumerator(DynamicDynocodeIterator ddi) {
|
||||||
|
this.ddi = ddi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Current {
|
||||||
|
get {
|
||||||
|
return (int)ddi.assemblyClient.GenericService.SendMessage(DynocodeService.MSG_CALL_GET_CURRENT, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
}
|
||||||
|
|
||||||
|
object System.Collections.IEnumerator.Current {
|
||||||
|
get { return Current; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext() {
|
||||||
|
return (bool)ddi.assemblyClient.GenericService.SendMessage(DynocodeService.MSG_CALL_MOVE_NEXT, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset() {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
if (assemblyClient != null)
|
||||||
|
assemblyClient.Dispose();
|
||||||
|
assemblyClient = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize(ModuleDef module) {
|
||||||
|
if (assemblyClient != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var serverVersion = NewProcessAssemblyClientFactory.GetServerClrVersion(module);
|
||||||
|
assemblyClient = new NewProcessAssemblyClientFactory(serverVersion).Create(AssemblyServiceType.Generic);
|
||||||
|
assemblyClient.Connect();
|
||||||
|
assemblyClient.WaitConnected();
|
||||||
|
|
||||||
|
assemblyClient.GenericService.LoadUserService(typeof(DynocodeService), null);
|
||||||
|
assemblyClient.GenericService.LoadAssembly(module.Location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateEnumerable(MethodDef ctor, object[] args) {
|
||||||
|
var type = ctor.DeclaringType;
|
||||||
|
while (type.DeclaringType != null)
|
||||||
|
type = type.DeclaringType;
|
||||||
|
dynocodeTypes.Add(type);
|
||||||
|
assemblyClient.GenericService.SendMessage(DynocodeService.MSG_CREATE_ENUMERABLE,
|
||||||
|
new object[] { ctor.MDToken.ToUInt32(), args });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteEnumerableField(uint fieldToken, object value) {
|
||||||
|
assemblyClient.GenericService.SendMessage(DynocodeService.MSG_WRITE_ENUMERABLE_FIELD,
|
||||||
|
new object[] { fieldToken, value });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateEnumerator() {
|
||||||
|
assemblyClient.GenericService.SendMessage(DynocodeService.MSG_CREATE_ENUMERATOR, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<int> GetEnumerator() {
|
||||||
|
return new MyEnumerator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
|
||||||
|
return new MyEnumerator(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,289 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (C) 2011-2013 de4dot@gmail.com
|
|
||||||
|
|
||||||
This file is part of de4dot.
|
|
||||||
|
|
||||||
de4dot is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
de4dot is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using dnlib.DotNet;
|
|
||||||
using dnlib.DotNet.Emit;
|
|
||||||
using de4dot.blocks;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
|
||||||
interface IDynocodeGenerator {
|
|
||||||
IEnumerable<int> GetValues(int input);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Something added in EF 3.5 which they call Dynocode. The string decrypter can now
|
|
||||||
// call some iterator classes that will return some integers that it will use to
|
|
||||||
// XOR some key.
|
|
||||||
class Dynocode {
|
|
||||||
ISimpleDeobfuscator simpleDeobfuscator;
|
|
||||||
Dictionary<TypeDef, IDynocodeGenerator> typeToDCGen = new Dictionary<TypeDef, IDynocodeGenerator>();
|
|
||||||
|
|
||||||
class DCGen1 : IDynocodeGenerator {
|
|
||||||
public int magic1;
|
|
||||||
public int magic2;
|
|
||||||
public int magic3;
|
|
||||||
public int magic4;
|
|
||||||
public int magic5;
|
|
||||||
public int magic6;
|
|
||||||
public int magic7;
|
|
||||||
|
|
||||||
public IEnumerable<int> GetValues(int input) {
|
|
||||||
yield return magic1;
|
|
||||||
yield return magic2;
|
|
||||||
yield return input ^ magic3;
|
|
||||||
yield return magic4;
|
|
||||||
yield return magic5;
|
|
||||||
yield return magic6;
|
|
||||||
yield return input ^ magic7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DCGen2 : IDynocodeGenerator {
|
|
||||||
public int magic1;
|
|
||||||
|
|
||||||
public IEnumerable<int> GetValues(int input) {
|
|
||||||
int x = 0;
|
|
||||||
int y = 1;
|
|
||||||
while (true) {
|
|
||||||
yield return y;
|
|
||||||
if (--input == 0)
|
|
||||||
break;
|
|
||||||
int tmp = y;
|
|
||||||
y = (x + y + input) ^ magic1;
|
|
||||||
x = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DCGen3 : IDynocodeGenerator {
|
|
||||||
public int magic1;
|
|
||||||
public int magic2;
|
|
||||||
public DCGen2 dc2;
|
|
||||||
|
|
||||||
public IEnumerable<int> GetValues(int input) {
|
|
||||||
int i = 7;
|
|
||||||
foreach (var val in dc2.GetValues(input)) {
|
|
||||||
int x = val ^ input;
|
|
||||||
if ((x % 4) == 0)
|
|
||||||
x ^= magic1;
|
|
||||||
if ((x % 16) == 0)
|
|
||||||
x ^= magic2;
|
|
||||||
yield return x;
|
|
||||||
if (--i == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<TypeDef> Types {
|
|
||||||
get {
|
|
||||||
foreach (var type in typeToDCGen.Keys)
|
|
||||||
yield return type.DeclaringType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dynocode(ISimpleDeobfuscator simpleDeobfuscator) {
|
|
||||||
this.simpleDeobfuscator = simpleDeobfuscator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDynocodeGenerator GetDynocodeGenerator(TypeDef type) {
|
|
||||||
if (type == null)
|
|
||||||
return null;
|
|
||||||
var dt = type.DeclaringType;
|
|
||||||
if (dt == null)
|
|
||||||
return null;
|
|
||||||
IDynocodeGenerator dcGen;
|
|
||||||
if (typeToDCGen.TryGetValue(type, out dcGen))
|
|
||||||
return dcGen;
|
|
||||||
|
|
||||||
if (dt.NestedTypes.Count == 1)
|
|
||||||
dcGen = GetDCGen1(type);
|
|
||||||
else if (dt.NestedTypes.Count == 2)
|
|
||||||
dcGen = GetDCGen3(type);
|
|
||||||
|
|
||||||
typeToDCGen[type] = dcGen;
|
|
||||||
|
|
||||||
return dcGen;
|
|
||||||
}
|
|
||||||
|
|
||||||
DCGen1 GetDCGen1(TypeDef type) {
|
|
||||||
var method = GetMoveNext(type);
|
|
||||||
if (method == null)
|
|
||||||
return null;
|
|
||||||
simpleDeobfuscator.Deobfuscate(method);
|
|
||||||
var swLabels = GetSwitchLabels(method);
|
|
||||||
if (swLabels == null || swLabels.Count < 7)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var dcGen = new DCGen1();
|
|
||||||
if (!GetMagicDC1(method, swLabels[0], out dcGen.magic1))
|
|
||||||
return null;
|
|
||||||
if (!GetMagicDC1(method, swLabels[1], out dcGen.magic2))
|
|
||||||
return null;
|
|
||||||
if (!GetMagicXorDC1(method, swLabels[2], out dcGen.magic3))
|
|
||||||
return null;
|
|
||||||
if (!GetMagicDC1(method, swLabels[3], out dcGen.magic4))
|
|
||||||
return null;
|
|
||||||
if (!GetMagicDC1(method, swLabels[4], out dcGen.magic5))
|
|
||||||
return null;
|
|
||||||
if (!GetMagicDC1(method, swLabels[5], out dcGen.magic6))
|
|
||||||
return null;
|
|
||||||
if (!GetMagicXorDC1(method, swLabels[6], out dcGen.magic7))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return dcGen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static IList<Instruction> GetSwitchLabels(MethodDef method) {
|
|
||||||
foreach (var instr in method.Body.Instructions) {
|
|
||||||
if (instr.OpCode.Code != Code.Switch)
|
|
||||||
continue;
|
|
||||||
return instr.Operand as IList<Instruction>;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetMagicDC1(MethodDef method, Instruction target, out int magic) {
|
|
||||||
magic = 0;
|
|
||||||
var instrs = method.Body.Instructions;
|
|
||||||
int index = instrs.IndexOf(target);
|
|
||||||
if (index < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = index; i < instrs.Count - 3; i++) {
|
|
||||||
var instr = instrs[i];
|
|
||||||
if (instr.OpCode.FlowControl != FlowControl.Next)
|
|
||||||
return false;
|
|
||||||
if (instr.OpCode.Code != Code.Stfld)
|
|
||||||
continue;
|
|
||||||
if (instrs[i + 1].OpCode.Code != Code.Ldarg_0)
|
|
||||||
continue;
|
|
||||||
var ldci4 = instrs[i + 2];
|
|
||||||
if (!ldci4.IsLdcI4())
|
|
||||||
continue;
|
|
||||||
if (instrs[i + 3].OpCode.Code != Code.Stfld)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
magic = ldci4.GetLdcI4Value();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetMagicXorDC1(MethodDef method, Instruction target, out int magic) {
|
|
||||||
magic = 0;
|
|
||||||
var instrs = method.Body.Instructions;
|
|
||||||
int index = instrs.IndexOf(target);
|
|
||||||
if (index < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = index; i < instrs.Count - 2; i++) {
|
|
||||||
var instr = instrs[i];
|
|
||||||
if (instr.OpCode.FlowControl != FlowControl.Next)
|
|
||||||
return false;
|
|
||||||
if (!instr.IsLdcI4())
|
|
||||||
continue;
|
|
||||||
if (instrs[i + 1].OpCode.Code != Code.Xor)
|
|
||||||
continue;
|
|
||||||
if (instrs[i + 2].OpCode.Code != Code.Stfld)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
magic = instr.GetLdcI4Value();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DCGen3 GetDCGen3(TypeDef type) {
|
|
||||||
var method = GetMoveNext(type);
|
|
||||||
if (method == null)
|
|
||||||
return null;
|
|
||||||
simpleDeobfuscator.Deobfuscate(method);
|
|
||||||
|
|
||||||
var dcGen = new DCGen3();
|
|
||||||
int index = 0;
|
|
||||||
if (!GetMagicDC3(method, ref index, out dcGen.magic1))
|
|
||||||
return null;
|
|
||||||
if (!GetMagicDC3(method, ref index, out dcGen.magic2))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var dt = type.DeclaringType;
|
|
||||||
dcGen.dc2 = GetDCGen2(dt.NestedTypes[0] == type ? dt.NestedTypes[1] : dt.NestedTypes[0]);
|
|
||||||
|
|
||||||
return dcGen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetMagicDC3(MethodDef method, ref int index, out int magic) {
|
|
||||||
var instrs = method.Body.Instructions;
|
|
||||||
for (int i = index; i < instrs.Count - 2; i++) {
|
|
||||||
var ldci4 = instrs[i];
|
|
||||||
if (!ldci4.IsLdcI4())
|
|
||||||
continue;
|
|
||||||
if (instrs[i + 1].OpCode.Code != Code.Xor)
|
|
||||||
continue;
|
|
||||||
if (instrs[i + 2].OpCode.Code != Code.Stfld)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
index = i + 3;
|
|
||||||
magic = ldci4.GetLdcI4Value();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
magic = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DCGen2 GetDCGen2(TypeDef type) {
|
|
||||||
var method = GetMoveNext(type);
|
|
||||||
if (method == null)
|
|
||||||
return null;
|
|
||||||
simpleDeobfuscator.Deobfuscate(method);
|
|
||||||
|
|
||||||
var dcGen = new DCGen2();
|
|
||||||
int index = 0;
|
|
||||||
if (!GetMagicDC3(method, ref index, out dcGen.magic1))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return dcGen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MethodDef GetMoveNext(TypeDef type) {
|
|
||||||
foreach (var m in type.Methods) {
|
|
||||||
if (!m.IsVirtual)
|
|
||||||
continue;
|
|
||||||
foreach (var mo in m.Overrides) {
|
|
||||||
if (mo.MethodDeclaration.FullName == "System.Boolean System.Collections.IEnumerator::MoveNext()")
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var m in type.Methods) {
|
|
||||||
if (!m.IsVirtual)
|
|
||||||
continue;
|
|
||||||
if (m.Name != "MoveNext")
|
|
||||||
continue;
|
|
||||||
if (!DotNetUtils.IsMethod(m, "System.Boolean", "()"))
|
|
||||||
continue;
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
100
de4dot.code/deobfuscators/Eazfuscator_NET/DynocodeService.cs
Normal file
100
de4dot.code/deobfuscators/Eazfuscator_NET/DynocodeService.cs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011-2013 de4dot@gmail.com
|
||||||
|
|
||||||
|
This file is part of de4dot.
|
||||||
|
|
||||||
|
de4dot is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
de4dot is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using AssemblyData;
|
||||||
|
|
||||||
|
namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
||||||
|
class DynocodeService : IUserGenericService {
|
||||||
|
public const int MSG_CREATE_ENUMERABLE = 0;
|
||||||
|
public const int MSG_WRITE_ENUMERABLE_FIELD = 1;
|
||||||
|
public const int MSG_CREATE_ENUMERATOR = 2;
|
||||||
|
public const int MSG_CALL_GET_CURRENT = 3;
|
||||||
|
public const int MSG_CALL_MOVE_NEXT = 4;
|
||||||
|
|
||||||
|
Module reflObfModule;
|
||||||
|
IEnumerable<int> ienumerable = null;
|
||||||
|
IEnumerator<int> ienumerator = null;
|
||||||
|
|
||||||
|
[CreateUserGenericService]
|
||||||
|
public static IUserGenericService Create() {
|
||||||
|
return new DynocodeService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AssemblyLoaded(Assembly assembly) {
|
||||||
|
this.reflObfModule = assembly.ManifestModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object HandleMessage(int msg, object[] args) {
|
||||||
|
switch (msg) {
|
||||||
|
case MSG_CREATE_ENUMERABLE:
|
||||||
|
CreateEnumerable((uint)args[0], args[1] as object[]);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MSG_WRITE_ENUMERABLE_FIELD:
|
||||||
|
WriteEnumerableField((uint)args[0], args[1] as object);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MSG_CREATE_ENUMERATOR:
|
||||||
|
CreateEnumerator();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MSG_CALL_GET_CURRENT:
|
||||||
|
return CallGetCurrent();
|
||||||
|
|
||||||
|
case MSG_CALL_MOVE_NEXT:
|
||||||
|
return CallMoveNext();
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ApplicationException(string.Format("Invalid msg: {0:X8}", msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateEnumerable(uint ctorToken, object[] args) {
|
||||||
|
var ctor = reflObfModule.ResolveMethod((int)ctorToken) as ConstructorInfo;
|
||||||
|
if (ctor == null)
|
||||||
|
throw new ApplicationException(string.Format("Invalid ctor with token: {0:X8}", ctorToken));
|
||||||
|
ienumerable = (IEnumerable<int>)ctor.Invoke(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteEnumerableField(uint fieldToken, object value) {
|
||||||
|
var field = reflObfModule.ResolveField((int)fieldToken);
|
||||||
|
if (field == null)
|
||||||
|
throw new ApplicationException(string.Format("Invalid field: {0:X8}", fieldToken));
|
||||||
|
field.SetValue(ienumerable, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateEnumerator() {
|
||||||
|
ienumerator = ienumerable.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallGetCurrent() {
|
||||||
|
return ienumerator.Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CallMoveNext() {
|
||||||
|
return ienumerator.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,9 +50,11 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
||||||
|
|
||||||
var getStream2 = GetTheOnlyMethod(type, "System.IO.Stream", "(System.Reflection.Assembly,System.Type,System.String)");
|
var getStream2 = GetTheOnlyMethod(type, "System.IO.Stream", "(System.Reflection.Assembly,System.Type,System.String)");
|
||||||
var getNames = GetTheOnlyMethod(type, "System.String[]", "(System.Reflection.Assembly)");
|
var getNames = GetTheOnlyMethod(type, "System.String[]", "(System.Reflection.Assembly)");
|
||||||
|
var getRefAsms = GetTheOnlyMethod(type, "System.Reflection.AssemblyName[]", "(System.Reflection.Assembly)");
|
||||||
var bitmapCtor = GetTheOnlyMethod(type, "System.Drawing.Bitmap", "(System.Type,System.String)");
|
var bitmapCtor = GetTheOnlyMethod(type, "System.Drawing.Bitmap", "(System.Type,System.String)");
|
||||||
var iconCtor = GetTheOnlyMethod(type, "System.Drawing.Icon", "(System.Type,System.String)");
|
var iconCtor = GetTheOnlyMethod(type, "System.Drawing.Icon", "(System.Type,System.String)");
|
||||||
if (getStream2 == null && getNames == null && bitmapCtor == null && iconCtor == null)
|
if (getStream2 == null && getNames == null && getRefAsms == null &&
|
||||||
|
bitmapCtor == null && iconCtor == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var resource = FindGetManifestResourceStreamTypeResource(type, simpleDeobfuscator, deob);
|
var resource = FindGetManifestResourceStreamTypeResource(type, simpleDeobfuscator, deob);
|
||||||
|
@ -62,6 +64,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
||||||
getManifestResourceStreamType = type;
|
getManifestResourceStreamType = type;
|
||||||
CreateGetManifestResourceStream2(getStream2);
|
CreateGetManifestResourceStream2(getStream2);
|
||||||
CreateGetManifestResourceNames(getNames);
|
CreateGetManifestResourceNames(getNames);
|
||||||
|
CreateGetReferencedAssemblies(getRefAsms);
|
||||||
CreateBitmapCtor(bitmapCtor);
|
CreateBitmapCtor(bitmapCtor);
|
||||||
CreateIconCtor(iconCtor);
|
CreateIconCtor(iconCtor);
|
||||||
getManifestResourceStreamTypeResource = resource;
|
getManifestResourceStreamTypeResource = resource;
|
||||||
|
|
|
@ -27,7 +27,7 @@ using de4dot.blocks;
|
||||||
using de4dot.blocks.cflow;
|
using de4dot.blocks.cflow;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
||||||
class StringDecrypter {
|
class StringDecrypter : IDisposable {
|
||||||
ModuleDefMD module;
|
ModuleDefMD module;
|
||||||
TypeDef stringType;
|
TypeDef stringType;
|
||||||
MethodDef stringMethod;
|
MethodDef stringMethod;
|
||||||
|
@ -47,7 +47,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
||||||
EfConstantsReader stringMethodConsts;
|
EfConstantsReader stringMethodConsts;
|
||||||
bool isV32OrLater;
|
bool isV32OrLater;
|
||||||
int? validStringDecrypterValue;
|
int? validStringDecrypterValue;
|
||||||
Dynocode dynocode;
|
DynamicDynocodeIterator dynocode;
|
||||||
|
|
||||||
class StreamHelperType {
|
class StreamHelperType {
|
||||||
public TypeDef type;
|
public TypeDef type;
|
||||||
|
@ -228,7 +228,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FindConstants(ISimpleDeobfuscator simpleDeobfuscator) {
|
bool FindConstants(ISimpleDeobfuscator simpleDeobfuscator) {
|
||||||
dynocode = new Dynocode(simpleDeobfuscator);
|
dynocode = new DynamicDynocodeIterator();
|
||||||
simpleDeobfuscator.Deobfuscate(stringMethod);
|
simpleDeobfuscator.Deobfuscate(stringMethod);
|
||||||
stringMethodConsts = new EfConstantsReader(stringMethod);
|
stringMethodConsts = new EfConstantsReader(stringMethod);
|
||||||
|
|
||||||
|
@ -671,7 +671,11 @@ done: ;
|
||||||
if (index + 4 >= instrs.Count)
|
if (index + 4 >= instrs.Count)
|
||||||
return false;
|
return false;
|
||||||
var ldloc = instrs[index + 3];
|
var ldloc = instrs[index + 3];
|
||||||
if (!ldloc.IsLdloc() || instrs[index + 4].OpCode.Code != Code.Stfld)
|
var stfld = instrs[index + 4];
|
||||||
|
if (!ldloc.IsLdloc() || stfld.OpCode.Code != Code.Stfld)
|
||||||
|
return false;
|
||||||
|
var enumerableField = stfld.Operand as FieldDef;
|
||||||
|
if (enumerableField == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var initValue = emu.GetLocal(ldloc.GetLocal(stringMethod.Body.Variables)) as Int32Value;
|
var initValue = emu.GetLocal(ldloc.GetLocal(stringMethod.Body.Variables)) as Int32Value;
|
||||||
|
@ -692,19 +696,46 @@ done: ;
|
||||||
if (initValue2 == null || !initValue2.AllBitsValid())
|
if (initValue2 == null || !initValue2.AllBitsValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var dcGen = dynocode.GetDynocodeGenerator(ctor.DeclaringType);
|
int loopStart = GetIndexOfCall(instrs, index, leaveIndex, "System.Int32 System.Collections.Generic.IEnumerator`1<System.Int32>::get_Current()");
|
||||||
if (dcGen == null)
|
int loopEnd = GetIndexOfCall(instrs, loopStart, leaveIndex, "System.Boolean System.Collections.IEnumerator::MoveNext()");
|
||||||
|
if (loopStart < 0 || loopEnd < 0)
|
||||||
return false;
|
return false;
|
||||||
int loopLocalValue = initValue2.value;
|
loopStart++;
|
||||||
foreach (var val in dcGen.GetValues(initValue.value))
|
loopEnd--;
|
||||||
loopLocalValue ^= val;
|
|
||||||
|
dynocode.Initialize(module);
|
||||||
|
var ctorArg = emu.Pop() as Int32Value;
|
||||||
|
if (ctorArg == null || !ctorArg.AllBitsValid())
|
||||||
|
return false;
|
||||||
|
dynocode.CreateEnumerable(ctor, new object[] { ctorArg.value });
|
||||||
|
dynocode.WriteEnumerableField(enumerableField.MDToken.ToUInt32(), initValue.value);
|
||||||
|
dynocode.CreateEnumerator();
|
||||||
|
foreach (var val in dynocode) {
|
||||||
|
emu.Push(new Int32Value(val));
|
||||||
|
for (int i = loopStart; i < loopEnd; i++)
|
||||||
|
emu.Emulate(instrs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
emu.SetLocal(loopLocal, new Int32Value(loopLocalValue));
|
|
||||||
emu.Emulate(instr);
|
|
||||||
index = newIndex - 1;
|
index = newIndex - 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int GetIndexOfCall(IList<Instruction> instrs, int startIndex, int endIndex, string fullMethodName) {
|
||||||
|
if (startIndex < 0 || endIndex < 0)
|
||||||
|
return -1;
|
||||||
|
for (int i = startIndex; i < endIndex; i++) {
|
||||||
|
var instr = instrs[i];
|
||||||
|
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt)
|
||||||
|
continue;
|
||||||
|
var method = instr.Operand as IMethod;
|
||||||
|
if (method == null || method.FullName != fullMethodName)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
Local GetDCLoopLocal(int start, int end) {
|
Local GetDCLoopLocal(int start, int end) {
|
||||||
var instrs = stringMethod.Body.Instructions;
|
var instrs = stringMethod.Body.Instructions;
|
||||||
for (int i = start; i < end - 1; i++) {
|
for (int i = start; i < end - 1; i++) {
|
||||||
|
@ -980,5 +1011,15 @@ done: ;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
CloseServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseServer() {
|
||||||
|
if (dynocode != null)
|
||||||
|
dynocode.Dispose();
|
||||||
|
dynocode = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -722,7 +722,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
|
||||||
decryptStringMethod.Body.ExceptionHandlers.Count >= 2 &&
|
decryptStringMethod.Body.ExceptionHandlers.Count >= 2 &&
|
||||||
new LocalTypes(decryptStringMethod).All(locals35) &&
|
new LocalTypes(decryptStringMethod).All(locals35) &&
|
||||||
CheckTypeFields2(fields35)) {
|
CheckTypeFields2(fields35)) {
|
||||||
return "3.5 - 3.6";
|
return "3.5 - 4.0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
||||||
public const string THE_NAME = "MaxtoCode";
|
public const string THE_NAME = "MaxtoCode";
|
||||||
public const string THE_TYPE = "mc";
|
public const string THE_TYPE = "mc";
|
||||||
const string DEFAULT_REGEX = @"!^[oO01l]+$&" + DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX;
|
const string DEFAULT_REGEX = @"!^[oO01l]+$&!^[A-F0-9]{20,}$&" + DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX;
|
||||||
IntOption stringCodePage;
|
IntOption stringCodePage;
|
||||||
|
|
||||||
public DeobfuscatorInfo()
|
public DeobfuscatorInfo()
|
||||||
|
@ -106,7 +106,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
|
|
||||||
var fileData = DeobUtils.ReadModule(module);
|
var fileData = DeobUtils.ReadModule(module);
|
||||||
decrypterInfo = new DecrypterInfo(mainType, fileData);
|
decrypterInfo = new DecrypterInfo(mainType, fileData);
|
||||||
var methodsDecrypter = new MethodsDecrypter(decrypterInfo);
|
var methodsDecrypter = new MethodsDecrypter(module, decrypterInfo);
|
||||||
|
|
||||||
if (!methodsDecrypter.Decrypt(ref dumpedMethods))
|
if (!methodsDecrypter.Decrypt(ref dumpedMethods))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -95,6 +95,28 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
MagicHi = 0x828ECDA3,
|
MagicHi = 0x828ECDA3,
|
||||||
Version = EncryptionVersion.V7,
|
Version = EncryptionVersion.V7,
|
||||||
},
|
},
|
||||||
|
// 513D4492
|
||||||
|
// 51413BD8
|
||||||
|
// 51413D68
|
||||||
|
// 5166DB4F
|
||||||
|
new EncryptionInfo {
|
||||||
|
MagicLo = 0x1A683B87,
|
||||||
|
MagicHi = 0x128ECDA3,
|
||||||
|
Version = EncryptionVersion.V8,
|
||||||
|
},
|
||||||
|
// 51927495
|
||||||
|
new EncryptionInfo {
|
||||||
|
MagicLo = 0x7A643B87,
|
||||||
|
MagicHi = 0x624ECDA3,
|
||||||
|
Version = EncryptionVersion.V8,
|
||||||
|
},
|
||||||
|
// 526BC020
|
||||||
|
// 526BDD12
|
||||||
|
new EncryptionInfo {
|
||||||
|
MagicLo = 0x9A683B87,
|
||||||
|
MagicHi = 0x928ECDA3,
|
||||||
|
Version = EncryptionVersion.V8,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly EncryptionInfo[] McKey8C0h = new EncryptionInfo[] {
|
public static readonly EncryptionInfo[] McKey8C0h = new EncryptionInfo[] {
|
||||||
|
@ -149,6 +171,23 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
MagicHi = 0x8723891F,
|
MagicHi = 0x8723891F,
|
||||||
Version = EncryptionVersion.V7,
|
Version = EncryptionVersion.V7,
|
||||||
},
|
},
|
||||||
|
// 513D4492
|
||||||
|
// 51413BD8
|
||||||
|
// 51413D68
|
||||||
|
// 5166DB4F
|
||||||
|
// 526BC020
|
||||||
|
// 526BDD12
|
||||||
|
new EncryptionInfo {
|
||||||
|
MagicLo = 0x1A731B13,
|
||||||
|
MagicHi = 0x1723891F,
|
||||||
|
Version = EncryptionVersion.V8,
|
||||||
|
},
|
||||||
|
// 51927495
|
||||||
|
new EncryptionInfo {
|
||||||
|
MagicLo = 0x7A731B13,
|
||||||
|
MagicHi = 0x1723891F,
|
||||||
|
Version = EncryptionVersion.V8,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
ModuleDefMD module;
|
ModuleDefMD module;
|
||||||
TypeDef mcType;
|
TypeDef mcType;
|
||||||
bool isOld;
|
bool isOld;
|
||||||
|
ModuleRef runtimeModule1, runtimeModule2;
|
||||||
|
|
||||||
public bool IsOld {
|
public bool IsOld {
|
||||||
get { return isOld; }
|
get { return isOld; }
|
||||||
|
@ -49,6 +50,15 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ModuleRef> RuntimeModuleRefs {
|
||||||
|
get {
|
||||||
|
if (runtimeModule1 != null)
|
||||||
|
yield return runtimeModule1;
|
||||||
|
if (runtimeModule2 != null)
|
||||||
|
yield return runtimeModule2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool Detected {
|
public bool Detected {
|
||||||
get { return mcType != null; }
|
get { return mcType != null; }
|
||||||
}
|
}
|
||||||
|
@ -80,9 +90,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
if (!DotNetUtils.IsMethod(method, "System.Void", "()"))
|
if (!DotNetUtils.IsMethod(method, "System.Void", "()"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ModuleRef module1, module2;
|
|
||||||
bool isOldTmp;
|
bool isOldTmp;
|
||||||
if (!CheckType(method.DeclaringType, out module1, out module2, out isOldTmp))
|
if (!CheckType(method.DeclaringType, out runtimeModule1, out runtimeModule2, out isOldTmp))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mcType = method.DeclaringType;
|
mcType = method.DeclaringType;
|
||||||
|
|
|
@ -21,15 +21,19 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using dnlib.DotNet;
|
||||||
using dnlib.IO;
|
using dnlib.IO;
|
||||||
|
using dnlib.PE;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.MaxtoCode {
|
namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
// Decrypts methods, resources and strings (#US heap)
|
// Decrypts methods, resources and strings (#US heap)
|
||||||
class MethodsDecrypter {
|
class MethodsDecrypter {
|
||||||
|
ModuleDef module;
|
||||||
DecrypterInfo decrypterInfo;
|
DecrypterInfo decrypterInfo;
|
||||||
|
|
||||||
class MethodInfos {
|
class MethodInfos {
|
||||||
|
ModuleDef module;
|
||||||
MainType mainType;
|
MainType mainType;
|
||||||
MyPEImage peImage;
|
MyPEImage peImage;
|
||||||
PeHeader peHeader;
|
PeHeader peHeader;
|
||||||
|
@ -43,16 +47,6 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
const int ENCRYPTED_DATA_INFO_SIZE = 0x13;
|
const int ENCRYPTED_DATA_INFO_SIZE = 0x13;
|
||||||
|
|
||||||
delegate byte[] DecryptFunc(byte[] encrypted);
|
delegate byte[] DecryptFunc(byte[] encrypted);
|
||||||
readonly DecryptFunc[] decryptHandlersV1a;
|
|
||||||
readonly DecryptFunc[] decryptHandlersV1b;
|
|
||||||
readonly DecryptFunc[] decryptHandlersV2;
|
|
||||||
readonly DecryptFunc[] decryptHandlersV3;
|
|
||||||
readonly DecryptFunc[] decryptHandlersV4;
|
|
||||||
readonly DecryptFunc[] decryptHandlersV5a;
|
|
||||||
readonly DecryptFunc[] decryptHandlersV5b;
|
|
||||||
readonly DecryptFunc[] decryptHandlersV5c;
|
|
||||||
readonly DecryptFunc[] decryptHandlersV6;
|
|
||||||
readonly DecryptFunc[] decryptHandlersV7;
|
|
||||||
|
|
||||||
public class DecryptedMethodInfo {
|
public class DecryptedMethodInfo {
|
||||||
public uint bodyRva;
|
public uint bodyRva;
|
||||||
|
@ -64,23 +58,13 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodInfos(MainType mainType, MyPEImage peImage, PeHeader peHeader, McKey mcKey) {
|
public MethodInfos(ModuleDef module, MainType mainType, MyPEImage peImage, PeHeader peHeader, McKey mcKey) {
|
||||||
|
this.module = module;
|
||||||
this.mainType = mainType;
|
this.mainType = mainType;
|
||||||
this.peImage = peImage;
|
this.peImage = peImage;
|
||||||
this.peHeader = peHeader;
|
this.peHeader = peHeader;
|
||||||
this.mcKey = mcKey;
|
this.mcKey = mcKey;
|
||||||
|
|
||||||
decryptHandlersV1a = new DecryptFunc[] { Decrypt1_v1, Decrypt4_v1, Decrypt2_v1, Decrypt3_v1, Decrypt5, Decrypt6, Decrypt7 };
|
|
||||||
decryptHandlersV1b = new DecryptFunc[] { Decrypt4_v1, Decrypt1_v1, Decrypt2_v1, Decrypt3_v1, Decrypt5, Decrypt6, Decrypt7 };
|
|
||||||
decryptHandlersV2 = new DecryptFunc[] { Decrypt3_v1, Decrypt2_v1, Decrypt1_v1, Decrypt4_v1, Decrypt5, Decrypt6, Decrypt7 };
|
|
||||||
decryptHandlersV3 = new DecryptFunc[] { Decrypt1_v1, Decrypt2_v1, Decrypt3_v1, Decrypt4_v1, Decrypt5, Decrypt6, Decrypt7 };
|
|
||||||
decryptHandlersV4 = new DecryptFunc[] { Decrypt2_v1, Decrypt1_v1, Decrypt3_v1, Decrypt4_v1, Decrypt5, Decrypt6, Decrypt7 };
|
|
||||||
decryptHandlersV5a = new DecryptFunc[] { Decrypt4_v1, Decrypt2_v1, Decrypt3_v1, Decrypt1_v1, Decrypt5, Decrypt6, Decrypt7 };
|
|
||||||
decryptHandlersV5b = new DecryptFunc[] { Decrypt4_v2, Decrypt2_v2, Decrypt3_v2, Decrypt1_v2, Decrypt6, Decrypt7, Decrypt5 };
|
|
||||||
decryptHandlersV5c = new DecryptFunc[] { Decrypt4_v3, Decrypt2_v3, Decrypt3_v3, Decrypt1_v3, Decrypt6, Decrypt7, Decrypt5 };
|
|
||||||
decryptHandlersV6 = new DecryptFunc[] { Decrypt4_v4, Decrypt2_v4, Decrypt3_v4, Decrypt1_v4, Decrypt6, Decrypt7, Decrypt5 };
|
|
||||||
decryptHandlersV7 = new DecryptFunc[] { Decrypt4_v5, Decrypt2_v5, Decrypt3_v5, Decrypt1_v5, Decrypt6, Decrypt8_v5, Decrypt9_v5, Decrypt7, Decrypt5 };
|
|
||||||
|
|
||||||
structSize = GetStructSize(mcKey);
|
structSize = GetStructSize(mcKey);
|
||||||
|
|
||||||
uint methodInfosRva = peHeader.GetRva(0x0FF8, mcKey.ReadUInt32(0x005A));
|
uint methodInfosRva = peHeader.GetRva(0x0FF8, mcKey.ReadUInt32(0x005A));
|
||||||
|
@ -152,13 +136,20 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
|
|
||||||
interface IDecrypter {
|
interface IDecrypter {
|
||||||
byte[] Decrypt(int type, byte[] encrypted);
|
byte[] Decrypt(int type, byte[] encrypted);
|
||||||
|
bool HasTimeStamp(uint timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Decrypter : IDecrypter {
|
class Decrypter : IDecrypter {
|
||||||
DecryptFunc[] decrypterHandlers;
|
DecryptFunc[] decrypterHandlers;
|
||||||
|
uint[] timeStamps;
|
||||||
|
|
||||||
public Decrypter(DecryptFunc[] decrypterHandlers) {
|
public Decrypter(DecryptFunc[] decrypterHandlers)
|
||||||
|
: this(decrypterHandlers, null) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Decrypter(DecryptFunc[] decrypterHandlers, uint[] timeStamps) {
|
||||||
this.decrypterHandlers = decrypterHandlers;
|
this.decrypterHandlers = decrypterHandlers;
|
||||||
|
this.timeStamps = timeStamps ?? new uint[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Decrypt(int type, byte[] encrypted) {
|
public byte[] Decrypt(int type, byte[] encrypted) {
|
||||||
|
@ -166,27 +157,44 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return decrypterHandlers[type - 1](encrypted);
|
return decrypterHandlers[type - 1](encrypted);
|
||||||
throw new ApplicationException(string.Format("Invalid encryption type: {0:X2}", type));
|
throw new ApplicationException(string.Format("Invalid encryption type: {0:X2}", type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HasTimeStamp(uint timeStamp) {
|
||||||
|
foreach (var ts in timeStamps) {
|
||||||
|
if (timeStamp == ts)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeDecrypter() {
|
void InitializeDecrypter() {
|
||||||
switch (GetVersion()) {
|
switch (GetVersion()) {
|
||||||
case EncryptionVersion.V1:
|
case EncryptionVersion.V1:
|
||||||
decrypters.Add(new Decrypter(decryptHandlersV1a));
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt1_v1, Decrypt4_v1, Decrypt2_v1, Decrypt3_v1, Decrypt5, Decrypt6, Decrypt7 }, new uint[] { 0x462FA2D2 }));
|
||||||
decrypters.Add(new Decrypter(decryptHandlersV1b));
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v1, Decrypt1_v1, Decrypt2_v1, Decrypt3_v1, Decrypt5, Decrypt6, Decrypt7 }, new uint[] { 0x471299D3 }));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EncryptionVersion.V2: decrypters.Add(new Decrypter(decryptHandlersV2)); break;
|
case EncryptionVersion.V2: decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt3_v1, Decrypt2_v1, Decrypt1_v1, Decrypt4_v1, Decrypt5, Decrypt6, Decrypt7 }, new uint[] { 0x482384FB, 0x4A5EEC64, 0x4BD6F703, 0x4C6220EC, 0x4C622357, 0x4C6E4605, 0x4D0E220D, 0x4DC2FC75, 0x4DC2FE0C, 0x4DFA3D5D })); break;
|
||||||
case EncryptionVersion.V3: decrypters.Add(new Decrypter(decryptHandlersV3)); break;
|
case EncryptionVersion.V3: decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt1_v1, Decrypt2_v1, Decrypt3_v1, Decrypt4_v1, Decrypt5, Decrypt6, Decrypt7 }, new uint[] { 0x4ECF2195, 0x4ED76740, 0x4EE1FAD1 })); break;
|
||||||
case EncryptionVersion.V4: decrypters.Add(new Decrypter(decryptHandlersV4)); break;
|
case EncryptionVersion.V4: decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt2_v1, Decrypt1_v1, Decrypt3_v1, Decrypt4_v1, Decrypt5, Decrypt6, Decrypt7 }, new uint[] { 0x4F832868, 0x4F8C86BE, 0x4F9447DB, 0x4FDEF2FF })); break;
|
||||||
|
|
||||||
case EncryptionVersion.V5:
|
case EncryptionVersion.V5:
|
||||||
decrypters.Add(new Decrypter(decryptHandlersV5a));
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v1, Decrypt2_v1, Decrypt3_v1, Decrypt1_v1, Decrypt5, Decrypt6, Decrypt7 }, new uint[] { 0x4F8E262C, 0x4F966B0B, 0x4FAB3CCF }));
|
||||||
decrypters.Add(new Decrypter(decryptHandlersV5b));
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v2, Decrypt2_v2, Decrypt3_v2, Decrypt1_v2, Decrypt6, Decrypt7, Decrypt5 }, new uint[] { 0x4FC7459E, 0x4FCEBD7B }));
|
||||||
decrypters.Add(new Decrypter(decryptHandlersV5c));
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v3, Decrypt2_v3, Decrypt3_v3, Decrypt1_v3, Decrypt6, Decrypt7, Decrypt5 }, new uint[] { 0x4FBE81DE }));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EncryptionVersion.V6: decrypters.Add(new Decrypter(decryptHandlersV6)); break;
|
case EncryptionVersion.V6: decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v4, Decrypt2_v4, Decrypt3_v4, Decrypt1_v4, Decrypt6, Decrypt7, Decrypt5 }, new uint[] { 0x50A0963C })); break;
|
||||||
case EncryptionVersion.V7: decrypters.Add(new Decrypter(decryptHandlersV7)); break;
|
case EncryptionVersion.V7: decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v5, Decrypt2_v5, Decrypt3_v5, Decrypt1_v5, Decrypt6, Decrypt8_v5, Decrypt9_v5, Decrypt7, Decrypt5 }, new uint[] { 0x50D367A5 })); break;
|
||||||
|
|
||||||
|
case EncryptionVersion.V8:
|
||||||
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v6, Decrypt2_v2, Decrypt3_v6, Decrypt1_v6, Decrypt6, Decrypt8_v6, Decrypt9_v6, Decrypt7, Decrypt10, Decrypt5 }, new uint[] { 0x5166DB4F, 0x51927495 }));
|
||||||
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v7, Decrypt2_v2, Decrypt3_v6, Decrypt1_v7, Decrypt6, Decrypt8_v7, Decrypt9_v7, Decrypt7, Decrypt5 }, new uint[] { 0x51413D68 }));
|
||||||
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v7, Decrypt2_v2, Decrypt3_v6, Decrypt1_v7, Decrypt6, Decrypt8_v8, Decrypt9_v8, Decrypt7, Decrypt5 }, new uint[] { 0x513D7124, 0x51413BD8 }));
|
||||||
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v5, Decrypt2_v2, Decrypt3_v6, Decrypt1_v9, Decrypt6, Decrypt8_v8, Decrypt9_v9, Decrypt7, Decrypt5 }, new uint[] { 0x513D4492, 0x5113E277 }));
|
||||||
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt3_v6, Decrypt2_v2, Decrypt4_v8, Decrypt1_v10, Decrypt8_v9, Decrypt9_v10, Decrypt6, Decrypt7, Decrypt5 }, new uint[] { 0x526BDD12 }));
|
||||||
|
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt1_v10, Decrypt4_v8, Decrypt2_v2, Decrypt3_v6, Decrypt6, Decrypt8_v9, Decrypt9_v10, Decrypt7, Decrypt5 }, new uint[] { 0x526BC020 }));
|
||||||
|
break;
|
||||||
|
|
||||||
case EncryptionVersion.Unknown:
|
case EncryptionVersion.Unknown:
|
||||||
default:
|
default:
|
||||||
|
@ -200,8 +208,46 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
throw new ApplicationException("Could not decrypt methods");
|
throw new ApplicationException("Could not decrypt methods");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint GetRuntimeTimeStamp() {
|
||||||
|
string path = module.Location;
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var rtNames = new List<string>();
|
||||||
|
foreach (var rtModRef in mainType.RuntimeModuleRefs) {
|
||||||
|
string dllName = rtModRef.Name;
|
||||||
|
if (!dllName.ToUpperInvariant().EndsWith(".DLL"))
|
||||||
|
dllName += ".dll";
|
||||||
|
rtNames.Add(dllName);
|
||||||
|
}
|
||||||
|
if (rtNames.Count == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (var di = new DirectoryInfo(Path.GetDirectoryName(path)); di != null; di = di.Parent) {
|
||||||
|
foreach (var dllName in rtNames) {
|
||||||
|
try {
|
||||||
|
using (var peImage = new PEImage(Path.Combine(di.FullName, dllName))) {
|
||||||
|
if (peImage.ImageNTHeaders.FileHeader.Machine == Machine.I386)
|
||||||
|
return peImage.ImageNTHeaders.FileHeader.TimeDateStamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool InitializeInfos2() {
|
bool InitializeInfos2() {
|
||||||
foreach (var decrypter in decrypters) {
|
uint rtTimeStamp = GetRuntimeTimeStamp();
|
||||||
|
if (rtTimeStamp != 0) {
|
||||||
|
var decrypter = GetCorrectDecrypter(rtTimeStamp);
|
||||||
|
if (decrypter != null) {
|
||||||
try {
|
try {
|
||||||
if (InitializeInfos2(decrypter))
|
if (InitializeInfos2(decrypter))
|
||||||
return true;
|
return true;
|
||||||
|
@ -209,7 +255,35 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
catch {
|
catch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<uint, DecryptedMethodInfo> savedInfos = null;
|
||||||
|
foreach (var decrypter in decrypters) {
|
||||||
|
try {
|
||||||
|
if (InitializeInfos2(decrypter)) {
|
||||||
|
if (savedInfos != null) {
|
||||||
|
Logger.w("Decryption probably failed. Make sure the correct MaxtoCode runtime file is present.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
savedInfos = infos;
|
||||||
|
infos = new Dictionary<uint, DecryptedMethodInfo>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (savedInfos == null)
|
||||||
return false;
|
return false;
|
||||||
|
infos = savedInfos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDecrypter GetCorrectDecrypter(uint timeStamp) {
|
||||||
|
foreach (var decrypter in decrypters) {
|
||||||
|
if (decrypter.HasTimeStamp(timeStamp))
|
||||||
|
return decrypter;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InitializeInfos2(IDecrypter decrypter) {
|
bool InitializeInfos2(IDecrypter decrypter) {
|
||||||
|
@ -222,6 +296,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
var encryptedDataInfos = new byte[numEncryptedDataInfos][];
|
var encryptedDataInfos = new byte[numEncryptedDataInfos][];
|
||||||
|
|
||||||
uint offset = 8;
|
uint offset = 8;
|
||||||
|
infos.Clear();
|
||||||
for (int i = 0; i < numMethods; i++, offset += structSize) {
|
for (int i = 0; i < numMethods; i++, offset += structSize) {
|
||||||
uint methodBodyRva = ReadEncryptedUInt32(offset);
|
uint methodBodyRva = ReadEncryptedUInt32(offset);
|
||||||
uint totalSize = ReadEncryptedUInt32(offset + 4);
|
uint totalSize = ReadEncryptedUInt32(offset + 4);
|
||||||
|
@ -313,6 +388,22 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return Decrypt1(encrypted, 9, 9, 0x500);
|
return Decrypt1(encrypted, 9, 9, 0x500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt1_v6(byte[] encrypted) {
|
||||||
|
return Decrypt1(encrypted, 0x27, 0x27, 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt1_v7(byte[] encrypted) {
|
||||||
|
return Decrypt1(encrypted, 0x1D, 0x1D, 0x400);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt1_v9(byte[] encrypted) {
|
||||||
|
return Decrypt1(encrypted, 9, 0x13, 0x400);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt1_v10(byte[] encrypted) {
|
||||||
|
return Decrypt1(encrypted, 0x11, 0x11, 0x400);
|
||||||
|
}
|
||||||
|
|
||||||
byte[] Decrypt1(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
|
byte[] Decrypt1(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
|
||||||
var decrypted = new byte[encrypted.Length];
|
var decrypted = new byte[encrypted.Length];
|
||||||
for (int i = 0, ki = keyStart; i < decrypted.Length; i++) {
|
for (int i = 0, ki = keyStart; i < decrypted.Length; i++) {
|
||||||
|
@ -386,6 +477,10 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return Decrypt3(encrypted, 0x015E + 7);
|
return Decrypt3(encrypted, 0x015E + 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt3_v6(byte[] encrypted) {
|
||||||
|
return Decrypt3(encrypted, 0x015E + 0x7F);
|
||||||
|
}
|
||||||
|
|
||||||
static readonly byte[] decrypt3Shifts = new byte[16] { 5, 11, 14, 21, 6, 20, 17, 29, 4, 10, 3, 2, 7, 1, 26, 18 };
|
static readonly byte[] decrypt3Shifts = new byte[16] { 5, 11, 14, 21, 6, 20, 17, 29, 4, 10, 3, 2, 7, 1, 26, 18 };
|
||||||
byte[] Decrypt3(byte[] encrypted, int offset) {
|
byte[] Decrypt3(byte[] encrypted, int offset) {
|
||||||
if ((encrypted.Length & 7) != 0)
|
if ((encrypted.Length & 7) != 0)
|
||||||
|
@ -435,6 +530,18 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return Decrypt4(encrypted, 0x15, 0x15, 0x100);
|
return Decrypt4(encrypted, 0x15, 0x15, 0x100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt4_v6(byte[] encrypted) {
|
||||||
|
return Decrypt4(encrypted, 0x63, 0x63, 0x150);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt4_v7(byte[] encrypted) {
|
||||||
|
return Decrypt4(encrypted, 0x0B, 0x0B, 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt4_v8(byte[] encrypted) {
|
||||||
|
return Decrypt4(encrypted, 9, 9, 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
byte[] Decrypt4(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
|
byte[] Decrypt4(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
|
||||||
var decrypted = new byte[encrypted.Length / 3 * 2 + 1];
|
var decrypted = new byte[encrypted.Length / 3 * 2 + 1];
|
||||||
|
|
||||||
|
@ -476,6 +583,22 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return Decrypt8(encrypted, 7, 7, 0x600);
|
return Decrypt8(encrypted, 7, 7, 0x600);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt8_v6(byte[] encrypted) {
|
||||||
|
return Decrypt8(encrypted, 0x1B, 0x1B, 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt8_v7(byte[] encrypted) {
|
||||||
|
return Decrypt8(encrypted, 0x0D, 0x0D, 0x600);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt8_v8(byte[] encrypted) {
|
||||||
|
return Decrypt8(encrypted, 0x11, 0x11, 0x600);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt8_v9(byte[] encrypted) {
|
||||||
|
return Decrypt8(encrypted, 0xA, 0xA, 0x600);
|
||||||
|
}
|
||||||
|
|
||||||
byte[] Decrypt8(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
|
byte[] Decrypt8(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
|
||||||
var decrypted = new byte[encrypted.Length];
|
var decrypted = new byte[encrypted.Length];
|
||||||
int ki = keyStart;
|
int ki = keyStart;
|
||||||
|
@ -493,6 +616,26 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return Decrypt9(encrypted, 0x11, 0x11, 0x610);
|
return Decrypt9(encrypted, 0x11, 0x11, 0x610);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt9_v6(byte[] encrypted) {
|
||||||
|
return Decrypt9(encrypted, 0x2E, 0x2E, 0x310);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt9_v7(byte[] encrypted) {
|
||||||
|
return Decrypt9(encrypted, 0x28, 0x28, 0x510);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt9_v8(byte[] encrypted) {
|
||||||
|
return Decrypt9(encrypted, 0x2C, 0x2C, 0x510);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt9_v9(byte[] encrypted) {
|
||||||
|
return Decrypt9(encrypted, 0x10, 0x10, 0x510);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt9_v10(byte[] encrypted) {
|
||||||
|
return Decrypt9(encrypted, 5, 5, 0x510);
|
||||||
|
}
|
||||||
|
|
||||||
byte[] Decrypt9(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
|
byte[] Decrypt9(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
|
||||||
var decrypted = new byte[encrypted.Length];
|
var decrypted = new byte[encrypted.Length];
|
||||||
int ki = keyStart;
|
int ki = keyStart;
|
||||||
|
@ -527,6 +670,31 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return decrypted;
|
return decrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] Decrypt10(byte[] encrypted) {
|
||||||
|
byte[] enc = (byte[])encrypted.Clone();
|
||||||
|
byte[] dest = new byte[enc.Length];
|
||||||
|
int halfSize = enc.Length / 2;
|
||||||
|
|
||||||
|
byte b = enc[0];
|
||||||
|
b ^= 0xA1;
|
||||||
|
dest[0] = b;
|
||||||
|
|
||||||
|
b = enc[enc.Length - 1];
|
||||||
|
b ^= 0x1A;
|
||||||
|
dest[enc.Length - 1] = b;
|
||||||
|
|
||||||
|
enc[0] = dest[0];
|
||||||
|
enc[enc.Length - 1] = b;
|
||||||
|
|
||||||
|
for (int i = 1; i < halfSize; i++)
|
||||||
|
dest[i] = (byte)(enc[i] ^ dest[i - 1]);
|
||||||
|
|
||||||
|
for (int i = enc.Length - 2; i >= halfSize; i--)
|
||||||
|
dest[i] = (byte)(enc[i] ^ dest[i + 1]);
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
byte[] blowfishKey;
|
byte[] blowfishKey;
|
||||||
byte[] GetBlowfishKey() {
|
byte[] GetBlowfishKey() {
|
||||||
if (blowfishKey != null)
|
if (blowfishKey != null)
|
||||||
|
@ -546,7 +714,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodsDecrypter(DecrypterInfo decrypterInfo) {
|
public MethodsDecrypter(ModuleDef module, DecrypterInfo decrypterInfo) {
|
||||||
|
this.module = module;
|
||||||
this.decrypterInfo = decrypterInfo;
|
this.decrypterInfo = decrypterInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,7 +734,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
var dumpedMethods = new DumpedMethods();
|
var dumpedMethods = new DumpedMethods();
|
||||||
|
|
||||||
var peImage = decrypterInfo.peImage;
|
var peImage = decrypterInfo.peImage;
|
||||||
var methodInfos = new MethodInfos(decrypterInfo.mainType, peImage, decrypterInfo.peHeader, decrypterInfo.mcKey);
|
var methodInfos = new MethodInfos(module, decrypterInfo.mainType, peImage, decrypterInfo.peHeader, decrypterInfo.mcKey);
|
||||||
methodInfos.InitializeInfos();
|
methodInfos.InitializeInfos();
|
||||||
|
|
||||||
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
|
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
|
||||||
|
@ -596,9 +765,14 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
var peImage = decrypterInfo.peImage;
|
var peImage = decrypterInfo.peImage;
|
||||||
var fileData = decrypterInfo.fileData;
|
var fileData = decrypterInfo.fileData;
|
||||||
|
|
||||||
|
uint decryptedResources = peHeader.ReadUInt32(0xFE8) ^ mcKey.ReadUInt32(0);
|
||||||
uint resourceRva = peHeader.GetRva(0x0E10, mcKey.ReadUInt32(0x00A0));
|
uint resourceRva = peHeader.GetRva(0x0E10, mcKey.ReadUInt32(0x00A0));
|
||||||
uint resourceSize = peHeader.ReadUInt32(0x0E14) ^ mcKey.ReadUInt32(0x00AA);
|
int resourceSize = (int)(peHeader.ReadUInt32(0x0E14) ^ mcKey.ReadUInt32(0x00AA));
|
||||||
if (resourceRva == 0 || resourceSize == 0)
|
if (decryptedResources == 1) {
|
||||||
|
Logger.v("Resources have already been decrypted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (resourceRva == 0 || resourceSize <= 0)
|
||||||
return;
|
return;
|
||||||
if (resourceRva != (uint)peImage.Cor20Header.Resources.VirtualAddress ||
|
if (resourceRva != (uint)peImage.Cor20Header.Resources.VirtualAddress ||
|
||||||
resourceSize != peImage.Cor20Header.Resources.Size) {
|
resourceSize != peImage.Cor20Header.Resources.Size) {
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
V5,
|
V5,
|
||||||
V6,
|
V6,
|
||||||
V7,
|
V7,
|
||||||
|
V8,
|
||||||
}
|
}
|
||||||
|
|
||||||
class PeHeader {
|
class PeHeader {
|
||||||
|
@ -44,6 +45,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
public PeHeader(MainType mainType, MyPEImage peImage) {
|
public PeHeader(MainType mainType, MyPEImage peImage) {
|
||||||
uint headerOffset;
|
uint headerOffset;
|
||||||
version = GetHeaderOffsetAndVersion(peImage, out headerOffset);
|
version = GetHeaderOffsetAndVersion(peImage, out headerOffset);
|
||||||
|
headerData = peImage.OffsetReadBytes(headerOffset, 0x1000);
|
||||||
|
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case EncryptionVersion.V1:
|
case EncryptionVersion.V1:
|
||||||
|
@ -62,9 +64,22 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
case EncryptionVersion.V7:
|
case EncryptionVersion.V7:
|
||||||
xorKey = 0x8ABA931;
|
xorKey = 0x8ABA931;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EncryptionVersion.V8:
|
||||||
|
if (CheckMcKeyRva(peImage, 0x99BA9A13))
|
||||||
|
break;
|
||||||
|
if (CheckMcKeyRva(peImage, 0x18ABA931))
|
||||||
|
break;
|
||||||
|
if (CheckMcKeyRva(peImage, 0x18ABA933))
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
headerData = peImage.OffsetReadBytes(headerOffset, 0x1000);
|
bool CheckMcKeyRva(MyPEImage peImage, uint newXorKey) {
|
||||||
|
xorKey = newXorKey;
|
||||||
|
uint rva = GetMcKeyRva();
|
||||||
|
return (rva & 0xFFF) == 0 && peImage.FindSection((RVA)rva) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetMcKeyRva() {
|
public uint GetMcKeyRva() {
|
||||||
|
|
|
@ -71,6 +71,15 @@ namespace de4dot.code.deobfuscators {
|
||||||
Add(oldMethod, newMethod, OpCodes.Callvirt);
|
Add(oldMethod, newMethod, OpCodes.Callvirt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateGetReferencedAssemblies(MethodDef oldMethod) {
|
||||||
|
if (oldMethod == null)
|
||||||
|
return;
|
||||||
|
var assemblyType = builder.Type("System.Reflection", "Assembly", builder.CorLib);
|
||||||
|
var asmNameArray = builder.Array(builder.Type("System.Reflection", "AssemblyName", builder.CorLib));
|
||||||
|
var newMethod = builder.InstanceMethod("GetReferencedAssemblies", assemblyType.TypeDefOrRef, asmNameArray);
|
||||||
|
Add(oldMethod, newMethod, OpCodes.Callvirt);
|
||||||
|
}
|
||||||
|
|
||||||
public void CreateBitmapCtor(MethodDef oldMethod) {
|
public void CreateBitmapCtor(MethodDef oldMethod) {
|
||||||
if (oldMethod == null)
|
if (oldMethod == null)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace de4dot.code.deobfuscators {
|
||||||
this.peStream = peImage.CreateFullStream();
|
this.peStream = peImage.CreateFullStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageSectionHeader FindSection(RVA rva) {
|
public ImageSectionHeader FindSection(RVA rva) {
|
||||||
foreach (var section in peImage.ImageSectionHeaders) {
|
foreach (var section in peImage.ImageSectionHeaders) {
|
||||||
if (section.VirtualAddress <= rva && rva < section.VirtualAddress + Math.Max(section.VirtualSize, section.SizeOfRawData))
|
if (section.VirtualAddress <= rva && rva < section.VirtualAddress + Math.Max(section.VirtualSize, section.SizeOfRawData))
|
||||||
return section;
|
return section;
|
||||||
|
|
|
@ -87,7 +87,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
var resolverLocals = new string[] {
|
var resolverLocals = new string[] {
|
||||||
"System.Byte[]",
|
"System.Byte[]",
|
||||||
"System.Reflection.Assembly",
|
"System.Reflection.Assembly",
|
||||||
"System.Security.Cryptography.MD5",
|
|
||||||
"System.String",
|
"System.String",
|
||||||
"System.IO.BinaryReader",
|
"System.IO.BinaryReader",
|
||||||
"System.IO.Stream",
|
"System.IO.Stream",
|
||||||
|
|
|
@ -26,12 +26,13 @@ using dnlib.DotNet;
|
||||||
using dnlib.DotNet.Emit;
|
using dnlib.DotNet.Emit;
|
||||||
using dnlib.DotNet.Writer;
|
using dnlib.DotNet.Writer;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
|
using de4dot.blocks.cflow;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
||||||
public const string THE_NAME = ".NET Reactor";
|
public const string THE_NAME = ".NET Reactor";
|
||||||
public const string THE_TYPE = "dr4";
|
public const string THE_TYPE = "dr4";
|
||||||
const string DEFAULT_REGEX = DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX;
|
const string DEFAULT_REGEX = @"!^[A-Za-z0-9]{2,3}$&" + DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX;
|
||||||
BoolOption decryptMethods;
|
BoolOption decryptMethods;
|
||||||
BoolOption decryptBools;
|
BoolOption decryptBools;
|
||||||
BoolOption restoreTypes;
|
BoolOption restoreTypes;
|
||||||
|
@ -142,6 +143,15 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
get { return startedDeobfuscating ? options.InlineMethods : true; }
|
get { return startedDeobfuscating ? options.InlineMethods : true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<IBlocksDeobfuscator> BlocksDeobfuscators {
|
||||||
|
get {
|
||||||
|
var list = new List<IBlocksDeobfuscator>();
|
||||||
|
if (CanInlineMethods)
|
||||||
|
list.Add(new DnrMethodCallInliner());
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Deobfuscator(Options options)
|
public Deobfuscator(Options options)
|
||||||
: base(options) {
|
: base(options) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
@ -168,7 +178,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
|
|
||||||
static Regex isRandomName = new Regex(@"^[A-Z]{30,40}$");
|
static Regex isRandomName = new Regex(@"^[A-Z]{30,40}$");
|
||||||
static Regex isRandomNameMembers = new Regex(@"^[a-zA-Z0-9]{9,11}$"); // methods, fields, props, events
|
static Regex isRandomNameMembers = new Regex(@"^[a-zA-Z0-9]{9,11}$"); // methods, fields, props, events
|
||||||
static Regex isRandomNameTypes = new Regex(@"^[a-zA-Z0-9]{18,19}(?:`\d+)?$"); // types, namespaces
|
static Regex isRandomNameTypes = new Regex(@"^[a-zA-Z0-9]{18,20}(?:`\d+)?$"); // types, namespaces
|
||||||
|
|
||||||
bool CheckValidName(string name, Regex regex) {
|
bool CheckValidName(string name, Regex regex) {
|
||||||
if (isRandomName.IsMatch(name))
|
if (isRandomName.IsMatch(name))
|
||||||
|
@ -333,8 +343,12 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
var compileMethod = MethodsDecrypter.FindDnrCompileMethod(methodsDecrypter.Method.DeclaringType);
|
var compileMethod = MethodsDecrypter.FindDnrCompileMethod(methodsDecrypter.Method.DeclaringType);
|
||||||
if (compileMethod == null)
|
if (compileMethod == null) {
|
||||||
|
DeobfuscatedFile.Deobfuscate(methodsDecrypter.Method);
|
||||||
|
if (!MethodsDecrypter.IsNewer45Decryption(methodsDecrypter.Method))
|
||||||
return DeobfuscatorInfo.THE_NAME + " < 4.0";
|
return DeobfuscatorInfo.THE_NAME + " < 4.0";
|
||||||
|
return DeobfuscatorInfo.THE_NAME + " 4.5+";
|
||||||
|
}
|
||||||
DeobfuscatedFile.Deobfuscate(compileMethod);
|
DeobfuscatedFile.Deobfuscate(compileMethod);
|
||||||
bool compileMethodHasConstant_0x70000000 = DeobUtils.HasInteger(compileMethod, 0x70000000); // 4.0-4.1
|
bool compileMethodHasConstant_0x70000000 = DeobUtils.HasInteger(compileMethod, 0x70000000); // 4.0-4.1
|
||||||
DeobfuscatedFile.Deobfuscate(methodsDecrypter.Method);
|
DeobfuscatedFile.Deobfuscate(methodsDecrypter.Method);
|
||||||
|
@ -346,11 +360,36 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
return DeobfuscatorInfo.THE_NAME + " 4.0";
|
return DeobfuscatorInfo.THE_NAME + " 4.0";
|
||||||
}
|
}
|
||||||
if (!hasCorEnableProfilingString) {
|
if (!hasCorEnableProfilingString) {
|
||||||
// 4.x or 4.5
|
// 4.x or 4.5 - 4.6
|
||||||
bool callsReverse = DotNetUtils.CallsMethod(methodsDecrypter.Method, "System.Void System.Array::Reverse(System.Array)");
|
bool callsReverse = DotNetUtils.CallsMethod(methodsDecrypter.Method, "System.Void System.Array::Reverse(System.Array)");
|
||||||
if (!callsReverse)
|
if (!callsReverse)
|
||||||
return DeobfuscatorInfo.THE_NAME + " 4.x";
|
return DeobfuscatorInfo.THE_NAME + " 4.0 - 4.4";
|
||||||
return DeobfuscatorInfo.THE_NAME + " 4.5";
|
|
||||||
|
int numIntPtrSizeCompares = CountCompareSystemIntPtrSize(methodsDecrypter.Method);
|
||||||
|
bool hasSymmetricAlgorithm = new LocalTypes(methodsDecrypter.Method).Exists("System.Security.Cryptography.SymmetricAlgorithm");
|
||||||
|
if (module.IsClr40) {
|
||||||
|
switch (numIntPtrSizeCompares) {
|
||||||
|
case 7:
|
||||||
|
case 9: return DeobfuscatorInfo.THE_NAME + " 4.5";
|
||||||
|
case 10:
|
||||||
|
if (!hasSymmetricAlgorithm)
|
||||||
|
return DeobfuscatorInfo.THE_NAME + " 4.6";
|
||||||
|
return DeobfuscatorInfo.THE_NAME + " 4.7";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (numIntPtrSizeCompares) {
|
||||||
|
case 6:
|
||||||
|
case 8: return DeobfuscatorInfo.THE_NAME + " 4.5";
|
||||||
|
case 9:
|
||||||
|
if (!hasSymmetricAlgorithm)
|
||||||
|
return DeobfuscatorInfo.THE_NAME + " 4.6";
|
||||||
|
return DeobfuscatorInfo.THE_NAME + " 4.7";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should never be reached unless it's a new version
|
||||||
|
return DeobfuscatorInfo.THE_NAME + " 4.5+";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4.2-4.4
|
// 4.2-4.4
|
||||||
|
@ -364,6 +403,29 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
return DeobfuscatorInfo.THE_NAME + " 4.3";
|
return DeobfuscatorInfo.THE_NAME + " 4.3";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CountCompareSystemIntPtrSize(MethodDef method) {
|
||||||
|
if (method == null || method.Body == null)
|
||||||
|
return 0;
|
||||||
|
int count = 0;
|
||||||
|
var instrs = method.Body.Instructions;
|
||||||
|
for (int i = 1; i < instrs.Count - 1; i++) {
|
||||||
|
var ldci4 = instrs[i];
|
||||||
|
if (!ldci4.IsLdcI4() || ldci4.GetLdcI4Value() != 4)
|
||||||
|
continue;
|
||||||
|
if (!instrs[i + 1].IsConditionalBranch())
|
||||||
|
continue;
|
||||||
|
var call = instrs[i - 1];
|
||||||
|
if (call.OpCode.Code != Code.Call)
|
||||||
|
continue;
|
||||||
|
var calledMethod = call.Operand as MemberRef;
|
||||||
|
if (calledMethod == null || calledMethod.FullName != "System.Int32 System.IntPtr::get_Size()")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static bool FindString(MethodDef method, string s) {
|
static bool FindString(MethodDef method, string s) {
|
||||||
foreach (var cs in DotNetUtils.GetCodeStrings(method)) {
|
foreach (var cs in DotNetUtils.GetCodeStrings(method)) {
|
||||||
if (cs == s)
|
if (cs == s)
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011-2013 de4dot@gmail.com
|
||||||
|
|
||||||
|
This file is part of de4dot.
|
||||||
|
|
||||||
|
de4dot is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
de4dot is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using dnlib.DotNet.Emit;
|
||||||
|
using de4dot.blocks;
|
||||||
|
using de4dot.blocks.cflow;
|
||||||
|
|
||||||
|
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
|
class DnrMethodCallInliner : MethodCallInliner {
|
||||||
|
public DnrMethodCallInliner()
|
||||||
|
: base(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Instruction GetFirstInstruction(IList<Instruction> instrs, ref int index) {
|
||||||
|
var instr = GetFirstInstruction(instrs, index);
|
||||||
|
if (instr != null)
|
||||||
|
index = instrs.IndexOf(instr);
|
||||||
|
return DotNetUtils.GetInstruction(instrs, ref index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction GetFirstInstruction(IList<Instruction> instrs, int index) {
|
||||||
|
try {
|
||||||
|
var instr = instrs[index];
|
||||||
|
if (!instr.IsBr())
|
||||||
|
return null;
|
||||||
|
instr = instr.Operand as Instruction;
|
||||||
|
if (instr == null)
|
||||||
|
return null;
|
||||||
|
if (!instr.IsLdcI4() || instr.GetLdcI4Value() != 0)
|
||||||
|
return null;
|
||||||
|
instr = instrs[instrs.IndexOf(instr) + 1];
|
||||||
|
if (!instr.IsBrtrue())
|
||||||
|
return null;
|
||||||
|
return instrs[instrs.IndexOf(instr) + 1];
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -91,7 +91,8 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
if (!localTypes.All(requiredTypes))
|
if (!localTypes.All(requiredTypes))
|
||||||
return false;
|
return false;
|
||||||
if (!localTypes.Exists("System.Security.Cryptography.RijndaelManaged") &&
|
if (!localTypes.Exists("System.Security.Cryptography.RijndaelManaged") &&
|
||||||
!localTypes.Exists("System.Security.Cryptography.AesManaged"))
|
!localTypes.Exists("System.Security.Cryptography.AesManaged") &&
|
||||||
|
!localTypes.Exists("System.Security.Cryptography.SymmetricAlgorithm"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (checkResource && FindMethodsDecrypterResource(method) == null)
|
if (checkResource && FindMethodsDecrypterResource(method) == null)
|
||||||
|
|
|
@ -121,8 +121,8 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static short[] nativeLdci4 = new short[] { 0x55, 0x8B, 0xEC, 0xB8, -1, -1, -1, -1, 0x5D, 0xC3 };
|
readonly static short[] nativeLdci4 = new short[] { 0x55, 0x8B, 0xEC, 0xB8, -1, -1, -1, -1, 0x5D, 0xC3 };
|
||||||
static short[] nativeLdci4_0 = new short[] { 0x55, 0x8B, 0xEC, 0x33, 0xC0, 0x5D, 0xC3 };
|
readonly static short[] nativeLdci4_0 = new short[] { 0x55, 0x8B, 0xEC, 0x33, 0xC0, 0x5D, 0xC3 };
|
||||||
public bool Decrypt(MyPEImage peImage, ISimpleDeobfuscator simpleDeobfuscator, ref DumpedMethods dumpedMethods, Dictionary<uint, byte[]> tokenToNativeCode, bool unpackedNativeFile) {
|
public bool Decrypt(MyPEImage peImage, ISimpleDeobfuscator simpleDeobfuscator, ref DumpedMethods dumpedMethods, Dictionary<uint, byte[]> tokenToNativeCode, bool unpackedNativeFile) {
|
||||||
if (encryptedResource.Method == null)
|
if (encryptedResource.Method == null)
|
||||||
return false;
|
return false;
|
||||||
|
@ -157,27 +157,29 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!hooksJitter || mode == 1) {
|
else if (!hooksJitter || mode == 1) {
|
||||||
// DNR 3.9.8.0, 4.0, 4.1, 4.2, 4.3, 4.4
|
// DNR 3.9.8.0, 4.0+
|
||||||
|
|
||||||
// If it's .NET 1.x, then offsets are used, not RVAs.
|
|
||||||
bool useOffsets = unpackedNativeFile && module.IsClr1x;
|
|
||||||
|
|
||||||
PatchDwords(peImage, methodsDataReader, patchCount);
|
PatchDwords(peImage, methodsDataReader, patchCount);
|
||||||
|
bool oldCode = !IsNewer45Decryption(encryptedResource.Method);
|
||||||
while (methodsDataReader.Position < methodsData.Length - 1) {
|
while (methodsDataReader.Position < methodsData.Length - 1) {
|
||||||
uint rva = methodsDataReader.ReadUInt32();
|
uint rva = methodsDataReader.ReadUInt32();
|
||||||
uint token = methodsDataReader.ReadUInt32(); // token, unknown, or index
|
int size;
|
||||||
int size = methodsDataReader.ReadInt32();
|
if (oldCode) {
|
||||||
if (size > 0) {
|
methodsDataReader.ReadUInt32(); // token, unknown, or index
|
||||||
|
size = methodsDataReader.ReadInt32();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
size = methodsDataReader.ReadInt32() * 4;
|
||||||
|
|
||||||
var newData = methodsDataReader.ReadBytes(size);
|
var newData = methodsDataReader.ReadBytes(size);
|
||||||
if (useOffsets)
|
if (unpackedNativeFile)
|
||||||
peImage.DotNetSafeWriteOffset(rva, newData);
|
peImage.DotNetSafeWriteOffset(rva, newData);
|
||||||
else
|
else
|
||||||
peImage.DotNetSafeWrite(rva, newData);
|
peImage.DotNetSafeWrite(rva, newData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
// DNR 4.0 - 4.5 (jitter is hooked)
|
// DNR 4.0+ (jitter is hooked)
|
||||||
|
|
||||||
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
|
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
|
||||||
var rvaToIndex = new Dictionary<uint, int>((int)methodDef.Rows);
|
var rvaToIndex = new Dictionary<uint, int>((int)methodDef.Rows);
|
||||||
|
@ -258,6 +260,33 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsNewer45Decryption(MethodDef method) {
|
||||||
|
if (method == null || method.Body == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var instrs = method.Body.Instructions;
|
||||||
|
for (int i = 0; i < instrs.Count - 4; i++) {
|
||||||
|
var ldci4 = instrs[i];
|
||||||
|
if (!ldci4.IsLdcI4() || ldci4.GetLdcI4Value() != 4)
|
||||||
|
continue;
|
||||||
|
if (instrs[i + 1].OpCode.Code != Code.Mul)
|
||||||
|
continue;
|
||||||
|
ldci4 = instrs[i + 2];
|
||||||
|
if (!ldci4.IsLdcI4() || ldci4.GetLdcI4Value() != 4)
|
||||||
|
continue;
|
||||||
|
if (instrs[i + 3].OpCode.Code != Code.Ldloca_S && instrs[i + 3].OpCode.Code != Code.Ldloca)
|
||||||
|
continue;
|
||||||
|
var call = instrs[i + 4];
|
||||||
|
if (call.OpCode.Code != Code.Call)
|
||||||
|
continue;
|
||||||
|
if (!DotNetUtils.IsPinvokeMethod(call.Operand as MethodDef, "kernel32", "VirtualProtect"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void PatchDwords(MyPEImage peImage, IBinaryReader reader, int count) {
|
static void PatchDwords(MyPEImage peImage, IBinaryReader reader, int count) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
uint rva = reader.ReadUInt32();
|
uint rva = reader.ReadUInt32();
|
||||||
|
@ -363,6 +392,12 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
Array.Copy(encrypted, resourceData, resourceData.Length);
|
Array.Copy(encrypted, resourceData, resourceData.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CompileMethodType {
|
||||||
|
Unknown,
|
||||||
|
V1, // <= DNR 4.5.0.0 (2012-11-06 <= endDate < 2013-01-31)
|
||||||
|
V2, // >= DNR 4.5.0.0 (2012-11-06 < startDate <= 2013-01-31)
|
||||||
|
}
|
||||||
|
|
||||||
public static MethodDef FindDnrCompileMethod(TypeDef type) {
|
public static MethodDef FindDnrCompileMethod(TypeDef type) {
|
||||||
foreach (var method in type.Methods) {
|
foreach (var method in type.Methods) {
|
||||||
if (!method.IsStatic || method.Body == null)
|
if (!method.IsStatic || method.Body == null)
|
||||||
|
@ -370,11 +405,19 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
var sig = method.MethodSig;
|
var sig = method.MethodSig;
|
||||||
if (sig == null || sig.Params.Count != 6)
|
if (sig == null || sig.Params.Count != 6)
|
||||||
continue;
|
continue;
|
||||||
if (!DotNetUtils.IsMethod(method, "System.UInt32", "(System.UInt64&,System.IntPtr,System.IntPtr,System.UInt32,System.IntPtr&,System.UInt32&)"))
|
if (GetCompileMethodType(method) == CompileMethodType.Unknown)
|
||||||
continue;
|
continue;
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CompileMethodType GetCompileMethodType(MethodDef method) {
|
||||||
|
if (DotNetUtils.IsMethod(method, "System.UInt32", "(System.UInt64&,System.IntPtr,System.IntPtr,System.UInt32,System.IntPtr&,System.UInt32&)"))
|
||||||
|
return CompileMethodType.V1;
|
||||||
|
if (DotNetUtils.IsMethod(method, "System.UInt32", "(System.IntPtr,System.IntPtr,System.IntPtr,System.UInt32,System.IntPtr,System.UInt32&)"))
|
||||||
|
return CompileMethodType.V2;
|
||||||
|
return CompileMethodType.Unknown;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user