added basic control flow protection
This commit is contained in:
Родитель
bf53857c6b
Коммит
ad552fd420
|
@ -43,9 +43,6 @@
|
|||
<Private>True</Private>
|
||||
<HintPath>..\packages\TaskParallelLibrary.1.0.2856.0\lib\Net35\System.Threading.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -137,6 +137,10 @@ namespace Confuser.Core
|
|||
{
|
||||
context.Logger.ErrorException("Failed to resolve a member, check if all dependencies are of correct version.", ex);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
context.Logger.ErrorException("An IO error occured, check if all input/output locations are read/writable.", ex);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
context.Logger.Error("Operation is canceled.");
|
||||
|
@ -320,6 +324,8 @@ namespace Confuser.Core
|
|||
|
||||
static void WriteModule(ConfuserContext context)
|
||||
{
|
||||
context.Logger.InfoFormat("Writing module '{0}'...", context.CurrentModule.Name);
|
||||
|
||||
MemoryStream ms = new MemoryStream();
|
||||
if (context.CurrentModuleWriterOptions is ModuleWriterOptions)
|
||||
context.CurrentModule.Write(ms, (ModuleWriterOptions)context.CurrentModuleWriterOptions);
|
||||
|
|
|
@ -280,6 +280,9 @@ namespace Confuser.Core
|
|||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="Stream"/> wrapper of <see cref="IImageStream"/>.
|
||||
/// </summary>
|
||||
public class ImageStream : Stream
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
@ -148,6 +148,7 @@ namespace Confuser.Core
|
|||
/// <summary>
|
||||
/// Parses the rules' patterns.
|
||||
/// </summary>
|
||||
/// <param name="proj">The project.</param>
|
||||
/// <param name="module">The module description.</param>
|
||||
/// <param name="context">The working context.</param>
|
||||
/// <returns>Parsed rule patterns.</returns>
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace Confuser.Core
|
|||
/// <returns>The value of the parameter.</returns>
|
||||
public T GetParameter<T>(ConfuserContext context, IDefinition target, string name, T defValue = default(T))
|
||||
{
|
||||
var objParams = context.Annotations.Get<ProtectionSettings>(comp, ParametersKey);
|
||||
var objParams = context.Annotations.Get<ProtectionSettings>(target, ParametersKey);
|
||||
if (objParams == null)
|
||||
return defValue;
|
||||
Dictionary<string, string> protParams;
|
||||
|
@ -55,7 +55,13 @@ namespace Confuser.Core
|
|||
return defValue;
|
||||
string ret;
|
||||
if (protParams.TryGetValue(name, out ret))
|
||||
return (T)Convert.ChangeType(ret, typeof(T));
|
||||
{
|
||||
Type paramType = typeof(T);
|
||||
if (paramType.IsEnum)
|
||||
return (T)Enum.Parse(paramType, ret, true);
|
||||
else
|
||||
return (T)Convert.ChangeType(ret, typeof(T));
|
||||
}
|
||||
else
|
||||
return defValue;
|
||||
}
|
||||
|
|
|
@ -98,8 +98,8 @@ namespace Confuser.Core.Services
|
|||
else
|
||||
{
|
||||
Buffer.BlockCopy(state, 32 - stateFilled, buffer, offset, length);
|
||||
length = 0;
|
||||
stateFilled -= length;
|
||||
length = 0;
|
||||
}
|
||||
if (stateFilled == 0)
|
||||
NextState();
|
||||
|
@ -155,6 +155,15 @@ namespace Confuser.Core.Services
|
|||
return BitConverter.ToUInt32(NextBytes(4), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random double floating pointer number from 0 (inclusive) to 1 (exclusive).
|
||||
/// </summary>
|
||||
/// <returns>Requested random number.</returns>
|
||||
public double NextDouble()
|
||||
{
|
||||
return NextUInt32() / ((double)uint.MaxValue + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random boolean value.
|
||||
/// </summary>
|
||||
|
@ -167,6 +176,22 @@ namespace Confuser.Core.Services
|
|||
NextState();
|
||||
return s % 2 == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuffles the element in the specified list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list">The list to shuffle.</param>
|
||||
public void Shuffle<T>(IList<T> list)
|
||||
{
|
||||
for (int i = list.Count - 1; i > 1; i--)
|
||||
{
|
||||
int k = NextInt32(i + 1);
|
||||
T tmp = list[k];
|
||||
list[k] = list[i];
|
||||
list[i] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Confuser.Core.Services
|
|||
/// Trace the stack of the specified method.
|
||||
/// </summary>
|
||||
/// <param name="method">The method to trace.</param>
|
||||
/// <exception cref="InvalidMethodException"><paramref name="member"/> has invalid body.</exception>
|
||||
/// <exception cref="InvalidMethodException"><paramref name="method"/> has invalid body.</exception>
|
||||
/// <exception cref="System.ArgumentNullException"><paramref name="method"/> is <c>null</c>.</exception>
|
||||
MethodTrace Trace(MethodDef method);
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ namespace Confuser.Core.Services
|
|||
for (int i = 0; i < instrs.Count; i++)
|
||||
{
|
||||
offset2index.Add(instrs[i].Offset, i);
|
||||
depths[i] = -1;
|
||||
depths[i] = int.MinValue;
|
||||
}
|
||||
|
||||
foreach (var eh in body.ExceptionHandlers)
|
||||
|
@ -121,7 +121,7 @@ namespace Confuser.Core.Services
|
|||
{
|
||||
var instr = instrs[i];
|
||||
|
||||
if (depths[i] != -1) // Already set due to being target of a branch / beginning of EHs.
|
||||
if (depths[i] != int.MinValue) // Already set due to being target of a branch / beginning of EHs.
|
||||
currentStack = depths[i];
|
||||
|
||||
switch (instr.OpCode.FlowControl)
|
||||
|
@ -160,7 +160,6 @@ namespace Confuser.Core.Services
|
|||
currentStack = 0;
|
||||
break;
|
||||
case FlowControl.Throw:
|
||||
currentStack = 0;
|
||||
break;
|
||||
default:
|
||||
throw new UnreachableException();
|
||||
|
@ -170,7 +169,7 @@ namespace Confuser.Core.Services
|
|||
depths[i] = currentStack;
|
||||
}
|
||||
foreach (var stackDepth in depths)
|
||||
if (stackDepth == -1)
|
||||
if (stackDepth == int.MinValue)
|
||||
throw new InvalidMethodException("Bad method body.");
|
||||
|
||||
StackDepths = depths;
|
||||
|
|
|
@ -11,7 +11,6 @@ namespace Confuser.Protections
|
|||
{
|
||||
public const string _Id = "anti ildasm";
|
||||
public const string _FullId = "Ki.AntiILDasm";
|
||||
public const string _ServiceId = "Ki.AntiILDasm";
|
||||
|
||||
protected override void Initialize(ConfuserContext context)
|
||||
{
|
||||
|
|
|
@ -43,8 +43,13 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AntiILDasmProtection.cs" />
|
||||
<Compile Include="ControlFlow\CFContext.cs" />
|
||||
<Compile Include="ControlFlow\ControlFlowPhase.cs" />
|
||||
<Compile Include="ControlFlow\ControlFlowProtection.cs" />
|
||||
<Compile Include="ControlFlow\BlockParser.cs" />
|
||||
<Compile Include="ControlFlow\Blocks.cs" />
|
||||
<Compile Include="ControlFlow\JumpMangler.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ReflectorTrapProtection.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
@ -63,6 +68,7 @@
|
|||
<Name>dnlib</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using dnlib.DotNet.Emit;
|
||||
using Confuser.Core;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Confuser.Protections.ControlFlow
|
||||
{
|
||||
static class BlockParser
|
||||
{
|
||||
public static ScopeBlock ParseBody(CilBody body)
|
||||
{
|
||||
var ehScopes = new Dictionary<ExceptionHandler, Tuple<ScopeBlock, ScopeBlock, ScopeBlock>>();
|
||||
foreach (var eh in body.ExceptionHandlers)
|
||||
{
|
||||
ScopeBlock tryBlock = new ScopeBlock(BlockType.Try, eh);
|
||||
|
||||
BlockType handlerType = BlockType.Handler;
|
||||
|
||||
if (eh.HandlerType == ExceptionHandlerType.Finally)
|
||||
handlerType = BlockType.Finally;
|
||||
else if (eh.HandlerType == ExceptionHandlerType.Fault)
|
||||
handlerType = BlockType.Fault;
|
||||
|
||||
ScopeBlock handlerBlock = new ScopeBlock(handlerType, eh);
|
||||
|
||||
if (eh.FilterStart != null)
|
||||
{
|
||||
ScopeBlock filterBlock = new ScopeBlock(BlockType.Filter, eh);
|
||||
ehScopes[eh] = Tuple.Create(tryBlock, handlerBlock, filterBlock);
|
||||
}
|
||||
else
|
||||
ehScopes[eh] = Tuple.Create(tryBlock, handlerBlock, (ScopeBlock)null);
|
||||
}
|
||||
|
||||
ScopeBlock root = new ScopeBlock(BlockType.Normal, null);
|
||||
Stack<ScopeBlock> scopeStack = new Stack<ScopeBlock>();
|
||||
|
||||
scopeStack.Push(root);
|
||||
foreach (var instr in body.Instructions)
|
||||
{
|
||||
foreach (var eh in body.ExceptionHandlers)
|
||||
{
|
||||
var ehScope = ehScopes[eh];
|
||||
|
||||
if (instr == eh.TryEnd)
|
||||
scopeStack.Pop();
|
||||
|
||||
if (instr == eh.HandlerEnd)
|
||||
scopeStack.Pop();
|
||||
|
||||
if (eh.FilterStart != null && instr == eh.HandlerStart)
|
||||
{
|
||||
// Filter must precede handler immediately
|
||||
Debug.Assert(scopeStack.Peek().Type == BlockType.Filter);
|
||||
scopeStack.Pop();
|
||||
}
|
||||
}
|
||||
foreach (var eh in body.ExceptionHandlers.Reverse())
|
||||
{
|
||||
var ehScope = ehScopes[eh];
|
||||
var parent = scopeStack.Count > 0 ? scopeStack.Peek() : null;
|
||||
|
||||
if (instr == eh.TryStart)
|
||||
{
|
||||
if (parent != null)
|
||||
parent.Children.Add(ehScope.Item1);
|
||||
scopeStack.Push(ehScope.Item1);
|
||||
}
|
||||
|
||||
if (instr == eh.HandlerStart)
|
||||
{
|
||||
if (parent != null)
|
||||
parent.Children.Add(ehScope.Item2);
|
||||
scopeStack.Push(ehScope.Item2);
|
||||
}
|
||||
|
||||
if (instr == eh.FilterStart)
|
||||
{
|
||||
if (parent != null)
|
||||
parent.Children.Add(ehScope.Item3);
|
||||
scopeStack.Push(ehScope.Item3);
|
||||
}
|
||||
}
|
||||
|
||||
ScopeBlock scope = scopeStack.Peek();
|
||||
InstrBlock block = scope.Children.LastOrDefault() as InstrBlock;
|
||||
if (block == null)
|
||||
scope.Children.Add(block = new InstrBlock());
|
||||
block.Instructions.Add(instr);
|
||||
}
|
||||
Debug.Assert(scopeStack.Count == 1);
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using dnlib.DotNet.Emit;
|
||||
|
||||
namespace Confuser.Protections.ControlFlow
|
||||
{
|
||||
abstract class BlockBase
|
||||
{
|
||||
public BlockBase(BlockType type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
public ScopeBlock Parent { get; private set; }
|
||||
|
||||
public abstract void ToBody(CilBody body);
|
||||
|
||||
public BlockType Type { get; private set; }
|
||||
}
|
||||
|
||||
enum BlockType
|
||||
{
|
||||
Normal,
|
||||
Try,
|
||||
Handler,
|
||||
Finally,
|
||||
Filter,
|
||||
Fault
|
||||
}
|
||||
|
||||
class ScopeBlock : BlockBase
|
||||
{
|
||||
public ScopeBlock(BlockType type, ExceptionHandler handler)
|
||||
: base(type)
|
||||
{
|
||||
this.Handler = handler;
|
||||
this.Children = new List<BlockBase>();
|
||||
}
|
||||
|
||||
public ExceptionHandler Handler { get; private set; }
|
||||
|
||||
public List<BlockBase> Children { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
if (Type == BlockType.Try)
|
||||
ret.Append("try ");
|
||||
else if (Type == BlockType.Handler)
|
||||
ret.Append("handler ");
|
||||
else if (Type == BlockType.Finally)
|
||||
ret.Append("finally ");
|
||||
else if (Type == BlockType.Fault)
|
||||
ret.Append("fault ");
|
||||
ret.AppendLine("{");
|
||||
foreach (var child in Children)
|
||||
ret.Append(child.ToString());
|
||||
ret.AppendLine("}");
|
||||
return ret.ToString();
|
||||
}
|
||||
|
||||
public Instruction GetFirstInstr()
|
||||
{
|
||||
BlockBase firstBlock = Children.First();
|
||||
if (firstBlock is ScopeBlock)
|
||||
return ((ScopeBlock)firstBlock).GetFirstInstr();
|
||||
else
|
||||
return ((InstrBlock)firstBlock).Instructions.First();
|
||||
}
|
||||
|
||||
public Instruction GetLastInstr()
|
||||
{
|
||||
BlockBase firstBlock = Children.Last();
|
||||
if (firstBlock is ScopeBlock)
|
||||
return ((ScopeBlock)firstBlock).GetLastInstr();
|
||||
else
|
||||
return ((InstrBlock)firstBlock).Instructions.Last();
|
||||
}
|
||||
|
||||
public override void ToBody(CilBody body)
|
||||
{
|
||||
if (Type != BlockType.Normal)
|
||||
{
|
||||
if (Type == BlockType.Try)
|
||||
{
|
||||
Handler.TryStart = GetFirstInstr();
|
||||
Handler.TryEnd = GetLastInstr();
|
||||
}
|
||||
else if (Type == BlockType.Filter)
|
||||
{
|
||||
Handler.FilterStart = GetFirstInstr();
|
||||
}
|
||||
else
|
||||
{
|
||||
Handler.HandlerStart = GetFirstInstr();
|
||||
Handler.HandlerEnd = GetLastInstr();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var block in Children)
|
||||
block.ToBody(body);
|
||||
}
|
||||
}
|
||||
|
||||
class InstrBlock : BlockBase
|
||||
{
|
||||
public InstrBlock()
|
||||
: base(BlockType.Normal)
|
||||
{
|
||||
this.Instructions = new List<Instruction>();
|
||||
}
|
||||
|
||||
public List<Instruction> Instructions { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
foreach (var instr in Instructions)
|
||||
ret.AppendLine(instr.ToString());
|
||||
return ret.ToString();
|
||||
}
|
||||
|
||||
public override void ToBody(CilBody body)
|
||||
{
|
||||
foreach (var instr in Instructions)
|
||||
body.Instructions.Add(instr);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Confuser.Core.Services;
|
||||
using dnlib.DotNet.Emit;
|
||||
using dnlib.DotNet;
|
||||
|
||||
namespace Confuser.Protections.ControlFlow
|
||||
{
|
||||
enum CFType
|
||||
{
|
||||
Switch,
|
||||
Jump,
|
||||
}
|
||||
|
||||
class CFContext
|
||||
{
|
||||
public RandomGenerator Random;
|
||||
public MethodDef Method;
|
||||
public CFType Type;
|
||||
public double Intensity;
|
||||
public bool JunkCode;
|
||||
public bool FakeBranch;
|
||||
|
||||
public void AddJump(IList<Instruction> instrs, Instruction target, IList<Instruction> candidates)
|
||||
{
|
||||
if (!Method.Module.IsClr40 && JunkCode &&
|
||||
!Method.DeclaringType.HasGenericParameters && !Method.HasGenericParameters &&
|
||||
(instrs[0].OpCode.FlowControl == FlowControl.Call || instrs[0].OpCode.FlowControl == FlowControl.Next))
|
||||
{
|
||||
switch (Random.NextInt32(3))
|
||||
{
|
||||
case 0:
|
||||
instrs.Add(Instruction.Create(OpCodes.Ldc_I4_0));
|
||||
instrs.Add(Instruction.Create(OpCodes.Brtrue, instrs[0]));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
instrs.Add(Instruction.Create(OpCodes.Ldc_I4_1));
|
||||
instrs.Add(Instruction.Create(OpCodes.Brfalse, instrs[0]));
|
||||
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));
|
||||
instrs.Add(Instruction.Create(OpCodes.Brfalse, instrs[0]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
instrs.Add(Instruction.Create(OpCodes.Br, target));
|
||||
}
|
||||
|
||||
public void AddJunk(IList<Instruction> instrs)
|
||||
{
|
||||
if (Method.Module.IsClr40 || !JunkCode)
|
||||
return;
|
||||
|
||||
switch (Random.NextInt32(6))
|
||||
{
|
||||
case 0:
|
||||
instrs.Add(Instruction.Create(OpCodes.Pop));
|
||||
break;
|
||||
case 1:
|
||||
instrs.Add(Instruction.Create(OpCodes.Dup));
|
||||
break;
|
||||
case 2:
|
||||
instrs.Add(Instruction.Create(OpCodes.Throw));
|
||||
break;
|
||||
case 3:
|
||||
instrs.Add(Instruction.Create(OpCodes.Ldarg, new Parameter(0xff)));
|
||||
break;
|
||||
case 4:
|
||||
instrs.Add(Instruction.Create(OpCodes.Ldloc, new Local(null) { Index = 0xff }));
|
||||
break;
|
||||
case 5:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
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;
|
||||
|
||||
namespace Confuser.Protections.ControlFlow
|
||||
{
|
||||
class ControlFlowPhase : ProtectionPhase
|
||||
{
|
||||
public ControlFlowPhase(ControlFlowProtection parent)
|
||||
: base(parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override ProtectionTargets Targets
|
||||
{
|
||||
get { return ProtectionTargets.Methods; }
|
||||
}
|
||||
|
||||
CFContext ParseParameter(
|
||||
MethodDef method, ConfuserContext context,
|
||||
ProtectionParameters parameters, RandomGenerator random)
|
||||
{
|
||||
CFContext ret = new CFContext();
|
||||
ret.Type = parameters.GetParameter<CFType>(context, method, "type", CFType.Switch);
|
||||
|
||||
int rawIntensity = parameters.GetParameter<int>(context, method, "intensity", 60);
|
||||
ret.Intensity = rawIntensity / 100.0;
|
||||
|
||||
ret.JunkCode = parameters.GetParameter<bool>(context, method, "junk", false);
|
||||
ret.FakeBranch = parameters.GetParameter<bool>(context, method, "fakeBr", false);
|
||||
ret.Random = random;
|
||||
ret.Method = method;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override void Execute(ConfuserContext context, ProtectionParameters parameters)
|
||||
{
|
||||
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, ParseParameter(method, context, parameters, random));
|
||||
}
|
||||
|
||||
context.CurrentModuleWriterOptions.MetaDataOptions.Flags |= dnlib.DotNet.Writer.MetaDataFlags.KeepOldMaxStack;
|
||||
}
|
||||
|
||||
void ProcessMethod(CilBody body, CFContext ctx)
|
||||
{
|
||||
ScopeBlock root = BlockParser.ParseBody(body);
|
||||
|
||||
JumpMangler.Mangle(body, root, ctx);
|
||||
|
||||
body.Instructions.Clear();
|
||||
root.ToBody(body);
|
||||
foreach (var eh in body.ExceptionHandlers)
|
||||
{
|
||||
eh.TryEnd = body.Instructions[body.Instructions.IndexOf(eh.TryEnd) + 1];
|
||||
eh.HandlerEnd = body.Instructions[body.Instructions.IndexOf(eh.HandlerEnd) + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Confuser.Core;
|
||||
using dnlib.DotNet;
|
||||
using Confuser.Protections.ControlFlow;
|
||||
|
||||
namespace Confuser.Protections
|
||||
{
|
||||
class ControlFlowProtection : Protection
|
||||
{
|
||||
public const string _Id = "ctrl flow";
|
||||
public const string _FullId = "Ki.ControlFlow";
|
||||
public const string _ServiceId = "Ki.ControlFlow";
|
||||
|
||||
protected override void Initialize(ConfuserContext context)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
protected override void PopulatePipeline(ProtectionPipeline pipeline)
|
||||
{
|
||||
pipeline.InsertPreStage(PipelineStage.OptimizeMethods, new ControlFlowPhase(this));
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return "Control Flow Protection"; }
|
||||
}
|
||||
|
||||
public override string Description
|
||||
{
|
||||
get { return "This protection mangles the code in the methods so that decompilers cannot decompile the methods."; }
|
||||
}
|
||||
|
||||
public override string Id
|
||||
{
|
||||
get { return _Id; }
|
||||
}
|
||||
|
||||
public override string FullId
|
||||
{
|
||||
get { return _FullId; }
|
||||
}
|
||||
|
||||
public override ProtectionPreset Preset
|
||||
{
|
||||
get { return ProtectionPreset.Aggressive; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
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.Protections.ControlFlow
|
||||
{
|
||||
class JumpMangler
|
||||
{
|
||||
static IEnumerable<InstrBlock> GetAllBlocks(ScopeBlock scope)
|
||||
{
|
||||
foreach (var child in scope.Children)
|
||||
{
|
||||
if (child is InstrBlock)
|
||||
yield return (InstrBlock)child;
|
||||
else
|
||||
{
|
||||
foreach (var block in GetAllBlocks((ScopeBlock)child))
|
||||
yield return block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LinkedList<Instruction[]> SpiltFragments(InstrBlock block, CFContext ctx)
|
||||
{
|
||||
LinkedList<Instruction[]> fragments = new LinkedList<Instruction[]>();
|
||||
List<Instruction> currentFragment = new List<Instruction>();
|
||||
|
||||
int skipCount = -1;
|
||||
for (int i = 0; i < block.Instructions.Count; i++)
|
||||
{
|
||||
if (skipCount != -1)
|
||||
{
|
||||
if (skipCount > 0)
|
||||
{
|
||||
currentFragment.Add(block.Instructions[i]);
|
||||
skipCount--;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
fragments.AddLast(currentFragment.ToArray());
|
||||
currentFragment.Clear();
|
||||
|
||||
skipCount = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (block.Instructions[i].OpCode.OpCodeType == OpCodeType.Prefix)
|
||||
{
|
||||
skipCount = 1;
|
||||
currentFragment.Add(block.Instructions[i]);
|
||||
continue;
|
||||
}
|
||||
else if (i + 2 < block.Instructions.Count &&
|
||||
block.Instructions[i + 0].OpCode.Code == Code.Dup &&
|
||||
block.Instructions[i + 1].OpCode.Code == Code.Ldvirtftn &&
|
||||
block.Instructions[i + 2].OpCode.Code == Code.Newobj)
|
||||
{
|
||||
skipCount = 2;
|
||||
currentFragment.Add(block.Instructions[i]);
|
||||
continue;
|
||||
}
|
||||
else if (i + 1 < block.Instructions.Count &&
|
||||
block.Instructions[i + 0].OpCode.Code == Code.Ldftn &&
|
||||
block.Instructions[i + 1].OpCode.Code == Code.Newobj)
|
||||
{
|
||||
skipCount = 1;
|
||||
currentFragment.Add(block.Instructions[i]);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentFragment.Add(block.Instructions[i]);
|
||||
|
||||
if (ctx.Intensity > ctx.Random.NextDouble())
|
||||
{
|
||||
fragments.AddLast(currentFragment.ToArray());
|
||||
currentFragment.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentFragment.Count > 0)
|
||||
fragments.AddLast(currentFragment.ToArray());
|
||||
|
||||
return fragments;
|
||||
}
|
||||
|
||||
public static void Mangle(CilBody body, ScopeBlock root, CFContext ctx)
|
||||
{
|
||||
body.MaxStack++;
|
||||
foreach (var block in GetAllBlocks(root))
|
||||
{
|
||||
var fragments = SpiltFragments(block, ctx);
|
||||
if (fragments.Count < 4) continue;
|
||||
|
||||
var current = fragments.First;
|
||||
while (current.Next != null)
|
||||
{
|
||||
List<Instruction> newFragment = new List<Instruction>(current.Value);
|
||||
ctx.AddJump(newFragment, current.Next.Value[0], block.Instructions);
|
||||
ctx.AddJunk(newFragment);
|
||||
current.Value = newFragment.ToArray();
|
||||
current = current.Next;
|
||||
}
|
||||
Instruction[] first = fragments.First.Value;
|
||||
fragments.RemoveFirst();
|
||||
Instruction[] last = fragments.Last.Value;
|
||||
fragments.RemoveLast();
|
||||
|
||||
var newFragments = fragments.ToList();
|
||||
ctx.Random.Shuffle(newFragments);
|
||||
|
||||
block.Instructions = first
|
||||
.Concat(newFragments.SelectMany(fragment => fragment))
|
||||
.Concat(last).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,9 +33,6 @@
|
|||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace Confuser.Renamer
|
|||
public NameService(ConfuserContext context)
|
||||
{
|
||||
this.context = context;
|
||||
this.random = context.Registry.GetService<IRandomService>().GetRandomGenerator(NameProtection._ServiceId);
|
||||
this.random = context.Registry.GetService<IRandomService>().GetRandomGenerator(NameProtection._FullId);
|
||||
this.nameSeed = random.NextBytes(20);
|
||||
|
||||
this.Renamers = new List<IRenamer>()
|
||||
|
|
2
dnlib
2
dnlib
|
@ -1 +1 @@
|
|||
Subproject commit a1bf585fee79a4a7bf709b79c8c27c33cf37a168
|
||||
Subproject commit 99c04ee6a1ffa4fd826d8386fdf6321a1cab9f5f
|
Загрузка…
Ссылка в новой задаче