Support Confuser 1.8 r75367 constants encrypter

This commit is contained in:
de4dot 2012-08-08 14:30:46 +02:00
parent 21deab4ee7
commit 09e20597f8

View File

@ -40,13 +40,16 @@ namespace de4dot.code.deobfuscators.Confuser {
MethodDefinition nativeMethod; MethodDefinition nativeMethod;
EmbeddedResource resource; EmbeddedResource resource;
byte[] constants; byte[] constants;
ConstType constType = ConstType.Unknown; ConfuserVersion version = ConfuserVersion.Unknown;
enum ConstType { public enum ConfuserVersion {
Unknown, Unknown,
Normal, // type is not dynamic and native v18_r75367_normal,
Dynamic, // type="dynamic" v18_r75367_dynamic,
Native, // type="native" v18_r75367_native,
vXX_normal,
vXX_dynamic,
vXX_native,
} }
public class DecrypterInfo { public class DecrypterInfo {
@ -54,10 +57,12 @@ namespace de4dot.code.deobfuscators.Confuser {
public readonly MethodDefinition method; public readonly MethodDefinition method;
public ulong key0l, key1l, key2l; public ulong key0l, key1l, key2l;
public uint key0, key0d; public uint key0, key0d;
readonly ConfuserVersion version;
public DecrypterInfo(ConstantsDecrypterV18 constantsDecrypter, MethodDefinition method) { public DecrypterInfo(ConstantsDecrypterV18 constantsDecrypter, MethodDefinition method, ConfuserVersion version) {
this.constantsDecrypter = constantsDecrypter; this.constantsDecrypter = constantsDecrypter;
this.method = method; this.method = method;
this.version = version;
} }
public string decryptString(uint magic1, ulong magic2) { public string decryptString(uint magic1, ulong magic2) {
@ -92,7 +97,21 @@ namespace de4dot.code.deobfuscators.Confuser {
} }
ulong hash(uint magic) { ulong hash(uint magic) {
ulong h0 = key0l * magic; switch (version) {
case ConfuserVersion.v18_r75367_normal:
case ConfuserVersion.v18_r75367_dynamic:
case ConfuserVersion.v18_r75367_native:
return hash1(key0l ^ magic);
case ConfuserVersion.vXX_normal:
case ConfuserVersion.vXX_dynamic:
case ConfuserVersion.vXX_native:
return hash1(key0l * magic);
default:
throw new ApplicationException("Invalid version");
}
}
ulong hash1(ulong h0) {
ulong h1 = key1l; ulong h1 = key1l;
ulong h2 = key2l; ulong h2 = key2l;
h1 *= h0; h1 *= h0;
@ -161,37 +180,46 @@ namespace de4dot.code.deobfuscators.Confuser {
if ((dataField = ConstantsDecrypterUtils.findDataField(cctor, cctor.DeclaringType)) == null) if ((dataField = ConstantsDecrypterUtils.findDataField(cctor, cctor.DeclaringType)) == null)
return; return;
nativeMethod = findNativeMethod(cctor, cctor.DeclaringType);
var method = getDecryptMethod();
if (method == null)
return;
simpleDeobfuscator.deobfuscate(method);
var info = new DecrypterInfo(this, method, ConfuserVersion.Unknown);
if (findKeys_v18_r75367(info))
initVersion(cctor, ConfuserVersion.v18_r75367_normal, ConfuserVersion.v18_r75367_dynamic, ConfuserVersion.v18_r75367_native);
else if (findKeys_vXX(info))
initVersion(cctor, ConfuserVersion.vXX_normal, ConfuserVersion.vXX_dynamic, ConfuserVersion.vXX_native);
else
return;
installMethod = cctor; installMethod = cctor;
} }
void initVersion(MethodDefinition installMethod, ConfuserVersion normal, ConfuserVersion dynamic, ConfuserVersion native) {
if (nativeMethod != null)
version = native;
else if (DeobUtils.hasInteger(installMethod, 0x10000))
version = normal;
else
version = dynamic;
}
public void initialize() { public void initialize() {
if (installMethod == null) if (installMethod == null)
return; return;
if (!findKeys()) if (!findKeys())
throw new ApplicationException("Could not find keys"); throw new ApplicationException("Could not find keys");
nativeMethod = findNativeMethod(installMethod, installMethod.DeclaringType);
constType = detectConstType();
if (constType == ConstType.Unknown)
throw new ApplicationException("Could not detect const type");
if ((resource = findResource(key0)) == null) if ((resource = findResource(key0)) == null)
throw new ApplicationException("Could not find resource"); throw new ApplicationException("Could not find resource");
constants = decrypt(resource.GetResourceData()); constants = decryptResource(resource.GetResourceData());
findDecrypters(); findDecrypters();
} }
ConstType detectConstType() {
if (nativeMethod != null)
return ConstType.Native;
else if (DeobUtils.hasInteger(installMethod, 0x10000))
return ConstType.Normal;
else
return ConstType.Dynamic;
}
EmbeddedResource findResource(uint magic) { EmbeddedResource findResource(uint magic) {
var name = Encoding.UTF8.GetString(BitConverter.GetBytes(magic)); var name = Encoding.UTF8.GetString(BitConverter.GetBytes(magic));
return DotNetUtils.getResource(module, name) as EmbeddedResource; return DotNetUtils.getResource(module, name) as EmbeddedResource;
@ -269,8 +297,57 @@ namespace de4dot.code.deobfuscators.Confuser {
return null; return null;
} }
MethodDefinition getDecryptMethod() {
foreach (var type in module.Types) {
if (type.Attributes != (TypeAttributes.Abstract | TypeAttributes.Sealed))
continue;
if (!checkMethods(type.Methods))
continue;
foreach (var method in type.Methods) {
if (isDecryptMethodSignature(method))
return method;
}
}
return null;
}
static bool checkMethods(IEnumerable<MethodDefinition> methods) {
int numMethods = 0;
foreach (var method in methods) {
if (method.Name == ".ctor" || method.Name == ".cctor")
return false;
if (!isDecryptMethodSignature(method))
return false;
numMethods++;
}
return numMethods > 0;
}
static bool isDecryptMethodSignature(MethodDefinition method) {
if (method == null || method.Body == null)
return false;
if (method.Attributes != (MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.CompilerControlled))
return false;
if (method.Parameters.Count != 2)
return false;
if (method.Parameters[0].ParameterType.EType != ElementType.U4)
return false;
if (method.Parameters[1].ParameterType.EType != ElementType.U8)
return false;
if (!(method.MethodReturnType.ReturnType is GenericParameter))
return false;
if (method.GenericParameters.Count != 1)
return false;
return true;
}
void findDecrypters() { void findDecrypters() {
foreach (var type in module.Types) { foreach (var type in module.Types) {
if (type.Attributes != (TypeAttributes.Abstract | TypeAttributes.Sealed))
continue;
if (!checkMethods(type.Methods))
continue;
foreach (var method in type.Methods) { foreach (var method in type.Methods) {
var info = createDecrypterInfo(method); var info = createDecrypterInfo(method);
if (info != null) if (info != null)
@ -280,34 +357,134 @@ namespace de4dot.code.deobfuscators.Confuser {
} }
DecrypterInfo createDecrypterInfo(MethodDefinition method) { DecrypterInfo createDecrypterInfo(MethodDefinition method) {
if (method == null || method.Body == null) if (!isDecryptMethodSignature(method))
return null;
if (!method.IsStatic)
return null;
if (method.Parameters.Count != 2)
return null;
if (method.Parameters[0].ParameterType.EType != ElementType.U4)
return null;
if (method.Parameters[1].ParameterType.EType != ElementType.U8)
return null;
if (!(method.MethodReturnType.ReturnType is GenericParameter))
return null;
if (method.GenericParameters.Count != 1)
return null; return null;
simpleDeobfuscator.deobfuscate(method); simpleDeobfuscator.deobfuscate(method);
var info = new DecrypterInfo(this, method); var info = new DecrypterInfo(this, method, version);
if (!findLKeys(info)) if (!findKeys(info))
return null;
if (!findKey0(info))
return null;
if (!findKey0d(info))
return null; return null;
return info; return info;
} }
static bool findLKeys(DecrypterInfo info) { bool findKeys(DecrypterInfo info) {
switch (version) {
case ConfuserVersion.v18_r75367_normal:
case ConfuserVersion.v18_r75367_dynamic:
case ConfuserVersion.v18_r75367_native:
return findKeys_v18_r75367(info);
case ConfuserVersion.vXX_normal:
case ConfuserVersion.vXX_dynamic:
case ConfuserVersion.vXX_native:
return findKeys_vXX(info);
default:
throw new ApplicationException("Invalid version");
}
}
static bool findKeys_v18_r75367(DecrypterInfo info) {
if (!findLKeys_v18_r75367(info))
return false;
if (!findKey0_v18_r75367(info))
return false;
if (!findKey0d_v18_r75367(info))
return false;
return true;
}
static bool findKeys_vXX(DecrypterInfo info) {
if (!findLKeys_vXX(info))
return false;
if (!findKey0_vXX(info))
return false;
if (!findKey0d_v18_r75367(info))
return false;
return true;
}
static bool findLKeys_v18_r75367(DecrypterInfo info) {
var instrs = info.method.Body.Instructions;
for (int i = 0; i < instrs.Count - 10; i++) {
var ldci4_1 = instrs[i];
if (!DotNetUtils.isLdcI4(ldci4_1))
continue;
if (!DotNetUtils.isLdloc(instrs[i + 1]))
continue;
if (instrs[i + 2].OpCode.Code != Code.Xor)
continue;
if (instrs[i + 3].OpCode.Code != Code.Conv_U8)
continue;
if (!DotNetUtils.isStloc(instrs[i + 4]))
continue;
var ldci4_2 = instrs[i + 5];
if (!DotNetUtils.isLdcI4(ldci4_2))
continue;
if (instrs[i + 6].OpCode.Code != Code.Conv_I8)
continue;
if (!DotNetUtils.isStloc(instrs[i + 7]))
continue;
var ldci4_3 = instrs[i + 8];
if (!DotNetUtils.isLdcI4(ldci4_3))
continue;
if (instrs[i + 9].OpCode.Code != Code.Conv_I8)
continue;
if (!DotNetUtils.isStloc(instrs[i + 10]))
continue;
info.key0l = (uint)DotNetUtils.getLdcI4Value(ldci4_1);
info.key1l = (uint)DotNetUtils.getLdcI4Value(ldci4_2);
info.key2l = (uint)DotNetUtils.getLdcI4Value(ldci4_3);
return true;
}
return false;
}
static bool findKey0_v18_r75367(DecrypterInfo info) {
var instrs = info.method.Body.Instructions;
for (int i = 0; i < instrs.Count - 4; i++) {
if (instrs[i].OpCode.Code != Code.Xor)
continue;
var ldci4 = instrs[i + 1];
if (!DotNetUtils.isLdcI4(ldci4))
continue;
if (instrs[i + 2].OpCode.Code != Code.Conv_I8)
continue;
if (instrs[i + 3].OpCode.Code != Code.Mul)
continue;
if (instrs[i + 4].OpCode.Code != Code.Add)
continue;
info.key0 = (uint)DotNetUtils.getLdcI4Value(ldci4);
return true;
}
return false;
}
static bool findKey0d_v18_r75367(DecrypterInfo info) {
var instrs = info.method.Body.Instructions;
for (int i = 0; i < instrs.Count; i++) {
int index = ConfuserUtils.findCallMethod(instrs, i, Code.Callvirt, "System.Int32 System.Reflection.MemberInfo::get_MetadataToken()");
if (index < 0)
break;
int index2 = ConfuserUtils.findCallMethod(instrs, index, Code.Call, "System.Byte[] System.BitConverter::GetBytes(System.Int32)");
if (index2 < 0)
break;
if (index2 - index != 3)
continue;
var ldci4 = instrs[index + 1];
if (!DotNetUtils.isLdcI4(ldci4))
continue;
if (instrs[index + 2].OpCode.Code != Code.Xor)
continue;
info.key0d = (uint)DotNetUtils.getLdcI4Value(ldci4);
return true;
}
return false;
}
static bool findLKeys_vXX(DecrypterInfo info) {
var instrs = info.method.Body.Instructions; var instrs = info.method.Body.Instructions;
for (int i = 0; i < instrs.Count - 8; i++) { for (int i = 0; i < instrs.Count - 8; i++) {
var ldci8_1 = instrs[i]; var ldci8_1 = instrs[i];
@ -340,7 +517,7 @@ namespace de4dot.code.deobfuscators.Confuser {
return false; return false;
} }
static bool findKey0(DecrypterInfo info) { static bool findKey0_vXX(DecrypterInfo info) {
var instrs = info.method.Body.Instructions; var instrs = info.method.Body.Instructions;
for (int i = 0; i < instrs.Count - 4; i++) { for (int i = 0; i < instrs.Count - 4; i++) {
if (!DotNetUtils.isLdloc(instrs[i])) if (!DotNetUtils.isLdloc(instrs[i]))
@ -361,35 +538,22 @@ namespace de4dot.code.deobfuscators.Confuser {
return false; return false;
} }
static bool findKey0d(DecrypterInfo info) { byte[] decryptResource(byte[] encrypted) {
var instrs = info.method.Body.Instructions; switch (version) {
for (int i = 0; i < instrs.Count; i++) { case ConfuserVersion.v18_r75367_normal:
int index = ConfuserUtils.findCallMethod(instrs, i, Code.Callvirt, "System.Int32 System.Reflection.MemberInfo::get_MetadataToken()"); case ConfuserVersion.vXX_normal:
if (index < 0) return decryptResource_v18_r75367_normal(encrypted);
break;
int index2 = ConfuserUtils.findCallMethod(instrs, index, Code.Call, "System.Byte[] System.BitConverter::GetBytes(System.Int32)");
if (index2 < 0)
break;
if (index2 - index != 3)
continue;
var ldci4 = instrs[index + 1];
if (!DotNetUtils.isLdcI4(ldci4))
continue;
if (instrs[index + 2].OpCode.Code != Code.Xor)
continue;
info.key0d = (uint)DotNetUtils.getLdcI4Value(ldci4); case ConfuserVersion.v18_r75367_dynamic:
return true; case ConfuserVersion.vXX_dynamic:
} return decryptResource_v18_r75367_dynamic(encrypted);
return false;
}
byte[] decrypt(byte[] encrypted) { case ConfuserVersion.v18_r75367_native:
switch (constType) { case ConfuserVersion.vXX_native:
case ConstType.Normal: return decryptNormal(encrypted); return decryptResource_v18_r75367_native(encrypted);
case ConstType.Dynamic: return decryptDynamic(encrypted);
case ConstType.Native: return decryptNative(encrypted); default:
default: throw new ApplicationException(string.Format("Unknown const type: {0}", constType)); throw new ApplicationException("Unknown version");
} }
} }
@ -400,7 +564,7 @@ namespace de4dot.code.deobfuscators.Confuser {
return module.GetSignatureBlob(sigToken); return module.GetSignatureBlob(sigToken);
} }
byte[] decryptNormal(byte[] encrypted) { byte[] decryptResource_v18_r75367_normal(byte[] encrypted) {
var key = getSigKey(); var key = getSigKey();
var decrypted = ConfuserUtils.decrypt(BitConverter.ToUInt32(key, 12) * (uint)key0, encrypted); var decrypted = ConfuserUtils.decrypt(BitConverter.ToUInt32(key, 12) * (uint)key0, encrypted);
return DeobUtils.inflate(DeobUtils.aesDecrypt(decrypted, key, DeobUtils.md5Sum(key)), true); return DeobUtils.inflate(DeobUtils.aesDecrypt(decrypted, key, DeobUtils.md5Sum(key)), true);
@ -448,7 +612,7 @@ namespace de4dot.code.deobfuscators.Confuser {
return null; return null;
} }
byte[] decryptDynamic(byte[] encrypted) { byte[] decryptResource_v18_r75367_dynamic(byte[] encrypted) {
int ldlocIndex; int ldlocIndex;
var local = getDynamicLocal(out ldlocIndex); var local = getDynamicLocal(out ldlocIndex);
if (local == null) if (local == null)
@ -462,7 +626,7 @@ namespace de4dot.code.deobfuscators.Confuser {
var constReader = new ConstantsReader(installMethod); var constReader = new ConstantsReader(installMethod);
return decrypt(encrypted, magic => { return decryptResource(encrypted, magic => {
constReader.setConstantInt32(local, magic); constReader.setConstantInt32(local, magic);
int index = startIndex, result; int index = startIndex, result;
if (!constReader.getNextInt32(ref index, out result)) if (!constReader.getNextInt32(ref index, out result))
@ -473,12 +637,12 @@ namespace de4dot.code.deobfuscators.Confuser {
}); });
} }
byte[] decryptNative(byte[] encrypted) { byte[] decryptResource_v18_r75367_native(byte[] encrypted) {
var x86Emu = new x86Emulator(new PeImage(fileData)); var x86Emu = new x86Emulator(new PeImage(fileData));
return decrypt(encrypted, magic => (byte)x86Emu.emulate((uint)nativeMethod.RVA, magic)); return decryptResource(encrypted, magic => (byte)x86Emu.emulate((uint)nativeMethod.RVA, magic));
} }
byte[] decrypt(byte[] encrypted, Func<uint, byte> decryptFunc) { byte[] decryptResource(byte[] encrypted, Func<uint, byte> decryptFunc) {
var key = getSigKey(); var key = getSigKey();
var decrypted = DeobUtils.aesDecrypt(encrypted, key, DeobUtils.md5Sum(key)); var decrypted = DeobUtils.aesDecrypt(encrypted, key, DeobUtils.md5Sum(key));