Add SN string decrypter
This commit is contained in:
parent
36b4806858
commit
b3f17a27a3
|
@ -116,7 +116,6 @@
|
|||
<Compile Include="deobfuscators\dotNET_Reactor\v4\MethodsDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\dotNET_Reactor\v4\NativeFileDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\dotNET_Reactor\v4\NativeImageUnpacker.cs" />
|
||||
<Compile Include="deobfuscators\dotNET_Reactor\QuickLZ.cs" />
|
||||
<Compile Include="deobfuscators\dotNET_Reactor\v4\ResourceResolver.cs" />
|
||||
<Compile Include="deobfuscators\dotNET_Reactor\v4\StringDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\dotNET_Reactor\v4\AntiStrongName.cs" />
|
||||
|
@ -142,10 +141,14 @@
|
|||
<Compile Include="deobfuscators\InlinedMethodsFinder.cs" />
|
||||
<Compile Include="deobfuscators\ISimpleDeobfuscator.cs" />
|
||||
<Compile Include="deobfuscators\MethodCollection.cs" />
|
||||
<Compile Include="deobfuscators\QuickLZ.cs" />
|
||||
<Compile Include="deobfuscators\RandomNameChecker.cs" />
|
||||
<Compile Include="deobfuscators\Skater_NET\Deobfuscator.cs" />
|
||||
<Compile Include="deobfuscators\Skater_NET\EnumClassFinder.cs" />
|
||||
<Compile Include="deobfuscators\Skater_NET\StringDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\Spices_Net\Deobfuscator.cs" />
|
||||
<Compile Include="deobfuscators\Spices_Net\QclzDecompressor.cs" />
|
||||
<Compile Include="deobfuscators\Spices_Net\StringDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\StringCounts.cs" />
|
||||
<Compile Include="deobfuscators\Operations.cs" />
|
||||
<Compile Include="deobfuscators\ProxyDelegateFinderBase.cs" />
|
||||
|
|
|
@ -11,44 +11,21 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace de4dot.code.deobfuscators.dotNET_Reactor {
|
||||
static class QuickLZ {
|
||||
static int sig = 0x5A4C4351; // "QCLZ"
|
||||
|
||||
public static bool isCompressed(byte[] data) {
|
||||
if (data.Length < 4)
|
||||
return false;
|
||||
return BitConverter.ToInt32(data, 0) == sig;
|
||||
}
|
||||
|
||||
static uint read32(byte[] data, int index) {
|
||||
namespace de4dot.code.deobfuscators {
|
||||
class QuickLZBase {
|
||||
protected static uint read32(byte[] data, int index) {
|
||||
return BitConverter.ToUInt32(data, index);
|
||||
}
|
||||
|
||||
// Can't use Array.Copy() when data overlaps so here's one that works
|
||||
static void copy(byte[] src, int srcIndex, byte[] dst, int dstIndex, int size) {
|
||||
protected static void copy(byte[] src, int srcIndex, byte[] dst, int dstIndex, int size) {
|
||||
for (int i = 0; i < size; i++)
|
||||
dst[dstIndex++] = src[srcIndex++];
|
||||
}
|
||||
|
||||
static int[] indexInc = new int[] { 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
|
||||
public static byte[] decompress(byte[] inData) {
|
||||
int mode = BitConverter.ToInt32(inData, 4);
|
||||
int compressedLength = BitConverter.ToInt32(inData, 8);
|
||||
int decompressedLength = BitConverter.ToInt32(inData, 12);
|
||||
bool isDataCompressed = BitConverter.ToInt32(inData, 16) == 1;
|
||||
int headerLength = 32;
|
||||
if (BitConverter.ToInt32(inData, 0) != sig || BitConverter.ToInt32(inData, compressedLength - 4) != sig)
|
||||
throw new ApplicationException("No QCLZ sig");
|
||||
|
||||
byte[] outData = new byte[decompressedLength];
|
||||
|
||||
if (!isDataCompressed) {
|
||||
copy(inData, headerLength, outData, 0, decompressedLength);
|
||||
return outData;
|
||||
}
|
||||
|
||||
int inIndex = headerLength;
|
||||
public static void decompress(byte[] inData, int inIndex, byte[] outData) {
|
||||
int decompressedLength = outData.Length;
|
||||
int outIndex = 0;
|
||||
uint val1 = 1;
|
||||
uint count;
|
||||
|
@ -89,18 +66,30 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor {
|
|||
inIndex += 3;
|
||||
}
|
||||
else if ((val2 & 8) == 0) {
|
||||
size = (int)((val2 >> 4) & 0x07FF) + 3;
|
||||
count = val2 >> 15;
|
||||
if (count != 0) {
|
||||
size = (int)((val2 >> 4) & 0x07FF) + 3;
|
||||
inIndex += 4;
|
||||
}
|
||||
else {
|
||||
size = (int)read32(inData, inIndex + 4);
|
||||
count = read32(inData, inIndex + 8);
|
||||
inIndex += 12;
|
||||
}
|
||||
copy(outData, (int)(outIndex - count), outData, outIndex, size);
|
||||
outIndex += size;
|
||||
inIndex += 4;
|
||||
}
|
||||
else {
|
||||
byte b = (byte)(val2 >> 16);
|
||||
size = (int)(val2 >> 4) & 0x0FFF;
|
||||
if (size == 0) {
|
||||
size = (int)read32(inData, inIndex + 3);
|
||||
inIndex += 7;
|
||||
}
|
||||
else
|
||||
inIndex += 3;
|
||||
for (int i = 0; i < size; i++)
|
||||
outData[outIndex++] = b;
|
||||
inIndex += 3;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -121,7 +110,39 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor {
|
|||
outData[outIndex++] = inData[inIndex++];
|
||||
val1 >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class QuickLZ : QuickLZBase {
|
||||
static int DEFAULT_QCLZ_SIG = 0x5A4C4351; // "QCLZ"
|
||||
|
||||
public static bool isCompressed(byte[] data) {
|
||||
if (data.Length < 4)
|
||||
return false;
|
||||
return BitConverter.ToInt32(data, 0) == DEFAULT_QCLZ_SIG;
|
||||
}
|
||||
|
||||
public static byte[] decompress(byte[] inData) {
|
||||
return decompress(inData, DEFAULT_QCLZ_SIG);
|
||||
}
|
||||
|
||||
public static byte[] decompress(byte[] inData, int sig) {
|
||||
int mode = BitConverter.ToInt32(inData, 4);
|
||||
int compressedLength = BitConverter.ToInt32(inData, 8);
|
||||
int decompressedLength = BitConverter.ToInt32(inData, 12);
|
||||
bool isDataCompressed = BitConverter.ToInt32(inData, 16) == 1;
|
||||
int headerLength = 32;
|
||||
if (BitConverter.ToInt32(inData, 0) != sig || BitConverter.ToInt32(inData, compressedLength - 4) != sig)
|
||||
throw new ApplicationException("No QCLZ sig");
|
||||
|
||||
byte[] outData = new byte[decompressedLength];
|
||||
|
||||
if (!isDataCompressed) {
|
||||
copy(inData, headerLength, outData, 0, decompressedLength);
|
||||
return outData;
|
||||
}
|
||||
|
||||
decompress(inData, headerLength, outData);
|
||||
return outData;
|
||||
}
|
||||
}
|
137
de4dot.code/deobfuscators/Spices_Net/Deobfuscator.cs
Normal file
137
de4dot.code/deobfuscators/Spices_Net/Deobfuscator.cs
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
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.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using de4dot.blocks.cflow;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Spices_Net {
|
||||
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
||||
public const string THE_NAME = "Spices.Net";
|
||||
public const string THE_TYPE = "sn";
|
||||
|
||||
public DeobfuscatorInfo()
|
||||
: base() {
|
||||
}
|
||||
|
||||
public override string Name {
|
||||
get { return THE_NAME; }
|
||||
}
|
||||
|
||||
public override string Type {
|
||||
get { return THE_TYPE; }
|
||||
}
|
||||
|
||||
public override IDeobfuscator createDeobfuscator() {
|
||||
return new Deobfuscator(new Deobfuscator.Options {
|
||||
ValidNameRegex = validNameRegex.get(),
|
||||
});
|
||||
}
|
||||
|
||||
protected override IEnumerable<Option> getOptionsInternal() {
|
||||
return new List<Option>() {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Deobfuscator : DeobfuscatorBase {
|
||||
Options options;
|
||||
bool foundSpicesAttribute = false;
|
||||
bool startedDeobfuscating = false;
|
||||
|
||||
StringDecrypter stringDecrypter;
|
||||
|
||||
internal class Options : OptionsBase {
|
||||
}
|
||||
|
||||
public override string Type {
|
||||
get { return DeobfuscatorInfo.THE_TYPE; }
|
||||
}
|
||||
|
||||
public override string TypeLong {
|
||||
get { return DeobfuscatorInfo.THE_NAME; }
|
||||
}
|
||||
|
||||
public override string Name {
|
||||
get { return DeobfuscatorInfo.THE_NAME; }
|
||||
}
|
||||
|
||||
public Deobfuscator(Options options)
|
||||
: base(options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
protected override int detectInternal() {
|
||||
int val = 0;
|
||||
|
||||
int sum = toInt32(stringDecrypter.Detected) +
|
||||
toInt32(foundSpicesAttribute);
|
||||
if (sum > 0)
|
||||
val += 100 + 10 * (sum - 1);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
protected override void scanForObfuscator() {
|
||||
stringDecrypter = new StringDecrypter(module);
|
||||
stringDecrypter.find();
|
||||
findSpicesAttributes();
|
||||
}
|
||||
|
||||
void findSpicesAttributes() {
|
||||
foreach (var type in module.Types) {
|
||||
if (type.FullName == "NineRays.Decompiler.NotDecompile") {
|
||||
addAttributeToBeRemoved(type, "Obfuscator attribute");
|
||||
foundSpicesAttribute = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void deobfuscateBegin() {
|
||||
base.deobfuscateBegin();
|
||||
|
||||
stringDecrypter.initialize();
|
||||
foreach (var info in stringDecrypter.DecrypterInfos) {
|
||||
staticStringInliner.add(info.method, (method2, args) => {
|
||||
return stringDecrypter.decrypt(method2);
|
||||
});
|
||||
}
|
||||
DeobfuscatedFile.stringDecryptersAdded();
|
||||
|
||||
startedDeobfuscating = true;
|
||||
}
|
||||
|
||||
public override void deobfuscateEnd() {
|
||||
if (Operations.DecryptStrings != OpDecryptString.None) {
|
||||
addTypeToBeRemoved(stringDecrypter.Type, "String decrypter type");
|
||||
stringDecrypter.cleanUp();
|
||||
}
|
||||
|
||||
base.deobfuscateEnd();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> getStringDecrypterMethods() {
|
||||
var list = new List<string>();
|
||||
foreach (var info in stringDecrypter.DecrypterInfos)
|
||||
list.Add(info.method.MetadataToken.ToInt32().ToString("X8"));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
50
de4dot.code/deobfuscators/Spices_Net/QclzDecompressor.cs
Normal file
50
de4dot.code/deobfuscators/Spices_Net/QclzDecompressor.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
namespace de4dot.code.deobfuscators.Spices_Net {
|
||||
class QclzDecompressor : QuickLZBase {
|
||||
static int SPICES_QCLZ_SIG = 0x3952534E; // "9RSN"
|
||||
|
||||
public static byte[] decompress(byte[] data) {
|
||||
if (read32(data, 0) == SPICES_QCLZ_SIG)
|
||||
return QuickLZ.decompress(data, SPICES_QCLZ_SIG);
|
||||
|
||||
int headerLength, decompressedLength, compressedLength;
|
||||
if ((data[0] & 2) != 0) {
|
||||
headerLength = 9;
|
||||
compressedLength = (int)read32(data, 1);
|
||||
decompressedLength = (int)read32(data, 5);
|
||||
}
|
||||
else {
|
||||
headerLength = 3;
|
||||
compressedLength = data[1];
|
||||
decompressedLength = data[2];
|
||||
}
|
||||
|
||||
bool isCompressed = (data[0] & 1) != 0;
|
||||
byte[] decompressed = new byte[decompressedLength];
|
||||
if (isCompressed)
|
||||
decompress(data, headerLength, decompressed);
|
||||
else
|
||||
copy(data, headerLength, decompressed, 0, decompressed.Length);
|
||||
|
||||
return decompressed;
|
||||
}
|
||||
}
|
||||
}
|
326
de4dot.code/deobfuscators/Spices_Net/StringDecrypter.cs
Normal file
326
de4dot.code/deobfuscators/Spices_Net/StringDecrypter.cs
Normal file
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
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.Text;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using Mono.Cecil.Metadata;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Spices_Net {
|
||||
class StringDecrypter {
|
||||
ModuleDefinition module;
|
||||
TypeDefinition decrypterType;
|
||||
FieldDefinition encryptedDataField;
|
||||
StringDataFlags stringDataFlags;
|
||||
MethodDefinitionAndDeclaringTypeDict<DecrypterInfo> methodToInfo = new MethodDefinitionAndDeclaringTypeDict<DecrypterInfo>();
|
||||
byte[] decryptedData;
|
||||
byte[] key;
|
||||
byte[] iv;
|
||||
|
||||
[Flags]
|
||||
enum StringDataFlags {
|
||||
Compressed = 0x1,
|
||||
Encrypted1 = 0x2,
|
||||
Encrypted2 = 0x4,
|
||||
Encrypted3DES = 0x8,
|
||||
}
|
||||
|
||||
public class DecrypterInfo {
|
||||
public MethodDefinition method;
|
||||
public int offset;
|
||||
public int length;
|
||||
|
||||
public DecrypterInfo(MethodDefinition method, int offset, int length) {
|
||||
this.method = method;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
}
|
||||
}
|
||||
|
||||
public TypeDefinition Type {
|
||||
get { return decrypterType; }
|
||||
}
|
||||
|
||||
public bool Detected {
|
||||
get { return decrypterType != null; }
|
||||
}
|
||||
|
||||
public IEnumerable<DecrypterInfo> DecrypterInfos {
|
||||
get { return methodToInfo.getValues(); }
|
||||
}
|
||||
|
||||
public StringDecrypter(ModuleDefinition module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public void find() {
|
||||
foreach (var type in module.Types) {
|
||||
if (type.HasNestedTypes || type.HasInterfaces)
|
||||
continue;
|
||||
if (type.HasEvents || type.HasProperties)
|
||||
continue;
|
||||
if (type.Fields.Count != 2)
|
||||
continue;
|
||||
if ((type.Attributes & ~TypeAttributes.Sealed) != 0)
|
||||
continue;
|
||||
if (type.BaseType == null || type.BaseType.FullName != "System.Object")
|
||||
continue;
|
||||
if (hasInstanceMethods(type))
|
||||
continue;
|
||||
var cctor = DotNetUtils.getMethod(type, ".cctor");
|
||||
if (cctor == null)
|
||||
continue;
|
||||
|
||||
FieldDefinition encryptedDataFieldTmp;
|
||||
StringDataFlags stringDataFlagsTmp;
|
||||
if (!checkCctor(cctor, out encryptedDataFieldTmp, out stringDataFlagsTmp))
|
||||
continue;
|
||||
|
||||
if (!initializeDecrypterInfos(type))
|
||||
continue;
|
||||
|
||||
encryptedDataField = encryptedDataFieldTmp;
|
||||
stringDataFlags = stringDataFlagsTmp;
|
||||
decrypterType = type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static bool hasInstanceMethods(TypeDefinition type) {
|
||||
foreach (var method in type.Methods) {
|
||||
if (!method.IsStatic)
|
||||
return true;
|
||||
if (method.PInvokeInfo != null)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkCctor(MethodDefinition cctor, out FieldDefinition compressedDataField, out StringDataFlags flags) {
|
||||
flags = 0;
|
||||
var instructions = cctor.Body.Instructions;
|
||||
for (int i = 0; i < instructions.Count; i++) {
|
||||
var ldci4 = instructions[i];
|
||||
if (!DotNetUtils.isLdcI4(ldci4))
|
||||
continue;
|
||||
|
||||
var instrs = DotNetUtils.getInstructions(instructions, i + 1, OpCodes.Newarr, OpCodes.Dup, OpCodes.Ldtoken, OpCodes.Call);
|
||||
if (instrs == null)
|
||||
continue;
|
||||
|
||||
var newarr = instrs[0];
|
||||
if (newarr.Operand.ToString() != "System.Byte")
|
||||
continue;
|
||||
|
||||
var field = instrs[2].Operand as FieldDefinition;
|
||||
if (field == null || field.InitialValue == null || field.InitialValue.Length == 0)
|
||||
continue;
|
||||
|
||||
int index = i + 1 + instrs.Count;
|
||||
if (index < instructions.Count && instructions[index].OpCode.Code == Code.Call)
|
||||
flags = getStringDataFlags(instructions[index].Operand as MethodDefinition);
|
||||
|
||||
compressedDataField = field;
|
||||
return true;
|
||||
}
|
||||
|
||||
compressedDataField = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
StringDataFlags getStringDataFlags(MethodDefinition method) {
|
||||
if (method == null || method.Body == null)
|
||||
return 0;
|
||||
if (method.Parameters.Count != 1)
|
||||
return 0;
|
||||
if (!checkClass(method.Parameters[0].ParameterType, "System.Byte[]"))
|
||||
return 0;
|
||||
if (!checkClass(method.MethodReturnType.ReturnType, "System.Byte[]"))
|
||||
return 0;
|
||||
|
||||
StringDataFlags flags = 0;
|
||||
|
||||
if (hasInstruction(method, Code.Not))
|
||||
flags |= StringDataFlags.Encrypted2;
|
||||
else if (hasInstruction(method, Code.Xor))
|
||||
flags |= StringDataFlags.Encrypted1;
|
||||
else if (check3DesCreator(method))
|
||||
flags |= StringDataFlags.Encrypted3DES;
|
||||
if (callsDecompressor(method))
|
||||
flags |= StringDataFlags.Compressed;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
bool check3DesCreator(MethodDefinition method) {
|
||||
foreach (var instr in method.Body.Instructions) {
|
||||
if (instr.OpCode.Code != Code.Call)
|
||||
continue;
|
||||
var calledMethod = instr.Operand as MethodDefinition;
|
||||
if (calledMethod == null)
|
||||
continue;
|
||||
if (calledMethod.MethodReturnType.ReturnType.EType == ElementType.Void)
|
||||
continue;
|
||||
if (calledMethod.Parameters.Count != 0)
|
||||
continue;
|
||||
if (!get3DesKeyIv(calledMethod, ref key, ref iv))
|
||||
continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get3DesKeyIv(MethodDefinition method, ref byte[] key, ref byte[] iv) {
|
||||
if (!new LocalTypes(method).exists("System.Security.Cryptography.TripleDESCryptoServiceProvider"))
|
||||
return false;
|
||||
|
||||
var instrs = method.Body.Instructions;
|
||||
var arrays = ArrayFinder.getArrays(method, module.TypeSystem.Byte);
|
||||
if (arrays.Count != 1 && arrays.Count != 2)
|
||||
return false;
|
||||
|
||||
key = arrays[0];
|
||||
if (arrays.Count == 1)
|
||||
iv = module.Assembly.Name.PublicKeyToken;
|
||||
else
|
||||
iv = arrays[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool callsDecompressor(MethodDefinition method) {
|
||||
foreach (var instr in method.Body.Instructions) {
|
||||
if (instr.OpCode.Code != Code.Call)
|
||||
continue;
|
||||
var called = instr.Operand as MethodDefinition;
|
||||
if (called == null)
|
||||
continue;
|
||||
if (called.MethodReturnType.ReturnType.EType != ElementType.I4)
|
||||
continue;
|
||||
var parameters = called.Parameters;
|
||||
if (parameters.Count != 4)
|
||||
continue;
|
||||
if (!checkClass(parameters[0].ParameterType, "System.Byte[]"))
|
||||
continue;
|
||||
if (parameters[1].ParameterType.EType != ElementType.I4)
|
||||
continue;
|
||||
if (!checkClass(parameters[2].ParameterType, "System.Byte[]"))
|
||||
continue;
|
||||
if (parameters[3].ParameterType.EType != ElementType.I4)
|
||||
continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hasInstruction(MethodDefinition method, Code code) {
|
||||
foreach (var instr in method.Body.Instructions) {
|
||||
if (instr.OpCode.Code == code)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool checkClass(TypeReference type, string fullName) {
|
||||
return type != null && (type.EType == ElementType.Object || type.FullName == fullName);
|
||||
}
|
||||
|
||||
static bool isStringType(TypeReference type) {
|
||||
return type != null && (type.EType == ElementType.Object || type.EType == ElementType.String);
|
||||
}
|
||||
|
||||
bool initializeDecrypterInfos(TypeDefinition type) {
|
||||
foreach (var method in type.Methods) {
|
||||
if (!method.IsStatic || method.Body == null)
|
||||
continue;
|
||||
if (method.Parameters.Count != 0)
|
||||
continue;
|
||||
if (!isStringType(method.MethodReturnType.ReturnType))
|
||||
continue;
|
||||
|
||||
var info = createInfo(method);
|
||||
if (info == null)
|
||||
continue;
|
||||
|
||||
methodToInfo.add(method, info);
|
||||
}
|
||||
|
||||
return methodToInfo.Count != 0;
|
||||
}
|
||||
|
||||
DecrypterInfo createInfo(MethodDefinition method) {
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 1; i++) {
|
||||
var ldci4_1 = instrs[i];
|
||||
var ldci4_2 = instrs[i + 1];
|
||||
if (!DotNetUtils.isLdcI4(ldci4_1) || !DotNetUtils.isLdcI4(ldci4_2))
|
||||
continue;
|
||||
|
||||
int offset = DotNetUtils.getLdcI4Value(ldci4_1);
|
||||
int length = DotNetUtils.getLdcI4Value(ldci4_2);
|
||||
return new DecrypterInfo(method, offset, length);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
if (decrypterType == null)
|
||||
return;
|
||||
|
||||
decryptedData = new byte[encryptedDataField.InitialValue.Length];
|
||||
Array.Copy(encryptedDataField.InitialValue, 0, decryptedData, 0, decryptedData.Length);
|
||||
|
||||
if ((stringDataFlags & StringDataFlags.Encrypted1) != 0) {
|
||||
for (int i = 0; i < decryptedData.Length; i++)
|
||||
decryptedData[i] ^= (byte)i;
|
||||
}
|
||||
|
||||
if ((stringDataFlags & StringDataFlags.Encrypted2) != 0) {
|
||||
var k = module.Assembly.Name.PublicKey;
|
||||
int mask = (byte)(~k.Length);
|
||||
for (int i = 0; i < decryptedData.Length; i++)
|
||||
decryptedData[i] ^= k[i & mask];
|
||||
}
|
||||
|
||||
if ((stringDataFlags & StringDataFlags.Encrypted3DES) != 0)
|
||||
decryptedData = DeobUtils.des3Decrypt(decryptedData, key, iv);
|
||||
|
||||
if ((stringDataFlags & StringDataFlags.Compressed) != 0)
|
||||
decryptedData = QclzDecompressor.decompress(decryptedData);
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
if (decrypterType == null)
|
||||
return;
|
||||
|
||||
encryptedDataField.InitialValue = new byte[1];
|
||||
encryptedDataField.FieldType = module.TypeSystem.Byte;
|
||||
}
|
||||
|
||||
public string decrypt(MethodDefinition method) {
|
||||
var info = methodToInfo.find(method);
|
||||
return Encoding.Unicode.GetString(decryptedData, info.offset, info.length);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -109,8 +109,6 @@ namespace de4dot.code.deobfuscators.Unknown {
|
|||
return "Manco .NET Obfuscator";
|
||||
if (Regex.IsMatch(type.FullName, @"^EMyPID_\d+_$"))
|
||||
return "BitHelmet Obfuscator";
|
||||
if (type.FullName == "NineRays.Decompiler.NotDecompile")
|
||||
return "Spices.Net Obfuscator";
|
||||
if (type.FullName == "YanoAttribute")
|
||||
return "Yano Obfuscator";
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace de4dot.cui {
|
|||
new de4dot.code.deobfuscators.Goliath_NET.DeobfuscatorInfo(),
|
||||
new de4dot.code.deobfuscators.Skater_NET.DeobfuscatorInfo(),
|
||||
new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(),
|
||||
new de4dot.code.deobfuscators.Spices_Net.DeobfuscatorInfo(),
|
||||
new de4dot.code.deobfuscators.Xenocode.DeobfuscatorInfo(),
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user