Update deobfuscator
This commit is contained in:
parent
0b5d4d864c
commit
929d943112
|
@ -43,11 +43,16 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
}
|
||||
|
||||
public void find() {
|
||||
var mainMethod = module.EntryPoint;
|
||||
if (mainMethod == null)
|
||||
if (find(module.EntryPoint))
|
||||
return;
|
||||
if (find(DotNetUtils.getMethod(DotNetUtils.getModuleType(module), ".cctor")))
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var info in DotNetUtils.getCalledMethods(module, mainMethod)) {
|
||||
bool find(MethodDefinition methodToCheck) {
|
||||
if (methodToCheck == null)
|
||||
return false;
|
||||
foreach (var info in DotNetUtils.getCalledMethods(module, methodToCheck)) {
|
||||
var type = info.Item1;
|
||||
var method = info.Item2;
|
||||
|
||||
|
@ -58,13 +63,15 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
if (DotNetUtils.getPInvokeMethod(type, "kernel32", "GetProcAddress") == null)
|
||||
continue;
|
||||
deobfuscate(method);
|
||||
if (!containsString(method, "debugger was detected"))
|
||||
if (!containsString(method, "debugger is active"))
|
||||
continue;
|
||||
|
||||
antiDebuggerType = type;
|
||||
antiDebuggerMethod = method;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void deobfuscate(MethodDefinition method) {
|
||||
|
|
|
@ -184,7 +184,9 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
addModuleCctorInitCallToBeRemoved(resourceResolver.Method);
|
||||
addModuleCctorInitCallToBeRemoved(assemblyResolver.Method);
|
||||
addCallToBeRemoved(module.EntryPoint, tamperDetection.Method);
|
||||
addModuleCctorInitCallToBeRemoved(tamperDetection.Method);
|
||||
addCallToBeRemoved(module.EntryPoint, antiDebugger.Method);
|
||||
addModuleCctorInitCallToBeRemoved(antiDebugger.Method);
|
||||
addTypeToBeRemoved(resourceResolver.Type, "Resource resolver type");
|
||||
addTypeToBeRemoved(assemblyResolver.Type, "Assembly resolver type");
|
||||
addTypeToBeRemoved(tamperDetection.Type, "Tamper detection type");
|
||||
|
|
|
@ -138,7 +138,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
createMethod = m;
|
||||
continue;
|
||||
}
|
||||
return null;
|
||||
continue;
|
||||
}
|
||||
if (createMethod == null || !createMethod.HasBody)
|
||||
return null;
|
||||
|
|
|
@ -22,16 +22,118 @@ using System.IO;
|
|||
using System.IO.Compression;
|
||||
using System.Security.Cryptography;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
||||
class ResourceDecrypter {
|
||||
const int BUFLEN = 0x8000;
|
||||
ModuleDefinition module;
|
||||
DecrypterVersion decrypterVersion = DecrypterVersion.V1;
|
||||
TypeDefinition resourceDecrypterType;
|
||||
byte[] buffer1 = new byte[BUFLEN];
|
||||
byte[] buffer2 = new byte[BUFLEN];
|
||||
byte desEncryptedFlag;
|
||||
byte deflatedFlag;
|
||||
byte bitwiseNotEncryptedFlag;
|
||||
|
||||
enum DecrypterVersion {
|
||||
V1,
|
||||
V2,
|
||||
}
|
||||
|
||||
public ResourceDecrypter(ModuleDefinition module) {
|
||||
this.module = module;
|
||||
find();
|
||||
}
|
||||
|
||||
void find() {
|
||||
var requiredTypes = new string[] {
|
||||
"System.IO.MemoryStream",
|
||||
"System.Object",
|
||||
"System.Int32",
|
||||
};
|
||||
|
||||
resourceDecrypterType = null;
|
||||
foreach (var type in module.Types) {
|
||||
if (type.Fields.Count != 5)
|
||||
continue;
|
||||
if (!new FieldTypes(type).exactly(requiredTypes))
|
||||
continue;
|
||||
|
||||
var cctor = DotNetUtils.getMethod(type, ".cctor");
|
||||
if (cctor == null)
|
||||
continue;
|
||||
|
||||
if (!checkCctor(cctor))
|
||||
continue;
|
||||
|
||||
resourceDecrypterType = type;
|
||||
break;
|
||||
}
|
||||
|
||||
initializeVersion();
|
||||
}
|
||||
|
||||
bool checkCctor(MethodDefinition cctor) {
|
||||
if (cctor.Body == null)
|
||||
return false;
|
||||
int stsfldCount = 0;
|
||||
foreach (var instr in cctor.Body.Instructions) {
|
||||
if (instr.OpCode.Code == Code.Stsfld) {
|
||||
var field = instr.Operand as FieldReference;
|
||||
if (!MemberReferenceHelper.compareTypes(cctor.DeclaringType, field.DeclaringType))
|
||||
return false;
|
||||
stsfldCount++;
|
||||
}
|
||||
}
|
||||
return stsfldCount == cctor.DeclaringType.Fields.Count;
|
||||
}
|
||||
|
||||
void initializeVersion() {
|
||||
decrypterVersion = DecrypterVersion.V1;
|
||||
if (resourceDecrypterType != null) {
|
||||
foreach (var method in resourceDecrypterType.Methods) {
|
||||
if (isPublicKeyTokenMethod(method)) {
|
||||
decrypterVersion = DecrypterVersion.V2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (decrypterVersion) {
|
||||
case DecrypterVersion.V1:
|
||||
desEncryptedFlag = 1;
|
||||
deflatedFlag = 2;
|
||||
bitwiseNotEncryptedFlag = 4;
|
||||
break;
|
||||
|
||||
case DecrypterVersion.V2:
|
||||
desEncryptedFlag = 2;
|
||||
deflatedFlag = 8;
|
||||
//TODO: bitwiseNotEncryptedFlag = ???;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ApplicationException("Invalid version");
|
||||
}
|
||||
}
|
||||
|
||||
bool isPublicKeyTokenMethod(MethodDefinition method) {
|
||||
if (!method.IsStatic)
|
||||
return false;
|
||||
if (method.Body == null)
|
||||
return false;
|
||||
if (method.Body.ExceptionHandlers.Count < 1)
|
||||
return false;
|
||||
if (!DotNetUtils.isMethod(method, "System.Byte[]", "(System.Reflection.Assembly)"))
|
||||
return false;
|
||||
|
||||
foreach (var s in DotNetUtils.getCodeStrings(method)) {
|
||||
if (s.ToLowerInvariant() == "publickeytoken=")
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public byte[] decrypt(Stream resourceStream) {
|
||||
|
@ -40,7 +142,11 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
int sourceStreamOffset = 1;
|
||||
bool didSomething = false;
|
||||
|
||||
if ((flags & 1) != 0) {
|
||||
byte allFlags = (byte)(desEncryptedFlag | deflatedFlag | bitwiseNotEncryptedFlag);
|
||||
if ((flags & ~allFlags) != 0)
|
||||
Log.w("Found unknown resource encryption flags: 0x{0:X2}", flags);
|
||||
|
||||
if ((flags & desEncryptedFlag) != 0) {
|
||||
var memStream = new MemoryStream((int)resourceStream.Length);
|
||||
using (var provider = new DESCryptoServiceProvider()) {
|
||||
var iv = new byte[8];
|
||||
|
@ -65,7 +171,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
didSomething = true;
|
||||
}
|
||||
|
||||
if ((flags & 2) != 0) {
|
||||
if ((flags & deflatedFlag) != 0) {
|
||||
var memStream = new MemoryStream((int)resourceStream.Length);
|
||||
sourceStream.Position = sourceStreamOffset;
|
||||
using (var inflater = new DeflateStream(sourceStream, CompressionMode.Decompress)) {
|
||||
|
@ -82,7 +188,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
didSomething = true;
|
||||
}
|
||||
|
||||
if ((flags & 4) != 0) {
|
||||
if ((flags & bitwiseNotEncryptedFlag) != 0) {
|
||||
var memStream = new MemoryStream((int)resourceStream.Length);
|
||||
sourceStream.Position = sourceStreamOffset;
|
||||
for (int i = sourceStreamOffset; i < sourceStream.Length; i++)
|
||||
|
|
|
@ -28,8 +28,14 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
ResourceDecrypter resourceDecrypter;
|
||||
TypeDefinition resolverType;
|
||||
MethodDefinition resolverMethod;
|
||||
ResolverVersion resolverVersion = ResolverVersion.V1;
|
||||
bool mergedIt = false;
|
||||
|
||||
enum ResolverVersion {
|
||||
V1,
|
||||
V2,
|
||||
}
|
||||
|
||||
public TypeDefinition Type {
|
||||
get { return resolverType; }
|
||||
}
|
||||
|
@ -63,7 +69,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
if (mergedIt)
|
||||
return null;
|
||||
|
||||
var resource = DotNetUtils.getResource(module, module.Assembly.Name.Name) as EmbeddedResource;
|
||||
var resource = DotNetUtils.getResource(module, getResourceName()) as EmbeddedResource;
|
||||
if (resource == null)
|
||||
return null;
|
||||
|
||||
|
@ -72,6 +78,14 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
return resource;
|
||||
}
|
||||
|
||||
string getResourceName() {
|
||||
switch (resolverVersion) {
|
||||
case ResolverVersion.V1: return module.Assembly.Name.Name;
|
||||
case ResolverVersion.V2: return string.Format("{0}{0}{0}", module.Assembly.Name.Name);
|
||||
default: throw new ApplicationException("Unknown version");
|
||||
}
|
||||
}
|
||||
|
||||
bool checkType(TypeDefinition type, MethodDefinition initMethod) {
|
||||
if (!initMethod.HasBody)
|
||||
return false;
|
||||
|
@ -79,6 +93,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
return false;
|
||||
|
||||
var instructions = initMethod.Body.Instructions;
|
||||
int foundCount = 0;
|
||||
for (int i = 0; i < instructions.Count; i++) {
|
||||
var instrs = DotNetUtils.getInstructions(instructions, i, OpCodes.Ldnull, OpCodes.Ldftn, OpCodes.Newobj);
|
||||
if (instrs == null)
|
||||
|
@ -96,12 +111,25 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
if (methodRef == null || methodRef.FullName != "System.Void System.ResolveEventHandler::.ctor(System.Object,System.IntPtr)")
|
||||
continue;
|
||||
|
||||
resolverType = type;
|
||||
resolverMethod = initMethod;
|
||||
return true;
|
||||
foundCount++;
|
||||
}
|
||||
if (foundCount == 0)
|
||||
return false;
|
||||
|
||||
switch (foundCount) {
|
||||
case 1:
|
||||
resolverVersion = ResolverVersion.V1;
|
||||
break;
|
||||
case 2:
|
||||
resolverVersion = ResolverVersion.V2;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
resolverType = type;
|
||||
resolverMethod = initMethod;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using Mono.Cecil;
|
||||
using de4dot.blocks;
|
||||
|
@ -63,7 +64,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
if (decryptedData != null)
|
||||
return;
|
||||
|
||||
var resourceName = module.Assembly.Name.Name + module.Assembly.Name.Name;
|
||||
var resourceName = getResourceName();
|
||||
stringResource = DotNetUtils.getResource(module, resourceName) as EmbeddedResource;
|
||||
if (stringResource == null)
|
||||
return;
|
||||
|
@ -72,6 +73,24 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
decryptedData = resourceDecrypter.decrypt(stringResource.GetResourceStream());
|
||||
}
|
||||
|
||||
string getResourceName() {
|
||||
var defaultName = module.Assembly.Name.Name + module.Assembly.Name.Name;
|
||||
|
||||
var cctor = DotNetUtils.getMethod(stringDecrypterType, ".cctor");
|
||||
if (cctor == null)
|
||||
return defaultName;
|
||||
|
||||
foreach (var s in DotNetUtils.getCodeStrings(cctor)) {
|
||||
try {
|
||||
return Encoding.UTF8.GetString(Convert.FromBase64String(s));
|
||||
}
|
||||
catch {
|
||||
}
|
||||
}
|
||||
|
||||
return defaultName;
|
||||
}
|
||||
|
||||
public string decrypt(int index) {
|
||||
int len;
|
||||
byte b = decryptedData[index++];
|
||||
|
|
|
@ -43,25 +43,35 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
|
|||
}
|
||||
|
||||
public void find() {
|
||||
var mainMethod = module.EntryPoint;
|
||||
if (mainMethod == null)
|
||||
if (find(module.EntryPoint))
|
||||
return;
|
||||
if (find(DotNetUtils.getMethod(DotNetUtils.getModuleType(module), ".cctor")))
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var info in DotNetUtils.getCalledMethods(module, mainMethod)) {
|
||||
bool find(MethodDefinition methodToCheck) {
|
||||
if (methodToCheck == null)
|
||||
return false;
|
||||
|
||||
foreach (var info in DotNetUtils.getCalledMethods(module, methodToCheck)) {
|
||||
var type = info.Item1;
|
||||
var method = info.Item2;
|
||||
|
||||
if (type.HasProperties || type.HasEvents)
|
||||
continue;
|
||||
if (!method.IsStatic || !DotNetUtils.isMethod(method, "System.Void", "()"))
|
||||
continue;
|
||||
if (type.Methods.Count != 3)
|
||||
if (type.Methods.Count < 3 || type.Methods.Count > 6)
|
||||
continue;
|
||||
if (DotNetUtils.getPInvokeMethod(type, "mscoree", "StrongNameSignatureVerificationEx") == null)
|
||||
continue;
|
||||
|
||||
tamperType = type;
|
||||
tamperMethod = method;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user