From c8129e0627d0ed1fec2bf2b3b1dfd9d054df48a2 Mon Sep 17 00:00:00 2001 From: Paolo Date: Fri, 9 Oct 2026 21:18:20 +0200 Subject: [PATCH 1/3] Fix (babel): correct AES key buffer initialization in Decrypter4 Initialize and populate the key array prior to handling public key offsets in Decrypter4. This prevents passing an invalid key length to the AES transform when processing resources that derive keys from the assembly public key or end-of-stream header boundaries. --- .../Babel_NET/ResourceDecrypter.cs | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/de4dot.code/deobfuscators/Babel_NET/ResourceDecrypter.cs b/de4dot.code/deobfuscators/Babel_NET/ResourceDecrypter.cs index f00da1b8..3da0db8f 100644 --- a/de4dot.code/deobfuscators/Babel_NET/ResourceDecrypter.cs +++ b/de4dot.code/deobfuscators/Babel_NET/ResourceDecrypter.cs @@ -199,28 +199,29 @@ bool GetKeyIv(byte[] headerData, out byte[] key, out byte[] iv) { } } - // v10/v11 + // v10/v11 - Fix (babel): correct AES key buffer initialization in Decrypter4 class Decrypter4 : IDecrypter { ModuleDefMD module; Inflater inflater; - + public Decrypter4(ModuleDefMD module, MethodDef decryptMethod, ISimpleDeobfuscator deobfuscator) { this.module = module; inflater = InflaterCreator.Create(decryptMethod, deobfuscator, true); } - + public byte[] Decrypt(byte[] encryptedData) { int index = 0; ParseHeader(GetHeaderData(encryptedData, ref index, out var iv), out var key, out var flag, out var cipherType); + bool isEncrypted = (flag & 2) != 0; bool isCompressed = (flag & 1) != 0; - + byte[] data = new byte[encryptedData.Length - index]; Array.Copy(encryptedData, index, data, 0, encryptedData.Length - index); - + if (isEncrypted) { if (cipherType == 1) data = DeobUtils.DesDecrypt(data, 0, data.Length, key, iv); @@ -231,44 +232,50 @@ public byte[] Decrypt(byte[] encryptedData) { else throw new Exception($"Unsupported cipher type {cipherType}"); } - + if (isCompressed) { data = DeobUtils.Inflate(data, inflater); } - + return data; } - - byte[] GetHeaderData(byte[] encryptedData, ref int index, out byte[] iv) { - var headerData = new byte[BitConverter.ToUInt16(encryptedData, index)]; + + byte[] GetHeaderData(byte[] encryptedData, ref int index, out byte[] iv) { + var headerLength = BitConverter.ToUInt16(encryptedData, index); + var headerData = new byte[headerLength]; Array.Copy(encryptedData, index + 2, headerData, 0, headerData.Length); index += headerData.Length + 2; - + iv = new byte[encryptedData[index++]]; Array.Copy(encryptedData, index, iv, 0, iv.Length); index += iv.Length; + for (int i = 0; i < headerData.Length; i++) headerData[i] ^= iv[i % iv.Length]; - + return headerData; } - + void ParseHeader(byte[] headerData, out byte[] key, out byte flag, out byte cipherType) { var reader = new BinaryReader(new MemoryStream(headerData)); - - /*var license =*/ reader.ReadString(); + + /*var license =*/ + reader.ReadString(); flag = reader.ReadByte(); cipherType = reader.ReadByte(); byte pubKeyOffset = reader.ReadByte(); - - key = reader.ReadBytes(reader.ReadByte()); + byte keyLength = reader.ReadByte(); + key = new byte[keyLength]; + if (pubKeyOffset < 64) { + reader.Read(key, 0, keyLength); if (reader.BaseStream.Position < reader.BaseStream.Length) throw new Exception("Expected end of header"); } else { - Array.Copy(module.Assembly.PublicKey.Data, pubKeyOffset + 12, key, 0, key.Length); - //key[5] |= 0x80; + if (module.Assembly != null && module.Assembly.PublicKey != null && module.Assembly.PublicKey.Data != null) { + Array.Copy(module.Assembly.PublicKey.Data, pubKeyOffset + 12, key, 0, keyLength); + } } } } From 9836f8f455cc6c77634f9fa07f3b4deee7375176 Mon Sep 17 00:00:00 2001 From: Paolo Date: Fri, 9 Oct 2026 21:20:12 +0200 Subject: [PATCH 2/3] Fix (babel) : loosen type signature check in MethodsDecrypter Remove the mandatory 'System.Collections.Hashtable' field requirement from the decrypter detection heuristic. This allows Babel helper types to be detected when caching tables are relocated into nested or internal classes. --- de4dot.code/deobfuscators/Babel_NET/MethodsDecrypter.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/de4dot.code/deobfuscators/Babel_NET/MethodsDecrypter.cs b/de4dot.code/deobfuscators/Babel_NET/MethodsDecrypter.cs index baa39306..7fd31535 100644 --- a/de4dot.code/deobfuscators/Babel_NET/MethodsDecrypter.cs +++ b/de4dot.code/deobfuscators/Babel_NET/MethodsDecrypter.cs @@ -45,8 +45,7 @@ public MethodsDecrypter(ModuleDefMD module, ResourceDecrypter resourceDecrypter, public void Find() { var requiredFields = new string[] { - "System.Threading.ReaderWriterLock", - "System.Collections.Hashtable", + "System.Threading.ReaderWriterLock" }; foreach (var type in module.GetTypes()) { var fieldTypes = new FieldTypes(type); From 325e7899981bc38c96c67f5acdb248bcbbd21c7b Mon Sep 17 00:00:00 2001 From: Melissa <65674838+meck-gd@users.noreply.github.com> Date: Tue, 13 Oct 2026 14:54:43 +0200 Subject: [PATCH 3/3] Remove surplus whitespace --- .../Babel_NET/ResourceDecrypter.cs | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/de4dot.code/deobfuscators/Babel_NET/ResourceDecrypter.cs b/de4dot.code/deobfuscators/Babel_NET/ResourceDecrypter.cs index 3da0db8f..0ef93c00 100644 --- a/de4dot.code/deobfuscators/Babel_NET/ResourceDecrypter.cs +++ b/de4dot.code/deobfuscators/Babel_NET/ResourceDecrypter.cs @@ -199,29 +199,29 @@ bool GetKeyIv(byte[] headerData, out byte[] key, out byte[] iv) { } } - // v10/v11 - Fix (babel): correct AES key buffer initialization in Decrypter4 + // v10/v11 class Decrypter4 : IDecrypter { ModuleDefMD module; Inflater inflater; - + public Decrypter4(ModuleDefMD module, MethodDef decryptMethod, ISimpleDeobfuscator deobfuscator) { this.module = module; inflater = InflaterCreator.Create(decryptMethod, deobfuscator, true); } - + public byte[] Decrypt(byte[] encryptedData) { int index = 0; ParseHeader(GetHeaderData(encryptedData, ref index, out var iv), out var key, out var flag, out var cipherType); - + bool isEncrypted = (flag & 2) != 0; bool isCompressed = (flag & 1) != 0; - + byte[] data = new byte[encryptedData.Length - index]; Array.Copy(encryptedData, index, data, 0, encryptedData.Length - index); - + if (isEncrypted) { if (cipherType == 1) data = DeobUtils.DesDecrypt(data, 0, data.Length, key, iv); @@ -232,41 +232,40 @@ public byte[] Decrypt(byte[] encryptedData) { else throw new Exception($"Unsupported cipher type {cipherType}"); } - + if (isCompressed) { data = DeobUtils.Inflate(data, inflater); } - + return data; } - + byte[] GetHeaderData(byte[] encryptedData, ref int index, out byte[] iv) { var headerLength = BitConverter.ToUInt16(encryptedData, index); var headerData = new byte[headerLength]; Array.Copy(encryptedData, index + 2, headerData, 0, headerData.Length); index += headerData.Length + 2; - + iv = new byte[encryptedData[index++]]; Array.Copy(encryptedData, index, iv, 0, iv.Length); index += iv.Length; - + for (int i = 0; i < headerData.Length; i++) headerData[i] ^= iv[i % iv.Length]; - + return headerData; } - + void ParseHeader(byte[] headerData, out byte[] key, out byte flag, out byte cipherType) { var reader = new BinaryReader(new MemoryStream(headerData)); - - /*var license =*/ - reader.ReadString(); + + /*var license =*/ reader.ReadString(); flag = reader.ReadByte(); cipherType = reader.ReadByte(); byte pubKeyOffset = reader.ReadByte(); byte keyLength = reader.ReadByte(); key = new byte[keyLength]; - + if (pubKeyOffset < 64) { reader.Read(key, 0, keyLength); if (reader.BaseStream.Position < reader.BaseStream.Length)