Родитель
c0f7141e04
Коммит
6ce1d2dcff
|
@ -58,6 +58,9 @@
|
|||
<Compile Include="..\GlobalAssemblyInfo.cs">
|
||||
<Link>Properties\GlobalAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="ObfAttrMarker.cs" />
|
||||
<Compile Include="ObfAttrParser.cs" />
|
||||
<Compile Include="Options.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
@ -82,6 +85,10 @@
|
|||
<Project>{A45C184F-F98F-4258-A928-BFF437034791}</Project>
|
||||
<Name>Confuser.Runtime</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\dnlib\src\dnlib.csproj">
|
||||
<Project>{FDFC1237-143F-4919-8318-4926901F4639}</Project>
|
||||
<Name>dnlib</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\ConfuserEx.snk">
|
||||
|
|
|
@ -0,0 +1,323 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Confuser.Core;
|
||||
using Confuser.Core.Project;
|
||||
using dnlib.DotNet;
|
||||
|
||||
namespace Confuser.CLI {
|
||||
internal class ObfAttrMarker : Marker {
|
||||
protected override void MarkMember(IDnlibDef member, ConfuserContext context) {
|
||||
ModuleDef module = ((IMemberRef)member).Module;
|
||||
ProtectionParameters.SetParameters(context, member, ProtectionParameters.GetParameters(context, module));
|
||||
}
|
||||
|
||||
protected override MarkerResult MarkProject(ConfuserProject proj, ConfuserContext context) {
|
||||
var modules = new List<Tuple<ProjectModule, ModuleDefMD>>();
|
||||
foreach (ProjectModule module in proj) {
|
||||
|
||||
ModuleDefMD modDef = module.Resolve(proj.BaseDirectory, context.Resolver.DefaultModuleContext);
|
||||
context.CheckCancellation();
|
||||
|
||||
context.Resolver.AddToCache(modDef);
|
||||
modules.Add(Tuple.Create(module, modDef));
|
||||
}
|
||||
|
||||
Tuple<Packer, Dictionary<string, string>> packerInfo = null;
|
||||
foreach (var module in modules) {
|
||||
context.Logger.InfoFormat("Loading '{0}'...", module.Item1.Path);
|
||||
|
||||
MarkModule(proj, context, module.Item2, module == modules[0], ref packerInfo);
|
||||
|
||||
// Packer parameters are stored in modules
|
||||
if (packerInfo != null)
|
||||
ProtectionParameters.GetParameters(context, module.Item2)[packerInfo.Item1] = packerInfo.Item2;
|
||||
}
|
||||
return new MarkerResult(modules.Select(module => module.Item2).ToList(), packerInfo == null ? null : packerInfo.Item1);
|
||||
}
|
||||
|
||||
private struct ObfuscationAttributeInfo {
|
||||
public bool? ApplyToMembers;
|
||||
public bool? Exclude;
|
||||
public string FeatureName;
|
||||
public string FeatureValue;
|
||||
}
|
||||
|
||||
private struct ProtectionSettingsInfo {
|
||||
public bool ApplyToMember;
|
||||
public bool Exclude;
|
||||
public string Settings;
|
||||
}
|
||||
|
||||
private class ProtectionSettingsStack {
|
||||
private Stack<ProtectionSettingsInfo[]> stack;
|
||||
|
||||
public ProtectionSettingsStack() {
|
||||
stack = new Stack<ProtectionSettingsInfo[]>();
|
||||
}
|
||||
|
||||
public ProtectionSettingsStack(ProtectionSettingsStack copy) {
|
||||
stack = new Stack<ProtectionSettingsInfo[]>(copy.stack);
|
||||
}
|
||||
|
||||
public void Push(IEnumerable<ProtectionSettingsInfo> infos) {
|
||||
stack.Push(infos.ToArray());
|
||||
}
|
||||
|
||||
public void Pop() {
|
||||
stack.Pop();
|
||||
}
|
||||
|
||||
public IEnumerable<ProtectionSettingsInfo> GetInfos() {
|
||||
return stack.Reverse().SelectMany(infos => infos);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ObfuscationAttributeInfo> ReadObfuscationAttributes(IHasCustomAttribute item) {
|
||||
var ret = new List<ObfuscationAttributeInfo>();
|
||||
for (int i = item.CustomAttributes.Count - 1; i >= 0; i--) {
|
||||
var ca = item.CustomAttributes[i];
|
||||
if (ca.TypeFullName != "System.Reflection.ObfuscationAttribute")
|
||||
continue;
|
||||
|
||||
var info = new ObfuscationAttributeInfo();
|
||||
bool strip = true;
|
||||
foreach (var prop in ca.Properties) {
|
||||
switch (prop.Name) {
|
||||
|
||||
case "ApplyToMembers":
|
||||
Debug.Assert(prop.Type.ElementType == ElementType.Boolean);
|
||||
info.ApplyToMembers = (bool)prop.Value;
|
||||
break;
|
||||
|
||||
case "Exclude":
|
||||
Debug.Assert(prop.Type.ElementType == ElementType.Boolean);
|
||||
info.Exclude = (bool)prop.Value;
|
||||
break;
|
||||
|
||||
case "StripAfterObfuscation":
|
||||
Debug.Assert(prop.Type.ElementType == ElementType.Boolean);
|
||||
strip = (bool)prop.Value;
|
||||
break;
|
||||
|
||||
case "Feature":
|
||||
Debug.Assert(prop.Type.ElementType == ElementType.String);
|
||||
string feature = (UTF8String)prop.Value;
|
||||
int sepIndex = feature.IndexOf(':');
|
||||
if (sepIndex == -1) {
|
||||
info.FeatureName = "";
|
||||
info.FeatureValue = feature;
|
||||
}
|
||||
else {
|
||||
info.FeatureName = feature.Substring(0, sepIndex);
|
||||
info.FeatureValue = feature.Substring(sepIndex + 1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException("Unsupported property: " + prop.Name);
|
||||
}
|
||||
}
|
||||
if (strip)
|
||||
item.CustomAttributes.RemoveAt(i);
|
||||
|
||||
ret.Add(info);
|
||||
}
|
||||
ret.Reverse();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static IEnumerable<ProtectionSettingsInfo> ProcessAttributes(IEnumerable<ObfuscationAttributeInfo> attrs) {
|
||||
foreach (var attr in attrs) {
|
||||
var info = new ProtectionSettingsInfo();
|
||||
|
||||
info.Exclude = (attr.Exclude ?? true);
|
||||
info.ApplyToMember = (attr.ApplyToMembers ?? true);
|
||||
info.Settings = attr.FeatureValue;
|
||||
|
||||
if (!string.IsNullOrEmpty(attr.FeatureName))
|
||||
throw new ArgumentException("Feature name must not be set.");
|
||||
if (info.Exclude && (!string.IsNullOrEmpty(attr.FeatureName) || !string.IsNullOrEmpty(attr.FeatureValue))) {
|
||||
throw new ArgumentException("Feature property cannot be set when Exclude is true.");
|
||||
}
|
||||
yield return info;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplySettings(ConfuserContext context, IDnlibDef def, IEnumerable<ProtectionSettingsInfo> infos) {
|
||||
var settings = new ProtectionSettings();
|
||||
|
||||
ProtectionSettingsInfo? last = null;
|
||||
var parser = new ObfAttrParser(protections);
|
||||
foreach (var info in infos) {
|
||||
|
||||
if (info.Exclude) {
|
||||
if (info.ApplyToMember)
|
||||
settings.Clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
last = info;
|
||||
|
||||
if (info.ApplyToMember) {
|
||||
parser.ParseProtectionString(settings, info.Settings);
|
||||
}
|
||||
}
|
||||
if (last != null && !last.Value.ApplyToMember) {
|
||||
parser.ParseProtectionString(settings, last.Value.Settings);
|
||||
}
|
||||
|
||||
ProtectionParameters.SetParameters(context, def, settings);
|
||||
}
|
||||
|
||||
private static readonly Regex NSPattern = new Regex("namespace '([^']*)'");
|
||||
|
||||
private void MarkModule(ConfuserProject proj, ConfuserContext context, ModuleDefMD module, bool isMain,
|
||||
ref Tuple<Packer, Dictionary<string, string>> packerInfo) {
|
||||
|
||||
var settingAttrs = new List<ObfuscationAttributeInfo>();
|
||||
string snKeyPath = null, snKeyPass = null;
|
||||
var namespaceAttrs = new Dictionary<string, List<ObfuscationAttributeInfo>>();
|
||||
|
||||
foreach (var attr in ReadObfuscationAttributes(module.Assembly)) {
|
||||
|
||||
if (attr.FeatureName.Equals("generate debug symbol", StringComparison.OrdinalIgnoreCase)) {
|
||||
if (!isMain)
|
||||
throw new ArgumentException("Only main module can set 'generate debug symbol'.");
|
||||
proj.Debug = bool.Parse(attr.FeatureValue);
|
||||
}
|
||||
if (proj.Debug) {
|
||||
module.LoadPdb();
|
||||
}
|
||||
|
||||
if (attr.FeatureName.Equals("random seed", StringComparison.OrdinalIgnoreCase)) {
|
||||
if (!isMain)
|
||||
throw new ArgumentException("Only main module can set 'random seed'.");
|
||||
proj.Seed = attr.FeatureValue;
|
||||
}
|
||||
|
||||
else if (attr.FeatureName.Equals("strong name key", StringComparison.OrdinalIgnoreCase)) {
|
||||
snKeyPath = Path.Combine(proj.BaseDirectory, attr.FeatureValue);
|
||||
}
|
||||
|
||||
else if (attr.FeatureName.Equals("strong name key password", StringComparison.OrdinalIgnoreCase)) {
|
||||
snKeyPass = attr.FeatureValue;
|
||||
}
|
||||
|
||||
else if (attr.FeatureName.Equals("packer", StringComparison.OrdinalIgnoreCase)) {
|
||||
if (!isMain)
|
||||
throw new ArgumentException("Only main module can set 'packer'.");
|
||||
Packer packer;
|
||||
Dictionary<string, string> packerParams;
|
||||
new ObfAttrParser(packers).ParsePackerString(attr.FeatureValue, out packer, out packerParams);
|
||||
packerInfo = Tuple.Create(packer, packerParams);
|
||||
}
|
||||
else if (attr.FeatureName == "") {
|
||||
settingAttrs.Add(attr);
|
||||
}
|
||||
else {
|
||||
var match = NSPattern.Match(attr.FeatureName);
|
||||
if (match.Success) {
|
||||
string ns = match.Groups[1].Value;
|
||||
var x = attr;
|
||||
x.FeatureName = "";
|
||||
namespaceAttrs.AddListEntry(ns, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProcessModule(module, context, snKeyPath, snKeyPass, settingAttrs, namespaceAttrs);
|
||||
}
|
||||
|
||||
private void ProcessModule(ModuleDefMD module, ConfuserContext context, string snKeyPath, string snKeyPass,
|
||||
List<ObfuscationAttributeInfo> settingAttrs,
|
||||
Dictionary<string, List<ObfuscationAttributeInfo>> namespaceAttrs) {
|
||||
|
||||
context.Annotations.Set(module, SNKey, LoadSNKey(context, snKeyPath, snKeyPass));
|
||||
|
||||
var moduleStack = new ProtectionSettingsStack();
|
||||
moduleStack.Push(ProcessAttributes(settingAttrs));
|
||||
ApplySettings(context, module, moduleStack.GetInfos());
|
||||
|
||||
var nsSettings = namespaceAttrs.ToDictionary(kvp => kvp.Key, kvp => {
|
||||
var nsStack = new ProtectionSettingsStack(moduleStack);
|
||||
nsStack.Push(ProcessAttributes(kvp.Value));
|
||||
return nsStack;
|
||||
});
|
||||
|
||||
foreach (var type in module.Types) {
|
||||
var typeStack = nsSettings.GetValueOrDefault(type.Namespace, moduleStack);
|
||||
typeStack.Push(ProcessAttributes(ReadObfuscationAttributes(type)));
|
||||
|
||||
ApplySettings(context, type, typeStack.GetInfos());
|
||||
ProcessTypeMembers(type, context, typeStack);
|
||||
|
||||
typeStack.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessTypeMembers(TypeDef type, ConfuserContext context, ProtectionSettingsStack stack) {
|
||||
foreach (var nestedType in type.NestedTypes) {
|
||||
stack.Push(ProcessAttributes(ReadObfuscationAttributes(nestedType)));
|
||||
|
||||
ApplySettings(context, nestedType, stack.GetInfos());
|
||||
ProcessTypeMembers(nestedType, context, stack);
|
||||
|
||||
stack.Pop();
|
||||
}
|
||||
|
||||
foreach (var prop in type.Properties) {
|
||||
stack.Push(ProcessAttributes(ReadObfuscationAttributes(prop)));
|
||||
|
||||
ApplySettings(context, prop, stack.GetInfos());
|
||||
if (prop.GetMethod != null) {
|
||||
ProcessMember(prop.GetMethod, context, stack);
|
||||
}
|
||||
if (prop.SetMethod != null) {
|
||||
ProcessMember(prop.GetMethod, context, stack);
|
||||
}
|
||||
foreach (var m in prop.OtherMethods)
|
||||
ProcessMember(m, context, stack);
|
||||
|
||||
stack.Pop();
|
||||
}
|
||||
|
||||
foreach (var evt in type.Events) {
|
||||
stack.Push(ProcessAttributes(ReadObfuscationAttributes(evt)));
|
||||
|
||||
ApplySettings(context, evt, stack.GetInfos());
|
||||
if (evt.AddMethod != null) {
|
||||
ProcessMember(evt.AddMethod, context, stack);
|
||||
}
|
||||
if (evt.RemoveMethod != null) {
|
||||
ProcessMember(evt.RemoveMethod, context, stack);
|
||||
}
|
||||
if (evt.InvokeMethod != null) {
|
||||
ProcessMember(evt.InvokeMethod, context, stack);
|
||||
}
|
||||
foreach (var m in evt.OtherMethods)
|
||||
ProcessMember(m, context, stack);
|
||||
|
||||
stack.Pop();
|
||||
}
|
||||
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.SemanticsAttributes == 0)
|
||||
ProcessMember(method, context, stack);
|
||||
}
|
||||
|
||||
foreach (var field in type.Fields) {
|
||||
ProcessMember(field, context, stack);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessMember(IDnlibDef member, ConfuserContext context, ProtectionSettingsStack stack) {
|
||||
stack.Push(ProcessAttributes(ReadObfuscationAttributes(member)));
|
||||
ApplySettings(context, member, stack.GetInfos());
|
||||
stack.Pop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Confuser.Core;
|
||||
|
||||
namespace Confuser.CLI {
|
||||
internal struct ObfAttrParser {
|
||||
private System.Collections.IDictionary items;
|
||||
|
||||
private string str;
|
||||
private int index;
|
||||
|
||||
public ObfAttrParser(System.Collections.IDictionary items) {
|
||||
this.items = items;
|
||||
this.str = null;
|
||||
this.index = -1;
|
||||
}
|
||||
|
||||
private enum ParseState {
|
||||
Init,
|
||||
ReadPreset,
|
||||
ReadItemName,
|
||||
ProcessItemName,
|
||||
ReadParam,
|
||||
EndItem,
|
||||
End
|
||||
}
|
||||
|
||||
private bool ReadId(StringBuilder sb) {
|
||||
while (index < str.Length) {
|
||||
switch (str[index]) {
|
||||
case '(':
|
||||
case ')':
|
||||
case '+':
|
||||
case '-':
|
||||
case '=':
|
||||
case ';':
|
||||
case ',':
|
||||
return true;
|
||||
default:
|
||||
sb.Append(str[index++]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void Expect(char chr) {
|
||||
if (str[index] != chr)
|
||||
throw new ArgumentException("Expect '" + chr + "' at position " + (index + 1) + ".");
|
||||
index++;
|
||||
}
|
||||
|
||||
private char Peek() {
|
||||
return str[index];
|
||||
}
|
||||
|
||||
private void Next() {
|
||||
index++;
|
||||
}
|
||||
|
||||
private bool IsEnd() {
|
||||
return index == str.Length;
|
||||
}
|
||||
|
||||
public void ParseProtectionString(ProtectionSettings settings, string str) {
|
||||
this.str = str;
|
||||
this.index = 0;
|
||||
|
||||
var state = ParseState.Init;
|
||||
var buffer = new StringBuilder();
|
||||
|
||||
bool protAct = true;
|
||||
string protId = null;
|
||||
var protParams = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
while (state != ParseState.End) {
|
||||
switch (state) {
|
||||
|
||||
case ParseState.Init:
|
||||
ReadId(buffer);
|
||||
if (buffer.ToString().Equals("preset", StringComparison.OrdinalIgnoreCase)) {
|
||||
if (IsEnd())
|
||||
throw new ArgumentException("Unexpected end of string in Init state.");
|
||||
Expect('(');
|
||||
buffer.Length = 0;
|
||||
state = ParseState.ReadPreset;
|
||||
}
|
||||
else if (buffer.Length == 0) {
|
||||
if (IsEnd())
|
||||
throw new ArgumentException("Unexpected end of string in Init state.");
|
||||
state = ParseState.ReadItemName;
|
||||
}
|
||||
else {
|
||||
protAct = true;
|
||||
state = ParseState.ProcessItemName;
|
||||
}
|
||||
break;
|
||||
|
||||
case ParseState.ReadPreset:
|
||||
if (!ReadId(buffer))
|
||||
throw new ArgumentException("Unexpected end of string in ReadPreset state.");
|
||||
Expect(')');
|
||||
|
||||
var preset = (ProtectionPreset)Enum.Parse(typeof(ProtectionPreset), buffer.ToString(), true);
|
||||
foreach (var item in items.Values.OfType<Protection>().Where(prot => prot.Preset <= preset)) {
|
||||
if (!settings.ContainsKey(item))
|
||||
settings.Add(item, new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
buffer.Length = 0;
|
||||
|
||||
if (IsEnd())
|
||||
state = ParseState.End;
|
||||
else {
|
||||
Expect(';');
|
||||
if (IsEnd())
|
||||
state = ParseState.End;
|
||||
else
|
||||
state = ParseState.ReadItemName;
|
||||
}
|
||||
break;
|
||||
|
||||
case ParseState.ReadItemName:
|
||||
protAct = true;
|
||||
if (Peek() == '+') {
|
||||
protAct = true;
|
||||
Next();
|
||||
}
|
||||
else if (Peek() == '-') {
|
||||
protAct = false;
|
||||
Next();
|
||||
}
|
||||
ReadId(buffer);
|
||||
state = ParseState.ProcessItemName;
|
||||
break;
|
||||
|
||||
case ParseState.ProcessItemName:
|
||||
protId = buffer.ToString();
|
||||
buffer.Length = 0;
|
||||
if (IsEnd() || Peek() == ';')
|
||||
state = ParseState.EndItem;
|
||||
else if (Peek() == '(') {
|
||||
if (!protAct)
|
||||
throw new ArgumentException("No parameters is allowed when removing protection.");
|
||||
Next();
|
||||
state = ParseState.ReadParam;
|
||||
}
|
||||
else
|
||||
throw new ArgumentException("Unexpected character in ProcessItemName state at " + index + ".");
|
||||
break;
|
||||
|
||||
case ParseState.ReadParam:
|
||||
string paramName, paramValue;
|
||||
|
||||
if (!ReadId(buffer))
|
||||
throw new ArgumentException("Unexpected end of string in ReadParam state.");
|
||||
paramName = buffer.ToString();
|
||||
buffer.Length = 0;
|
||||
|
||||
Expect('=');
|
||||
if (!ReadId(buffer))
|
||||
throw new ArgumentException("Unexpected end of string in ReadParam state.");
|
||||
paramValue = buffer.ToString();
|
||||
buffer.Length = 0;
|
||||
|
||||
protParams.Add(paramName, paramValue);
|
||||
|
||||
if (Peek() == ',') {
|
||||
Next();
|
||||
state = ParseState.ReadParam;
|
||||
}
|
||||
else if (Peek() == ')') {
|
||||
Next();
|
||||
state = ParseState.EndItem;
|
||||
}
|
||||
else
|
||||
throw new ArgumentException("Unexpected character in ReadParam state at " + index + ".");
|
||||
break;
|
||||
|
||||
case ParseState.EndItem:
|
||||
if (protAct) {
|
||||
settings[(Protection)items[protId]] = protParams;
|
||||
protParams = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
else
|
||||
settings.Remove((Protection)items[protId]);
|
||||
|
||||
if (IsEnd())
|
||||
state = ParseState.End;
|
||||
else {
|
||||
Expect(';');
|
||||
if (IsEnd())
|
||||
state = ParseState.End;
|
||||
else
|
||||
state = ParseState.ReadItemName;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ParsePackerString(string str, out Packer packer, out Dictionary<string, string> packerParams) {
|
||||
this.str = str;
|
||||
this.index = 0;
|
||||
|
||||
var state = ParseState.ReadItemName;
|
||||
var buffer = new StringBuilder();
|
||||
var ret = new ProtectionSettings();
|
||||
|
||||
packer = null;
|
||||
packerParams = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
while (state != ParseState.End) {
|
||||
switch (state) {
|
||||
case ParseState.ReadItemName:
|
||||
if (!ReadId(buffer))
|
||||
throw new ArgumentException("Unexpected end of string in ReadItemName state.");
|
||||
|
||||
packer = (Packer)items[buffer.ToString()];
|
||||
buffer.Length = 0;
|
||||
|
||||
if (IsEnd() || Peek() == ';')
|
||||
state = ParseState.EndItem;
|
||||
else if (Peek() == '(') {
|
||||
Next();
|
||||
state = ParseState.ReadParam;
|
||||
}
|
||||
else
|
||||
throw new ArgumentException("Unexpected character in ReadItemName state at " + index + ".");
|
||||
break;
|
||||
|
||||
case ParseState.ReadParam:
|
||||
string paramName, paramValue;
|
||||
|
||||
if (!ReadId(buffer))
|
||||
throw new ArgumentException("Unexpected end of string in ReadParam state.");
|
||||
paramName = buffer.ToString();
|
||||
buffer.Length = 0;
|
||||
|
||||
Expect('=');
|
||||
if (!ReadId(buffer))
|
||||
throw new ArgumentException("Unexpected end of string in ReadParam state.");
|
||||
paramValue = buffer.ToString();
|
||||
buffer.Length = 0;
|
||||
|
||||
packerParams.Add(paramName, paramValue);
|
||||
|
||||
if (Peek() == ',') {
|
||||
Next();
|
||||
state = ParseState.ReadParam;
|
||||
}
|
||||
else if (Peek() == ')') {
|
||||
Next();
|
||||
state = ParseState.EndItem;
|
||||
}
|
||||
else
|
||||
throw new ArgumentException("Unexpected character in ReadParam state at " + index + ".");
|
||||
break;
|
||||
|
||||
case ParseState.EndItem:
|
||||
if (IsEnd())
|
||||
state = ParseState.End;
|
||||
else {
|
||||
Expect(';');
|
||||
if (!IsEnd())
|
||||
throw new ArgumentException("Unexpected character in EndItem state at " + index + ".");
|
||||
state = ParseState.End;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using Confuser.Core;
|
||||
using Confuser.Core.Project;
|
||||
using NDesk.Options;
|
||||
|
||||
namespace Confuser.CLI {
|
||||
internal class Program {
|
||||
|
@ -14,40 +16,67 @@ namespace Confuser.CLI {
|
|||
string originalTitle = Console.Title;
|
||||
Console.Title = "ConfuserEx";
|
||||
|
||||
bool noPause = false;
|
||||
string outDir = null;
|
||||
var p = new OptionSet() {
|
||||
{ "n|nopause", "no pause after finishing protection.",
|
||||
value => { noPause = (value != null); } },
|
||||
{ "o|out=", "specifies output directory.",
|
||||
value => { outDir = value; } },
|
||||
};
|
||||
|
||||
List<string> files;
|
||||
try {
|
||||
if (args.Length < 1) {
|
||||
PrintUsage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
var proj = new ConfuserProject();
|
||||
try {
|
||||
var xmlDoc = new XmlDocument();
|
||||
xmlDoc.Load(args[0]);
|
||||
proj.Load(xmlDoc);
|
||||
proj.BaseDirectory = Path.Combine(Path.GetDirectoryName(args[0]), proj.BaseDirectory);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteLineWithColor(ConsoleColor.Red, "Failed to load project:");
|
||||
WriteLineWithColor(ConsoleColor.Red, ex.ToString());
|
||||
return -1;
|
||||
}
|
||||
files = p.Parse(args);
|
||||
if (files.Count == 0)
|
||||
throw new ArgumentException("No input files specified.");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Console.Write("ConfuserEx.CLI: ");
|
||||
Console.WriteLine(ex.Message);
|
||||
PrintUsage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
var parameters = new ConfuserParameters();
|
||||
parameters.Project = proj;
|
||||
var logger = new ConsoleLogger();
|
||||
parameters.Logger = new ConsoleLogger();
|
||||
|
||||
Console.Title = "ConfuserEx - Running...";
|
||||
ConfuserEngine.Run(parameters).Wait();
|
||||
if (files.Count == 1 && Path.GetExtension(files[0]) == "crproj") {
|
||||
var proj = new ConfuserProject();
|
||||
try {
|
||||
var xmlDoc = new XmlDocument();
|
||||
xmlDoc.Load(args[0]);
|
||||
proj.Load(xmlDoc);
|
||||
proj.BaseDirectory = Path.Combine(Path.GetDirectoryName(args[0]), proj.BaseDirectory);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
WriteLineWithColor(ConsoleColor.Red, "Failed to load project:");
|
||||
WriteLineWithColor(ConsoleColor.Red, ex.ToString());
|
||||
return -1;
|
||||
}
|
||||
|
||||
parameters.Project = proj;
|
||||
}
|
||||
else {
|
||||
// Generate a ConfuserProject for input modules
|
||||
// Assuming first file = main module
|
||||
var proj = new ConfuserProject();
|
||||
foreach (var input in files)
|
||||
proj.Add(new ProjectModule() { Path = input });
|
||||
proj.BaseDirectory = Path.GetDirectoryName(files[0]);
|
||||
proj.OutputDirectory = outDir;
|
||||
parameters.Project = proj;
|
||||
parameters.Marker = new ObfAttrMarker();
|
||||
}
|
||||
|
||||
int retVal = RunProject(parameters);
|
||||
|
||||
bool noPause = args.Length > 1 && args[1].ToUpperInvariant() == "NOPAUSE";
|
||||
if (NeedPause() && !noPause) {
|
||||
Console.WriteLine("Press any key to continue...");
|
||||
Console.ReadKey(true);
|
||||
}
|
||||
|
||||
return logger.ReturnValue;
|
||||
return retVal;
|
||||
}
|
||||
finally {
|
||||
Console.ForegroundColor = original;
|
||||
|
@ -55,13 +84,26 @@ namespace Confuser.CLI {
|
|||
}
|
||||
}
|
||||
|
||||
private static int RunProject(ConfuserParameters parameters) {
|
||||
var logger = new ConsoleLogger();
|
||||
parameters.Logger = new ConsoleLogger();
|
||||
|
||||
Console.Title = "ConfuserEx - Running...";
|
||||
ConfuserEngine.Run(parameters).Wait();
|
||||
|
||||
return logger.ReturnValue;
|
||||
}
|
||||
|
||||
private static bool NeedPause() {
|
||||
return Debugger.IsAttached || string.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROMPT"));
|
||||
}
|
||||
|
||||
private static void PrintUsage() {
|
||||
WriteLine("Usage:");
|
||||
WriteLine("Confuser.CLI.exe <project configuration>");
|
||||
WriteLine("Confuser.CLI -n|noPause <project configuration>");
|
||||
WriteLine("Confuser.CLI -n|noPause -o|out=<output directory> <modules>");
|
||||
WriteLine(" -n|noPause : no pause after finishing protection.");
|
||||
WriteLine(" -o|out : specifies output directory.");
|
||||
}
|
||||
|
||||
private static void WriteLineWithColor(ConsoleColor color, string txt) {
|
||||
|
|
|
@ -26,8 +26,14 @@ namespace Confuser.Core {
|
|||
/// </summary>
|
||||
public static readonly object RulesKey = new object();
|
||||
|
||||
private Dictionary<string, Packer> packers;
|
||||
private Dictionary<string, Protection> protections;
|
||||
/// <summary>
|
||||
/// The packers available to use.
|
||||
/// </summary>
|
||||
protected Dictionary<string, Packer> packers;
|
||||
/// <summary>
|
||||
/// The protections available to use.
|
||||
/// </summary>
|
||||
protected Dictionary<string, Protection> protections;
|
||||
|
||||
/// <summary>
|
||||
/// Initalizes the Marker with specified protections and packers.
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
ConfuserEx declarative obfuscation:
|
||||
|
||||
Attribute semantics:
|
||||
ApplyToMembers: The children uses this protection settings as base.
|
||||
Exclude: No protection will be applied to this item.
|
||||
!ApplyToMembers + !Exclude: The protection settings just apply to this item.
|
||||
ApplyToMembers + Exclude: This item and its chilren will have no protection.
|
||||
|
||||
Pattern examples:
|
||||
|
||||
generate debug symbol:true
|
||||
random seed:ABCDEFG
|
||||
strong name key:C:\key.snk
|
||||
strong name key password:hunter2
|
||||
packer:compressor(mode=dynamic)
|
||||
namespace 'ConfuserEx.CLI':preset(normal);+rename;anti tamper(mode=jit,key=dynamic);-anti debug
|
||||
preset(none);+rename;
|
||||
|
||||
Usage examples:
|
||||
|
||||
[assembly: Obfuscation(Exclude = false, Feature = "preset(minimum);+ctrl flow;-anti debug;+rename(mode=letters,flatten=false);")]
|
||||
[assembly: Obfuscation(Exclude = false, Feature = "random seed: Hello!")]
|
||||
[assembly: Obfuscation(Exclude = false, Feature = "namespace 'Test':-rename")]
|
||||
namespace Test {
|
||||
[Obfuscation(Exclude = false, Feature = "constants")]
|
||||
class Program {
|
||||
public static void Main() {
|
||||
Console.WriteLine("Hi");
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче