Support more than one string decrypter method
This commit is contained in:
parent
291b83e325
commit
43453f3863
|
@ -66,6 +66,7 @@
|
|||
<Compile Include="deobfuscators\Agile_NET\ResourceDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\Agile_NET\StackFrameHelper.cs" />
|
||||
<Compile Include="deobfuscators\Agile_NET\StringDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\Agile_NET\StringDecrypterInfo.cs" />
|
||||
<Compile Include="deobfuscators\Agile_NET\vm\CilOperandInstructionRestorer.cs" />
|
||||
<Compile Include="deobfuscators\Agile_NET\vm\CsvmDataReader.cs" />
|
||||
<Compile Include="deobfuscators\Agile_NET\vm\CsvmMethodData.cs" />
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
TypeDef cliSecureRtType;
|
||||
MethodDef postInitializeMethod;
|
||||
MethodDef initializeMethod;
|
||||
MethodDef stringDecrypterMethod;
|
||||
Dictionary<StringDecrypterInfo, bool> stringDecrypterInfos = new Dictionary<StringDecrypterInfo, bool>();
|
||||
MethodDef loadMethod;
|
||||
bool foundSig;
|
||||
|
||||
|
@ -41,8 +41,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
get { return cliSecureRtType; }
|
||||
}
|
||||
|
||||
public MethodDef StringDecrypterMethod {
|
||||
get { return stringDecrypterMethod; }
|
||||
public IEnumerable<StringDecrypterInfo> StringDecrypterInfos {
|
||||
get { return stringDecrypterInfos.Keys; }
|
||||
}
|
||||
|
||||
public MethodDef PostInitializeMethod {
|
||||
|
@ -66,7 +66,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
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");
|
||||
foreach (var info in oldOne.stringDecrypterInfos.Keys) {
|
||||
var m = Lookup(info.Method, "Could not find string decrypter method");
|
||||
var f = Lookup(info.Field, "Could not find string decrypter field");
|
||||
stringDecrypterInfos[new StringDecrypterInfo(m, f)] = true;
|
||||
}
|
||||
loadMethod = Lookup(oldOne.loadMethod, "Could not find loadMethod method");
|
||||
foundSig = oldOne.foundSig;
|
||||
}
|
||||
|
@ -100,11 +104,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
if (!HasInitializeMethod(type, "_Initialize") && !HasInitializeMethod(type, "_Initialize64"))
|
||||
continue;
|
||||
|
||||
stringDecrypterMethod = FindStringDecrypterMethod(type);
|
||||
initializeMethod = calledMethod;
|
||||
postInitializeMethod = FindMethod(type, "System.Void", "PostInitialize", "()");
|
||||
loadMethod = FindMethod(type, "System.IntPtr", "Load", "()");
|
||||
cliSecureRtType = type;
|
||||
FindStringDecrypters();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +116,15 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
return false;
|
||||
}
|
||||
|
||||
void FindStringDecrypters() {
|
||||
AddStringDecrypterMethod(FindStringDecrypterMethod(cliSecureRtType));
|
||||
}
|
||||
|
||||
void AddStringDecrypterMethod(MethodDef method) {
|
||||
if (method != null)
|
||||
stringDecrypterInfos[new StringDecrypterInfo(method)] = true;
|
||||
}
|
||||
|
||||
static string[] requiredFields6 = new string[] {
|
||||
"System.Byte[]",
|
||||
};
|
||||
|
@ -134,7 +147,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
if (cs == null)
|
||||
continue;
|
||||
|
||||
stringDecrypterMethod = cs;
|
||||
AddStringDecrypterMethod(cs);
|
||||
cliSecureRtType = type;
|
||||
return true;
|
||||
}
|
||||
|
@ -208,7 +221,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
continue;
|
||||
|
||||
cliSecureRtType = type;
|
||||
stringDecrypterMethod = cs;
|
||||
AddStringDecrypterMethod(cs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,7 +180,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
FindCliSecureAttribute();
|
||||
cliSecureRtType = new CliSecureRtType(module);
|
||||
cliSecureRtType.Find(ModuleBytes);
|
||||
stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterMethod);
|
||||
stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterInfos);
|
||||
stringDecrypter.Find();
|
||||
resourceDecrypter = new ResourceDecrypter(module);
|
||||
resourceDecrypter.Find();
|
||||
|
@ -246,7 +246,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
base.DeobfuscateBegin();
|
||||
|
||||
cliSecureRtType.FindStringDecrypterMethod();
|
||||
stringDecrypter.Method = cliSecureRtType.StringDecrypterMethod;
|
||||
stringDecrypter.AddDecrypterInfos(cliSecureRtType.StringDecrypterInfos);
|
||||
stringDecrypter.Initialize();
|
||||
|
||||
AddAttributesToBeRemoved(cliSecureAttributes, "Obfuscator attribute");
|
||||
|
||||
|
@ -265,7 +266,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
|
||||
proxyCallFixer.Find();
|
||||
|
||||
staticStringInliner.Add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
|
||||
foreach (var info in stringDecrypter.StringDecrypterInfos)
|
||||
staticStringInliner.Add(info.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
|
||||
DeobfuscatedFile.StringDecryptersAdded();
|
||||
|
||||
if (options.DecryptMethods) {
|
||||
|
@ -295,6 +297,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
}
|
||||
|
||||
public override void DeobfuscateMethodEnd(Blocks blocks) {
|
||||
if (Operations.DecryptStrings != OpDecryptString.None)
|
||||
stringDecrypter.Deobfuscate(blocks);
|
||||
proxyCallFixer.Deobfuscate(blocks);
|
||||
RemoveStackFrameHelperCode(blocks);
|
||||
base.DeobfuscateMethodEnd(blocks);
|
||||
|
@ -310,8 +314,14 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
}
|
||||
if (CanRemoveStringDecrypterType) {
|
||||
AddTypeToBeRemoved(stringDecrypter.Type, "String decrypter type");
|
||||
foreach (var info in stringDecrypter.StringDecrypterInfos) {
|
||||
if (info.Method.DeclaringType != cliSecureRtType.Type)
|
||||
AddMethodToBeRemoved(info.Method, "String decrypter method");
|
||||
if (info.Field != null && info.Field.DeclaringType != stringDecrypter.Type)
|
||||
AddFieldToBeRemoved(info.Field, "String decrypter field");
|
||||
}
|
||||
if (options.DecryptMethods)
|
||||
AddTypeToBeRemoved(cliSecureRtType.Type, "Obfuscator type");
|
||||
AddTypeToBeRemoved(cliSecureRtType.Type ?? stringDecrypter.KeyArrayFieldType, "Obfuscator type");
|
||||
}
|
||||
if (options.DecryptMethods) {
|
||||
AddResources("Obfuscator protection files");
|
||||
|
@ -327,8 +337,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
|
||||
public override IEnumerable<int> GetStringDecrypterMethods() {
|
||||
var list = new List<int>();
|
||||
if (stringDecrypter.Method != null)
|
||||
list.Add(stringDecrypter.Method.MDToken.ToInt32());
|
||||
foreach (var info in stringDecrypter.StringDecrypterInfos)
|
||||
list.Add(info.Method.MDToken.ToInt32());
|
||||
return list;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,38 +18,53 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Emit;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Agile_NET {
|
||||
class StringDecrypter {
|
||||
ModuleDefMD module;
|
||||
TypeDef stringDecrypterType;
|
||||
MethodDef stringDecrypterMethod;
|
||||
FieldDef keyInitField;
|
||||
FieldDef keyArrayField;
|
||||
Dictionary<StringDecrypterInfo, bool> stringDecrypterInfos = new Dictionary<StringDecrypterInfo, bool>();
|
||||
byte[] stringDecrypterKey;
|
||||
|
||||
public bool Detected {
|
||||
get { return stringDecrypterMethod != null; }
|
||||
get { return stringDecrypterInfos.Count != 0; }
|
||||
}
|
||||
|
||||
public TypeDef Type {
|
||||
get { return stringDecrypterType; }
|
||||
}
|
||||
|
||||
public MethodDef Method {
|
||||
get { return stringDecrypterMethod; }
|
||||
set { stringDecrypterMethod = value; }
|
||||
public TypeDef KeyArrayFieldType {
|
||||
get { return keyArrayField == null ? null : keyArrayField.DeclaringType; }
|
||||
}
|
||||
|
||||
public StringDecrypter(ModuleDefMD module, MethodDef stringDecrypterMethod) {
|
||||
public IEnumerable<StringDecrypterInfo> StringDecrypterInfos {
|
||||
get { return stringDecrypterInfos.Keys; }
|
||||
}
|
||||
|
||||
public StringDecrypter(ModuleDefMD module, IEnumerable<StringDecrypterInfo> stringDecrypterMethods) {
|
||||
this.module = module;
|
||||
this.stringDecrypterMethod = stringDecrypterMethod;
|
||||
foreach (var sdm in stringDecrypterMethods)
|
||||
this.stringDecrypterInfos[sdm] = true;
|
||||
}
|
||||
|
||||
public StringDecrypter(ModuleDefMD module, StringDecrypter oldOne) {
|
||||
this.module = module;
|
||||
stringDecrypterType = Lookup(oldOne.stringDecrypterType, "Could not find stringDecrypterType");
|
||||
stringDecrypterMethod = Lookup(oldOne.stringDecrypterMethod, "Could not find stringDecrypterMethod");
|
||||
keyInitField = Lookup(oldOne.keyInitField, "Could not find key init field");
|
||||
keyArrayField = Lookup(oldOne.keyArrayField, "Could not find key array field");
|
||||
foreach (var info in oldOne.stringDecrypterInfos.Keys) {
|
||||
var m = Lookup(info.Method, "Could not find string decrypter method");
|
||||
var f = Lookup(info.Field, "Could not find string decrypter field");
|
||||
stringDecrypterInfos[new StringDecrypterInfo(m, f)] = true;
|
||||
}
|
||||
stringDecrypterKey = oldOne.stringDecrypterKey;
|
||||
}
|
||||
|
||||
|
@ -57,6 +72,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
return DeobUtils.Lookup(module, def, errorMessage);
|
||||
}
|
||||
|
||||
public void AddDecrypterInfos(IEnumerable<StringDecrypterInfo> infos) {
|
||||
foreach (var info in infos)
|
||||
stringDecrypterInfos[info] = true;
|
||||
}
|
||||
|
||||
public void Find() {
|
||||
stringDecrypterKey = new byte[1] { 0xFF };
|
||||
foreach (var type in module.Types) {
|
||||
|
@ -64,6 +84,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
stringDecrypterType = type;
|
||||
foreach (var field in type.Fields) {
|
||||
if (field.FullName == "<D234> <D234>::345" || field.FullName == "<ClassD234>/D234 <ClassD234>::345") {
|
||||
keyInitField = field;
|
||||
stringDecrypterKey = field.InitialValue;
|
||||
break;
|
||||
}
|
||||
|
@ -73,6 +94,119 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
|||
}
|
||||
}
|
||||
|
||||
public void Initialize() {
|
||||
if (keyInitField == null)
|
||||
return;
|
||||
|
||||
foreach (var type in module.Types) {
|
||||
var cctor = type.FindStaticConstructor();
|
||||
if (cctor == null)
|
||||
continue;
|
||||
keyArrayField = GetKeyArrayField(cctor, keyInitField);
|
||||
if (keyArrayField != null)
|
||||
break;
|
||||
}
|
||||
if (keyArrayField == null)
|
||||
return;
|
||||
|
||||
foreach (var type in module.GetTypes()) {
|
||||
FieldDef field;
|
||||
var method = FindStringDecrypters(type, keyArrayField, out field);
|
||||
if (method == null)
|
||||
continue;
|
||||
|
||||
stringDecrypterInfos[new StringDecrypterInfo(method, field)] = true;
|
||||
}
|
||||
}
|
||||
|
||||
static FieldDef GetKeyArrayField(MethodDef method, FieldDef keyInitField) {
|
||||
if (method == null || method.Body == null)
|
||||
return null;
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count; i++) {
|
||||
if (instrs[i].OpCode.Code != Code.Ldtoken)
|
||||
continue;
|
||||
|
||||
i++;
|
||||
for (; i < instrs.Count; i++) {
|
||||
var instr = instrs[i];
|
||||
if (instr.OpCode.Code != Code.Stsfld)
|
||||
continue;
|
||||
var field = instr.Operand as FieldDef;
|
||||
if (field == null || !field.IsStatic || field.DeclaringType != method.DeclaringType)
|
||||
continue;
|
||||
if (field.FieldSig.GetFieldType().GetFullName() != "System.Byte[]")
|
||||
continue;
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static MethodDef FindStringDecrypters(TypeDef type, FieldDef keyArrayField, out FieldDef field) {
|
||||
FieldDef foundField = null;
|
||||
foreach (var method in type.Methods) {
|
||||
if (!method.IsAssembly || !method.IsStatic)
|
||||
continue;
|
||||
if (!DotNetUtils.IsMethod(method, "System.String", "(System.String)"))
|
||||
continue;
|
||||
if (!method.HasBody)
|
||||
continue;
|
||||
|
||||
bool accessedArrayField = false;
|
||||
foreach (var instr in method.Body.Instructions) {
|
||||
var f = instr.Operand as FieldDef;
|
||||
accessedArrayField |= f == keyArrayField;
|
||||
if (f == null || f == keyArrayField || f == foundField)
|
||||
continue;
|
||||
if (f.FieldSig.GetFieldType().GetFullName() != "System.Collections.Hashtable" ||
|
||||
foundField != null)
|
||||
goto exit;
|
||||
foundField = f;
|
||||
}
|
||||
if (!accessedArrayField)
|
||||
continue;
|
||||
|
||||
field = foundField;
|
||||
return method;
|
||||
}
|
||||
|
||||
exit: ;
|
||||
field = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Deobfuscate(Blocks blocks) {
|
||||
if (!blocks.Method.IsStaticConstructor)
|
||||
return;
|
||||
|
||||
var decrypterFields = new Dictionary<FieldDef, bool>(stringDecrypterInfos.Count);
|
||||
foreach (var info in stringDecrypterInfos.Keys) {
|
||||
if (info.Field != null)
|
||||
decrypterFields[info.Field] = true;
|
||||
}
|
||||
|
||||
foreach (var block in blocks.MethodBlocks.GetAllBlocks()) {
|
||||
var instrs = block.Instructions;
|
||||
for (int i = instrs.Count - 2; i >= 0; i--) {
|
||||
var newobj = instrs[i];
|
||||
if (newobj.OpCode.Code != Code.Newobj)
|
||||
continue;
|
||||
var ctor = newobj.Operand as IMethod;
|
||||
if (ctor == null || ctor.FullName != "System.Void System.Collections.Hashtable::.ctor()")
|
||||
continue;
|
||||
var stsfld = instrs[i + 1];
|
||||
if (stsfld.OpCode.Code != Code.Stsfld)
|
||||
continue;
|
||||
var field = stsfld.Operand as FieldDef;
|
||||
if (field == null || !decrypterFields.ContainsKey(field))
|
||||
continue;
|
||||
|
||||
block.Remove(i, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Decrypt(string es) {
|
||||
if (stringDecrypterKey == null)
|
||||
throw new ApplicationException("Trying to decrypt strings when stringDecrypterKey is null (could not find it!)");
|
||||
|
|
52
de4dot.code/deobfuscators/Agile_NET/StringDecrypterInfo.cs
Normal file
52
de4dot.code/deobfuscators/Agile_NET/StringDecrypterInfo.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (C) 2011-2014 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 dnlib.DotNet;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Agile_NET {
|
||||
class StringDecrypterInfo {
|
||||
public readonly MethodDef Method;
|
||||
public readonly FieldDef Field;
|
||||
|
||||
public StringDecrypterInfo(MethodDef method)
|
||||
: this(method, null) {
|
||||
}
|
||||
|
||||
public StringDecrypterInfo(MethodDef method, FieldDef field) {
|
||||
this.Method = method;
|
||||
this.Field = field;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
int hash = 0;
|
||||
if (Method != null)
|
||||
hash ^= Method.GetHashCode();
|
||||
if (Field != null)
|
||||
hash ^= Field.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
var other = obj as StringDecrypterInfo;
|
||||
return other != null &&
|
||||
Method == other.Method &&
|
||||
Field == other.Field;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,11 +33,13 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
|||
public MyDeobfuscator(ModuleDefMD module) {
|
||||
cliSecureRtType = new CliSecureRtType(module);
|
||||
cliSecureRtType.Find(null);
|
||||
stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterMethod);
|
||||
stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterInfos);
|
||||
stringDecrypter.Find();
|
||||
cliSecureRtType.FindStringDecrypterMethod();
|
||||
stringDecrypter.Method = cliSecureRtType.StringDecrypterMethod;
|
||||
staticStringInliner.Add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
|
||||
stringDecrypter.AddDecrypterInfos(cliSecureRtType.StringDecrypterInfos);
|
||||
stringDecrypter.Initialize();
|
||||
foreach (var info in stringDecrypter.StringDecrypterInfos)
|
||||
staticStringInliner.Add(info.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
|
||||
}
|
||||
|
||||
void RestoreMethod(Blocks blocks) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user