mirror of
https://github.com/MadMin3r/UnconfuserEx
synced 2026-06-23 09:25:19 +00:00
Fix minor issues with AntiTamper and Constants. Start work on dynamic/x86 Constants
This commit is contained in:
@@ -12,6 +12,7 @@ using UnConfuserEx.Protections;
|
||||
using System.IO;
|
||||
using UnConfuserEx.Protections.AntiTamper;
|
||||
using log4net;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace UnConfuserEx.Protections
|
||||
{
|
||||
@@ -198,17 +199,15 @@ namespace UnConfuserEx.Protections
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
int derivationLength = (lastInstr - firstInstr);
|
||||
|
||||
List<Instruction> derivation = new();
|
||||
for (int i = 0; i <= derivationLength; i++)
|
||||
for (int i = 0; i <= (lastInstr - firstInstr); i++)
|
||||
{
|
||||
derivation.Add(instrs[firstInstr + i]);
|
||||
}
|
||||
|
||||
// Normal deriver is 16 iterations of 10 instructions
|
||||
const int normalDeriationLength = 16 * 10;
|
||||
DeriverType type = (derivationLength == normalDeriationLength) ? DeriverType.Normal : DeriverType.Dynamic;
|
||||
DeriverType type = (derivation.Count == normalDeriationLength) ? DeriverType.Normal : DeriverType.Dynamic;
|
||||
return (type, derivation);
|
||||
}
|
||||
|
||||
@@ -216,18 +215,30 @@ namespace UnConfuserEx.Protections
|
||||
{
|
||||
var cctor = module.GlobalType.FindStaticConstructor();
|
||||
|
||||
if (cctor == null || !(cctor.HasBody) || cctor.Body.Instructions[0].OpCode != OpCodes.Call)
|
||||
if (cctor == null || !(cctor.HasBody))
|
||||
return null;
|
||||
|
||||
var method = cctor.Body.Instructions[0].Operand as MethodDef;
|
||||
IList<Instruction> instrs;
|
||||
|
||||
foreach (var instr in method!.Body.Instructions)
|
||||
// Check the first call in the cctor first
|
||||
if (cctor.Body.Instructions[0].OpCode == OpCodes.Call)
|
||||
{
|
||||
if (instr.Operand != null && instr.Operand.ToString()!.Contains("Marshal::GetHINSTANCE"))
|
||||
var method = cctor.Body.Instructions[0].Operand as MethodDef;
|
||||
|
||||
instrs = method!.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 2; i++)
|
||||
{
|
||||
return method;
|
||||
if (instrs[i].OpCode == OpCodes.Ldtoken &&
|
||||
instrs[i].Operand == module.GlobalType &&
|
||||
instrs[i + 1].OpCode == OpCodes.Call &&
|
||||
instrs[i + 1].Operand is MemberRef m &&
|
||||
m.Name == "GetTypeFromHandle")
|
||||
{
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -143,13 +143,14 @@ namespace UnConfuserEx.Protections
|
||||
resolver.Resolve(getter, instances.ToList());
|
||||
|
||||
Logger.Debug($"Removed all instances of getter ${getter.FullName}");
|
||||
//module.GlobalType.Remove(getter);
|
||||
}
|
||||
|
||||
module.GlobalType.Fields.Remove(dataField);
|
||||
|
||||
var cctor = module.GlobalType.FindStaticConstructor();
|
||||
|
||||
// Delete the encrypted data and decryption instructions
|
||||
if (initializeMethod == module.GlobalType.FindStaticConstructor())
|
||||
if (initializeMethod == cctor)
|
||||
{
|
||||
for (int i = 0; i < initializeMethod.Body.Instructions.Count; i++)
|
||||
{
|
||||
@@ -168,7 +169,9 @@ namespace UnConfuserEx.Protections
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Constants decryption not done in the static constructor!");
|
||||
cctor.Body.Instructions.RemoveAt(0);
|
||||
initializeMethod.Body.Instructions.Clear();
|
||||
initializeMethod.Body.Instructions.Add(new Instruction(OpCodes.Ret));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,120 @@
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Emit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace UnConfuserEx.Protections.Constants
|
||||
{
|
||||
internal interface IResolver
|
||||
internal abstract class IResolver
|
||||
{
|
||||
protected byte[]? data;
|
||||
|
||||
public void Resolve(MethodDef method, IList<MethodDef> instances);
|
||||
public abstract void Resolve(MethodDef method, IList<MethodDef> instances);
|
||||
|
||||
protected (int stringId, int numId, int objectId) GetIdsFromGetter(MethodDef getter)
|
||||
{
|
||||
var locals = getter.Body.Variables;
|
||||
var keyLocal = getter.Body.Variables.Locals[0];
|
||||
|
||||
var indices = getter.Body.Instructions
|
||||
.Where(i => i.IsLdloc() && i.GetLocal(locals) == keyLocal)
|
||||
.Select(i => getter.Body.Instructions.IndexOf(i) + 1).ToList();
|
||||
|
||||
var stringId = getter.Body.Instructions[indices[0]].GetLdcI4Value();
|
||||
var numId = getter.Body.Instructions[indices[1]].GetLdcI4Value();
|
||||
var objectId = getter.Body.Instructions[indices[2]].GetLdcI4Value();
|
||||
|
||||
return (stringId, numId, objectId);
|
||||
}
|
||||
|
||||
protected int GetNextInstanceInMethod(MethodDef getter, MethodDef method, out TypeSig? genericType)
|
||||
{
|
||||
var instrs = method.Body.Instructions;
|
||||
|
||||
for (int i = 0; i < instrs.Count; i++)
|
||||
{
|
||||
if (instrs[i].OpCode == OpCodes.Call &&
|
||||
instrs[i].Operand is MethodSpec ms &&
|
||||
ms.Method.ResolveMethodDef() is MethodDef md &&
|
||||
md.Equals(getter))
|
||||
{
|
||||
genericType = ms.GenericInstMethodSig.GenericArguments[0];
|
||||
|
||||
if (instrs[i - 1].IsBr() &&
|
||||
instrs[i - 1].Operand is Instruction target &&
|
||||
target == instrs[i])
|
||||
{
|
||||
method.Body.Instructions.RemoveAt(i - 1);
|
||||
i--;
|
||||
}
|
||||
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
genericType = null;
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected void FixStringConstant(MethodDef method, int instrOffset, int id)
|
||||
{
|
||||
uint count = (uint)(data![id] | (data[id + 1] << 8) | (data[id + 2] << 16) | (data[id + 3] << 24));
|
||||
//count = (count << 4) | (count >> 0x1C);
|
||||
string result = string.Intern(Encoding.UTF8.GetString(data, id + 4, (int)count));
|
||||
|
||||
method.Body.Instructions[instrOffset].OpCode = OpCodes.Ldstr;
|
||||
method.Body.Instructions[instrOffset].Operand = result;
|
||||
method.Body.Instructions.RemoveAt(instrOffset + 1);
|
||||
}
|
||||
|
||||
protected void FixNumberConstant(MethodDef method, int instrOffset, int id, TypeSig type)
|
||||
{
|
||||
switch (type.ElementType)
|
||||
{
|
||||
case ElementType.I4:
|
||||
FixNumberConstant<int>(method, instrOffset, id);
|
||||
method.Body.Instructions[instrOffset].OpCode = OpCodes.Ldc_I4;
|
||||
break;
|
||||
case ElementType.R8:
|
||||
FixNumberConstant<double>(method, instrOffset, id);
|
||||
method.Body.Instructions[instrOffset].OpCode = OpCodes.Ldc_R8;
|
||||
break;
|
||||
case ElementType.R4:
|
||||
FixNumberConstant<Single>(method, instrOffset, id);
|
||||
method.Body.Instructions[instrOffset].OpCode = OpCodes.Ldc_R4;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"Can't fix number constant. Type is {type.TypeName}");
|
||||
}
|
||||
}
|
||||
|
||||
protected void FixNumberConstant<T>(MethodDef method, int instrOffset, int id)
|
||||
{
|
||||
T[] array = new T[1];
|
||||
Buffer.BlockCopy(data!, id, array, 0, Marshal.SizeOf(default(T)));
|
||||
|
||||
method.Body.Instructions[instrOffset].Operand = array[0];
|
||||
method.Body.Instructions.RemoveAt(instrOffset + 1);
|
||||
}
|
||||
|
||||
protected void FixObjectConstant(MethodDef method, int instrOffset, int id, TypeSig type)
|
||||
{
|
||||
int num0 = data![id] | (data[id + 1] << 8) | (data[id + 2] << 16) | (data[id + 3] << 24);
|
||||
uint num1 = (uint)(data![id + 4] | (data[id + 5] << 8) | (data[id + 6] << 16) | (data[id + 7] << 24));
|
||||
num1 = (num1 << 4) | (num1 >> 0x1C);
|
||||
|
||||
throw new NotImplementedException("Object constant not handled");
|
||||
}
|
||||
|
||||
protected void FixDefaultConstant(MethodDef method, int instrOffset, TypeSig type)
|
||||
{
|
||||
method.Body.Instructions[instrOffset].OpCode = OpCodes.Initobj;
|
||||
method.Body.Instructions[instrOffset].Operand = type.ToTypeDefOrRef();
|
||||
method.Body.Instructions.RemoveAt(instrOffset + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,12 @@ namespace UnConfuserEx.Protections.Constants
|
||||
{
|
||||
private static ILog Logger = LogManager.GetLogger("Constants");
|
||||
|
||||
private byte[] data;
|
||||
|
||||
public NormalResolver(byte[] data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void Resolve(MethodDef getter, IList<MethodDef> instances)
|
||||
public override void Resolve(MethodDef getter, IList<MethodDef> instances)
|
||||
{
|
||||
var key1 = (int)getter.Body.Instructions[5].Operand;
|
||||
var key2 = (int)getter.Body.Instructions[7].Operand;
|
||||
@@ -78,99 +76,5 @@ namespace UnConfuserEx.Protections.Constants
|
||||
method.Body.UpdateInstructionOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
private int GetNextInstanceInMethod(MethodDef getter, MethodDef method, out TypeSig? genericType)
|
||||
{
|
||||
var instrs = method.Body.Instructions;
|
||||
|
||||
for (int i = 0; i < instrs.Count; i++)
|
||||
{
|
||||
if (instrs[i].OpCode == OpCodes.Call &&
|
||||
instrs[i].Operand is MethodSpec ms &&
|
||||
ms.Method.ResolveMethodDef() is MethodDef md &&
|
||||
md.Equals(getter) &&
|
||||
instrs[i - 1].IsLdcI4())
|
||||
{
|
||||
genericType = ms.GenericInstMethodSig.GenericArguments[0];
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
genericType = null;
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void FixStringConstant(MethodDef method, int instrOffset, int id)
|
||||
{
|
||||
uint count = (uint)(data![id] | (data[id + 1] << 8) | (data[id + 2] << 16) | (data[id + 3] << 24));
|
||||
count = (count << 4) | (count >> 0x1C);
|
||||
string result = string.Intern(Encoding.UTF8.GetString(data, id + 4, (int)count));
|
||||
|
||||
method.Body.Instructions[instrOffset].OpCode = OpCodes.Ldstr;
|
||||
method.Body.Instructions[instrOffset].Operand = result;
|
||||
method.Body.Instructions.RemoveAt(instrOffset + 1);
|
||||
}
|
||||
|
||||
private void FixNumberConstant(MethodDef method, int instrOffset, int id, TypeSig type)
|
||||
{
|
||||
switch (type.ElementType)
|
||||
{
|
||||
case ElementType.I4:
|
||||
FixNumberConstant<int>(method, instrOffset, id);
|
||||
method.Body.Instructions[instrOffset].OpCode = OpCodes.Ldc_I4;
|
||||
break;
|
||||
case ElementType.R8:
|
||||
FixNumberConstant<double>(method, instrOffset, id);
|
||||
method.Body.Instructions[instrOffset].OpCode = OpCodes.Ldc_R8;
|
||||
break;
|
||||
case ElementType.R4:
|
||||
FixNumberConstant<Single>(method, instrOffset, id);
|
||||
method.Body.Instructions[instrOffset].OpCode = OpCodes.Ldc_R4;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"Can't fix number constant. Type is {type.TypeName}");
|
||||
}
|
||||
}
|
||||
|
||||
private void FixNumberConstant<T>(MethodDef method, int instrOffset, int id)
|
||||
{
|
||||
T[] array = new T[1];
|
||||
Buffer.BlockCopy(data!, id, array, 0, Marshal.SizeOf(default(T)));
|
||||
|
||||
method.Body.Instructions[instrOffset].Operand = array[0];
|
||||
method.Body.Instructions.RemoveAt(instrOffset + 1);
|
||||
}
|
||||
|
||||
private void FixObjectConstant(MethodDef method, int instrOffset, int id, TypeSig type)
|
||||
{
|
||||
int num0 = data![id] | (data[id + 1] << 8) | (data[id + 2] << 16) | (data[id + 3] << 24);
|
||||
uint num1 = (uint)(data![id + 4] | (data[id + 5] << 8) | (data[id + 6] << 16) | (data[id + 7] << 24));
|
||||
num1 = (num1 << 4) | (num1 >> 0x1C);
|
||||
|
||||
throw new NotImplementedException("Object constant not handled");
|
||||
}
|
||||
|
||||
private void FixDefaultConstant(MethodDef method, int instrOffset, TypeSig type)
|
||||
{
|
||||
method.Body.Instructions[instrOffset].OpCode = OpCodes.Initobj;
|
||||
method.Body.Instructions[instrOffset].Operand = type.ToTypeDefOrRef();
|
||||
method.Body.Instructions.RemoveAt(instrOffset + 1);
|
||||
}
|
||||
|
||||
private (int stringId, int numId, int objectId) GetIdsFromGetter(MethodDef getter)
|
||||
{
|
||||
var locals = getter.Body.Variables;
|
||||
var keyLocal = getter.Body.Variables.Locals[0];
|
||||
|
||||
var indices = getter.Body.Instructions
|
||||
.Where(i => i.IsLdloc() && i.GetLocal(locals) == keyLocal)
|
||||
.Select(i => getter.Body.Instructions.IndexOf(i) + 1).ToList();
|
||||
|
||||
var stringId = getter.Body.Instructions[indices[0]].GetLdcI4Value();
|
||||
var numId = getter.Body.Instructions[indices[1]].GetLdcI4Value();
|
||||
var objectId = getter.Body.Instructions[indices[2]].GetLdcI4Value();
|
||||
|
||||
return (stringId, numId, objectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using dnlib.DotNet.Emit;
|
||||
using log4net;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using X86Emulator;
|
||||
|
||||
namespace UnConfuserEx.Protections.Constants
|
||||
@@ -12,46 +13,69 @@ namespace UnConfuserEx.Protections.Constants
|
||||
private static ILog Logger = LogManager.GetLogger("Constants");
|
||||
|
||||
private ModuleDefMD Module;
|
||||
private byte[] Data;
|
||||
|
||||
public X86Resolver(ModuleDefMD module, byte[] data)
|
||||
{
|
||||
Module = module;
|
||||
Data = data;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void Resolve(MethodDef getter, IList<MethodDef> instances)
|
||||
public override void Resolve(MethodDef getter, IList<MethodDef> instances)
|
||||
{
|
||||
var x86MethodDef = (MethodDef)getter.Body.Instructions[5].Operand;
|
||||
|
||||
var x86Method = new X86Method(Module, x86MethodDef);
|
||||
|
||||
var (stringId, numId, objectId) = GetIdsFromGetter(getter);
|
||||
|
||||
|
||||
foreach (var method in instances)
|
||||
{
|
||||
int id = -1;
|
||||
TypeSig? genericType = null;
|
||||
var instrs = method.Body.Instructions;
|
||||
for (int i = 0; i < instrs.Count; i++)
|
||||
if (ConstantsCFG.IsCFGPresent(method))
|
||||
{
|
||||
if (instrs[i].OpCode == OpCodes.Call
|
||||
&& instrs[i].Operand is MethodSpec m
|
||||
&& m.Method.ResolveMethodDef().Equals(getter))
|
||||
{
|
||||
id = (int)instrs[i - 1].Operand;
|
||||
genericType = m.GenericInstMethodSig.GenericArguments[0];
|
||||
break;
|
||||
}
|
||||
new ConstantsCFG(method).RemoveFromMethod();
|
||||
}
|
||||
|
||||
if (id == -1)
|
||||
throw new Exception("Failed to get ID for constant decryption");
|
||||
TypeSig? genericType;
|
||||
int instanceOffset = GetNextInstanceInMethod(getter, method, out genericType);
|
||||
|
||||
while (instanceOffset != -1)
|
||||
{
|
||||
var instrs = method.Body.Instructions;
|
||||
|
||||
var id = instrs[instanceOffset].GetLdcI4Value();
|
||||
id = x86Method.Emulate(new int[] { id });
|
||||
int type = (int)((uint)id >> 0x1e);
|
||||
id = (id & 0x3fffffff) << 2;
|
||||
|
||||
try
|
||||
{
|
||||
if (type == stringId)
|
||||
{
|
||||
FixStringConstant(method, instanceOffset, id);
|
||||
}
|
||||
else if (type == numId)
|
||||
{
|
||||
FixNumberConstant(method, instanceOffset, id, genericType!);
|
||||
}
|
||||
else if (type == objectId)
|
||||
{
|
||||
FixObjectConstant(method, instanceOffset, id, genericType!);
|
||||
}
|
||||
else
|
||||
{
|
||||
FixDefaultConstant(method, instanceOffset, genericType!);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"Failed to remove constants obfuscation from method ${method.FullName} ({ex.Message})");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
id = x86Method.Emulate(new int[] { id });
|
||||
var type = (int)((uint)id >> 0x1E);
|
||||
id = (id & 0x3FFFFFFF) << 2;
|
||||
instanceOffset = GetNextInstanceInMethod(getter, method, out genericType);
|
||||
}
|
||||
|
||||
Logger.Debug($"X86 Constant getter:\n\tid: {id}\n\ttype: {type}\n\tgenericType: {genericType}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user