added reference proxy protection

This commit is contained in:
yck1509 2014-03-09 23:01:34 +08:00
Родитель 65d1aff0d3
Коммит a10c2c8657
44 изменённых файлов: 1454 добавлений и 67 удалений

Просмотреть файл

@ -24,7 +24,8 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\Debug\bin\Confuser.CLI.XML</DocumentationFile>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -34,7 +35,8 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\Release\bin\Confuser.CLI.XML</DocumentationFile>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />

Просмотреть файл

@ -159,7 +159,7 @@ namespace Confuser.CLI
{
DateTime now = DateTime.Now;
string timeString = string.Format(
"at {0}, {1}:{2} elapsed.",
"at {0}, {1}:{2:d2} elapsed.",
now.ToShortTimeString(),
(int)now.Subtract(begin).TotalMinutes,
now.Subtract(begin).Seconds);

Просмотреть файл

@ -53,6 +53,7 @@
<Compile Include="ConfuserComponent.cs" />
<Compile Include="DnlibUtils.cs" />
<Compile Include="Helpers\InjectHelper.cs" />
<Compile Include="Helpers\MutationHelper.cs" />
<Compile Include="ILogger.cs" />
<Compile Include="Marker.cs" />
<Compile Include="MarkerResult.cs" />

Просмотреть файл

@ -125,6 +125,27 @@ namespace Confuser.Core
return fullName == "System.Delegate" || fullName == "System.MulticastDelegate";
}
/// <summary>
/// Determines whether the specified type is inherited from a base type in corlib.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="baseType">The full name of base type.</param>
/// <returns><c>true</c> if the specified type is inherited from a base type; otherwise, <c>false</c>.</returns>
public static bool InheritsFromCorlib(this TypeDef type, string baseType)
{
if (type.BaseType == null)
return false;
TypeDef bas = type;
do
{
bas = bas.BaseType.ResolveTypeDefThrow();
if (bas.ReflectionFullName == baseType)
return true;
} while (bas.BaseType != null && bas.BaseType.DefinitionAssembly.IsCorLib());
return false;
}
/// <summary>
/// Determines whether the specified type implements the specified interface.
/// </summary>

Просмотреть файл

@ -46,7 +46,7 @@ namespace Confuser.Core.Helpers
{
OriginModule = module;
TargetModule = target;
importer = new Importer(target);
importer = new Importer(target, ImporterOptions.TryToUseTypeDefs);
importer.Resolver = this;
}
@ -282,6 +282,20 @@ namespace Confuser.Core.Helpers
return (TypeDef)ctx.Map[typeDef];
}
/// <summary>
/// Injects the specified MethodDef to another module.
/// </summary>
/// <param name="methodDef">The source MethodDef.</param>
/// <param name="target">The target module.</param>
/// <returns>The injected MethodDef.</returns>
public static MethodDef Inject(MethodDef methodDef, ModuleDef target)
{
InjectContext ctx = new InjectContext(methodDef.Module, target);
ctx.Map[methodDef] = Clone(methodDef);
CopyMethodDef(methodDef, ctx);
return (MethodDef)ctx.Map[methodDef];
}
/// <summary>
/// Injects the members of specified TypeDef to another module.
/// </summary>

Просмотреть файл

@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Confuser.Core.Services;
namespace Confuser.Core.Helpers
{
/// <summary>
/// Provides methods to mutated injected methods.
/// </summary>
public static class MutationHelper
{
const string mutationType = "Mutation";
static Dictionary<string, int> field2index = new Dictionary<string, int>()
{
{ "KeyI0", 0 },
{ "KeyI1", 1 },
{ "KeyI2", 2 },
{ "KeyI3", 3 },
{ "KeyI4", 4 },
{ "KeyI5", 5 },
{ "KeyI6", 6 },
{ "KeyI7", 7 },
{ "KeyI8", 8 },
{ "KeyI9", 9 },
{ "KeyI10", 10 },
{ "KeyI11", 11 },
{ "KeyI12", 12 },
{ "KeyI13", 13 },
{ "KeyI14", 14 },
{ "KeyI15", 15 }
};
/// <summary>
/// Replaces the mutation key placeholder in method with actual key.
/// </summary>
/// <param name="method">The method to process.</param>
/// <param name="keyId">The mutation key ID.</param>
/// <param name="key">The actual key.</param>
public static void InjectKey(MethodDef method, int keyId, int key)
{
foreach (var instr in method.Body.Instructions)
{
if (instr.OpCode == OpCodes.Ldsfld)
{
IField field = (IField)instr.Operand;
int _keyId;
if (field.DeclaringType.FullName == mutationType &&
field2index.TryGetValue(field.Name, out _keyId) &&
_keyId == keyId)
{
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = key;
}
}
}
}
/// <summary>
/// Replaces the mutation key placeholders in method with actual keys.
/// </summary>
/// <param name="method">The method to process.</param>
/// <param name="keyId">The mutation key IDs.</param>
/// <param name="key">The actual keys.</param>
public static void InjectKeys(MethodDef method, int[] keyIds, int[] keys)
{
foreach (var instr in method.Body.Instructions)
{
if (instr.OpCode == OpCodes.Ldsfld)
{
IField field = (IField)instr.Operand;
int _keyIndex;
if (field.DeclaringType.FullName == mutationType &&
field2index.TryGetValue(field.Name, out _keyIndex) &&
(_keyIndex = Array.IndexOf(keyIds, _keyIndex)) != -1)
{
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = keys[_keyIndex];
}
}
}
}
/// <summary>
/// Replaces the placeholder call in method with actual instruction sequence.
/// </summary>
/// <param name="method">The methodto process.</param>
/// <param name="repl">The function replacing the argument of placeholder call with actual instruction sequence.</param>
public static void ReplacePlaceholder(MethodDef method, Func<Instruction[], Instruction[]> repl)
{
MethodTrace trace = new MethodTrace(method).Trace();
for (int i = 0; i < method.Body.Instructions.Count; i++)
{
var instr = method.Body.Instructions[i];
if (instr.OpCode == OpCodes.Call)
{
IMethod operand = (IMethod)instr.Operand;
if (operand.DeclaringType.FullName == mutationType &&
operand.Name == "Placeholder")
{
var argIndexes = trace.TraceArguments(instr);
if (argIndexes == null)
throw new ArgumentException("Failed to trace placeholder argument.");
var argIndex = argIndexes[0];
Instruction[] arg = method.Body.Instructions.Skip(argIndex).Take(i - argIndex).ToArray();
for (int j = 0; j < arg.Length; j++)
method.Body.Instructions.RemoveAt(argIndex);
method.Body.Instructions.RemoveAt(argIndex);
arg = repl(arg);
for (int j = arg.Length - 1; j >= 0; j--)
method.Body.Instructions.Insert(argIndex, arg[j]);
return;
}
}
}
}
}
}

Просмотреть файл

@ -116,7 +116,6 @@ namespace Confuser.Core
{
context.Logger.InfoFormat("Loading '{0}'...", module.Path);
ModuleDefMD modDef = module.Resolve(proj.BaseDirectory, context.Resolver.DefaultModuleContext);
modDef.EnableTypeDefFindCache = true;
var rules = ParseRules(proj, module, context);
context.Annotations.Set(modDef, SNKey, LoadSNKey(context, module.SNKeyPath, module.SNKeyPassword));

Просмотреть файл

@ -106,6 +106,19 @@ namespace Confuser.Core.Services
}
}
/// <summary>
/// Returns a random byte.
/// </summary>
/// <returns>Requested random byte.</returns>
public byte NextByte()
{
byte ret = state[32 - stateFilled];
stateFilled--;
if (stateFilled == 0)
NextState();
return ret;
}
/// <summary>
/// Gets a buffer of random bytes with the specified length.
/// </summary>
@ -126,6 +139,7 @@ namespace Confuser.Core.Services
{
return BitConverter.ToInt32(NextBytes(4), 0);
}
/// <summary>
/// Returns a nonnegative random integer that is less than the specified maximum.
/// </summary>
@ -135,6 +149,7 @@ namespace Confuser.Core.Services
{
return (int)(NextUInt32() % max);
}
/// <summary>
/// Returns a random integer that is within a specified range.
/// </summary>

Просмотреть файл

