Decrypt embedded assemblies

This commit is contained in:
de4dot 2012-05-26 17:36:26 +02:00
parent 3a96ae391a
commit adaf41c769
3 changed files with 227 additions and 0 deletions

View File

@ -107,6 +107,7 @@
<Compile Include="deobfuscators\CodeVeil\Deobfuscator.cs" />
<Compile Include="deobfuscators\CodeVeil\ProxyDelegateFinder.cs" />
<Compile Include="deobfuscators\CodeVeil\TamperDetection.cs" />
<Compile Include="deobfuscators\CodeWall\AssemblyDecrypter.cs" />
<Compile Include="deobfuscators\CodeWall\Deobfuscator.cs" />
<Compile Include="deobfuscators\CodeWall\MethodsDecrypter.cs" />
<Compile Include="deobfuscators\CodeWall\randomc\CRandomMersenne.cs" />

View File

@ -0,0 +1,206 @@
/*
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 System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
using de4dot.code.resources;
namespace de4dot.code.deobfuscators.CodeWall {
class AssemblyDecrypter {
ModuleDefinition module;
ISimpleDeobfuscator simpleDeobfuscator;
IDeobfuscator deob;
List<AssemblyInfo> assemblyInfos = new List<AssemblyInfo>();
string entryPointAssemblyKey;
string resourcePassword;
string resourceSalt;
EmbeddedResource assemblyResource;
public class AssemblyInfo {
public readonly byte[] data;
public readonly string extension;
public readonly string assemblyFullName;
public readonly string assemblySimpleName;
public readonly bool isEntryPointAssembly;
public AssemblyInfo(byte[] data, string extension, string assemblyFullName, string assemblySimpleName, bool isEntryPointAssembly) {
this.data = data;
this.extension = extension;
this.assemblyFullName = assemblyFullName;
this.assemblySimpleName = assemblySimpleName;
this.isEntryPointAssembly = isEntryPointAssembly;
}
public override string ToString() {
return assemblyFullName;
}
}
public IEnumerable<AssemblyInfo> AssemblyInfos {
get { return assemblyInfos; }
}
public AssemblyDecrypter(ModuleDefinition module, ISimpleDeobfuscator simpleDeobfuscator, IDeobfuscator deob) {
this.module = module;
this.simpleDeobfuscator = simpleDeobfuscator;
this.deob = deob;
}
static readonly string[] requiredLocals = new string[] {
"System.AppDomain",
"System.DateTime",
};
public void find() {
var method = module.EntryPoint;
if (!checkEntryPoint(method))
return;
MethodDefinition decryptAssemblyMethod;
var mainKey = getMainResourceKey(method, out decryptAssemblyMethod);
if (mainKey == null)
return;
deobfuscateAll(decryptAssemblyMethod);
var resource = getResource(decryptAssemblyMethod);
if (resource == null)
return;
string password, salt;
if (!getPassword(decryptAssemblyMethod, out password, out salt))
return;
entryPointAssemblyKey = mainKey;
resourcePassword = password;
resourceSalt = salt;
assemblyResource = resource;
decryptAllAssemblies();
}
bool checkEntryPoint(MethodDefinition method) {
if (method == null)
return false;
if (!new LocalTypes(method).all(requiredLocals))
return false;
var handlers = DeobUtils.getAllResolveHandlers(method);
if (handlers.Count != 1)
return false;
return true;
}
void deobfuscateAll(MethodDefinition method) {
simpleDeobfuscator.deobfuscate(method);
simpleDeobfuscator.decryptStrings(method, deob);
}
string getMainResourceKey(MethodDefinition method, out MethodDefinition decryptAssemblyMethod) {
foreach (var calledMethod in DotNetUtils.getCalledMethods(module, method)) {
if (!calledMethod.IsStatic || calledMethod.Body == null)
continue;
if (!DotNetUtils.isMethod(calledMethod, "System.Void", "(System.String[])"))
continue;
deobfuscateAll(calledMethod);
string keyInfo = getMainResourceKeyInfo(calledMethod, out decryptAssemblyMethod);
if (keyInfo == null)
continue;
return BitConverter.ToString(new MD5CryptoServiceProvider().ComputeHash(new ASCIIEncoding().GetBytes(keyInfo))).Replace("-", "");
}
decryptAssemblyMethod = null;
return null;
}
string getMainResourceKeyInfo(MethodDefinition method, out MethodDefinition decryptAssemblyMethod) {
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 1; i++) {
var ldstr = instrs[i];
if (ldstr.OpCode.Code != Code.Ldstr)
continue;
var call = instrs[i + 1];
if (call.OpCode.Code != Code.Call)
continue;
var calledMethod = call.Operand as MethodDefinition;
if (calledMethod == null)
continue;
decryptAssemblyMethod = calledMethod;
return (string)ldstr.Operand;
}
decryptAssemblyMethod = null;
return null;
}
EmbeddedResource getResource(MethodDefinition method) {
foreach (var s in DotNetUtils.getCodeStrings(method)) {
var resource = DotNetUtils.getResource(module, s + ".resources") as EmbeddedResource;
if (resource != null)
return resource;
}
return null;
}
bool getPassword(MethodDefinition method, out string password, out string salt) {
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 1; i++) {
var ldstr1 = instrs[i];
if (ldstr1.OpCode.Code != Code.Ldstr)
continue;
var ldstr2 = instrs[i + 1];
if (ldstr2.OpCode.Code != Code.Ldstr)
continue;
password = (string)ldstr1.Operand;
salt = (string)ldstr2.Operand;
if (password == null || salt == null)
continue;
return true;
}
password = null;
salt = null;
return false;
}
void decryptAllAssemblies() {
if (assemblyResource == null)
return;
var resourceSet = ResourceReader.read(module, assemblyResource.GetResourceStream());
foreach (var resourceElement in resourceSet.ResourceElements) {
if (resourceElement.ResourceData.Code != ResourceTypeCode.ByteArray)
throw new ApplicationException("Invalid resource");
var resourceData = (BuiltInResourceData)resourceElement.ResourceData;
var assemblyData = decrypt((byte[])resourceData.Data);
var theModule = ModuleDefinition.ReadModule(new MemoryStream(assemblyData));
bool isMain = resourceElement.Name == entryPointAssemblyKey;
assemblyInfos.Add(new AssemblyInfo(assemblyData, DeobUtils.getExtension(theModule.Kind), theModule.Assembly.FullName, theModule.Assembly.Name.Name, isMain));
}
}
byte[] decrypt(byte[] encrypted) {
var keyGenerator = new PasswordDeriveBytes(resourcePassword, Encoding.ASCII.GetBytes(resourceSalt));
return DeobUtils.inflate(DeobUtils.aesDecrypt(encrypted, keyGenerator.GetBytes(32), keyGenerator.GetBytes(16)), false);
}
}
}

View File

@ -29,9 +29,11 @@ namespace de4dot.code.deobfuscators.CodeWall {
public const string THE_NAME = "CodeWall";
public const string THE_TYPE = "cw";
const string DEFAULT_REGEX = @"!^[_<>{}$.`-]$&" + DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX;
BoolOption dumpEmbeddedAssemblies;
public DeobfuscatorInfo()
: base(DEFAULT_REGEX) {
dumpEmbeddedAssemblies = new BoolOption(null, makeArgName("embedded"), "Dump embedded assemblies", true);
}
public override string Name {
@ -45,11 +47,13 @@ namespace de4dot.code.deobfuscators.CodeWall {
public override IDeobfuscator createDeobfuscator() {
return new Deobfuscator(new Deobfuscator.Options {
ValidNameRegex = validNameRegex.get(),
DumpEmbeddedAssemblies = dumpEmbeddedAssemblies.get(),
});
}
protected override IEnumerable<Option> getOptionsInternal() {
return new List<Option>() {
dumpEmbeddedAssemblies,
};
}
}
@ -60,6 +64,7 @@ namespace de4dot.code.deobfuscators.CodeWall {
StringDecrypter stringDecrypter;
internal class Options : OptionsBase {
public bool DumpEmbeddedAssemblies { get; set; }
}
public override string Type {
@ -127,6 +132,21 @@ namespace de4dot.code.deobfuscators.CodeWall {
foreach (var info in stringDecrypter.Infos)
staticStringInliner.add(info.Method, (method, args) => stringDecrypter.decrypt(method, (int)args[0], (int)args[1], (int)args[2]));
DeobfuscatedFile.stringDecryptersAdded();
dumpEmbeddedAssemblies();
}
void dumpEmbeddedAssemblies() {
if (!options.DumpEmbeddedAssemblies)
return;
var asmDecrypter = new AssemblyDecrypter(module, DeobfuscatedFile, this);
asmDecrypter.find();
foreach (var info in asmDecrypter.AssemblyInfos) {
var asmName = info.assemblySimpleName;
if (info.isEntryPointAssembly)
asmName += "_real";
DeobfuscatedFile.createAssemblyFile(info.data, asmName, info.extension);
}
}
public override void deobfuscateMethodEnd(Blocks blocks) {