Skip to content
This repository has been archived by the owner on Jan 27, 2019. It is now read-only.

Commit

Permalink
Add prototype Advanced API
Browse files Browse the repository at this point in the history
  • Loading branch information
yck1509 committed Jan 7, 2015
1 parent d4c528a commit 8885b97
Show file tree
Hide file tree
Showing 27 changed files with 307 additions and 40 deletions.
98 changes: 98 additions & 0 deletions Confuser.Core/API/APIStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using Confuser.Core.Services;
using dnlib.DotNet;

namespace Confuser.Core.API {
internal class APIStore : IAPIStore {
readonly ConfuserContext context;
readonly RandomGenerator random;
readonly SortedList<int, List<IDataStore>> dataStores;
readonly List<IOpaquePredicateDescriptor> predicates;

/// <summary>
/// Initializes a new instance of the <see cref="APIStore" /> class.
/// </summary>
/// <param name="context">The working context.</param>
public APIStore(ConfuserContext context) {
this.context = context;
random = context.Registry.GetService<IRandomService>().GetRandomGenerator("APIStore");

dataStores = new SortedList<int, List<IDataStore>>();
predicates = new List<IOpaquePredicateDescriptor>();
}

/// <inheritdoc />
public void AddStore(IDataStore dataStore) {
dataStores.AddListEntry(dataStore.Priority, dataStore);
}

/// <inheritdoc />
public void AddPredicate(IOpaquePredicateDescriptor predicate) {
predicates.Add(predicate);
}

/// <inheritdoc />
public IDataStore GetStore(MethodDef method) {
for (int i = dataStores.Count - 1; i >= 0; i--) {
var list = dataStores[i];
for (int j = list.Count - 1; j >= 0; i--) {
if (list[j].IsUsable(method))
return list[j];
}
}
return null;
}

/// <inheritdoc />
public IOpaquePredicateDescriptor GetPredicate(MethodDef method, OpaquePredicateType? type, params int[] argCount) {
var randomPredicates = predicates.ToArray();
random.Shuffle(randomPredicates);
foreach (var predicate in randomPredicates) {
if (predicate.IsUsable(method) &&
(type == null || predicate.Type == type.Value) &&
(argCount == null || Array.IndexOf(argCount, predicate.ArgumentCount) != -1))
return predicate;
}
return null;
}
}

/// <summary>
/// Provides storage for API interfaces
/// </summary>
public interface IAPIStore {
/// <summary>
/// Adds the specified data store into this store.
/// </summary>
/// <param name="dataStore">The data store.</param>
void AddStore(IDataStore dataStore);

/// <summary>
/// Finds a suitable data store for the specified method, with the
/// specified number of keys.
/// </summary>
/// <param name="method">The method.</param>
/// <returns>The suitable data store if found, or <c>null</c> if not found.</returns>
/// <remarks>
/// It should never returns null --- ConfuserEx has internal data store.
/// </remarks>
IDataStore GetStore(MethodDef method);

/// <summary>
/// Adds the specified opaque predicate into this store.
/// </summary>
/// <param name="predicate">The opaque predicate.</param>
void AddPredicate(IOpaquePredicateDescriptor predicate);

/// <summary>
/// Finds a suitable opaque predicate for the specified method, with the
/// specified properties.
/// </summary>
/// <param name="method">The method.</param>
/// <param name="type">The required type of predicate, or <c>null</c> if it does not matter.</param>
/// <param name="argCount">The required numbers of arguments, or <c>null</c> if it does not matter.</param>
/// <returns>The suitable opaque predicate if found, or <c>null</c> if not found.</returns>
IOpaquePredicateDescriptor GetPredicate(MethodDef method, OpaquePredicateType? type, params int[] argCount);
}
}
53 changes: 53 additions & 0 deletions Confuser.Core/API/IDataStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using dnlib.DotNet;
using dnlib.DotNet.Emit;

namespace Confuser.Core.API {
/// <summary>
/// A data store.
/// </summary>
public interface IDataStore {
/// <summary>
/// Gets the priority of this data store; higher priority means it
/// would be tried earlier.
/// </summary>
/// <value>The priority of this data store.</value>
int Priority { get; }

/// <summary>
/// Gets the number of keys this predicate has.
/// </summary>
/// <remarks>
/// Keys are used by the data store to encrypt data/whatever purpose.
/// </remarks>
/// <value>The number of keys this data store has.</value>
int KeyCount { get; }

/// <summary>
/// Determines whether this data store can be used in the specified method.
/// </summary>
/// <param name="method">The method.</param>
/// <value><c>true</c> if this data store can be used in the specified method; otherwise, <c>false</c>.</value>
bool IsUsable(MethodDef method);

/// <summary>
/// Creates an accessor of this data store for the specified method.
/// </summary>
/// <param name="method">The method.</param>
/// <param name="keys">The keys.</param>
/// <param name="data">The data to store.</param>
/// <returns>A newly accessor of this data store.</returns>
IDataStoreAccessor CreateAccessor(MethodDef method, uint[] keys, byte[] data);
}

/// <summary>
/// An accessor of data store.
/// </summary>
public interface IDataStoreAccessor {
/// <summary>
/// Emits the runtime instruction sequence for this accessor.
/// </summary>
/// <returns>An instruction sequence that returns the stored data.</returns>
Instruction[] Emit();
}
}
79 changes: 79 additions & 0 deletions Confuser.Core/API/IOpaquePredicate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using dnlib.DotNet;
using dnlib.DotNet.Emit;