@ -27,7 +27,7 @@ namespace Confuser.Core.Services
{
if (method == null)
throw new ArgumentNullException("method");
return cache.GetValueOrDefaultLazy(method, m => cache[m] = new MethodTrace(this, m)).Trace();
return cache.GetValueOrDefaultLazy(method, m => cache[m] = new MethodTrace(m)).Trace();
}
}
@ -51,17 +51,14 @@ namespace Confuser.Core.Services
/// </summary>
public class MethodTrace
{
TraceService service;
MethodDef method;
/// <summary>
/// Initializes a new instance of the <see cref="MethodTrace"/> class.
/// </summary>
/// <param name="service">The trace service.</param>
/// <param name="method">The method to trace.</param>
internal MethodTrace(TraceService service, MethodDef method)
internal MethodTrace(MethodDef method)
{
this.service = service;
this.method = method;
}
@ -222,7 +219,7 @@ namespace Confuser.Core.Services
/// <exception cref="InvalidMethodException">The method body is invalid.</exception>
public int[] TraceArguments(Instruction instr)
{
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt)
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt && instr.OpCode.Code != Code.Newobj)
throw new ArgumentException("Invalid call instruction.", "instr");
int push, pop;
@ -259,12 +256,12 @@ namespace Confuser.Core.Services
index--;
}
if (index < 0)
throw new InvalidMethodException("Empty evaluation stack.");
return null;
if (beginInstrIndex == -1)
beginInstrIndex = index;
else if (beginInstrIndex != index)
throw new InvalidMethodException("Stack depth not matched.");
return null;
}
// Trace the index of arguments
@ -279,9 +276,9 @@ namespace Confuser.Core.Services
int index = tuple.Item1;
Stack<int> evalStack = tuple.Item2;
while (index != instrIndex)
while (index != instrIndex && index < method.Body.Instructions.Count)
{
Instruction currentInstr = method.Body.Instructions[index];
Instruction currentInstr = Instructions[index];
currentInstr.CalculateStackUsage(out push, out pop);
int stackUsage = pop - push;
if (stackUsage < 0)
@ -291,6 +288,9 @@ namespace Confuser.Core.Services
}
else
{
if (evalStack.Count < stackUsage)
return null;
for (int i = 0; i < stackUsage; i++)
evalStack.Pop();
}
@ -319,17 +319,17 @@ namespace Confuser.Core.Services
}
if (evalStack.Count != argCount)
throw new InvalidMethodException("Cannot find argument index.");
return null;
else if (ret != null && !evalStack.SequenceEqual(ret))
throw new InvalidMethodException("Stack depths mismatched.");
return null;
else
ret = evalStack.ToArray();
}
Array.Reverse(ret);
if (ret == null)
throw new InvalidMethodException("Cannot find argument index.");
return ret;
Array.Reverse(ret);
return ret;
}
}

Просмотреть файл

@ -38,7 +38,7 @@ namespace Confuser.DynCipher.Elements
break;
case CryptoNumOps.Mul:
Key = random.NextUInt32() | 1;
InverseKey = Utils.modInv(Key);
InverseKey = MathsUtils.modInv(Key);
break;
case CryptoNumOps.Xnor:
Key = random.NextUInt32();

Просмотреть файл

@ -51,7 +51,7 @@ namespace Confuser.DynCipher.Elements
Target = a
}).Emit(new AssignmentStatement()
{
Value = tmp * (LiteralExpression)Utils.modInv(Key),
Value = tmp * (LiteralExpression)MathsUtils.modInv(Key),
Target = b
});
}
@ -76,7 +76,7 @@ namespace Confuser.DynCipher.Elements
Target = a
}).Emit(new AssignmentStatement()
{
Value = (b & notMask) | (tmp * (LiteralExpression)Utils.modInv(Key)),
Value = (b & notMask) | (tmp * (LiteralExpression)MathsUtils.modInv(Key)),
Target = b
});
}

Просмотреть файл

@ -158,7 +158,7 @@ namespace Confuser.DynCipher.Generation
{
Debug.Assert(constExp is LiteralExpression);
uint val = ((LiteralExpression)constExp).Value;
val = Utils.modInv(val);
val = MathsUtils.modInv(val);
result = new BinOpExpression()
{
Operation = BinOps.Mul,

Просмотреть файл

@ -5,10 +5,10 @@ using System.Text;
namespace Confuser.DynCipher
{
static class Utils
public static class MathsUtils
{
const ulong MODULO32 = 0x100000000;
static ulong modInv(ulong num, ulong mod)
public static ulong modInv(ulong num, ulong mod)
{
ulong a = mod, b = num % mod;
ulong p0 = 0, p1 = 1;
@ -31,5 +31,10 @@ namespace Confuser.DynCipher
{
return (uint)modInv(num, MODULO32);
}
public static byte modInv(byte num)
{
return (byte)modInv(num, 0x100);
}
}
}

Просмотреть файл

@ -116,6 +116,9 @@ namespace Confuser.Protections
foreach (var member in members)
{
marker.Mark(member);
name.Analyze(member);
bool ren = true;
if (member is MethodDef)
{
@ -126,6 +129,7 @@ namespace Confuser.Protections
method.IsSpecialName = false;
else
ren = false;
var ca = method.CustomAttributes.Find(attrName);
if (ca != null)
ca.Constructor = attr.FindMethod(".ctor");
@ -146,9 +150,6 @@ namespace Confuser.Protections
member.Name = name.ObfuscateName(member.Name, RenameMode.Unicode);
name.SetCanRename(member, false);
}
marker.Mark(member);
name.Analyze(member);
}
}
}

Просмотреть файл

@ -49,7 +49,7 @@ namespace Confuser.Protections
public override ProtectionPreset Preset
{
get { return ProtectionPreset.Aggressive; }
get { return ProtectionPreset.Maximum; }
}
class AntiDumpPhase : ProtectionPhase

Просмотреть файл

@ -19,7 +19,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<OutputPath>..\Debug\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
@ -27,7 +27,7 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<OutputPath>..\Release\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
@ -57,8 +57,11 @@
<Compile Include="AntiDumpProtection.cs" />
<Compile Include="AntiDebugProtection.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReferenceProxy\NormalEncoding.cs" />
<Compile Include="ReferenceProxy\MildMode.cs" />
<Compile Include="ReferenceProxy\IRPEncoding.cs" />
<Compile Include="ReferenceProxy\IRPMode.cs" />
<Compile Include="ReferenceProxy\RPMode.cs" />
<Compile Include="ReferenceProxy\StrongMode.cs" />
<Compile Include="ReferenceProxy\ReferenceProxyPhase.cs" />
<Compile Include="ReferenceProxy\ReferenceProxyProtection.cs" />
<Compile Include="ReferenceProxy\RPContext.cs" />

Просмотреть файл

@ -56,9 +56,29 @@ namespace Confuser.Protections.ControlFlow
break;
case 2: // Take that, de4dot + ILSpy :)
instrs.Add(Instruction.Create(OpCodes.Ldc_I4, Random.NextBoolean() ? 0 : 1));
instrs.Add(Instruction.Create(OpCodes.Box, Method.Module.CorLibTypes.Int32.TypeDefOrRef));
bool addDefOk = false;
if (Random.NextBoolean())
{
TypeDef randomType;
randomType = Method.Module.Types[Random.NextInt32(Method.Module.Types.Count)];
if (randomType.HasMethods)
{
instrs.Add(Instruction.Create(OpCodes.Ldtoken, randomType.Methods[Random.NextInt32(randomType.Methods.Count)]));
instrs.Add(Instruction.Create(OpCodes.Box, Method.Module.CorLibTypes.GetTypeRef("System", "RuntimeMethodHandle")));
addDefOk = true;
}
}
if (!addDefOk)
{
instrs.Add(Instruction.Create(OpCodes.Ldc_I4, Random.NextBoolean() ? 0 : 1));
instrs.Add(Instruction.Create(OpCodes.Box, Method.Module.CorLibTypes.Int32.TypeDefOrRef));
}
var pop = Instruction.Create(OpCodes.Pop);
instrs.Add(Instruction.Create(OpCodes.Brfalse, instrs[0]));
instrs.Add(Instruction.Create(OpCodes.Ldc_I4, Random.NextBoolean() ? 0 : 1));
instrs.Add(pop);
break;
}
}
@ -89,6 +109,7 @@ namespace Confuser.Protections.ControlFlow
instrs.Add(Instruction.Create(OpCodes.Ldloc, new Local(null) { Index = 0xff }));
break;
case 5:
instrs.Add(Instruction.Create(OpCodes.Ldtoken, Method));
break;
}
}

Просмотреть файл

