de4dot-cex/de4dot.code/deobfuscators/ConfuserEx/LzmaFinder.cs

192 lines
7.5 KiB
C#

using System.Collections.Generic;
using System.Linq;
using de4dot.blocks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
namespace de4dot.code.deobfuscators.ConfuserEx
{
public class LzmaFinder
{
private readonly ISimpleDeobfuscator _deobfuscator;
private readonly ModuleDef _module;
public LzmaFinder(ModuleDef module, ISimpleDeobfuscator deobfuscator)
{
this._module = module;
this._deobfuscator = deobfuscator;
}
public MethodDef Method { get; private set; }
public List<TypeDef> Types { get; } = new List<TypeDef>();
public bool FoundLzma => Method != null && Types.Count != 0;
public void Find()
{
var moduleType = DotNetUtils.GetModuleType(_module);
if (moduleType == null)
return;
foreach (var method in moduleType.Methods)
{
if (!method.HasBody || !method.IsStatic)
continue;
if (!DotNetUtils.IsMethod(method, "System.Byte[]", "(System.Byte[])"))
continue;
_deobfuscator.Deobfuscate(method, SimpleDeobfuscatorFlags.Force);
if (!IsLzmaMethod(method))
continue;
Method = method;
var type = ((MethodDef) method.Body.Instructions[3].Operand).DeclaringType;
ExtractNestedTypes(type);
}
}
private bool IsLzmaMethod(MethodDef method)
{
var instructions = method.Body.Instructions;
if (instructions.Count < 60)
return false;
var firstInstruction = instructions.FirstOrDefault(
instr =>
instr.OpCode == OpCodes.Newobj &&
instr.Operand.ToString() == "System.Void System.IO.MemoryStream::.ctor(System.Byte[])");
if (firstInstruction == null)
return false;
var i = instructions.IndexOf(firstInstruction) + 1;
if (!instructions[i++].IsStloc())
return false;
if (instructions[i++].OpCode != OpCodes.Newobj)
return false;
if (!instructions[i++].IsStloc()) //<Module>.Class1 @class = new <Module>.Class1();
return false;
if (!instructions[i].IsLdcI4() || instructions[i++].GetLdcI4Value() != 5)
return false;
if (instructions[i++].OpCode != OpCodes.Newarr)
return false;
if (!instructions[i++].IsStloc()) //byte[] buffer = new byte[5];
return false;
if (!instructions[i++].IsLdloc())
return false;
if (!instructions[i++].IsLdloc())
return false;
if (!instructions[i].IsLdcI4() || instructions[i++].GetLdcI4Value() != 0)
return false;
if (!instructions[i].IsLdcI4() || instructions[i++].GetLdcI4Value() != 5)
return false;
if (instructions[i].OpCode != OpCodes.Callvirt || instructions[i++].Operand.ToString() !=
"System.Int32 System.IO.Stream::Read(System.Byte[],System.Int32,System.Int32)")
return false;
if (instructions[i++].OpCode != OpCodes.Pop) //memoryStream.Read(buffer, 0, 5);
return false;
if (!instructions[i++].IsLdloc())
return false;
if (!instructions[i++].IsLdloc())
return false;
if (instructions[i++].OpCode != OpCodes.Callvirt) //@class.method_5(buffer);
return false;
firstInstruction =
instructions.FirstOrDefault(
instr =>
instr.OpCode == OpCodes.Callvirt &&
instr.Operand.ToString() == "System.Int32 System.IO.Stream::ReadByte()");
if (firstInstruction == null)
return false;
if (i >= instructions.IndexOf(firstInstruction))
return false;
i = instructions.IndexOf(firstInstruction) + 1;
if (!instructions[i++].IsStloc()) //int num2 = memoryStream.ReadByte();
return false;
if (!instructions[i++].IsLdloc())
return false;
if (!instructions[i++].IsLdloc())
return false;
if (instructions[i++].OpCode != OpCodes.Conv_U1)
return false;
if (instructions[i++].OpCode != OpCodes.Conv_U8)
return false;
if (!instructions[i].IsLdcI4() || instructions[i++].GetLdcI4Value() != 8)
return false;
if (!instructions[i++].IsLdloc())
return false;
if (instructions[i++].OpCode != OpCodes.Mul)
return false;
if (!instructions[i].IsLdcI4() || instructions[i++].GetLdcI4Value() != 0x3F)
return false;
if (instructions[i++].OpCode != OpCodes.And)
return false;
if (instructions[i++].OpCode != OpCodes.Shl)
return false;
if (instructions[i++].OpCode != OpCodes.Or)
return false;
if (!instructions[i++].IsStloc()) //num |= (long)((long)((ulong)((byte)num2)) << 8 * i);
return false;
firstInstruction =
instructions.FirstOrDefault(
instr =>
instr.OpCode == OpCodes.Newobj &&
instr.Operand.ToString() ==
"System.Void System.IO.MemoryStream::.ctor(System.Byte[],System.Boolean)");
if (firstInstruction == null)
return false;
if (i >= instructions.IndexOf(firstInstruction))
return false;
i = instructions.IndexOf(firstInstruction) + 1;
if (!instructions[i++].IsStloc()) //MemoryStream stream_ = new MemoryStream(array, true);
return false;
if (!instructions[i++].IsLdloc())
return false;
if (instructions[i].OpCode != OpCodes.Callvirt || instructions[i++].Operand.ToString() !=
"System.Int64 System.IO.Stream::get_Length()")
return false;
if (instructions[i].OpCode != OpCodes.Ldc_I8 || (long) instructions[i++].Operand != 13L)
return false;
if (instructions[i++].OpCode != OpCodes.Sub)
return false;
if (!instructions[i++].IsStloc()) //long long_ = memoryStream.Length - 13L;
return false;
return true;
}
private void ExtractNestedTypes(TypeDef type)
{
foreach (var method in type.Methods)
if (method.HasBody)
{
var instr = method.Body.Instructions;
foreach (var inst in instr)
if (inst.Operand is MethodDef)
{
var ntype = (inst.Operand as MethodDef).DeclaringType;
if (!ntype.IsNested)
continue;
if (Types.Contains(ntype))
continue;
Types.Add(ntype);
ExtractNestedTypes(ntype);
}
}
}
}
}