Update array cflow deobfuscator
This commit is contained in:
parent
574eb0ee3d
commit
bbbdf0b0ff
|
@ -91,6 +91,48 @@ namespace de4dot.code.deobfuscators.DeepSea {
|
||||||
return changed;
|
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) {
|
bool deobfuscate1(Block block, int i) {
|
||||||
var instrs = block.Instructions;
|
var instrs = block.Instructions;
|
||||||
if (i >= instrs.Count - 2)
|
if (i >= instrs.Count - 2)
|
||||||
|
@ -111,11 +153,11 @@ namespace de4dot.code.deobfuscators.DeepSea {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var ldelem = instrs[i + 2];
|
var ldelem = instrs[i + 2];
|
||||||
if (ldelem.OpCode.Code != Code.Ldelem_U1)
|
if (!IsLdelem(info, ldelem.OpCode.Code))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
block.remove(i, 3 - 1);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,11 +178,11 @@ namespace de4dot.code.deobfuscators.DeepSea {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var ldelem = instrs[i + 2];
|
var ldelem = instrs[i + 2];
|
||||||
if (ldelem.OpCode.Code != Code.Ldelem_U1)
|
if (!IsLdelem(info, ldelem.OpCode.Code))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
block.remove(i, 3 - 1);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +211,7 @@ namespace de4dot.code.deobfuscators.DeepSea {
|
||||||
if (i >= instrs.Count)
|
if (i >= instrs.Count)
|
||||||
return false;
|
return false;
|
||||||
var stelem = instrs[i];
|
var stelem = instrs[i];
|
||||||
if (stelem.OpCode.Code != Code.Stelem_I1)
|
if (!IsStelem(info, stelem.OpCode.Code))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
block.remove(start, i - start + 1);
|
block.remove(start, i - start + 1);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using dot10.DotNet.Emit;
|
using dot10.DotNet.Emit;
|
||||||
|
@ -28,14 +29,62 @@ namespace de4dot.code.deobfuscators.DeepSea {
|
||||||
FieldDefAndDeclaringTypeDict<FieldInfo> fieldToInfo = new FieldDefAndDeclaringTypeDict<FieldInfo>();
|
FieldDefAndDeclaringTypeDict<FieldInfo> fieldToInfo = new FieldDefAndDeclaringTypeDict<FieldInfo>();
|
||||||
|
|
||||||
public class FieldInfo {
|
public class FieldInfo {
|
||||||
|
public readonly ElementType elementType;
|
||||||
public readonly FieldDef field;
|
public readonly FieldDef field;
|
||||||
public readonly FieldDef arrayInitField;
|
public readonly FieldDef arrayInitField;
|
||||||
public readonly byte[] array;
|
public readonly Array array;
|
||||||
|
|
||||||
public FieldInfo(FieldDef field, FieldDef arrayInitField) {
|
public FieldInfo(FieldDef field, FieldDef arrayInitField) {
|
||||||
this.field = field;
|
this.field = field;
|
||||||
|
this.elementType = ((SZArraySig)field.FieldType).Next.GetElementType();
|
||||||
this.arrayInitField = arrayInitField;
|
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)
|
if (instrs == null)
|
||||||
continue;
|
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;
|
var arrayInitField = instrs[2].Operand as FieldDef;
|
||||||
if (arrayInitField == null || arrayInitField.InitialValue == null || arrayInitField.InitialValue.Length == 0)
|
if (arrayInitField == null || arrayInitField.InitialValue == null || arrayInitField.InitialValue.Length == 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -84,7 +129,10 @@ namespace de4dot.code.deobfuscators.DeepSea {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var targetField = instrs[4].Operand as FieldDef;
|
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;
|
continue;
|
||||||
|
|
||||||
if (fieldToInfo.find(targetField) == null) {
|
if (fieldToInfo.find(targetField) == null) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user