Add static methods decrypter and refactor into multiple classes
This commit is contained in:
parent
a0509d2735
commit
f424e8eabf
|
@ -56,8 +56,13 @@
|
|||
<Compile Include="AssemblyResolver.cs" />
|
||||
<Compile Include="CommandLineParser.cs" />
|
||||
<Compile Include="deobfuscators\ArrayFinder.cs" />
|
||||
<Compile Include="deobfuscators\CliSecure\CliSecureRtType.cs" />
|
||||
<Compile Include="deobfuscators\CliSecure\Deobfuscator.cs" />
|
||||
<Compile Include="deobfuscators\CliSecure\MethodsDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\CliSecure\ProxyDelegateFinder.cs" />
|
||||
<Compile Include="deobfuscators\CliSecure\ResourceDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\CliSecure\StackFrameHelper.cs" />
|
||||
<Compile Include="deobfuscators\CliSecure\StringDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\CryptoObfuscator\AntiDebugger.cs" />
|
||||
<Compile Include="deobfuscators\CryptoObfuscator\AssemblyResolver.cs" />
|
||||
<Compile Include="deobfuscators\CryptoObfuscator\Deobfuscator.cs" />
|
||||
|
|
118
de4dot.code/deobfuscators/CliSecure/CliSecureRtType.cs
Normal file
118
de4dot.code/deobfuscators/CliSecure/CliSecureRtType.cs
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
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 Mono.Cecil;
|
||||
|
||||
namespace de4dot.deobfuscators.CliSecure {
|
||||
class CliSecureRtType {
|
||||
ModuleDefinition module;
|
||||
TypeDefinition cliSecureRtType;
|
||||
MethodDefinition postInitializeMethod;
|
||||
MethodDefinition initializeMethod;
|
||||
MethodDefinition stringDecrypterMethod;
|
||||
MethodDefinition loadMethod;
|
||||
|
||||
public bool Detected {
|
||||
get { return cliSecureRtType != null; }
|
||||
}
|
||||
|
||||
public TypeDefinition Type {
|
||||
get { return cliSecureRtType; }
|
||||
}
|
||||
|
||||
public MethodDefinition StringDecrypterMethod {
|
||||
get { return stringDecrypterMethod; }
|
||||
}
|
||||
|
||||
public MethodDefinition PostInitializeMethod {
|
||||
get { return postInitializeMethod; }
|
||||
}
|
||||
|
||||
public MethodDefinition InitializeMethod {
|
||||
get { return initializeMethod; }
|
||||
}
|
||||
|
||||
public MethodDefinition LoadMethod {
|
||||
get { return loadMethod; }
|
||||
}
|
||||
|
||||
public CliSecureRtType(ModuleDefinition module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public CliSecureRtType(ModuleDefinition module, CliSecureRtType oldOne) {
|
||||
this.module = module;
|
||||
cliSecureRtType = lookup(oldOne.cliSecureRtType, "Could not find CliSecureRt type");
|
||||
postInitializeMethod = lookup(oldOne.postInitializeMethod, "Could not find postInitializeMethod method");
|
||||
initializeMethod = lookup(oldOne.initializeMethod, "Could not find initializeMethod method");
|
||||
stringDecrypterMethod = lookup(oldOne.stringDecrypterMethod, "Could not find stringDecrypterMethod method");
|
||||
loadMethod = lookup(oldOne.loadMethod, "Could not find loadMethod method");
|
||||
}
|
||||
|
||||
T lookup<T>(T def, string errorMessage) where T : MemberReference {
|
||||
return DeobUtils.lookup(module, def, errorMessage);
|
||||
}
|
||||
|
||||
public void find() {
|
||||
if (cliSecureRtType != null)
|
||||
return;
|
||||
|
||||
foreach (var type in module.Types) {
|
||||
if (type.Namespace != "")
|
||||
continue;
|
||||
var typeName = type.FullName;
|
||||
|
||||
MethodDefinition cs = null;
|
||||
MethodDefinition initialize = null;
|
||||
MethodDefinition postInitialize = null;
|
||||
MethodDefinition load = null;
|
||||
|
||||
int methods = 0;
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.FullName == "System.String " + typeName + "::cs(System.String)") {
|
||||
cs = method;
|
||||
methods++;
|
||||
}
|
||||
else if (method.FullName == "System.Void " + typeName + "::Initialize()") {
|
||||
initialize = method;
|
||||
methods++;
|
||||
}
|
||||
else if (method.FullName == "System.Void " + typeName + "::PostInitialize()") {
|
||||
postInitialize = method;
|
||||
methods++;
|
||||
}
|
||||
else if (method.FullName == "System.IntPtr " + typeName + "::Load()") {
|
||||
load = method;
|
||||
methods++;
|
||||
}
|
||||
}
|
||||
if (methods < 2)
|
||||
continue;
|
||||
|
||||
stringDecrypterMethod = cs;
|
||||
initializeMethod = initialize;
|
||||
postInitializeMethod = postInitialize;
|
||||
loadMethod = load;
|
||||
cliSecureRtType = type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,23 +18,24 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using Mono.MyStuff;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.deobfuscators.CliSecure {
|
||||
class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
||||
public const string THE_NAME = "CliSecure";
|
||||
const string DEFAULT_REGEX = @"[a-zA-Z_0-9>}$]$";
|
||||
BoolOption decryptMethods;
|
||||
BoolOption fixResources;
|
||||
BoolOption removeStackFrameHelper;
|
||||
|
||||
public DeobfuscatorInfo()
|
||||
: base(DEFAULT_REGEX) {
|
||||
decryptMethods = new BoolOption(null, makeArgName("methods"), "Decrypt methods", true);
|
||||
fixResources = new BoolOption(null, makeArgName("rsrc"), "Decrypt resources", true);
|
||||
removeStackFrameHelper = new BoolOption(null, makeArgName("stack"), "Remove all StackFrameHelper code", true);
|
||||
}
|
||||
|
@ -50,6 +51,7 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
public override IDeobfuscator createDeobfuscator() {
|
||||
return new Deobfuscator(new Deobfuscator.Options {
|
||||
ValidNameRegex = validNameRegex.get(),
|
||||
DecryptMethods = decryptMethods.get(),
|
||||
FixResources = fixResources.get(),
|
||||
RemoveStackFrameHelper = removeStackFrameHelper.get(),
|
||||
});
|
||||
|
@ -57,6 +59,7 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
|
||||
protected override IEnumerable<Option> getOptionsInternal() {
|
||||
return new List<Option>() {
|
||||
decryptMethods,
|
||||
fixResources,
|
||||
removeStackFrameHelper,
|
||||
};
|
||||
|
@ -65,25 +68,17 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
|
||||
class Deobfuscator : DeobfuscatorBase {
|
||||
Options options;
|
||||
bool foundCliSecureAttribute = false;
|
||||
bool foundProxyDelegateMethod = false;
|
||||
|
||||
MethodDefinition decryptStringMethod;
|
||||
byte[] decryptStringBuffer;
|
||||
|
||||
TypeDefinition cliSecureAttribute;
|
||||
ProxyDelegateFinder proxyDelegateFinder;
|
||||
CliSecureRtType cliSecureRtType;
|
||||
StringDecrypter stringDecrypter;
|
||||
|
||||
TypeDefinition cliSecureRtType;
|
||||
MethodDefinition postInitializeMethod;
|
||||
MethodDefinition initializeMethod;
|
||||
TypeDefinition stackFrameHelperType;
|
||||
|
||||
ExceptionLoggerRemover exceptionLoggerRemover = new ExceptionLoggerRemover();
|
||||
|
||||
MethodDefinition rsrcRrrMethod;
|
||||
MethodDefinition rsrcDecryptMethod;
|
||||
ResourceDecrypter resourceDecrypter;
|
||||
StackFrameHelper stackFrameHelper;
|
||||
|
||||
internal class Options : OptionsBase {
|
||||
public bool DecryptMethods { get; set; }
|
||||
public bool FixResources { get; set; }
|
||||
public bool RemoveStackFrameHelper { get; set; }
|
||||
}
|
||||
|
@ -108,215 +103,96 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
protected override int detectInternal() {
|
||||
int val = 0;
|
||||
|
||||
if (cliSecureRtType != null || foundCliSecureAttribute)
|
||||
if (cliSecureRtType.Detected || cliSecureAttribute != null)
|
||||
val += 100;
|
||||
if (decryptStringBuffer != null)
|
||||
if (stringDecrypter.Detected)
|
||||
val += 10;
|
||||
if (foundProxyDelegateMethod)
|
||||
if (proxyDelegateFinder.Detected)
|
||||
val += 10;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
protected override void scanForObfuscator() {
|
||||
proxyDelegateFinder = new ProxyDelegateFinder(module);
|
||||
findCliSecureAttribute();
|
||||
findCliSecureRtType();
|
||||
findStringDecryptBuffer();
|
||||
findDelegateCreatorType();
|
||||
cliSecureRtType = new CliSecureRtType(module);
|
||||
cliSecureRtType.find();
|
||||
stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterMethod);
|
||||
stringDecrypter.find();
|
||||
proxyDelegateFinder = new ProxyDelegateFinder(module);
|
||||
proxyDelegateFinder.findDelegateCreator();
|
||||
}
|
||||
|
||||
void findCliSecureAttribute() {
|
||||
foreach (var type in module.Types) {
|
||||
if (type.FullName == "SecureTeam.Attributes.ObfuscatedByCliSecureAttribute") {
|
||||
this.addAttributeToBeRemoved(type, "Obfuscator attribute");
|
||||
foundCliSecureAttribute = true;
|
||||
cliSecureAttribute = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void findCliSecureRtType() {
|
||||
if (cliSecureRtType != null)
|
||||
return;
|
||||
public override bool getDecryptedModule(ref byte[] newFileData, ref Dictionary<uint, DumpedMethod> dumpedMethods) {
|
||||
if (!options.DecryptMethods)
|
||||
return false;
|
||||
|
||||
foreach (var type in module.Types) {
|
||||
if (type.Namespace != "")
|
||||
continue;
|
||||
var typeName = type.FullName;
|
||||
|
||||
MethodDefinition cs = null;
|
||||
MethodDefinition initialize = null;
|
||||
MethodDefinition postInitialize = null;
|
||||
MethodDefinition load = null;
|
||||
|
||||
int methods = 0;
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.FullName == "System.String " + typeName + "::cs(System.String)") {
|
||||
cs = method;
|
||||
methods++;
|
||||
}
|
||||
else if (method.FullName == "System.Void " + typeName + "::Initialize()") {
|
||||
initialize = method;
|
||||
methods++;
|
||||
}
|
||||
else if (method.FullName == "System.Void " + typeName + "::PostInitialize()") {
|
||||
postInitialize = method;
|
||||
methods++;
|
||||
}
|
||||
else if (method.FullName == "System.IntPtr " + typeName + "::Load()") {
|
||||
load = method;
|
||||
methods++;
|
||||
}
|
||||
}
|
||||
if (methods < 2)
|
||||
continue;
|
||||
|
||||
decryptStringMethod = cs;
|
||||
initializeMethod = initialize;
|
||||
postInitializeMethod = postInitialize;
|
||||
cliSecureRtType = type;
|
||||
if (load != null)
|
||||
findPossibleNamesToRemove(load);
|
||||
return;
|
||||
byte[] fileData;
|
||||
using (var fileStream = new FileStream(module.FullyQualifiedName, FileMode.Open, FileAccess.Read, FileShare.Read)) {
|
||||
fileData = new byte[(int)fileStream.Length];
|
||||
fileStream.Read(fileData, 0, fileData.Length);
|
||||
}
|
||||
var peImage = new PE.PeImage(fileData);
|
||||
|
||||
if (!new MethodsDecrypter().decrypt(peImage, ref dumpedMethods))
|
||||
return false;
|
||||
|
||||
newFileData = fileData;
|
||||
return true;
|
||||
}
|
||||
|
||||
void findStringDecryptBuffer() {
|
||||
foreach (var type in module.Types) {
|
||||
if (type.FullName == "<D234>" || type.FullName == "<ClassD234>") {
|
||||
addTypeToBeRemoved(type, "Obfuscator string decrypter type");
|
||||
foreach (var field in type.Fields) {
|
||||
if (field.FullName == "<D234> <D234>::345" || field.FullName == "<ClassD234>/D234 <ClassD234>::345") {
|
||||
decryptStringBuffer = field.InitialValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void findDelegateCreatorType() {
|
||||
foreach (var type in module.Types) {
|
||||
var methodName = "System.Void " + type.FullName + "::icgd(System.Int32)";
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.FullName == methodName) {
|
||||
proxyDelegateFinder.setDelegateCreatorMethod(method);
|
||||
foundProxyDelegateMethod = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
public override IDeobfuscator moduleReloaded(ModuleDefinition module) {
|
||||
var newOne = new Deobfuscator(options);
|
||||
newOne.setModule(module);
|
||||
newOne.cliSecureAttribute = DeobUtils.lookup(module, cliSecureAttribute, "Could not find CliSecure attribute");
|
||||
newOne.cliSecureRtType = new CliSecureRtType(module, cliSecureRtType);
|
||||
newOne.stringDecrypter = new StringDecrypter(module, stringDecrypter);
|
||||
newOne.proxyDelegateFinder = new ProxyDelegateFinder(module, proxyDelegateFinder);
|
||||
return newOne;
|
||||
}
|
||||
|
||||
public override void deobfuscateBegin() {
|
||||
base.deobfuscateBegin();
|
||||
|
||||
addAttributeToBeRemoved(cliSecureAttribute, "Obfuscator attribute");
|
||||
addTypeToBeRemoved(stringDecrypter.StringDecrypterType, "Obfuscator string decrypter type");
|
||||
findPossibleNamesToRemove(cliSecureRtType.LoadMethod);
|
||||
|
||||
resourceDecrypter = new ResourceDecrypter(module);
|
||||
resourceDecrypter.find();
|
||||
stackFrameHelper = new StackFrameHelper(module);
|
||||
stackFrameHelper.find();
|
||||
|
||||
foreach (var type in module.Types) {
|
||||
if (type.FullName == "InitializeDelegate" && DotNetUtils.derivesFromDelegate(type))
|
||||
this.addTypeToBeRemoved(type, "Obfuscator type");
|
||||
else if (findResourceDecrypter(type)) {
|
||||
// Nothing
|
||||
}
|
||||
if (options.RemoveStackFrameHelper)
|
||||
findStackFrameHelper(type);
|
||||
}
|
||||
|
||||
proxyDelegateFinder.find();
|
||||
|
||||
if (decryptStringMethod != null)
|
||||
staticStringDecrypter.add(decryptStringMethod, (method, args) => decryptString((string)args[0]));
|
||||
staticStringDecrypter.add(stringDecrypter.StringDecrypterMethod, (method, args) => stringDecrypter.decrypt((string)args[0]));
|
||||
|
||||
addCctorInitCallToBeRemoved(initializeMethod);
|
||||
addCctorInitCallToBeRemoved(postInitializeMethod);
|
||||
addCctorInitCallToBeRemoved(cliSecureRtType.InitializeMethod);
|
||||
addCctorInitCallToBeRemoved(cliSecureRtType.PostInitializeMethod);
|
||||
if (options.FixResources)
|
||||
addCctorInitCallToBeRemoved(rsrcRrrMethod);
|
||||
}
|
||||
|
||||
bool findResourceDecrypter(TypeDefinition type) {
|
||||
MethodDefinition rrrMethod = null;
|
||||
MethodDefinition decryptMethod = null;
|
||||
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.Name == "rrr" && DotNetUtils.isMethod(method, "System.Void", "()"))
|
||||
rrrMethod = method;
|
||||
else if (DotNetUtils.isMethod(method, "System.Reflection.Assembly", "(System.Object,System.ResolveEventArgs)"))
|
||||
decryptMethod = method;
|
||||
}
|
||||
if (rrrMethod == null || decryptMethod == null)
|
||||
return false;
|
||||
|
||||
var methodCalls = DotNetUtils.getMethodCallCounts(rrrMethod);
|
||||
if (methodCalls.count("System.Void System.ResolveEventHandler::.ctor(System.Object,System.IntPtr)") != 1)
|
||||
return false;
|
||||
|
||||
rsrcRrrMethod = rrrMethod;
|
||||
rsrcDecryptMethod = decryptMethod;
|
||||
return true;
|
||||
addCctorInitCallToBeRemoved(resourceDecrypter.RsrcRrrMethod);
|
||||
}
|
||||
|
||||
void decryptResources() {
|
||||
if (rsrcDecryptMethod == null)
|
||||
var rsrc = resourceDecrypter.mergeResources();
|
||||
if (rsrc == null)
|
||||
return;
|
||||
var resource = getResource(DotNetUtils.getCodeStrings(rsrcDecryptMethod)) as EmbeddedResource;
|
||||
if (resource == null)
|
||||
return;
|
||||
|
||||
DeobUtils.decryptAndAddResources(module, resource.Name, () => decryptResource(resource));
|
||||
|
||||
addResourceToBeRemoved(resource, "Encrypted resource");
|
||||
if (rsrcDecryptMethod != null)
|
||||
addTypeToBeRemoved(rsrcDecryptMethod.DeclaringType, "Obfuscator resource decrypter type");
|
||||
}
|
||||
|
||||
byte[] decryptResource(EmbeddedResource resource) {
|
||||
using (var rsrcStream = resource.GetResourceStream()) {
|
||||
using (var reader = new BinaryReader(rsrcStream)) {
|
||||
var key = reader.ReadString();
|
||||
var data = reader.ReadBytes((int)(rsrcStream.Length - rsrcStream.Position));
|
||||
var cryptoTransform = new DESCryptoServiceProvider {
|
||||
Key = Encoding.ASCII.GetBytes(key),
|
||||
IV = Encoding.ASCII.GetBytes(key),
|
||||
}.CreateDecryptor();
|
||||
var memStream = new MemoryStream(data);
|
||||
using (var reader2 = new BinaryReader(new CryptoStream(memStream, cryptoTransform, CryptoStreamMode.Read))) {
|
||||
return reader2.ReadBytes((int)memStream.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void findStackFrameHelper(TypeDefinition type) {
|
||||
if (!type.HasMethods)
|
||||
return;
|
||||
if (type.Methods.Count > 3)
|
||||
return;
|
||||
|
||||
MethodDefinition errorMethod = null;
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.IsRuntimeSpecialName && method.Name == ".ctor" && method.HasParameters == false)
|
||||
continue; // .ctor is allowed
|
||||
if (method.IsRuntimeSpecialName && method.Name == ".cctor" && method.HasParameters == false)
|
||||
continue; // .cctor is allowed
|
||||
if (method.IsStatic && method.CallingConvention == MethodCallingConvention.Default &&
|
||||
method.ExplicitThis == false && method.HasThis == false &&
|
||||
method.HasBody && method.IsManaged && method.IsIL && method.HasParameters &&
|
||||
method.Parameters.Count == 2 && method.HasGenericParameters == false &&
|
||||
!DotNetUtils.hasReturnValue(method) &&
|
||||
MemberReferenceHelper.verifyType(method.Parameters[0].ParameterType, "mscorlib", "System.Exception") &&
|
||||
MemberReferenceHelper.verifyType(method.Parameters[1].ParameterType, "mscorlib", "System.Object", "[]")) {
|
||||
errorMethod = method;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
if (errorMethod != null) {
|
||||
if (stackFrameHelperType != null)
|
||||
throw new ApplicationException("Found another StackFrameHelper");
|
||||
stackFrameHelperType = type;
|
||||
exceptionLoggerRemover.add(errorMethod);
|
||||
}
|
||||
addResourceToBeRemoved(rsrc, "Encrypted resource");
|
||||
addTypeToBeRemoved(resourceDecrypter.Type, "Obfuscator resource decrypter type");
|
||||
}
|
||||
|
||||
public override void deobfuscateMethodEnd(Blocks blocks) {
|
||||
|
@ -329,10 +205,12 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
if (options.FixResources)
|
||||
decryptResources();
|
||||
removeProxyDelegates(proxyDelegateFinder);
|
||||
if (exceptionLoggerRemover.NumRemovedExceptionLoggers > 0)
|
||||
addTypeToBeRemoved(stackFrameHelperType, "StackFrameHelper type");
|
||||
if (options.RemoveStackFrameHelper) {
|
||||
if (stackFrameHelper.ExceptionLoggerRemover.NumRemovedExceptionLoggers > 0)
|
||||
addTypeToBeRemoved(stackFrameHelper.Type, "StackFrameHelper type");
|
||||
}
|
||||
if (Operations.DecryptStrings != OpDecryptString.None)
|
||||
addTypeToBeRemoved(cliSecureRtType, "Obfuscator type");
|
||||
addTypeToBeRemoved(cliSecureRtType.Type, "Obfuscator type");
|
||||
addResources("Obfuscator protection files");
|
||||
addModuleReferences("Obfuscator protection files");
|
||||
|
||||
|
@ -341,22 +219,13 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
|
||||
public override IEnumerable<string> getStringDecrypterMethods() {
|
||||
var list = new List<string>();
|
||||
if (decryptStringMethod != null)
|
||||
list.Add(decryptStringMethod.MetadataToken.ToInt32().ToString("X8"));
|
||||
if (stringDecrypter.StringDecrypterMethod != null)
|
||||
list.Add(stringDecrypter.StringDecrypterMethod.MetadataToken.ToInt32().ToString("X8"));
|
||||
return list;
|
||||
}
|
||||
|
||||
string decryptString(string es) {
|
||||
if (decryptStringBuffer == null)
|
||||
throw new ApplicationException("Trying to decrypt strings when decryptStringBuffer is null (could not find it!)");
|
||||
StringBuilder sb = new StringBuilder(es.Length);
|
||||
for (int i = 0; i < es.Length; i++)
|
||||
sb.Append(Convert.ToChar((int)(es[i] ^ decryptStringBuffer[i % decryptStringBuffer.Length])));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
void removeStackFrameHelperCode(Blocks blocks) {
|
||||
if (exceptionLoggerRemover.remove(blocks))
|
||||
if (stackFrameHelper.ExceptionLoggerRemover.remove(blocks))
|
||||
Log.v("Removed StackFrameHelper code");
|
||||
}
|
||||
}
|
||||
|
|
169
de4dot.code/deobfuscators/CliSecure/MethodsDecrypter.cs
Normal file
169
de4dot.code/deobfuscators/CliSecure/MethodsDecrypter.cs
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
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 System.Collections.Generic;
|
||||
using Mono.MyStuff;
|
||||
|
||||
namespace de4dot.deobfuscators.CliSecure {
|
||||
class CodeHeader {
|
||||
public byte[] signature;
|
||||
public byte[] decryptionKey;
|
||||
public uint totalCodeSize;
|
||||
public uint numMethods;
|
||||
public uint methodDefTableOffset;
|
||||
public uint methodDefElemSize;
|
||||
}
|
||||
|
||||
struct MethodInfo {
|
||||
public uint codeOffs, codeSize, flags, localVarSigTok;
|
||||
|
||||
public MethodInfo(uint codeOffs, uint codeSize, uint flags, uint localVarSigTok) {
|
||||
this.codeOffs = codeOffs;
|
||||
this.codeSize = codeSize;
|
||||
this.flags = flags;
|
||||
this.localVarSigTok = localVarSigTok;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return string.Format("{0:X8} {1:X8} {2:X8} {3:X8}", codeOffs, codeSize, flags, localVarSigTok);
|
||||
}
|
||||
}
|
||||
|
||||
class MethodsDecrypter {
|
||||
static byte[] SIGNATURE = new byte[16] { 0x08, 0x44, 0x65, 0xE1, 0x8C, 0x82, 0x13, 0x4C, 0x9C, 0x85, 0xB4, 0x17, 0xDA, 0x51, 0xAD, 0x25 };
|
||||
PE.PeImage peImage;
|
||||
CodeHeader codeHeader = new CodeHeader();
|
||||
uint endOfMetadata;
|
||||
|
||||
public bool decrypt(PE.PeImage peImage, ref Dictionary<uint, DumpedMethod> dumpedMethods) {
|
||||
this.peImage = peImage;
|
||||
|
||||
endOfMetadata = peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size);
|
||||
uint offset = endOfMetadata;
|
||||
if (!readCodeHeader(offset))
|
||||
return false;
|
||||
|
||||
var methodInfos = getMethodInfos(offset + 0x30 + codeHeader.totalCodeSize);
|
||||
var metadataTables = peImage.Cor20Header.createMetadataTables();
|
||||
var methodDefTable = metadataTables.getMetadataType(PE.MetadataIndex.iMethodDef);
|
||||
|
||||
offset = methodDefTable.fileOffset - methodDefTable.totalSize;
|
||||
foreach (var methodInfo in methodInfos) {
|
||||
offset += methodDefTable.totalSize;
|
||||
if (methodInfo.flags == 0 || methodInfo.localVarSigTok == 0)
|
||||
continue;
|
||||
uint rva = peImage.offsetReadUInt32(offset);
|
||||
peImage.writeUint16(rva, (ushort)methodInfo.flags);
|
||||
peImage.writeUint32(rva + 8, methodInfo.localVarSigTok);
|
||||
}
|
||||
|
||||
dumpedMethods = new Dictionary<uint, DumpedMethod>();
|
||||
offset = methodDefTable.fileOffset;
|
||||
for (int i = 0; i < methodInfos.Count; i++, offset += methodDefTable.totalSize) {
|
||||
var methodInfo = methodInfos[i];
|
||||
if (methodInfo.codeOffs == 0)
|
||||
continue;
|
||||
|
||||
var dm = new DumpedMethod();
|
||||
dm.token = 0x06000001 + (uint)i;
|
||||
|
||||
uint rva = peImage.offsetReadUInt32(offset);
|
||||
dm.mdImplFlags = peImage.offsetReadUInt16(offset + (uint)methodDefTable.fields[1].offset);
|
||||
dm.mdFlags = peImage.offsetReadUInt16(offset + (uint)methodDefTable.fields[2].offset);
|
||||
dm.mdName = peImage.offsetRead(offset + (uint)methodDefTable.fields[3].offset, methodDefTable.fields[3].size);
|
||||
dm.mdSignature = peImage.offsetRead(offset + (uint)methodDefTable.fields[4].offset, methodDefTable.fields[4].size);
|
||||
dm.mdParamList = peImage.offsetRead(offset + (uint)methodDefTable.fields[5].offset, methodDefTable.fields[5].size);
|
||||
|
||||
dm.code = getDecryptedCode(methodInfo);
|
||||
|
||||
if ((peImage.readByte(rva) & 3) == 2) {
|
||||
dm.mhFlags = 2;
|
||||
dm.mhMaxStack = 8;
|
||||
dm.mhCodeSize = (uint)dm.code.Length;
|
||||
dm.mhLocalVarSigTok = 0;
|
||||
}
|
||||
else {
|
||||
dm.mhFlags = peImage.readUInt16(rva);
|
||||
dm.mhMaxStack = peImage.readUInt16(rva + 2);
|
||||
dm.mhCodeSize = (uint)dm.code.Length;
|
||||
dm.mhLocalVarSigTok = peImage.readUInt32(rva + 8);
|
||||
}
|
||||
|
||||
dumpedMethods[dm.token] = dm;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
byte[] getDecryptedCode(MethodInfo methodInfo) {
|
||||
byte[] data = peImage.offsetReadBytes(endOfMetadata + methodInfo.codeOffs, (int)methodInfo.codeSize);
|
||||
for (int i = 0; i < data.Length; i++) {
|
||||
byte b = data[i];
|
||||
b ^= codeHeader.decryptionKey[(methodInfo.codeOffs - 0x30 + i) % 16];
|
||||
b ^= codeHeader.decryptionKey[(methodInfo.codeOffs - 0x30 + i + 7) % 16];
|
||||
data[i] = b;
|
||||
}
|
||||
|
||||
int codeOffset, codeSize;
|
||||
if ((data[0] & 3) == 2) {
|
||||
codeOffset = 1;
|
||||
codeSize = data[0] >> 2;
|
||||
}
|
||||
else {
|
||||
codeOffset = 4 * (data[1] >> 4);
|
||||
codeSize = BitConverter.ToInt32(data, 4);
|
||||
}
|
||||
|
||||
var code = new byte[codeSize];
|
||||
Array.Copy(data, codeOffset, code, 0, codeSize);
|
||||
return code;
|
||||
}
|
||||
|
||||
bool readCodeHeader(uint offset) {
|
||||
codeHeader.signature = peImage.offsetReadBytes(offset, 16);
|
||||
if (!Utils.compare(SIGNATURE, codeHeader.signature))
|
||||
return false;
|
||||
codeHeader.decryptionKey = peImage.offsetReadBytes(offset + 0x10, 16);
|
||||
codeHeader.totalCodeSize = peImage.offsetReadUInt32(offset + 0x20);
|
||||
codeHeader.numMethods = peImage.offsetReadUInt32(offset + 0x24);
|
||||
codeHeader.methodDefTableOffset = peImage.offsetReadUInt32(offset + 0x28);
|
||||
codeHeader.methodDefElemSize = peImage.offsetReadUInt32(offset + 0x2C);
|
||||
|
||||
if (codeHeader.totalCodeSize > 0x10000000)
|
||||
throw new ApplicationException("Invalid total code size");
|
||||
if (codeHeader.numMethods > 512*1024)
|
||||
throw new ApplicationException("Invalid num methods");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
List<MethodInfo> getMethodInfos(uint offset) {
|
||||
var methodInfos = new List<MethodInfo>((int)codeHeader.numMethods);
|
||||
for (int i = 0; i < (int)codeHeader.numMethods; i++, offset += 16) {
|
||||
uint codeOffs = peImage.offsetReadUInt32(offset);
|
||||
uint codeSize = peImage.offsetReadUInt32(offset + 4);
|
||||
uint flags = peImage.offsetReadUInt32(offset + 8);
|
||||
uint localVarSigTok = peImage.offsetReadUInt32(offset + 12);
|
||||
methodInfos.Add(new MethodInfo(codeOffs, codeSize, flags, localVarSigTok));
|
||||
}
|
||||
return methodInfos;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,7 +29,28 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
|
||||
public ProxyDelegateFinder(ModuleDefinition module)
|
||||
: base(module) {
|
||||
this.memberReferences = new List<MemberReference>(module.GetMemberReferences());
|
||||
}
|
||||
|
||||
public ProxyDelegateFinder(ModuleDefinition module, ProxyDelegateFinder oldOne)
|
||||
: base(module) {
|
||||
foreach (var method in oldOne.delegateCreatorMethods)
|
||||
setDelegateCreatorMethod(lookup(method, "Could not find delegate creator method"));
|
||||
}
|
||||
|
||||
T lookup<T>(T def, string errorMessage) where T : MemberReference {
|
||||
return DeobUtils.lookup(module, def, errorMessage);
|
||||
}
|
||||
|
||||
public void findDelegateCreator() {
|
||||
foreach (var type in module.Types) {
|
||||
var methodName = "System.Void " + type.FullName + "::icgd(System.Int32)";
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.FullName == methodName) {
|
||||
setDelegateCreatorMethod(method);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override object checkCctor(TypeDefinition type, MethodDefinition cctor) {
|
||||
|
@ -53,6 +74,9 @@ namespace de4dot.deobfuscators.CliSecure {
|
|||
}
|
||||
|
||||
protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) {
|
||||
if (memberReferences == null)
|
||||
memberReferences = new List<MemberReference>(module.GetMemberReferences());
|
||||
|
||||
var name = field.Name;
|
||||
callOpcode = OpCodes.Call;
|
||||
if (name.EndsWith("%", StringComparison.Ordinal)) {
|
||||
|
|
101
de4dot.code/deobfuscators/CliSecure/ResourceDecrypter.cs
Normal file
101
de4dot.code/deobfuscators/CliSecure/ResourceDecrypter.cs
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
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.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Mono.Cecil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.deobfuscators.CliSecure {
|
||||
class ResourceDecrypter {
|
||||
ModuleDefinition module;
|
||||
TypeDefinition rsrcType;
|
||||
MethodDefinition rsrcRrrMethod;
|
||||
MethodDefinition rsrcDecryptMethod;
|
||||
|
||||
public TypeDefinition Type {
|
||||
get { return rsrcType; }
|
||||
}
|
||||
|
||||
public MethodDefinition RsrcRrrMethod {
|
||||
get { return rsrcRrrMethod; }
|
||||
}
|
||||
|
||||
public ResourceDecrypter(ModuleDefinition module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public void find() {
|
||||
findResourceType();
|
||||
}
|
||||
|
||||
void findResourceType() {
|
||||
foreach (var type in module.Types) {
|
||||
MethodDefinition rrrMethod = null;
|
||||
MethodDefinition decryptMethod = null;
|
||||
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.Name == "rrr" && DotNetUtils.isMethod(method, "System.Void", "()"))
|
||||
rrrMethod = method;
|
||||
else if (DotNetUtils.isMethod(method, "System.Reflection.Assembly", "(System.Object,System.ResolveEventArgs)"))
|
||||
decryptMethod = method;
|
||||
}
|
||||
if (rrrMethod == null || decryptMethod == null)
|
||||
continue;
|
||||
|
||||
var methodCalls = DotNetUtils.getMethodCallCounts(rrrMethod);
|
||||
if (methodCalls.count("System.Void System.ResolveEventHandler::.ctor(System.Object,System.IntPtr)") != 1)
|
||||
continue;
|
||||
|
||||
rsrcType = type;
|
||||
rsrcRrrMethod = rrrMethod;
|
||||
rsrcDecryptMethod = decryptMethod;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public EmbeddedResource mergeResources() {
|
||||
if (rsrcDecryptMethod == null)
|
||||
return null;
|
||||
var resource = DotNetUtils.getResource(module, DotNetUtils.getCodeStrings(rsrcDecryptMethod)) as EmbeddedResource;
|
||||
if (resource == null)
|
||||
return null;
|
||||
DeobUtils.decryptAndAddResources(module, resource.Name, () => decryptResource(resource));
|
||||
return resource;
|
||||
}
|
||||
|
||||
byte[] decryptResource(EmbeddedResource resource) {
|
||||
using (var rsrcStream = resource.GetResourceStream()) {
|
||||
using (var reader = new BinaryReader(rsrcStream)) {
|
||||
var key = reader.ReadString();
|
||||
var data = reader.ReadBytes((int)(rsrcStream.Length - rsrcStream.Position));
|
||||
var cryptoTransform = new DESCryptoServiceProvider {
|
||||
Key = Encoding.ASCII.GetBytes(key),
|
||||
IV = Encoding.ASCII.GetBytes(key),
|
||||
}.CreateDecryptor();
|
||||
var memStream = new MemoryStream(data);
|
||||
using (var reader2 = new BinaryReader(new CryptoStream(memStream, cryptoTransform, CryptoStreamMode.Read))) {
|
||||
return reader2.ReadBytes((int)memStream.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
75
de4dot.code/deobfuscators/CliSecure/StackFrameHelper.cs
Normal file
75
de4dot.code/deobfuscators/CliSecure/StackFrameHelper.cs
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
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 Mono.Cecil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.deobfuscators.CliSecure {
|
||||
class StackFrameHelper {
|
||||
ModuleDefinition module;
|
||||
TypeDefinition stackFrameHelperType;
|
||||
ExceptionLoggerRemover exceptionLoggerRemover = new ExceptionLoggerRemover();
|
||||
|
||||
public TypeDefinition Type {
|
||||
get { return stackFrameHelperType; }
|
||||
}
|
||||
|
||||
public ExceptionLoggerRemover ExceptionLoggerRemover {
|
||||
get { return exceptionLoggerRemover; }
|
||||
}
|
||||
|
||||
public StackFrameHelper(ModuleDefinition module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public void find() {
|
||||
foreach (var type in module.Types) {
|
||||
if (!type.HasMethods)
|
||||
continue;
|
||||
if (type.Methods.Count > 3)
|
||||
continue;
|
||||
|
||||
MethodDefinition errorMethod = null;
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.IsRuntimeSpecialName && method.Name == ".ctor" && !method.HasParameters)
|
||||
continue; // .ctor is allowed
|
||||
if (method.IsRuntimeSpecialName && method.Name == ".cctor" && !method.HasParameters)
|
||||
continue; // .cctor is allowed
|
||||
if (method.IsStatic && method.CallingConvention == MethodCallingConvention.Default &&
|
||||
method.ExplicitThis == false && method.HasThis == false &&
|
||||
method.HasBody && method.IsManaged && method.IsIL && method.HasParameters &&
|
||||
method.Parameters.Count == 2 && !method.HasGenericParameters &&
|
||||
!DotNetUtils.hasReturnValue(method) &&
|
||||
method.Parameters[0].ParameterType.FullName == "System.Exception" &&
|
||||
method.Parameters[1].ParameterType.FullName == "System.Object[]") {
|
||||
errorMethod = method;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (errorMethod != null) {
|
||||
stackFrameHelperType = type;
|
||||
exceptionLoggerRemover.add(errorMethod);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
83
de4dot.code/deobfuscators/CliSecure/StringDecrypter.cs
Normal file
83
de4dot.code/deobfuscators/CliSecure/StringDecrypter.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
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 System.Text;
|
||||
using Mono.Cecil;
|
||||
|
||||
namespace de4dot.deobfuscators.CliSecure {
|
||||
class StringDecrypter {
|
||||
ModuleDefinition module;
|
||||
TypeDefinition stringDecrypterType;
|
||||
MethodDefinition stringDecrypterMethod;
|
||||
byte[] stringDecrypterKey;
|
||||
|
||||
public bool Detected {
|
||||
get { return stringDecrypterKey != null; }
|
||||
}
|
||||
|
||||
public TypeDefinition StringDecrypterType {
|
||||
get { return stringDecrypterType; }
|
||||
}
|
||||
|
||||
public MethodDefinition StringDecrypterMethod {
|
||||
get { return stringDecrypterMethod; }
|
||||
}
|
||||
|
||||
public StringDecrypter(ModuleDefinition module, MethodDefinition stringDecrypterMethod) {
|
||||
this.module = module;
|
||||
this.stringDecrypterMethod = stringDecrypterMethod;
|
||||
}
|
||||
|
||||
public StringDecrypter(ModuleDefinition module, StringDecrypter oldOne) {
|
||||
this.module = module;
|
||||
stringDecrypterType = lookup(oldOne.stringDecrypterType, "Could not find stringDecrypterType");
|
||||
stringDecrypterMethod = lookup(oldOne.stringDecrypterMethod, "Could not find stringDecrypterMethod");
|
||||
stringDecrypterKey = oldOne.stringDecrypterKey;
|
||||
}
|
||||
|
||||
T lookup<T>(T def, string errorMessage) where T : MemberReference {
|
||||
return DeobUtils.lookup(module, def, errorMessage);
|
||||
}
|
||||
|
||||
public void find() {
|
||||
foreach (var type in module.Types) {
|
||||
if (type.FullName == "<D234>" || type.FullName == "<ClassD234>") {
|
||||
stringDecrypterType = type;
|
||||
foreach (var field in type.Fields) {
|
||||
if (field.FullName == "<D234> <D234>::345" || field.FullName == "<ClassD234>/D234 <ClassD234>::345") {
|
||||
stringDecrypterKey = field.InitialValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string decrypt(string es) {
|
||||
if (stringDecrypterKey == null)
|
||||
throw new ApplicationException("Trying to decrypt strings when stringDecrypterKey is null (could not find it!)");
|
||||
StringBuilder sb = new StringBuilder(es.Length);
|
||||
for (int i = 0; i < es.Length; i++)
|
||||
sb.Append(Convert.ToChar((int)(es[i] ^ stringDecrypterKey[i % stringDecrypterKey.Length])));
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user