diff --git a/de4dot.code/deobfuscators/DeepSea/ArrayBlockDeobfuscator.cs b/de4dot.code/deobfuscators/DeepSea/ArrayBlockDeobfuscator.cs index c757bd9e..2d6a6fca 100644 --- a/de4dot.code/deobfuscators/DeepSea/ArrayBlockDeobfuscator.cs +++ b/de4dot.code/deobfuscators/DeepSea/ArrayBlockDeobfuscator.cs @@ -91,6 +91,48 @@ namespace de4dot.code.deobfuscators.DeepSea { return changed; } + static bool IsLdelem(ArrayBlockState.FieldInfo info, Code code) { + switch (info.elementType) { + case ElementType.Boolean: + case ElementType.I1: + case ElementType.U1: + return code == Code.Ldelem_I1 || code == Code.Ldelem_U1; + + case ElementType.Char: + case ElementType.I2: + case ElementType.U2: + return code == Code.Ldelem_I2 || code == Code.Ldelem_U2; + + case ElementType.I4: + case ElementType.U4: + return code == Code.Ldelem_I4 || code == Code.Ldelem_U4; + + default: + return false; + } + } + + static bool IsStelem(ArrayBlockState.FieldInfo info, Code code) { + switch (info.elementType) { + case ElementType.Boolean: + case ElementType.I1: + case ElementType.U1: + return code == Code.Stelem_I1; + + case ElementType.Char: + case ElementType.I2: + case ElementType.U2: + return code == Code.Stelem_I2; + + case ElementType.I4: + case ElementType.U4: + return code == Code.Stelem_I4; + + default: + return false; + } + } + bool deobfuscate1(Block block, int i) { var instrs = block.Instructions; if (i >= instrs.Count - 2) @@ -111,11 +153,11 @@ namespace de4dot.code.deobfuscators.DeepSea { return false; var ldelem = instrs[i + 2]; - if (ldelem.OpCode.Code != Code.Ldelem_U1) + if (!IsLdelem(info, ldelem.OpCode.Code)) return false; block.remove(i, 3 - 1); - instrs[i] = new Instr(Instruction.CreateLdcI4(info.array[ldci4.getLdcI4Value()])); + instrs[i] = new Instr(Instruction.CreateLdcI4((int)info.readArrayElement(ldci4.getLdcI4Value()))); return true; } @@ -136,11 +178,11 @@ namespace de4dot.code.deobfuscators.DeepSea { return false; var ldelem = instrs[i + 2]; - if (ldelem.OpCode.Code != Code.Ldelem_U1) + if (!IsLdelem(info, ldelem.OpCode.Code)) return false; block.remove(i, 3 - 1); - instrs[i] = new Instr(Instruction.CreateLdcI4(info.array[ldci4.getLdcI4Value()])); + instrs[i] = new Instr(Instruction.CreateLdcI4((int)info.readArrayElement(ldci4.getLdcI4Value()))); return true; } @@ -169,7 +211,7 @@ namespace de4dot.code.deobfuscators.DeepSea { if (i >= instrs.Count) return false; var stelem = instrs[i]; - if (stelem.OpCode.Code != Code.Stelem_I1) + if (!IsStelem(info, stelem.OpCode.Code)) return false; block.remove(start, i - start + 1); diff --git a/de4dot.code/deobfuscators/DeepSea/ArrayBlockState.cs b/de4dot.code/deobfuscators/DeepSea/ArrayBlockState.cs index fb665c2a..7ebef092 100644 --- a/de4dot.code/deobfuscators/DeepSea/ArrayBlockState.cs +++ b/de4dot.code/deobfuscators/DeepSea/ArrayBlockState.cs @@ -17,6 +17,7 @@ along with de4dot. If not, see . */ +using System; using System.Collections.Generic; using dot10.DotNet; using dot10.DotNet.Emit; @@ -28,14 +29,62 @@ namespace de4dot.code.deobfuscators.DeepSea { FieldDefAndDeclaringTypeDict fieldToInfo = new FieldDefAndDeclaringTypeDict(); public class FieldInfo { + public readonly ElementType elementType; public readonly FieldDef field; public readonly FieldDef arrayInitField; - public readonly byte[] array; + public readonly Array array; public FieldInfo(FieldDef field, FieldDef arrayInitField) { this.field = field; + this.elementType = ((SZArraySig)field.FieldType).Next.GetElementType(); this.arrayInitField = arrayInitField; - this.array = (byte[])arrayInitField.InitialValue.Clone(); + this.array = createArray(elementType, arrayInitField.InitialValue); + } + + static Array createArray(ElementType etype, byte[] data) { + switch (etype) { + case ElementType.Boolean: + case ElementType.I1: + case ElementType.U1: + return (byte[])data.Clone(); + + case ElementType.Char: + case ElementType.I2: + case ElementType.U2: + var ary2 = new ushort[data.Length / 2]; + Buffer.BlockCopy(data, 0, ary2, 0, ary2.Length * 2); + return ary2; + + case ElementType.I4: + case ElementType.U4: + var ary4 = new uint[data.Length / 4]; + Buffer.BlockCopy(data, 0, ary4, 0, ary4.Length * 4); + return ary4; + + default: + throw new ApplicationException("Invalid etype"); + } + } + + public uint readArrayElement(int index) { + switch (elementType) { + case ElementType.Boolean: + case ElementType.I1: + case ElementType.U1: + return ((byte[])array)[index]; + + case ElementType.Char: + case ElementType.I2: + case ElementType.U2: + return ((ushort[])array)[index]; + + case ElementType.I4: + case ElementType.U4: + return ((uint[])array)[index]; + + default: + throw new ApplicationException("Invalid etype"); + } } } @@ -71,10 +120,6 @@ namespace de4dot.code.deobfuscators.DeepSea { if (instrs == null) continue; - var arrayType = instrs[0].Operand as ITypeDefOrRef; - if (arrayType == null || (arrayType.FullName != "System.Byte" && !arrayType.DefinitionAssembly.IsCorLib())) - continue; - var arrayInitField = instrs[2].Operand as FieldDef; if (arrayInitField == null || arrayInitField.InitialValue == null || arrayInitField.InitialValue.Length == 0) continue; @@ -84,7 +129,10 @@ namespace de4dot.code.deobfuscators.DeepSea { continue; var targetField = instrs[4].Operand as FieldDef; - if (targetField == null) + if (targetField == null || targetField.FieldType.GetElementType() != ElementType.SZArray) + continue; + var etype = ((SZArraySig)targetField.FieldType).Next.GetElementType(); + if (etype < ElementType.Boolean || etype > ElementType.U4) continue; if (fieldToInfo.find(targetField) == null) {