@ -8,6 +8,8 @@ using dnlib.DotNet.Emit;
using Confuser.Core.Services;
using Confuser.DynCipher;
using Confuser.Renamer;
using dnlib.DotNet.Writer;
using System.Diagnostics;
namespace Confuser.Protections.ControlFlow
{
@ -23,7 +25,7 @@ namespace Confuser.Protections.ControlFlow
get { return ProtectionTargets.Methods; }
}
static CFContext ParseParameters(MethodDef method, ConfuserContext context, ProtectionParameters parameters, RandomGenerator random)
static CFContext ParseParameters(MethodDef method, ConfuserContext context, ProtectionParameters parameters, RandomGenerator random, bool disableOpti)
{
CFContext ret = new CFContext();
ret.Type = parameters.GetParameter<CFType>(context, method, "type", CFType.Switch);
@ -31,9 +33,9 @@ namespace Confuser.Protections.ControlFlow
int rawIntensity = parameters.GetParameter<int>(context, method, "intensity", 60);
ret.Intensity = rawIntensity / 100.0;
ret.Depth = parameters.GetParameter<int>(context, method, "depth", 5);
ret.Depth = parameters.GetParameter<int>(context, method, "depth", 4);
ret.JunkCode = parameters.GetParameter<bool>(context, method, "junk", false);
ret.JunkCode = parameters.GetParameter<bool>(context, method, "junk", false) && !disableOpti;
ret.Random = random;
ret.Method = method;
@ -43,16 +45,38 @@ namespace Confuser.Protections.ControlFlow
return ret;
}
static bool DisabledOptimization(ModuleDef module)
{
bool disableOpti = false;
var debugAttr = module.Assembly.CustomAttributes.Find("System.Diagnostics.DebuggableAttribute");
if (debugAttr != null)
{
if (debugAttr.ConstructorArguments.Count == 1)
disableOpti |= ((DebuggableAttribute.DebuggingModes)(int)debugAttr.ConstructorArguments[0].Value & DebuggableAttribute.DebuggingModes.DisableOptimizations) != 0;
else
disableOpti |= (bool)debugAttr.ConstructorArguments[1].Value;
}
debugAttr = module.CustomAttributes.Find("System.Diagnostics.DebuggableAttribute");
if (debugAttr != null)
{
if (debugAttr.ConstructorArguments.Count == 1)
disableOpti |= ((DebuggableAttribute.DebuggingModes)(int)debugAttr.ConstructorArguments[0].Value & DebuggableAttribute.DebuggingModes.DisableOptimizations) != 0;
else
disableOpti |= (bool)debugAttr.ConstructorArguments[1].Value;
}
return disableOpti;
}
protected override void Execute(ConfuserContext context, ProtectionParameters parameters)
{
bool disabledOpti = DisabledOptimization(context.CurrentModule);
var random = context.Registry.GetService<IRandomService>().GetRandomGenerator(ControlFlowProtection._FullId);
foreach (var method in parameters.Targets.OfType<MethodDef>())
if (method.HasBody && method.Body.Instructions.Count > 0)
{
ProcessMethod(method.Body, ParseParameters(method, context, parameters, random));
ProcessMethod(method.Body, ParseParameters(method, context, parameters, random, disabledOpti));
}
context.CurrentModuleWriterOptions.MetaDataOptions.Flags |= dnlib.DotNet.Writer.MetaDataFlags.KeepOldMaxStack;
}
static readonly JumpMangler Jump = new JumpMangler();
@ -68,6 +92,13 @@ namespace Confuser.Protections.ControlFlow
void ProcessMethod(CilBody body, CFContext ctx)
{
uint maxStack;
if (!MaxStackCalculator.GetMaxStack(body.Instructions, body.ExceptionHandlers, out maxStack))
{
ctx.Context.Logger.Error("Failed to calcuate maxstack.");
throw new ConfuserException(null);
}
body.MaxStack = (ushort)maxStack;
ScopeBlock root = BlockParser.ParseBody(body);
GetMangler(ctx.Type).Mangle(body, root, ctx);
@ -79,6 +110,7 @@ namespace Confuser.Protections.ControlFlow
eh.TryEnd = body.Instructions[body.Instructions.IndexOf(eh.TryEnd) + 1];
eh.HandlerEnd = body.Instructions[body.Instructions.IndexOf(eh.HandlerEnd) + 1];
}
body.KeepOldMaxStack = true;
}
}
}

Просмотреть файл

@ -8,7 +8,12 @@ using Confuser.Protections.ControlFlow;
namespace Confuser.Protections
{
class ControlFlowProtection : Protection
public interface IControlFlowService
{
void ExcludeMethod(ConfuserContext context, MethodDef method);
}
class ControlFlowProtection : Protection, IControlFlowService
{
public const string _Id = "ctrl flow";
public const string _FullId = "Ki.ControlFlow";
@ -16,7 +21,7 @@ namespace Confuser.Protections
protected override void Initialize(ConfuserContext context)
{
//
context.Registry.RegisterService(_ServiceId, typeof(IControlFlowService), this);
}
protected override void PopulatePipeline(ProtectionPipeline pipeline)
@ -48,5 +53,10 @@ namespace Confuser.Protections
{
get { return ProtectionPreset.Normal; }
}
public void ExcludeMethod(ConfuserContext context, MethodDef method)
{
ProtectionParameters.GetParameters(context, method).Remove(this);
}
}
}

Просмотреть файл

@ -58,6 +58,7 @@ namespace Confuser.Protections.ControlFlow
invCompiled = new List<Instruction>();
new CodeGen(stateVar, ctx, invCompiled).GenerateCIL(inverse);
body.MaxStack += (ushort)ctx.Depth;
}
bool inited = false;

Просмотреть файл

@ -73,7 +73,7 @@ namespace Confuser.Protections.ControlFlow
{
MethodTrace trace = ctx.Context.Registry.GetService<ITraceService>().Trace(ctx.Method);
body.MaxStack++;
body.MaxStack += 2;
IPredicate predicate = null;
if (ctx.Predicate == PredicateType.Expression)
predicate = new ExpressionPredicate(ctx);

Просмотреть файл

@ -33,9 +33,12 @@ namespace Confuser.Protections.ControlFlow
Variable result = new Variable("{RESULT}");
var int32 = ctx.Method.Module.CorLibTypes.Int32;
native = new MethodDefUser(ctx.Context.Registry.GetService<INameService>().RandomName(), MethodSig.CreateStatic(int32, int32),
MethodAttributes.PinvokeImpl | MethodAttributes.PrivateScope | MethodAttributes.Static);
native = new MethodDefUser(ctx.Context.Registry.GetService<INameService>().RandomName(), MethodSig.CreateStatic(int32, int32), MethodAttributes.PinvokeImpl | MethodAttributes.PrivateScope | MethodAttributes.Static);
native.ImplAttributes = MethodImplAttributes.Native | MethodImplAttributes.Unmanaged | MethodImplAttributes.PreserveSig;
// Attempt to improve performance --- failed with StackOverflowException... :/
//var suppressAttr = ctx.Method.Module.CorLibTypes.GetTypeRef("System.Security", "SuppressUnmanagedCodeSecurityAttribute").ResolveThrow();
//native.CustomAttributes.Add(new CustomAttribute((MemberRef)ctx.Method.Module.Import(suppressAttr.FindDefaultConstructor())));
//native.HasSecurity = true;
ctx.Method.Module.GlobalType.Methods.Add(native);
ctx.Context.Registry.GetService<IMarkerService>().Mark(native);

Просмотреть файл

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using dnlib.DotNet.Emit;
using dnlib.DotNet;
namespace Confuser.Protections.ReferenceProxy
{
interface IRPEncoding
{
Instruction[] EmitDecode(MethodDef init, RPContext ctx, Instruction[] arg);
int Encode(MethodDef init, RPContext ctx, int value);
}
}

Просмотреть файл

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using dnlib.DotNet.Emit;
using dnlib.DotNet;
using System.Diagnostics;
using Confuser.Core;
using Confuser.Core.Services;
using Confuser.Renamer;
namespace Confuser.Protections.ReferenceProxy
{
class MildMode : RPMode
{
// proxy method, { opCode, calling type, target method}
Dictionary<Tuple<Code, TypeDef, IMethod>, MethodDef> proxies = new Dictionary<Tuple<Code, TypeDef, IMethod>, MethodDef>();
public override void ProcessCall(RPContext ctx, int instrIndex)
{
Instruction invoke = ctx.Body.Instructions[instrIndex];
IMethod target = (IMethod)invoke.Operand;
// Value type proxy is not supported in mild mode.
if (target.DeclaringType.ResolveTypeDefThrow().IsValueType)
return;
// Skipping visibility is not supported in mild mode.
if (!target.ResolveThrow().IsPublic && !target.ResolveThrow().IsAssembly)
return;
var key = Tuple.Create(invoke.OpCode.Code, ctx.Method.DeclaringType, target);
MethodDef proxy;
if (!proxies.TryGetValue(key, out proxy))
{
MethodSig sig = CreateProxySignature(ctx, target, invoke.OpCode.Code == Code.Newobj);
proxy = new MethodDefUser(ctx.Name.RandomName(), sig);
proxy.Attributes = MethodAttributes.PrivateScope | MethodAttributes.Static;
proxy.ImplAttributes = MethodImplAttributes.Managed | MethodImplAttributes.IL;
ctx.Method.DeclaringType.Methods.Add(proxy);
// Fix peverify --- Non-virtual call to virtual methods must be done on this pointer
if (invoke.OpCode.Code == Code.Call && target.ResolveThrow().IsVirtual)
{
proxy.IsStatic = false;
sig.HasThis = true;
sig.Params.RemoveAt(0);
}
ctx.Marker.Mark(proxy);
ctx.Name.Analyze(proxy);
ctx.Name.SetCanRename(proxy, false);
proxy.Body = new CilBody();
for (int i = 0; i < proxy.Parameters.Count; i++)
proxy.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg, proxy.Parameters[i]));
proxy.Body.Instructions.Add(Instruction.Create(invoke.OpCode, target));
proxy.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
proxies[key] = proxy;
}
invoke.OpCode = OpCodes.Call;
if (ctx.Method.DeclaringType.HasGenericParameters)
{
var genArgs = new GenericVar[ctx.Method.DeclaringType.GenericParameters.Count];
for (int i = 0; i < genArgs.Length; i++)
genArgs[i] = new GenericVar(i);
invoke.Operand = new MemberRefUser(
ctx.Module,
proxy.Name,
proxy.MethodSig,
new GenericInstSig((ClassOrValueTypeSig)ctx.Method.DeclaringType.ToTypeSig(), genArgs).ToTypeDefOrRef());
}
else
invoke.Operand = proxy;
}
public override void Finalize(RPContext ctx)
{
}
}
}