namespace Confuser.Core.API {
/// <summary>
/// The descriptor of a type of opaque predicate.
/// </summary>
public interface IOpaquePredicateDescriptor {
/// <summary>
/// Gets the type of the opaque predicate.
/// </summary>
/// <value>The type of the opaque predicate.</value>
OpaquePredicateType Type { get; }

/// <summary>
/// Gets the number of arguments this predicate has.
/// </summary>
/// <remarks>
/// When <see cref="IOpaquePredicateDescriptor.Type" /> is <see cref="OpaquePredicateType.Invariant" />,
/// there can be 0 or more arguments.
/// When <see cref="IOpaquePredicateDescriptor.Type" /> is <see cref="OpaquePredicateType.Function" />,
/// there must be more than 0 arguments.
/// </remarks>
/// <value>The number of arguments this predicate has.</value>
int ArgumentCount { get; }

/// <summary>
/// Determines whether this predicate can be used with the specified method.
/// </summary>
/// <param name="method">The method.</param>
/// <value><c>true</c> if this predicate can be used with the specified method; otherwise, <c>false</c>.</value>
bool IsUsable(MethodDef method);

/// <summary>
/// Creates a new opaque predicate for the specified method.
/// </summary>
/// <param name="method">The method.</param>
/// <returns>A newly create opaque predicate.</returns>
IOpaquePredicate CreatePredicate(MethodDef method);
}

/// <summary>
/// An instance of opaque predicate.
/// </summary>
public interface IOpaquePredicate {
/// <summary>
/// Emits the runtime instruction sequence for this predicate.
/// </summary>
/// <param name="loadArg">
/// A function that returns an instruction sequence that returns the input value,
/// or <c>null</c> if <see cref="IOpaquePredicateDescriptor.ArgumentCount" /> is 0.
/// </param>
/// <returns>An instruction sequence that returns the value of this predicate.</returns>
Instruction[] Emit(Func<Instruction[]> loadArg);

/// <summary>
/// Computes the value of this predicate with the specified argument.
/// </summary>
/// <param name="arg">The argument to this predicate.</param>
/// <returns>The return value of this predicate.</returns>
uint GetValue(uint[] arg);
}

/// <summary>
/// The type of opaque predicate.
/// </summary>
public enum OpaquePredicateType {
/// <summary>
/// A function, in a mathematics sense, with one input and one output.
/// </summary>
Function,

/// <summary>
/// A constant function, always returning the same value.
/// </summary>
Invariant
}
}
3 changes: 3 additions & 0 deletions Confuser.Core/Confuser.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Annotations.cs" />
<Compile Include="API\APIStore.cs" />
<Compile Include="API\IDataStore.cs" />
<Compile Include="API\IOpaquePredicate.cs" />
<Compile Include="Helpers\ControlFlowGraph.cs" />
<Compile Include="Helpers\KeySequence.cs" />
<Compile Include="LZMA\Common\CRC.cs" />
Expand Down
8 changes: 4 additions & 4 deletions Confuser.Core/ConfuserEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,19 +280,19 @@ static void Inspection(ConfuserContext context) {
modType = new TypeDefUser("", "<Module>", null);
modType.Attributes = TypeAttributes.AnsiClass;
module.Types.Add(modType);
marker.Mark(modType);
marker.Mark(modType, null);
}
MethodDef cctor = modType.FindOrCreateStaticConstructor();
if (!marker.IsMarked(cctor))
marker.Mark(cctor);
marker.Mark(cctor, null);
}

