mirror of
https://github.com/MadMin3r/UnconfuserEx
synced 2026-06-23 09:25:19 +00:00
Add support for expression predicate in switch obfuscation
This commit is contained in:
@@ -30,7 +30,7 @@ namespace MSILEmulator
|
||||
Ctx = new();
|
||||
}
|
||||
|
||||
public ILMethod(IList<Instruction> instructions)
|
||||
public ILMethod(IEnumerable<Instruction> instructions)
|
||||
{
|
||||
Method = null;
|
||||
Instructions = instructions.ToList();
|
||||
@@ -47,11 +47,6 @@ namespace MSILEmulator
|
||||
Ctx.Locals[index] = value;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Ctx = new();
|
||||
}
|
||||
|
||||
public Context Emulate()
|
||||
{
|
||||
|
||||
|
||||
@@ -26,14 +26,9 @@ namespace UnConfuserEx.Protections.Constants
|
||||
{
|
||||
if (decryptInstructions[i + 2].OpCode == OpCodes.Ldelem_U4)
|
||||
{
|
||||
if (decryptInstructions[i].OpCode == OpCodes.Ldloc_S)
|
||||
if (decryptInstructions[i].IsLdloc())
|
||||
{
|
||||
arrays.Add(((Local)decryptInstructions[i].Operand).Index);
|
||||
}
|
||||
else if (decryptInstructions[i].OpCode.Value >= OpCodes.Ldloc_0.Value
|
||||
&& decryptInstructions[i].OpCode.Value <= OpCodes.Ldloc_3.Value)
|
||||
{
|
||||
arrays.Add(decryptInstructions[i].OpCode.Value - OpCodes.Ldloc_0.Value);
|
||||
arrays.Add(Utils.GetLoadLocalIndex(decryptInstructions[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +105,11 @@ namespace UnConfuserEx.Protections
|
||||
|
||||
public static bool IsSwitchObfuscation(List<Instruction> instrs)
|
||||
{
|
||||
if (instrs.Count < 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < instrs.Count; i++)
|
||||
{
|
||||
if (instrs[i].OpCode == OpCodes.Switch
|
||||
|
||||
@@ -3,6 +3,7 @@ using de4dot.blocks.cflow;
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Emit;
|
||||
using log4net;
|
||||
using MSILEmulator;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using X86Emulator;
|
||||
@@ -22,6 +23,9 @@ namespace UnConfuserEx.Protections.ControlFlow
|
||||
private int methodOffset = -1;
|
||||
private X86Method? x86Method = null;
|
||||
|
||||
private ILMethod? ilMethod = null;
|
||||
private int? keyIndex = null;
|
||||
|
||||
public SwitchDeobfuscator(ModuleDefMD module)
|
||||
{
|
||||
Module = module;
|
||||
@@ -68,6 +72,16 @@ namespace UnConfuserEx.Protections.ControlFlow
|
||||
methodOffset = i - 5;
|
||||
x86Method = new X86Method(Module, (MethodDef)instrs[i - 5].Operand);
|
||||
}
|
||||
else if (!switchBlock.FirstInstr.Instruction.IsLdcI4())
|
||||
{
|
||||
var decodeInstrsLength = switchBlock.Instructions.Count - 6;
|
||||
|
||||
ilMethod = new ILMethod(switchBlock.Instructions
|
||||
.Skip(1)
|
||||
.Take(decodeInstrsLength)
|
||||
.Select(instr => instr.Instruction));
|
||||
keyIndex = Utils.GetStoreLocalIndex(switchBlock.FirstInstr.Instruction);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -95,9 +109,12 @@ namespace UnConfuserEx.Protections.ControlFlow
|
||||
{
|
||||
modified = false;
|
||||
|
||||
// Sometimes de4dot doesn't split the ldc.i4 going into the switchblock
|
||||
// so we need to handle that in a special case
|
||||
if (switchBlock!.FirstInstr.IsLdcI4())
|
||||
|
||||
// Sometimes with the x86 predicate, the ldc.i4 going into the switch block
|
||||
// doesn't get split into a separate block which can cause issues
|
||||
|
||||
// TODO: Not entirely convinced this solution won't cause issues...
|
||||
if (x86Method != null && switchBlock!.FirstInstr.IsLdcI4())
|
||||
{
|
||||
var key = switchBlock.FirstInstr.GetLdcI4Value();
|
||||
var (nextKey, nextCase) = GetNextKeyAndCase(key);
|
||||
@@ -218,17 +235,27 @@ namespace UnConfuserEx.Protections.ControlFlow
|
||||
|
||||
private (int nextKey, int nextCase) GetNextKeyAndCase(int key)
|
||||
{
|
||||
if (x86Method == null)
|
||||
// x86 predicate
|
||||
if (x86Method != null)
|
||||
{
|
||||
var nextKey = x86Method.Emulate(new int[] { key });
|
||||
return (nextKey, nextKey % switchCases.Count);
|
||||
}
|
||||
// Expression Predicate
|
||||
else if (ilMethod != null)
|
||||
{
|
||||
ilMethod.SetLocal((int)keyIndex!, key);
|
||||
|
||||
var nextKey = (int)ilMethod.Emulate().Stack.Pop();
|
||||
return (nextKey, nextKey % switchCases.Count);
|
||||
}
|
||||
// Normal predicate
|
||||
else
|
||||
{
|
||||
var xorKey = switchBlock!.FirstInstr.GetLdcI4Value();
|
||||
var nextKey = key ^ xorKey;
|
||||
return (nextKey, nextKey % switchCases.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
var nextKey = x86Method.Emulate(new int[] { key });
|
||||
return (nextKey, nextKey % switchCases.Count);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateKeyInBlock(Block block, int key)
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace UnConfuserEx
|
||||
|
||||
var pipeline = new List<IProtection>
|
||||
{
|
||||
new ControlFlowRemover(),
|
||||
|
||||
// If this is present, it MUST be removed first
|
||||
new AntiTamperRemover(),
|
||||
|
||||
|
||||
@@ -52,5 +52,29 @@ namespace UnConfuserEx
|
||||
return Encoding.UTF8.GetByteCount(name) != name.Length
|
||||
|| (name.Any(c => InvalidChars.Contains(c)));
|
||||
}
|
||||
|
||||
public static int GetStoreLocalIndex(Instruction instr)
|
||||
{
|
||||
if (instr.OpCode == OpCodes.Stloc_S || instr.OpCode == OpCodes.Stloc)
|
||||
{
|
||||
return ((Local)instr.Operand).Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
return instr.OpCode.Code - Code.Stloc_0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetLoadLocalIndex(Instruction instr)
|
||||
{
|
||||
if (instr.OpCode == OpCodes.Ldloc_S || instr.OpCode == OpCodes.Ldloc)
|
||||
{
|
||||
return ((Local)instr.Operand).Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
return instr.OpCode.Code - Code.Ldloc_0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user