Unpack compressed Confuser assemblies

This commit is contained in:
de4dot 2012-07-30 14:11:04 +02:00
parent 7321e51a78
commit 2e99bac40c
3 changed files with 160 additions and 22 deletions

View File

@ -81,6 +81,7 @@
<Compile Include="deobfuscators\Confuser\ProxyCallFixerV1.cs" />
<Compile Include="deobfuscators\Confuser\ResourceDecrypter.cs" />
<Compile Include="deobfuscators\Confuser\StringDecrypter.cs" />
<Compile Include="deobfuscators\Confuser\Unpacker.cs" />
<Compile Include="deobfuscators\Confuser\x86Emulator.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\v4\ProxyCallFixer.cs" />
<Compile Include="deobfuscators\ILProtector\MethodReader.cs" />

View File

@ -79,6 +79,7 @@ namespace de4dot.code.deobfuscators.Confuser {
SingleValueInliner singleValueInliner;
DoubleValueInliner doubleValueInliner;
StringDecrypter stringDecrypter;
Unpacker unpacker;
bool startedDeobfuscating = false;
@ -129,7 +130,8 @@ namespace de4dot.code.deobfuscators.Confuser {
toInt32(antiDumping != null ? antiDumping.Detected : false) +
toInt32(resourceDecrypter != null ? resourceDecrypter.Detected : false) +
toInt32(constantsDecrypter != null ? constantsDecrypter.Detected : false) +
toInt32(stringDecrypter != null ? stringDecrypter.Detected : false);
toInt32(stringDecrypter != null ? stringDecrypter.Detected : false) +
toInt32(unpacker != null ? unpacker.Detected : false);
if (sum > 0)
val += 100 + 10 * (sum - 1);
@ -171,6 +173,9 @@ namespace de4dot.code.deobfuscators.Confuser {
antiDumping.find(DeobfuscatedFile);
stringDecrypter = new StringDecrypter(module);
stringDecrypter.find(DeobfuscatedFile);
initializeStringDecrypter();
unpacker = new Unpacker(module);
unpacker.find(DeobfuscatedFile, this);
}
byte[] getFileData() {
@ -179,29 +184,48 @@ namespace de4dot.code.deobfuscators.Confuser {
return ModuleBytes = DeobUtils.readModule(module);
}
[Flags]
enum DecryptState {
CanDecryptMethods = 1,
CanUnpack = 2,
}
DecryptState decryptState = DecryptState.CanDecryptMethods | DecryptState.CanUnpack;
public override bool getDecryptedModule(int count, ref byte[] newFileData, ref DumpedMethods dumpedMethods) {
if (count != 0 || (!jitMethodsDecrypter.Detected && !memoryMethodsDecrypter.Detected))
return false;
byte[] fileData = getFileData();
var peImage = new PeImage(fileData);
if (jitMethodsDecrypter != null && jitMethodsDecrypter.Detected) {
jitMethodsDecrypter.initialize();
if (!jitMethodsDecrypter.decrypt(peImage, fileData, ref dumpedMethods))
return false;
if ((decryptState & DecryptState.CanDecryptMethods) != 0) {
if (jitMethodsDecrypter != null && jitMethodsDecrypter.Detected) {
jitMethodsDecrypter.initialize();
if (!jitMethodsDecrypter.decrypt(peImage, fileData, ref dumpedMethods))
return false;
newFileData = fileData;
return true;
decryptState &= ~DecryptState.CanDecryptMethods;
newFileData = fileData;
ModuleBytes = newFileData;
return true;
}
if (memoryMethodsDecrypter != null && memoryMethodsDecrypter.Detected) {
memoryMethodsDecrypter.initialize();
if (!memoryMethodsDecrypter.decrypt(peImage, fileData, ref dumpedMethods))
return false;
decryptState &= ~DecryptState.CanDecryptMethods;
newFileData = fileData;
ModuleBytes = newFileData;
return true;
}
}
if (memoryMethodsDecrypter != null && memoryMethodsDecrypter.Detected) {
memoryMethodsDecrypter.initialize();
if (!memoryMethodsDecrypter.decrypt(peImage, fileData, ref dumpedMethods))
return false;
newFileData = fileData;
return true;
if ((decryptState & DecryptState.CanUnpack) != 0) {
if (unpacker != null && unpacker.Detected) {
decryptState &= ~DecryptState.CanUnpack;
decryptState |= DecryptState.CanDecryptMethods;
newFileData = unpacker.unpack();
ModuleBytes = newFileData;
return true;
}
}
return false;
@ -210,6 +234,7 @@ namespace de4dot.code.deobfuscators.Confuser {
public override IDeobfuscator moduleReloaded(ModuleDefinition module) {
var newOne = new Deobfuscator(options);
DeobfuscatedFile.setDeobfuscator(newOne);
newOne.decryptState = decryptState;
newOne.DeobfuscatedFile = DeobfuscatedFile;
newOne.ModuleBytes = ModuleBytes;
newOne.setModule(module);
@ -224,6 +249,7 @@ namespace de4dot.code.deobfuscators.Confuser {
removeObfuscatorAttribute();
initializeConstantsDecrypter();
initializeStringDecrypter();
if (jitMethodsDecrypter != null) {
addModuleCctorInitCallToBeRemoved(jitMethodsDecrypter.InitMethod);
@ -250,19 +276,26 @@ namespace de4dot.code.deobfuscators.Confuser {
if (proxyCallFixerV1 != null)
proxyCallFixerV1.find();
startedDeobfuscating = true;
}
bool hasInitializedStringDecrypter = false;
void initializeStringDecrypter() {
if (hasInitializedStringDecrypter)
return;
hasInitializedStringDecrypter = true;
if (stringDecrypter != null) {
stringDecrypter.initialize();
staticStringInliner.add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.decrypt(staticStringInliner.Method, (int)args[0]));
}
startedDeobfuscating = true;
}
bool hasInitializeConstantsDecrypter = false;
bool hasInitializedConstantsDecrypter = false;
void initializeConstantsDecrypter() {
if (hasInitializeConstantsDecrypter)
if (hasInitializedConstantsDecrypter)
return;
hasInitializeConstantsDecrypter = true;
hasInitializedConstantsDecrypter = true;
decryptResources();
constantsDecrypter.initialize();

View File

@ -0,0 +1,104 @@
/*
Copyright (C) 2011-2012 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 Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Confuser {
class Unpacker {
ModuleDefinition module;
EmbeddedResource resource;
public bool Detected {
get { return resource != null; }
}
public Unpacker(ModuleDefinition module) {
this.module = module;
}
static string[] requiredFields = new string[] {
"System.String",
};
static string[] requiredEntryPointLocals = new string[] {
"System.Byte[]",
"System.Diagnostics.Process",
"System.Int32",
"System.IO.BinaryReader",
"System.IO.Stream",
"System.String",
"System.String[]",
};
public void find(ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) {
var entryPoint = module.EntryPoint;
if (entryPoint == null)
return;
if (!new LocalTypes(entryPoint).all(requiredEntryPointLocals))
return;
var type = entryPoint.DeclaringType;
if (!new FieldTypes(type).all(requiredFields))
return;
if (findDecryptMethod(type) == null)
return;
var cctor = DotNetUtils.getMethod(type, ".cctor");
if (cctor == null)
return;
simpleDeobfuscator.deobfuscate(cctor);
simpleDeobfuscator.decryptStrings(cctor, deob);
resource = findResource(cctor);
}
EmbeddedResource findResource(MethodDefinition method) {
return DotNetUtils.getResource(module, DotNetUtils.getCodeStrings(method)) as EmbeddedResource;
}
static string[] requiredDecryptLocals = new string[] {
"System.Byte[]",
"System.IO.Compression.DeflateStream",
"System.IO.MemoryStream",
};
static MethodDefinition findDecryptMethod(TypeDefinition type) {
foreach (var method in type.Methods) {
if (!method.IsStatic || method.Body == null)
continue;
if (!DotNetUtils.isMethod(method, "System.Byte[]", "(System.Byte[])"))
continue;
if (!new LocalTypes(method).all(requiredDecryptLocals))
continue;
return method;
}
return null;
}
public byte[] unpack() {
if (resource == null)
return null;
var data = resource.GetResourceData();
for (int i = 0; i < data.Length; i++)
data[i] ^= (byte)i;
data = DeobUtils.inflate(data, true);
return data;
}
}
}