Add code to unpack DNR 4.0/4.1 + .NET 2.0+ native files

This commit is contained in:
de4dot 2011-11-30 18:28:48 +01:00
parent f567e09845
commit b7a44b459d
6 changed files with 202 additions and 12 deletions

View File

@ -85,6 +85,8 @@
<Compile Include="deobfuscators\dotNET_Reactor\EncryptedResource.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\MetadataTokenObfuscator.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\MethodsDecrypter.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\NativeFileDecrypter.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\NativeImageUnpacker.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\QuickLZ.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\ResourceResolver.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\StringDecrypter.cs" />
@ -137,6 +139,10 @@
<Compile Include="PE\MetadataTypeBuilder.cs" />
<Compile Include="PE\OptionalHeader.cs" />
<Compile Include="PE\PeImage.cs" />
<Compile Include="PE\ResourceData.cs" />
<Compile Include="PE\ResourceDirectory.cs" />
<Compile Include="PE\ResourceDirectoryEntry.cs" />
<Compile Include="PE\Resources.cs" />
<Compile Include="PE\SectionHeader.cs" />
<Compile Include="PE\DotNetStream.cs" />
<Compile Include="Program.cs" />

View File

@ -25,6 +25,7 @@ using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.MyStuff;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.deobfuscators.dotNET_Reactor {
class DeobfuscatorInfo : DeobfuscatorInfoBase {
@ -100,7 +101,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
Options options;
string obfuscatorName = ".NET Reactor";
PE.PeImage peImage;
PeImage peImage;
byte[] fileData;
MethodsDecrypter methodsDecrypter;
StringDecrypter stringDecrypter;
@ -112,6 +113,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
AntiStrongName antiStrongname;
EmptyClass emptyClass;
bool unpackedNativeFile = false;
bool canRemoveDecrypterType = true;
bool startedDeobfuscating = false;
@ -154,6 +156,11 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
this.RenamingOptions &= ~RenamingOptions.RemoveNamespaceIfOneType;
}
public override byte[] unpackNativeFile(PeImage peImage) {
unpackedNativeFile = true;
return new NativeImageUnpacker(peImage).unpack();
}
public override void init(ModuleDefinition module) {
base.init(module);
}
@ -243,6 +250,8 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
assemblyResolver = new AssemblyResolver(module);
assemblyResolver.find(DeobfuscatedFile);
obfuscatorName = detectVersion();
if (unpackedNativeFile)
obfuscatorName += " (native)";
resourceResolver = new ResourceResolver(module);
resourceResolver.find(DeobfuscatedFile);
}
@ -366,7 +375,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
public override bool getDecryptedModule(ref byte[] newFileData, ref Dictionary<uint, DumpedMethod> dumpedMethods) {
fileData = DeobUtils.readModule(module);
peImage = new PE.PeImage(fileData);
peImage = new PeImage(fileData);
if (!options.DecryptMethods)
return false;
@ -398,7 +407,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
var newOne = new Deobfuscator(options);
newOne.setModule(module);
newOne.fileData = fileData;
newOne.peImage = new PE.PeImage(fileData);
newOne.peImage = new PeImage(fileData);
newOne.methodsDecrypter = new MethodsDecrypter(module, methodsDecrypter);
newOne.stringDecrypter = new StringDecrypter(module, stringDecrypter);
newOne.booleanDecrypter = new BooleanDecrypter(module, booleanDecrypter);

View File

@ -24,6 +24,7 @@ using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.MyStuff;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.deobfuscators.dotNET_Reactor {
class MethodsDecrypter {
@ -31,7 +32,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
EncryptedResource encryptedResource;
Dictionary<uint, byte[]> tokenToNativeMethod = new Dictionary<uint, byte[]>();
Dictionary<MethodDefinition, byte[]> methodToNativeMethod = new Dictionary<MethodDefinition, byte[]>();
int totalEncryptedMethods = 0;
int totalEncryptedNativeMethods = 0;
long xorKey;
public bool Detected {
@ -63,13 +64,12 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
this.module = module;
this.encryptedResource = new EncryptedResource(module, oldOne.encryptedResource);
this.tokenToNativeMethod = oldOne.tokenToNativeMethod;
this.totalEncryptedMethods = oldOne.totalEncryptedMethods;
this.totalEncryptedNativeMethods = oldOne.totalEncryptedNativeMethods;
this.xorKey = oldOne.xorKey;
}
public void find() {
var additionalTypes = new string[] {
// "System.Diagnostics.StackFrame", //TODO: Not in DNR <= 3.7.0.3
"System.IntPtr",
// "System.Reflection.Assembly", //TODO: Not in unknown DNR version with jitter support
};
@ -123,7 +123,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
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 };
public bool decrypt(PE.PeImage peImage, ISimpleDeobfuscator simpleDeobfuscator, ref Dictionary<uint, DumpedMethod> dumpedMethods, Dictionary<uint,byte[]> tokenToNativeCode) {
public bool decrypt(PeImage peImage, ISimpleDeobfuscator simpleDeobfuscator, ref Dictionary<uint, DumpedMethod> dumpedMethods, Dictionary<uint,byte[]> tokenToNativeCode) {
if (encryptedResource.Method == null)
return false;
@ -205,7 +205,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
uint methodToken = 0x06000001 + (uint)methodIndex;
if (isNativeCode) {
totalEncryptedMethods++;
totalEncryptedNativeMethods++;
if (tokenToNativeCode != null)
tokenToNativeCode[methodToken] = methodData;
@ -276,7 +276,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
return true;
}
static void patchDwords(PE.PeImage peImage, BinaryReader reader, int count) {
static void patchDwords(PeImage peImage, BinaryReader reader, int count) {
for (int i = 0; i < count; i++) {
uint rva = reader.ReadUInt32();
uint data = reader.ReadUInt32();
@ -346,7 +346,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
}
if (index != 0)
Log.n("Re-encrypted {0}/{1} native methods", index, totalEncryptedMethods);
Log.n("Re-encrypted {0}/{1} native methods", index, totalEncryptedNativeMethods);
var encryptedData = stream.ToArray();
xorEncrypt(encryptedData);

View File

@ -0,0 +1,104 @@
/*
Copyright (C) 2011 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;
namespace de4dot.deobfuscators.dotNET_Reactor {
class NativeFileDecrypter {
byte[] key;
byte kb = 0;
byte[,] transform = new byte[256, 256];
public NativeFileDecrypter(byte[] keyData) {
var keyInit = new byte[] {
0x78, 0x61, 0x32, keyData[0], keyData[2],
0x62, keyData[3], keyData[0], keyData[1], keyData[1],
0x66, keyData[1], keyData[5], 0x33, keyData[2],
keyData[4], 0x74, 0x32, keyData[3], keyData[2],
};
key = new byte[32];
for (int i = 0; i < 32; i++) {
key[i] = (byte)(i + keyInit[i % keyInit.Length] * keyInit[((i + 0x0B) | 0x1F) % keyInit.Length]);
kb += key[i];
}
var transformTemp = new ushort[256, 256];
for (int i = 0; i < 256; i++)
for (int j = 0; j < 256; j++)
transformTemp[i, j] = 0x400;
int counter = 0x0B;
byte newByte = 0;
int ki = 0;
for (int i = 0; i < 256; i++) {
while (true) {
for (int j = key.Length - 1; j >= ki; j--)
newByte += (byte)(key[j] + counter);
bool done = true;
ki = (ki + 1) % key.Length;
for (int k = 0; k <= i; k++) {
if (newByte == transformTemp[k, 0]) {
done = false;
break;
}
}
if (done)
break;
counter++;
}
transformTemp[i, 0] = newByte;
}
counter = ki = 0;
for (int i = 1; i < 256; i++) {
ki++;
int i1;
do {
counter++;
i1 = 1 + (this.key[(i + 37 + counter) % key.Length] + counter + kb) % 255;
} while (transformTemp[0, i1] != 0x400);
for (int i0 = 0; i0 < 256; i0++)
transformTemp[i0, i1] = transformTemp[(i0 + ki) % 256, 0];
}
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++)
transform[(byte)transformTemp[i, j], j] = (byte)i;
}
}
public void decrypt(byte[] data, int offset, int count) {
for (int i = 0; i < count; i += 1024, offset += 1024) {
int blockLen = Math.Min(1024, count - i);
if (blockLen == 1) {
data[offset] = transform[data[offset], kb];
continue;
}
for (int j = 0; j < blockLen - 1; j++)
data[offset + j] = transform[data[offset + j], data[offset + j + 1]];
data[offset + blockLen - 1] = transform[data[offset + blockLen - 1], kb ^ 0x55];
for (int j = blockLen - 1; j > 0; j--)
data[offset + j] = transform[data[offset + j], data[offset + j - 1]];
data[offset] = transform[data[offset], kb];
}
}
}
}

View File

@ -0,0 +1,70 @@
/*
Copyright (C) 2011 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 ICSharpCode.SharpZipLib.Zip.Compression;
using de4dot.PE;
namespace de4dot.deobfuscators.dotNET_Reactor {
class NativeImageUnpacker {
PeImage peImage;
public NativeImageUnpacker(PeImage peImage) {
this.peImage = peImage;
}
public byte[] unpack() {
var resources = peImage.Resources;
var dir = resources.getRoot();
if ((dir = dir.getDirectory(10)) == null)
return null;
if ((dir = dir.getDirectory("__")) == null)
return null;
var dataEntry = dir.getData(0);
if (dataEntry == null)
return null;
var encryptedData = peImage.readBytes(dataEntry.RVA, (int)dataEntry.Size);
if (encryptedData.Length != dataEntry.Size)
return null;
//TODO: Hard coded offsets: DNR 4.0/4.1 + .NET 2.0+
var keyData = new byte[6] {
peImage.offsetReadByte(7173),
peImage.offsetReadByte(7183),
peImage.offsetReadByte(7256),
peImage.offsetReadByte(7277),
peImage.offsetReadByte(7320),
peImage.offsetReadByte(7334),
};
var decrypter = new NativeFileDecrypter(keyData);
decrypter.decrypt(encryptedData, 0, encryptedData.Length);
int inflatedSize = BitConverter.ToInt32(encryptedData, 0);
var inflater = new Inflater();
byte[] inflatedData = new byte[inflatedSize];
inflater.SetInput(encryptedData, 4, encryptedData.Length - 4);
int count = inflater.Inflate(inflatedData);
if (count != inflatedSize)
return null;
return inflatedData;
}
}
}

View File

@ -24,6 +24,7 @@ using System.Security.Cryptography;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.deobfuscators.dotNET_Reactor {
class StringDecrypter {
@ -32,7 +33,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
List<DecrypterInfo> decrypterInfos = new List<DecrypterInfo>();
MethodDefinition otherStringDecrypter;
byte[] decryptedData;
PE.PeImage peImage;
PeImage peImage;
byte[] fileData;
StringDecrypterVersion stringDecrypterVersion;
@ -150,7 +151,7 @@ namespace de4dot.deobfuscators.dotNET_Reactor {
}
}
public void init(PE.PeImage peImage, byte[] fileData, ISimpleDeobfuscator simpleDeobfuscator) {
public void init(PeImage peImage, byte[] fileData, ISimpleDeobfuscator simpleDeobfuscator) {
if (encryptedResource.Method == null)
return;
this.peImage = peImage;