Просмотреть файл

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using dnlib.DotNet.Emit;
using dnlib.DotNet;
using Confuser.Core;
using Confuser.Core.Services;
using Confuser.DynCipher;
namespace Confuser.Protections.ReferenceProxy
{
class NormalEncoding : IRPEncoding
{
Dictionary<MethodDef, Tuple<int, int>> keys = new Dictionary<MethodDef, Tuple<int, int>>();
Tuple<int, int> GetKey(RandomGenerator random, MethodDef init)
{
Tuple<int, int> ret;
if (!keys.TryGetValue(init, out ret))
{
int key = random.NextInt32() | 1;
keys[init] = ret = Tuple.Create(key, (int)MathsUtils.modInv((uint)key));
}
return ret;
}
public Instruction[] EmitDecode(MethodDef init, RPContext ctx, Instruction[] arg)
{
var key = GetKey(ctx.Random, init);
List<Instruction> ret = new List<Instruction>();
if (ctx.Random.NextBoolean())
{
ret.Add(Instruction.Create(OpCodes.Ldc_I4, key.Item1));
ret.AddRange(arg);
}
else
{
ret.AddRange(arg);
ret.Add(Instruction.Create(OpCodes.Ldc_I4, key.Item1));
}
ret.Add(Instruction.Create(OpCodes.Mul));
return ret.ToArray();
}
public int Encode(MethodDef init, RPContext ctx, int value)
{
var key = GetKey(ctx.Random, init);
return value * key.Item2;
}
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Confuser.Core.Services;
using Confuser.Core;
using dnlib.DotNet;
using Confuser.DynCipher;
using dnlib.DotNet.Emit;
using Confuser.Renamer;
namespace Confuser.Protections.ReferenceProxy
{
enum Mode
{
Mild,
Strong,
Ftn
}
enum EncodingType
{
Normal,
Expression,
x86
}
class RPContext
{
public RandomGenerator Random;
public ConfuserContext Context;
public ModuleDef Module;
public MethodDef Method;
public HashSet<Instruction> BranchTargets;
public CilBody Body;
public IMarkerService Marker;
public IDynCipherService DynCipher;
public INameService Name;
public Mode Mode;
public EncodingType Encoding;
public bool TypeErasure;
public bool InternalAlso;
public RPMode ModeHandler;
public IRPEncoding EncodingHandler;
public Dictionary<MethodSig, TypeDef> Delegates;
}
}

Просмотреть файл

@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using dnlib.DotNet.Emit;
using dnlib.DotNet;
using System.Diagnostics;
using Confuser.Core;
using Confuser.Renamer.References;
namespace Confuser.Protections.ReferenceProxy
{
abstract class RPMode
{
public abstract void ProcessCall(RPContext ctx, int instrIndex);
public abstract void Finalize(RPContext ctx);
static ITypeDefOrRef Import(RPContext ctx, TypeDef typeDef)
{
var retTypeRef = new Importer(ctx.Module, ImporterOptions.TryToUseTypeDefs).Import(typeDef);
if (typeDef.Module != ctx.Module && ctx.Context.Modules.Contains((ModuleDefMD)typeDef.Module))
ctx.Name.AddReference(typeDef, new TypeRefReference((TypeRef)retTypeRef, typeDef));
return retTypeRef;
}
protected static MethodSig CreateProxySignature(RPContext ctx, IMethod method, bool newObj)
{
var module = ctx.Module;
if (newObj)
{
Debug.Assert(method.MethodSig.HasThis);
Debug.Assert(method.Name == ".ctor");
TypeSig[] paramTypes = method.MethodSig.Params.Select(type =>
{
if (ctx.TypeErasure && type.IsClassSig && method.MethodSig.HasThis)
return module.CorLibTypes.Object;
return type;
}).ToArray();
TypeSig retType;
if (ctx.TypeErasure) // newobj will not be used with value types
retType = module.CorLibTypes.Object;
else
{
var declType = method.DeclaringType.ResolveTypeDefThrow();
retType = Import(ctx, declType).ToTypeSig();
}
return MethodSig.CreateStatic(retType, paramTypes);
}
else
{
var paramTypes = method.MethodSig.Params.Select(type =>
{
if (ctx.TypeErasure && type.IsClassSig && method.MethodSig.HasThis)
return module.CorLibTypes.Object;
return type;
});
if (method.MethodSig.HasThis && !method.MethodSig.ExplicitThis)
{
var declType = method.DeclaringType.ResolveTypeDefThrow();
if (ctx.TypeErasure && !declType.IsValueType)
paramTypes = new[] { module.CorLibTypes.Object }.Concat(paramTypes);
else
paramTypes = new[] { Import(ctx, declType).ToTypeSig() }.Concat(paramTypes);
}
TypeSig retType = method.MethodSig.RetType;
if (ctx.TypeErasure && retType.IsClassSig)
retType = module.CorLibTypes.Object;
return MethodSig.CreateStatic(retType, paramTypes.ToArray());
}
}
protected static TypeDef GetDelegateType(RPContext ctx, MethodSig sig)
{
TypeDef ret;
if (ctx.Delegates.TryGetValue(sig, out ret))
return ret;
ret = new TypeDefUser(ctx.Name.ObfuscateName(ctx.Method.DeclaringType.Namespace, Renamer.RenameMode.Unicode), ctx.Name.RandomName(), ctx.Module.CorLibTypes.GetTypeRef("System", "MulticastDelegate"));
ret.Attributes = TypeAttributes.NotPublic | TypeAttributes.Sealed;
var ctor = new MethodDefUser(".ctor", MethodSig.CreateInstance(ctx.Module.CorLibTypes.Void, ctx.Module.CorLibTypes.Object, ctx.Module.CorLibTypes.IntPtr));
ctor.Attributes = MethodAttributes.Assembly | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName;
ctor.ImplAttributes = MethodImplAttributes.Runtime;
ret.Methods.Add(ctor);
var invoke = new MethodDefUser("Invoke", sig.Clone());
invoke.MethodSig.HasThis = true;
invoke.Attributes = MethodAttributes.Assembly | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot;
invoke.ImplAttributes = MethodImplAttributes.Runtime;
ret.Methods.Add(invoke);
ctx.Module.Types.Add(ret);
foreach (var def in ret.FindDefinitions())
{
ctx.Marker.Mark(def);
ctx.Name.SetCanRename(def, false);
}
ctx.Delegates[sig] = ret;
return ret;
}
}
}

Просмотреть файл

@ -0,0 +1,174 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Confuser.Core;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Confuser.Core.Services;
using Confuser.Renamer;
using Confuser.DynCipher;
namespace Confuser.Protections.ReferenceProxy
{
class ReferenceProxyPhase : ProtectionPhase
{
public ReferenceProxyPhase(ReferenceProxyProtection parent)
: base(parent)
{
}
public override ProtectionTargets Targets
{
get { return ProtectionTargets.Methods; }
}
class RPStore
{
public RandomGenerator random;
public MildMode mild;
public StrongMode strong;
public NormalEncoding normal;
class MethodSigComparer : IEqualityComparer<MethodSig>
{
public bool Equals(MethodSig x, MethodSig y)
{
return new SigComparer().Equals(x, y);
}
public int GetHashCode(MethodSig obj)
{
return new SigComparer().GetHashCode(obj);
}
}
public Dictionary<MethodSig, TypeDef> delegates = new Dictionary<MethodSig, TypeDef>(new MethodSigComparer());
}
static RPContext ParseParameters(MethodDef method, ConfuserContext context, ProtectionParameters parameters, RPStore store)
{
RPContext ret = new RPContext();
ret.Mode = parameters.GetParameter<Mode>(context, method, "mode", Mode.Mild);
ret.Encoding = parameters.GetParameter<EncodingType>(context, method, "encoding", EncodingType.Normal);
ret.InternalAlso = parameters.GetParameter<bool>(context, method, "internal", false);
ret.TypeErasure = parameters.GetParameter<bool>(context, method, "typeErasure", false);
ret.Module = method.Module;
ret.Method = method;
ret.Body = method.Body;
ret.BranchTargets = new HashSet<Instruction>(
method.Body.Instructions
.Select(instr => instr.Operand as Instruction)
.Concat(method.Body.Instructions
.Where(instr => instr.Operand is Instruction[])
.SelectMany(instr => (Instruction[])instr.Operand))
.Where(target => target != null));
ret.Random = store.random;
ret.Context = context;
ret.Marker = context.Registry.GetService<IMarkerService>();
ret.DynCipher = context.Registry.GetService<IDynCipherService>();
ret.Name = context.Registry.GetService<INameService>();
ret.Delegates = store.delegates;
switch (ret.Mode)
{
case Mode.Mild:
ret.ModeHandler = store.mild ?? (store.mild = new MildMode());
break;
case Mode.Strong:
ret.ModeHandler = store.strong ?? (store.strong = new StrongMode());
break;
default:
throw new UnreachableException();
}
switch (ret.Encoding)
{
case EncodingType.Normal:
ret.EncodingHandler = store.normal ?? (store.normal = new NormalEncoding());
break;
default:
throw new UnreachableException();
}
return ret;
}
static RPContext ParseParameters(ModuleDef module, ConfuserContext context, ProtectionParameters parameters, RPStore store)
{
RPContext ret = new RPContext();
ret.Random = store.random;
ret.Module = module;
ret.Context = context;
ret.Marker = context.Registry.GetService<IMarkerService>();
ret.DynCipher = context.Registry.GetService<IDynCipherService>();
ret.Name = context.Registry.GetService<INameService>();
ret.Delegates = store.delegates;
return ret;
}
protected override void Execute(ConfuserContext context, ProtectionParameters parameters)
{
var random = context.Registry.GetService<IRandomService>().GetRandomGenerator(ReferenceProxyProtection._FullId);
RPStore store = new RPStore() { random = random };
foreach (var method in parameters.Targets.OfType<MethodDef>())
if (method.HasBody && method.Body.Instructions.Count > 0)
{
ProcessMethod(ParseParameters(method, context, parameters, store));
}
var ctx = ParseParameters(context.CurrentModule, context, parameters, store);
if (store.mild != null)
store.mild.Finalize(ctx);
if (store.strong != null)
store.strong.Finalize(ctx);
}
void ProcessMethod(RPContext ctx)
{
for (int i = 0; i < ctx.Body.Instructions.Count; i++)
{
var instr = ctx.Body.Instructions[i];
if (instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt || instr.OpCode.Code == Code.Newobj)
{
IMethod operand = (IMethod)instr.Operand;
// Call constructor
if (instr.OpCode.Code != Code.Newobj && operand.Name == ".ctor")
continue;
// Internal reference option
if (operand is MethodDef && !ctx.InternalAlso)
continue;
// No generic methods
if (operand is MethodSpec)
continue;
// No generic types / array types
if (operand.DeclaringType is TypeSpec)
continue;
var declType = operand.DeclaringType.ResolveTypeDefThrow();
// No delegates
if (declType.IsDelegate())
continue;
// No instance value type methods
if (declType.IsValueType && operand.MethodSig.HasThis)
return;
// No prefixed call
if (i - 1 >= 0 && ctx.Body.Instructions[i - 1].OpCode.OpCodeType == OpCodeType.Prefix)
continue;
ctx.ModeHandler.ProcessCall(ctx, i);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Confuser.Core;
using dnlib.DotNet;
using Confuser.Protections.ReferenceProxy;
namespace Confuser.Protections
{
public interface IReferenceProxyService
{
void ExcludeMethod(ConfuserContext context, MethodDef method);
}
[AfterProtection("Ki.AntiDebug", "Ki.AntiDump")]
[BeforeProtection("Ki.ControlFlow")]
class ReferenceProxyProtection : Protection, IReferenceProxyService
{
public const string _Id = "ref proxy";
public const string _FullId = "Ki.RefProxy";
public const string _ServiceId = "Ki.RefProxy";
protected override void Initialize(ConfuserContext context)
{
context.Registry.RegisterService(_ServiceId, typeof(IReferenceProxyService), this);
}
protected override void PopulatePipeline(ProtectionPipeline pipeline)
{
pipeline.InsertPostStage(PipelineStage.BeginModule, new ReferenceProxyPhase(this));
}
public override string Name
{
get { return "Reference Proxy Protection"; }
}
public override string Description
{
get { return "This protection encodes and hides references to type/method/fields."; }
}
public override string Id
{
get { return _Id; }
}
public override string FullId
{
get { return _FullId; }
}
public override ProtectionPreset Preset
{
get { return ProtectionPreset.Normal; }
}
public void ExcludeMethod(ConfuserContext context, MethodDef method)
{
ProtectionParameters.GetParameters(context, method).Remove(this);
}
}
}

Просмотреть файл

@ -0,0 +1,451 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using dnlib.DotNet.Emit;
using dnlib.DotNet;
using Confuser.Core.Services;
using System.Diagnostics;
using Confuser.Core;
using Confuser.Renamer;
using Confuser.Core.Helpers;
using Confuser.DynCipher.AST;
using Confuser.DynCipher.Generation;
using dnlib.DotNet.Writer;
using Confuser.DynCipher;
namespace Confuser.Protections.ReferenceProxy
{
class StrongMode : RPMode
{
static int? TraceBeginning(RPContext ctx, int index, int argCount)
{
if (ctx.BranchTargets.Contains(ctx.Body.Instructions[index]))
return null;
int currentStack = argCount;
int currentIndex = index;
while (currentStack > 0)
{
currentIndex--;
Instruction currentInstr = ctx.Body.Instructions[currentIndex];
// Disrupt stack analysis :/ Used by array initializer
if (currentInstr.OpCode == OpCodes.Pop || currentInstr.OpCode == OpCodes.Dup)
return null;
// No branch instr.
switch (currentInstr.OpCode.FlowControl)
{
case FlowControl.Call:
case FlowControl.Break:
case FlowControl.Meta:
case FlowControl.Next:
break;
default:
return null;
}
int push, pop;
currentInstr.CalculateStackUsage(out push, out pop);
currentStack += pop;
currentStack -= push;
// No branch target
if (ctx.BranchTargets.Contains(currentInstr) && currentStack != 0)
return null;
}
if (currentStack < 0)
return null;
return currentIndex;
}
public override void ProcessCall(RPContext ctx, int instrIndex)
{
Instruction invoke = ctx.Body.Instructions[instrIndex];
var declType = ((IMethod)invoke.Operand).DeclaringType.ResolveTypeDefThrow();
if (!declType.Module.IsILOnly) // Reflection doesn't like mixed mode modules.
return;
if (declType.IsGlobalModuleType) // Reflection doesn't like global methods too.
return;
int push, pop;
invoke.CalculateStackUsage(out push, out pop);
int? begin = TraceBeginning(ctx, instrIndex, pop);
// Fail to trace the arguments => fall back to bridge method
bool fallBack = begin == null;
if (fallBack)
{
ProcessBridge(ctx, instrIndex);
}
else
{
ProcessInvoke(ctx, instrIndex, begin.Value);
}
}
// { key attribute, encoding }
Tuple<TypeDef, Func<int, int>>[] keyAttrs;
// { invoke opCode, invoke target, encoding}, { proxy field, bridge method }
Dictionary<Tuple<Code, IMethod, IRPEncoding>, Tuple<FieldDef, MethodDef>> fields = new Dictionary<Tuple<Code, IMethod, IRPEncoding>, Tuple<FieldDef, MethodDef>>();
class InitMethodDesc
{
public MethodDef Method;
public int[] TokenNameOrder;
public int[] TokenByteOrder;
public int OpCodeIndex;
public IRPEncoding Encoding;
}
Dictionary<IRPEncoding, InitMethodDesc[]> inits = new Dictionary<IRPEncoding, InitMethodDesc[]>();
void ProcessBridge(RPContext ctx, int instrIndex)
{
var instr = ctx.Body.Instructions[instrIndex];
IMethod target = (IMethod)instr.Operand;
var declType = target.DeclaringType.ResolveTypeDefThrow();
if (!declType.Module.IsILOnly) // Reflection doesn't like mixed mode modules.
return;
if (declType.IsGlobalModuleType) // Reflection doesn't like global methods too.
return;
var key = Tuple.Create(instr.OpCode.Code, target, ctx.EncodingHandler);
Tuple<FieldDef, MethodDef> proxy;
if (fields.TryGetValue(key, out proxy))
{
if (proxy.Item2 != null)
{
instr.OpCode = OpCodes.Call;
instr.Operand = proxy.Item2;
return;
}
}
else
proxy = new Tuple<FieldDef, MethodDef>(null, null);
MethodSig sig = CreateProxySignature(ctx, target, instr.OpCode.Code == Code.Newobj);
var delegateType = GetDelegateType(ctx, sig);
// Create proxy field
if (proxy.Item1 == null)
proxy.Item1 = CreateField(ctx, delegateType);
// Create proxy bridge
Debug.Assert(proxy.Item2 == null);
proxy.Item2 = CreateBridge(ctx, delegateType, proxy.Item1, sig);
fields[key] = proxy;
// Replace instruction
instr.OpCode = OpCodes.Call;
instr.Operand = proxy.Item2;
}
void ProcessInvoke(RPContext ctx, int instrIndex, int argBeginIndex)
{
var instr = ctx.Body.Instructions[instrIndex];
IMethod target = (IMethod)instr.Operand;
MethodSig sig = CreateProxySignature(ctx, target, instr.OpCode.Code == Code.Newobj);
var delegateType = GetDelegateType(ctx, sig);
var key = Tuple.Create(instr.OpCode.Code, target, ctx.EncodingHandler);
Tuple<FieldDef, MethodDef> proxy;
if (!fields.TryGetValue(key, out proxy))
{
// Create proxy field
proxy = new Tuple<FieldDef, MethodDef>(CreateField(ctx, delegateType), null);
fields[key] = proxy;
}
// Insert field load & replace instruction
if (argBeginIndex == instrIndex)
{
ctx.Body.Instructions.Insert(instrIndex + 1,
new Instruction(OpCodes.Call, delegateType.FindMethod("Invoke")));
instr.OpCode = OpCodes.Ldsfld;
instr.Operand = proxy.Item1;
}
else
{
var argBegin = ctx.Body.Instructions[argBeginIndex];
ctx.Body.Instructions.Insert(argBeginIndex + 1,
new Instruction(argBegin.OpCode, argBegin.Operand));
argBegin.OpCode = OpCodes.Ldsfld;
argBegin.Operand = proxy.Item1;
instr.OpCode = OpCodes.Call;
instr.Operand = delegateType.FindMethod("Invoke");
}
}
MethodDef CreateBridge(RPContext ctx, TypeDef delegateType, FieldDef field, MethodSig sig)
{
var method = new MethodDefUser(ctx.Name.RandomName(), sig);
method.Attributes = MethodAttributes.PrivateScope | MethodAttributes.Static;
method.ImplAttributes = MethodImplAttributes.Managed | MethodImplAttributes.IL;
method.Body = new CilBody();
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, field));
for (int i = 0; i < method.Parameters.Count; i++)
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg, method.Parameters[i]));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Call, delegateType.FindMethod("Invoke")));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
delegateType.Methods.Add(method);
ctx.Context.Registry.GetService<IMarkerService>().Mark(method);
ctx.Name.SetCanRename(method, false);
return method;
}
FieldDef CreateField(RPContext ctx, TypeDef delegateType)
{
// Details will be filled in during metadata writing
TypeDef randomType;
do
{
randomType = ctx.Module.Types[ctx.Random.NextInt32(ctx.Module.Types.Count)];
} while (randomType.HasGenericParameters || randomType.IsGlobalModuleType || randomType.IsDelegate());
TypeSig fieldType = new CModOptSig(randomType, delegateType.ToTypeSig());
var field = new FieldDefUser("", new FieldSig(fieldType), FieldAttributes.Static | FieldAttributes.Assembly);
field.CustomAttributes.Add(new CustomAttribute(GetKeyAttr(ctx).FindInstanceConstructors().First()));
delegateType.Fields.Add(field);
ctx.Marker.Mark(field);
ctx.Name.SetCanRename(field, false);
return field;
}
class CodeGen : CILCodeGen
{
Instruction[] arg;
public CodeGen(Instruction[] arg, MethodDef method, IList<Instruction> instrs)
: base(method, instrs)
{
this.arg = arg;
}
protected override void LoadVar(Variable var)
{
if (var.Name == "{RESULT}")
{
foreach (var instr in arg)
base.Emit(instr);
}
else
base.LoadVar(var);
}
}
TypeDef GetKeyAttr(RPContext ctx)
{
if (keyAttrs == null)
keyAttrs = new Tuple<TypeDef, Func<int, int>>[0x10];
int index = (int)ctx.Random.NextInt32(keyAttrs.Length);
if (keyAttrs[index] == null)
{
TypeDef rtType = ctx.Context.Registry.GetService<IRuntimeService>().GetRuntimeType("Confuser.Runtime.RefProxyKey");
var injectedAttr = InjectHelper.Inject(rtType, ctx.Module);
injectedAttr.Name = ctx.Name.RandomName();
injectedAttr.Namespace = string.Empty;
Expression expression, inverse;
Variable var = new Variable("{VAR}");
Variable result = new Variable("{RESULT}");
ctx.DynCipher.GenerateExpressionPair(
ctx.Random,
new VariableExpression() { Variable = var }, new VariableExpression() { Variable = result },
3, out expression, out inverse);
var expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) })
.GenerateCIL(expression)
.Compile<Func<int, int>>();
MethodDef ctor = injectedAttr.FindMethod(".ctor");
MutationHelper.ReplacePlaceholder(ctor, arg =>
{
var invCompiled = new List<Instruction>();
new CodeGen(arg, ctor, invCompiled).GenerateCIL(inverse);
return invCompiled.ToArray();
});
keyAttrs[index] = Tuple.Create(injectedAttr, expCompiled);
ctx.Module.AddAsNonNestedType(injectedAttr);
foreach (var def in injectedAttr.FindDefinitions())
{
ctx.Marker.Mark(def);
if (def is FieldDef)
def.Name = ctx.Name.RandomName();
ctx.Name.SetCanRename(def, false);
}
}
return keyAttrs[index].Item1;
}
InitMethodDesc GetInitMethod(RPContext ctx, IRPEncoding encoding)
{
InitMethodDesc[] initDescs;
if (!inits.TryGetValue(encoding, out initDescs))
inits[encoding] = initDescs = new InitMethodDesc[0x10];
int index = (int)ctx.Random.NextInt32(initDescs.Length);
if (initDescs[index] == null)
{
TypeDef rtType = ctx.Context.Registry.GetService<IRuntimeService>().GetRuntimeType("Confuser.Runtime.RefProxyStrong");
var injectedMethod = InjectHelper.Inject(rtType.FindMethod("Initialize"), ctx.Module);
ctx.Module.GlobalType.Methods.Add(injectedMethod);
injectedMethod.Access = MethodAttributes.PrivateScope;
injectedMethod.Name = ctx.Name.RandomName();
ctx.Name.SetCanRename(injectedMethod, false);
ctx.Marker.Mark(injectedMethod);
InitMethodDesc desc = new InitMethodDesc() { Method = injectedMethod };
// Field name has five bytes, each bytes has different order & meaning
int[] order = Enumerable.Range(0, 5).ToArray();
ctx.Random.Shuffle(order);
desc.OpCodeIndex = order[4];
desc.TokenNameOrder = new int[4];
Array.Copy(order, 0, desc.TokenNameOrder, 0, 4);
desc.TokenByteOrder = Enumerable.Range(0, 4).Select(x => x * 8).ToArray();
ctx.Random.Shuffle(desc.TokenByteOrder);
int[] keyInjection = new int[9];
Array.Copy(desc.TokenNameOrder, 0, keyInjection, 0, 4);
Array.Copy(desc.TokenByteOrder, 0, keyInjection, 4, 4);
keyInjection[8] = desc.OpCodeIndex;
MutationHelper.InjectKeys(injectedMethod, Enumerable.Range(0, 9).ToArray(), keyInjection);
// Encoding
MutationHelper.ReplacePlaceholder(injectedMethod, arg =>
{
return encoding.EmitDecode(injectedMethod, ctx, arg);
});
desc.Encoding = encoding;
initDescs[index] = desc;
}
return initDescs[index];
}
class FieldDesc
{
public FieldDef Field;
public Code OpCode;
public IMethod Method;
public InitMethodDesc InitDesc;
public byte OpKey;
}
List<FieldDesc> fieldDescs = new List<FieldDesc>();
public override void Finalize(RPContext ctx)
{
foreach (var field in fields)
{
var init = GetInitMethod(ctx, field.Key.Item3);
byte opKey;
do
{
// No zero bytes
opKey = ctx.Random.NextByte();
} while (opKey == (byte)field.Key.Item1);
var delegateType = field.Value.Item1.DeclaringType;
var cctor = delegateType.FindOrCreateStaticConstructor();
cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init.Method));
cctor.Body.Instructions.Insert(0, Instruction.CreateLdcI4(opKey));
cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Ldtoken, field.Value.Item1));
fieldDescs.Add(new FieldDesc()
{
Field = field.Value.Item1,
OpCode = field.Key.Item1,
Method = field.Key.Item2,
OpKey = opKey,
InitDesc = init
});
}
foreach (var delegateType in ctx.Delegates.Values)
{
var cctor = delegateType.FindOrCreateStaticConstructor();
ctx.Marker.Mark(cctor);
ctx.Name.SetCanRename(cctor, false);
}
ctx.Context.CurrentModuleWriterListener.OnWriterEvent += EncodeField;
encodeCtx = ctx;
}
RPContext encodeCtx;
void EncodeField(object sender, ModuleWriterListenerEventArgs e)
{
ModuleWriter writer = (ModuleWriter)sender;
if (e.WriterEvent == ModuleWriterEvent.MDMemberDefRidsAllocated)
{
var keyFuncs = keyAttrs
.Where(entry => entry != null)
.ToDictionary(entry => entry.Item1, entry => entry.Item2);
foreach (var desc in fieldDescs)
{
uint token = writer.MetaData.GetToken(desc.Method).Raw;
uint key = encodeCtx.Random.NextUInt32() | 1;
// CA
var ca = desc.Field.CustomAttributes[0];
int encodedKey = keyFuncs[(TypeDef)ca.AttributeType]((int)MathsUtils.modInv(key));
ca.ConstructorArguments.Add(new CAArgument(encodeCtx.Module.CorLibTypes.Int32, encodedKey));
token *= key;
// Encoding
token = (uint)desc.InitDesc.Encoding.Encode(desc.InitDesc.Method, encodeCtx, (int)token);
// Field name
char[] name = new char[5];
name[desc.InitDesc.OpCodeIndex] = (char)((byte)desc.OpCode ^ desc.OpKey);
byte[] nameKey = encodeCtx.Random.NextBytes(4);
uint encodedNameKey = 0;
for (int i = 0; i < 4; i++)
{
// No zero bytes
while (nameKey[i] == 0)
nameKey[i] = encodeCtx.Random.NextByte();
name[desc.InitDesc.TokenNameOrder[i]] = (char)nameKey[i];
encodedNameKey |= (uint)nameKey[i] << desc.InitDesc.TokenByteOrder[i];
}
desc.Field.Name = new string(name);
// Field sig
FieldSig sig = desc.Field.FieldSig;
uint encodedToken = (token - writer.MetaData.GetToken(((CModOptSig)sig.Type).Modifier).Raw) ^ encodedNameKey;
byte[] extra = new byte[8];
extra[0] = 0xc0;
extra[3] = (byte)(encodedToken >> desc.InitDesc.TokenByteOrder[3]);
extra[4] = 0xc0;
extra[5] = (byte)(encodedToken >> desc.InitDesc.TokenByteOrder[2]);
extra[6] = (byte)(encodedToken >> desc.InitDesc.TokenByteOrder[1]);
extra[7] = (byte)(encodedToken >> desc.InitDesc.TokenByteOrder[0]);
sig.ExtraData = extra;
}
}
}
}
}

