Support .NET Reactor 4.5 (an updated version) and 4.6

This commit is contained in:
de4dot 2013-10-13 08:49:34 +02:00
parent 8dc7249033
commit 689635cf69
4 changed files with 177 additions and 21 deletions

View File

@ -157,6 +157,7 @@
<Compile Include="deobfuscators\DeobUtils.cs" />
<Compile Include="deobfuscators\Dotfuscator\Deobfuscator.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\MyPEImage.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\v3\AntiStrongName.cs" />

View File

@ -26,6 +26,7 @@ using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnlib.DotNet.Writer;
using de4dot.blocks;
using de4dot.blocks.cflow;
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
@ -142,6 +143,15 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
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)
: base(options) {
this.options = options;
@ -333,8 +343,12 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
}
var compileMethod = MethodsDecrypter.FindDnrCompileMethod(methodsDecrypter.Method.DeclaringType);
if (compileMethod == null)
return DeobfuscatorInfo.THE_NAME + " < 4.0";
if (compileMethod == null) {
DeobfuscatedFile.Deobfuscate(methodsDecrypter.Method);
if (!MethodsDecrypter.IsNewer45Decryption(methodsDecrypter.Method))
return DeobfuscatorInfo.THE_NAME + " < 4.0";
return DeobfuscatorInfo.THE_NAME + " 4.5+";
}
DeobfuscatedFile.Deobfuscate(compileMethod);
bool compileMethodHasConstant_0x70000000 = DeobUtils.HasInteger(compileMethod, 0x70000000); // 4.0-4.1
DeobfuscatedFile.Deobfuscate(methodsDecrypter.Method);
@ -346,11 +360,27 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return DeobfuscatorInfo.THE_NAME + " 4.0";
}
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)");
if (!callsReverse)
return DeobfuscatorInfo.THE_NAME + " 4.x";
return DeobfuscatorInfo.THE_NAME + " 4.5";
return DeobfuscatorInfo.THE_NAME + " 4.0 - 4.4";
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
@ -364,6 +394,29 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
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) {
foreach (var cs in DotNetUtils.GetCodeStrings(method)) {
if (cs == s)

View File

@ -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;
}
}
}
}

View File

@ -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 };
static short[] nativeLdci4_0 = new short[] { 0x55, 0x8B, 0xEC, 0x33, 0xC0, 0x5D, 0xC3 };
readonly static short[] nativeLdci4 = new short[] { 0x55, 0x8B, 0xEC, 0xB8, -1, -1, -1, -1, 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) {
if (encryptedResource.Method == null)
return false;
@ -157,27 +157,29 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
}
}
else if (!hooksJitter || mode == 1) {
// DNR 3.9.8.0, 4.0, 4.1, 4.2, 4.3, 4.4
// If it's .NET 1.x, then offsets are used, not RVAs.
bool useOffsets = unpackedNativeFile && module.IsClr1x;
// DNR 3.9.8.0, 4.0+
PatchDwords(peImage, methodsDataReader, patchCount);
bool oldCode = !IsNewer45Decryption(encryptedResource.Method);
while (methodsDataReader.Position < methodsData.Length - 1) {
uint rva = methodsDataReader.ReadUInt32();
uint token = methodsDataReader.ReadUInt32(); // token, unknown, or index
int size = methodsDataReader.ReadInt32();
if (size > 0) {
var newData = methodsDataReader.ReadBytes(size);
if (useOffsets)
peImage.DotNetSafeWriteOffset(rva, newData);
else
peImage.DotNetSafeWrite(rva, newData);
int size;
if (oldCode) {
methodsDataReader.ReadUInt32(); // token, unknown, or index
size = methodsDataReader.ReadInt32();
}
else
size = methodsDataReader.ReadInt32() * 4;
var newData = methodsDataReader.ReadBytes(size);
if (unpackedNativeFile)
peImage.DotNetSafeWriteOffset(rva, newData);
else
peImage.DotNetSafeWrite(rva, newData);
}
}
else {
// DNR 4.0 - 4.5 (jitter is hooked)
// DNR 4.0+ (jitter is hooked)
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
var rvaToIndex = new Dictionary<uint, int>((int)methodDef.Rows);
@ -258,6 +260,33 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
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) {
for (int i = 0; i < count; i++) {
uint rva = reader.ReadUInt32();
@ -363,6 +392,12 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
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) {
foreach (var method in type.Methods) {
if (!method.IsStatic || method.Body == null)
@ -370,11 +405,19 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
var sig = method.MethodSig;
if (sig == null || sig.Params.Count != 6)
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;
return method;
}
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;
}
}
}