context.Logger.Debug("Watermarking...");
foreach (ModuleDefMD module in context.Modules) {
TypeRef attrRef = module.CorLibTypes.GetTypeRef("System", "Attribute");
var attrType = new TypeDefUser("", "ConfusedByAttribute", attrRef);
module.Types.Add(attrType);
marker.Mark(attrType);
marker.Mark(attrType, null);

var ctor = new MethodDefUser(
".ctor",
Expand All @@ -305,7 +305,7 @@ static void Inspection(ConfuserContext context) {
ctor.Body.Instructions.Add(OpCodes.Call.ToInstruction(new MemberRefUser(module, ".ctor", MethodSig.CreateInstance(module.CorLibTypes.Void), attrRef)));
ctor.Body.Instructions.Add(OpCodes.Ret.ToInstruction());
attrType.Methods.Add(ctor);
marker.Mark(ctor);
marker.Mark(ctor, null);

var attr = new CustomAttribute(ctor);
attr.ConstructorArguments.Add(new CAArgument(module.CorLibTypes.String, Version));
Expand Down
7 changes: 7 additions & 0 deletions Confuser.Core/CoreComponent.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Confuser.Core.API;
using Confuser.Core.Services;

namespace Confuser.Core {
Expand Down Expand Up @@ -31,6 +32,11 @@ public class CoreComponent : ConfuserComponent {
/// </summary>
public const string _CompressionServiceId = "Confuser.Compression";

/// <summary>
/// The service ID of API Store
/// </summary>
public const string _APIStoreId = "Confuser.APIStore";

readonly Marker marker;
readonly ConfuserParameters parameters;

Expand Down Expand Up @@ -71,6 +77,7 @@ protected internal override void Initialize(ConfuserContext context) {
context.Registry.RegisterService(_TraceServiceId, typeof(ITraceService), new TraceService(context));
context.Registry.RegisterService(_RuntimeServiceId, typeof(IRuntimeService), new RuntimeService());
context.Registry.RegisterService(_CompressionServiceId, typeof(ICompressionService), new CompressionService(context));
context.Registry.RegisterService(_APIStoreId, typeof(IAPIStore), new APIStore(context));
}

/// <inheritdoc />
Expand Down
25 changes: 23 additions & 2 deletions Confuser.Core/Services/MarkerService.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using dnlib.DotNet;

namespace Confuser.Core.Services {
internal class MarkerService : IMarkerService {
readonly ConfuserContext context;
readonly Marker marker;
readonly Dictionary<IDnlibDef, ConfuserComponent> helperParents;

/// <summary>
/// Initializes a new instance of the <see cref="MarkerService" /> class.
Expand All @@ -14,10 +16,11 @@ internal class MarkerService : IMarkerService {
public MarkerService(ConfuserContext context, Marker marker) {
this.context = context;
this.marker = marker;
helperParents = new Dictionary<IDnlibDef, ConfuserComponent>();
}

/// <inheritdoc />
public void Mark(IDnlibDef member) {
public void Mark(IDnlibDef member, ConfuserComponent parentComp) {
if (member == null)
throw new ArgumentNullException("member");
if (member is ModuleDef)
Expand All @@ -26,12 +29,22 @@ public void Mark(IDnlibDef member) {
return;

marker.MarkMember(member, context);
if (parentComp != null)
helperParents[member] = parentComp;
}

/// <inheritdoc />
public bool IsMarked(IDnlibDef def) {
return ProtectionParameters.GetParameters(context, def) != null;
}

/// <inheritdoc />
public ConfuserComponent GetHelperParent(IDnlibDef def) {
ConfuserComponent parent;
if (!helperParents.TryGetValue(def, out parent))
return null;
return parent;
}
}

/// <summary>
Expand All @@ -42,15 +55,23 @@ public interface IMarkerService {
/// Marks the helper member.
/// </summary>
/// <param name="member">The helper member.</param>
/// <param name="parentComp">The parent component.</param>
/// <exception cref="System.ArgumentException"><paramref name="member" /> is a <see cref="ModuleDef" />.</exception>
/// <exception cref="System.ArgumentNullException"><paramref name="member" /> is <c>null</c>.</exception>
void Mark(IDnlibDef member);
void Mark(IDnlibDef member, ConfuserComponent parentComp);

/// <summary>
/// Determines whether the specified definition is marked.
/// </summary>
/// <param name="def">The definition.</param>
/// <returns><c>true</c> if the specified definition is marked; otherwise, <c>false</c>.</returns>
bool IsMarked(IDnlibDef def);

/// <summary>
/// Gets the parent component of the specified helper.
/// </summary>
/// <param name="def">The helper definition.</param>
/// <returns>The parent component of the helper, or <c>null</c> if the specified definition is not a helper.</returns>
ConfuserComponent GetHelperParent(IDnlibDef def);
}
}
2 changes: 1 addition & 1 deletion Confuser.Core/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static TValue GetValueOrDefaultLazy<TKey, TValue>(
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add.</param>
/// <exception cref="System.ArgumentNullException">key is <c>null</c>.</exception>
public static void AddListEntry<TKey, TValue>(this Dictionary<TKey, List<TValue>> self, TKey key, TValue value) {
public static void AddListEntry<TKey, TValue>(this IDictionary<TKey, List<TValue>> self, TKey key, TValue value) {
if (key == null)
throw new ArgumentNullException("key");
List<TValue> list;
Expand Down
Loading

0 comments on commit 8885b97

Please sign in to comment.