Просмотреть файл

@ -102,9 +102,9 @@ namespace Confuser.Renamer
service.SetCanRename(type, false);
}
if (type.BaseType != null && type.BaseType.DefinitionAssembly.IsCorLib() && type.BaseType.FullName == "System.Attribute")
if (type.InheritsFromCorlib("System.Attribute"))
{
service.SetRenameMode(type, RenameMode.Letters);
service.ReduceRenameMode(type, RenameMode.ASCII);
}
}

Просмотреть файл

@ -73,10 +73,13 @@ namespace Confuser.Renamer.Analyzers
TypeSig typeSig = (TypeSig)arg.Value;
foreach (var typeRef in typeSig.FindTypeRefs())
{
if (!(typeRef is TypeRef)) continue;
TypeDef typeDef = typeRef.ResolveTypeDefThrow();
if (context.Modules.Contains((ModuleDefMD)typeDef.Module))
service.AddReference(typeDef, new TypeRefReference((TypeRef)typeRef, typeDef));
{
if (typeRef is TypeRef)
service.AddReference(typeDef, new TypeRefReference((TypeRef)typeRef, typeDef));
service.ReduceRenameMode(typeDef, RenameMode.ASCII);
}
}
}
else if (arg.Value is CAArgument[])

Просмотреть файл

