Support .NET Reactor 4.5 (an updated version) and 4.6
This commit is contained in:
parent
8dc7249033
commit
689635cf69
|
@ -157,6 +157,7 @@
|
||||||
<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\dotNET_Reactor\v4\DnrMethodCallInliner.cs" />
|
||||||
<Compile Include="deobfuscators\Eazfuscator_NET\Dynocode.cs" />
|
<Compile Include="deobfuscators\Eazfuscator_NET\Dynocode.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" />
|
||||||
|
|
|
@ -26,6 +26,7 @@ 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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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,27 @@ 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);
|
||||||
|
if (module.IsClr40) {
|
||||||
|
switch (numIntPtrSizeCompares) {
|
||||||
|
case 9: return DeobfuscatorInfo.THE_NAME + " 4.5";
|
||||||
|
case 10:return DeobfuscatorInfo.THE_NAME + " 4.6";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (numIntPtrSizeCompares) {
|
||||||
|
case 8: return DeobfuscatorInfo.THE_NAME + " 4.5";
|
||||||
|
case 9: return DeobfuscatorInfo.THE_NAME + " 4.6";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 +394,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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