@ -69,6 +69,13 @@ namespace Confuser.Renamer.Analyzers
foreach (var instrInfo in dpRegInstrs)
{
int[] args = trace.TraceArguments(instrInfo.Item2);
if (args == null)
{
if (!erred)
context.Logger.WarnFormat("Failed to extract dependency property name in '{0}'.", method.FullName);
erred = true;
continue;
}
Instruction ldstr = method.Body.Instructions[args[0]];
if (ldstr.OpCode.Code != Code.Ldstr)
{
@ -129,6 +136,13 @@ namespace Confuser.Renamer.Analyzers
foreach (var instr in routedEvtRegInstrs)
{
int[] args = trace.TraceArguments(instr);
if (args == null)
{
if (!erred)
context.Logger.WarnFormat("Failed to extract routed event name in '{0}'.", method.FullName);
erred = true;
continue;
}
Instruction ldstr = method.Body.Instructions[args[0]];
if (ldstr.OpCode.Code != Code.Ldstr)
{

Просмотреть файл

@ -302,7 +302,7 @@ namespace Confuser.Renamer.BAML
var typeDef = type.ResolveTypeDefThrow();
if (context.Modules.Contains((ModuleDefMD)typeDef.Module))
{
service.SetRenameMode(typeDef, RenameMode.Letters);
service.ReduceRenameMode(typeDef, RenameMode.Letters);
service.AddReference(typeDef, reference);
}
}
@ -475,7 +475,7 @@ namespace Confuser.Renamer.BAML
{
var reference = new BAMLConverterMemberReference(xmlnsCtx, sig, property, rec);
AddTypeSigReference(sig, reference);
service.SetRenameMode(property, RenameMode.Letters);
service.ReduceRenameMode(property, RenameMode.Letters);
service.AddReference(property, reference);
}
FieldDef field = typeDef.FindField(cmdName);
@ -483,7 +483,7 @@ namespace Confuser.Renamer.BAML
{
var reference = new BAMLConverterMemberReference(xmlnsCtx, sig, field, rec);
AddTypeSigReference(sig, reference);
service.SetRenameMode(field, RenameMode.Letters);
service.ReduceRenameMode(field, RenameMode.Letters);
service.AddReference(field, reference);
}
if (property == null && field == null)

Просмотреть файл

@ -17,7 +17,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<OutputPath>..\Debug\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
@ -25,7 +25,7 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<OutputPath>..\Release\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>

Просмотреть файл

@ -20,9 +20,11 @@ namespace Confuser.Renamer
RenameMode GetRenameMode(object obj);
void SetRenameMode(object obj, RenameMode val);
void ReduceRenameMode(object obj, RenameMode val);
string ObfuscateName(string name, RenameMode mode);
string RandomName();
string RandomName(RenameMode mode);
void RegisterRenamer(IRenamer renamer);
void AddReference<T>(T obj, INameReference<T> reference);
@ -83,6 +85,12 @@ namespace Confuser.Renamer
{
context.Annotations.Set<RenameMode>(obj, RenameModeKey, val);
}
public void ReduceRenameMode(object obj, RenameMode val)
{
RenameMode original = GetRenameMode(obj);
if (original < val)
context.Annotations.Set<RenameMode>(obj, RenameModeKey, val);
}
static readonly object ReferencesKey = new object();
public void AddReference<T>(T obj, INameReference<T> reference)
@ -110,7 +118,10 @@ namespace Confuser.Renamer
}
#region Charsets
static char[] asciiCharset = Enumerable.Range(32, 95).Select(ord => (char)ord).ToArray();
static char[] asciiCharset = Enumerable.Range(32, 95)
.Select(ord => (char)ord)
.Except(new [] { '.' })
.ToArray();
static char[] letterCharset = Enumerable.Range(0, 26)
.SelectMany(ord => new[] { (char)('a' + ord), (char)('A' + ord) })
.ToArray();
@ -126,6 +137,9 @@ namespace Confuser.Renamer
public string ObfuscateName(string name, RenameMode mode)
{
if (string.IsNullOrEmpty(name))
return string.Empty;
if (mode == RenameMode.Empty)
return "";
else if (mode == RenameMode.Debug)
@ -148,7 +162,11 @@ namespace Confuser.Renamer
}
public string RandomName()
{
return ObfuscateName(Utils.ToHexString(random.NextBytes(16)), RenameMode.Unicode);
return RandomName(RenameMode.Unicode);
}
public string RandomName(RenameMode mode)
{
return ObfuscateName(Utils.ToHexString(random.NextBytes(16)), mode);
}
static readonly object OriginalNameKey = new object();

Просмотреть файл

@ -7,7 +7,7 @@ using Confuser.Core;
namespace Confuser.Renamer.References
{
class MemberRefReference : INameReference<IDefinition>
public class MemberRefReference : INameReference<IDefinition>
{
MemberRef memberRef;
IDefinition memberDef;

Просмотреть файл

@ -27,14 +27,16 @@ namespace Confuser.Renamer.References
{
var declType = (GenericInstSig)baseSlot.DeclaringType;
target = new MemberRefUser(method.Module, baseSlot.MethodDef.Name, baseSlot.MethodDef.MethodSig, declType.ToTypeDefOrRef());
target = (IMethodDefOrRef)method.Module.Import(target);
target = (IMethodDefOrRef)new Importer(method.Module, ImporterOptions.TryToUseTypeDefs).Import(target);
}
else
{
target = baseSlot.MethodDef;
if (target.Module != method.Module)
target = (IMethodDefOrRef)method.Module.Import(baseSlot.MethodDef);
target = (IMethodDefOrRef)new Importer(method.Module, ImporterOptions.TryToUseTypeDefs).Import(baseSlot.MethodDef);
}
if(target is MemberRef)
service.AddReference(baseSlot.MethodDef, new MemberRefReference((MemberRef)target, baseSlot.MethodDef));
if (method.Overrides.Any(impl =>
new SigComparer().Equals(impl.MethodDeclaration.MethodSig, target.MethodSig) &&

Просмотреть файл

@ -7,7 +7,7 @@ using Confuser.Core;
namespace Confuser.Renamer.References
{
class TypeRefReference : INameReference<TypeDef>
public class TypeRefReference : INameReference<TypeDef>
{
TypeRef typeRef;
TypeDef typeDef;

Просмотреть файл

@ -54,7 +54,7 @@ namespace Confuser.Renamer
typeDef.Namespace = service.ObfuscateName(typeDef.Namespace, mode);
}
foreach (var refer in references)
foreach (var refer in references.ToList())
{
if (!refer.UpdateNameReference(context, service))
{
@ -63,9 +63,6 @@ namespace Confuser.Renamer
}
}
}
foreach (var module in context.Modules)
module.ResetTypeDefFindCache();
}
}
}

Просмотреть файл

@ -41,9 +41,9 @@
<Compile Include="antinet\AntiManagedProfiler.cs" />
<Compile Include="antinet\HandleProcessCorruptedStateExceptionsAttribute.cs" />
<Compile Include="antinet\PEInfo.cs" />
<Compile Include="Mutation.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="RefProxy.Strong.cs" />
<Compile Include="AntiDebug.Safe.cs" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -0,0 +1,25 @@

class Mutation
{
public static readonly int KeyI0 = 0;
public static readonly int KeyI1 = 1;
public static readonly int KeyI2 = 2;
public static readonly int KeyI3 = 3;
public static readonly int KeyI4 = 4;
public static readonly int KeyI5 = 5;
public static readonly int KeyI6 = 6;
public static readonly int KeyI7 = 7;
public static readonly int KeyI8 = 8;
public static readonly int KeyI9 = 9;
public static readonly int KeyI10 = 10;
public static readonly int KeyI11 = 11;
public static readonly int KeyI12 = 12;
public static readonly int KeyI13 = 13;
public static readonly int KeyI14 = 14;
public static readonly int KeyI15 = 15;
public static int Placeholder(int val)
{
return val;
}
}

Просмотреть файл

@ -0,0 +1,84 @@
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace Confuser.Runtime
{
class RefProxyKey : Attribute
{
int key;
public RefProxyKey(int key)
{
this.key = Mutation.Placeholder(key);
}
public override int GetHashCode()
{
return key;
}
}
static class RefProxyStrong
{
internal static void Initialize(RuntimeFieldHandle field, byte opKey)
{
FieldInfo fieldInfo = FieldInfo.GetFieldFromHandle(field);
var sig = fieldInfo.Module.ResolveSignature(fieldInfo.MetadataToken);
int len = sig.Length;
int key = fieldInfo.GetOptionalCustomModifiers()[0].MetadataToken;
key += (fieldInfo.Name[Mutation.KeyI0] ^ sig[--len]) << Mutation.KeyI4;
key += (fieldInfo.Name[Mutation.KeyI1] ^ sig[--len]) << Mutation.KeyI5;
key += (fieldInfo.Name[Mutation.KeyI2] ^ sig[--len]) << Mutation.KeyI6;
len--;
key += (fieldInfo.Name[Mutation.KeyI3] ^ sig[--len]) << Mutation.KeyI7;
int token = Mutation.Placeholder(key);
token *= fieldInfo.GetCustomAttributes(false)[0].GetHashCode();
var method = fieldInfo.Module.ResolveMethod(token);
Type delegateType = fieldInfo.FieldType;
if (method.IsStatic)
fieldInfo.SetValue(null, Delegate.CreateDelegate(delegateType, (MethodInfo)method));
else
{
DynamicMethod dm = null;
Type[] argTypes = null;
foreach (var invoke in fieldInfo.FieldType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance))
if (invoke.DeclaringType == delegateType)
{
var paramTypes = invoke.GetParameters();
argTypes = new Type[paramTypes.Length];
for (int i = 0; i < argTypes.Length; i++)
argTypes[i] = paramTypes[i].ParameterType;
var declType = method.DeclaringType;
dm = new DynamicMethod("", invoke.ReturnType, argTypes, (declType.IsInterface || declType.IsArray) ? delegateType : declType, true);
break;
}
var info = dm.GetDynamicILInfo();
info.SetLocalSignature(new byte[] { 0x7, 0x0 });
byte[] code = new byte[2 * argTypes.Length + 6];
int index = 0;
for (int i = 0; i < argTypes.Length; i++)
{
code[index++] = 0x0e;
code[index++] = (byte)i;
}
code[index++] = (byte)((byte)fieldInfo.Name[Mutation.KeyI8] ^ opKey);
int dmToken = info.GetTokenFor(method.MethodHandle);
code[index++] = (byte)dmToken;
code[index++] = (byte)(dmToken >> 8);
code[index++] = (byte)(dmToken >> 16);
code[index++] = (byte)(dmToken >> 24);
code[index] = 0x2a;
info.SetCode(code, argTypes.Length + 1);
fieldInfo.SetValue(null, dm.CreateDelegate(delegateType));
}
}
}
}

2
dnlib

@ -1 +1 @@
Subproject commit 1473092e24b2b08e58e7e50f32f2c266d8919dbe
Subproject commit 03b22aba6e6fe9bf2c7e0be0b5fb425414f80809