Adapted to changes of dnlib 3.x
This commit is contained in:
Родитель
694e0ca0a5
Коммит
d32a89400c
|
@ -0,0 +1,110 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
#end_of_line =
|
||||
indent_size = 4
|
||||
indent_style = tab
|
||||
insert_final_newline = true
|
||||
tab_width = 4
|
||||
|
||||
[*.json]
|
||||
|
||||
[App.config]
|
||||
|
||||
[*.yml]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[*.{proj,csproj,vbproj,props,targets,resx,vsixmanifest}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[app.manifest]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[*.xml]
|
||||
|
||||
[*.xaml]
|
||||
indent_style = space
|
||||
|
||||
[*.{cs,vb}]
|
||||
dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = true
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:none
|
||||
dotnet_style_predefined_type_for_member_access = true:none
|
||||
dotnet_style_prefer_auto_properties = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_require_accessibility_modifiers = never:info
|
||||
|
||||
[*.cs]
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = false
|
||||
csharp_indent_labels = flush_left
|
||||
csharp_indent_switch_labels = false
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = none
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
csharp_prefer_braces = false
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
#csharp_preferred_modifier_order =
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses =
|
||||
csharp_space_between_square_brackets = false
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
csharp_style_deconstructed_variable_declaration = false:none
|
||||
csharp_style_expression_bodied_accessors = true:suggestion
|
||||
csharp_style_expression_bodied_constructors = true:suggestion
|
||||
csharp_style_expression_bodied_indexers = true:suggestion
|
||||
csharp_style_expression_bodied_methods = true:suggestion
|
||||
csharp_style_expression_bodied_operators = true:suggestion
|
||||
csharp_style_expression_bodied_properties = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
csharp_style_var_for_built_in_types = false:none
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
|
||||
[*.vb]
|
||||
#visual_basic_preferred_modifier_order =
|
|
@ -84,7 +84,6 @@
|
|||
<Compile Include="ILogger.cs" />
|
||||
<Compile Include="Marker.cs" />
|
||||
<Compile Include="MarkerResult.cs" />
|
||||
<Compile Include="ModuleWriterListener.cs" />
|
||||
<Compile Include="NativeEraser.cs" />
|
||||
<Compile Include="ObfAttrMarker.cs" />
|
||||
<Compile Include="ObfAttrParser.cs" />
|
||||
|
|
|
@ -124,12 +124,6 @@ namespace Confuser.Core {
|
|||
/// <value>The writer options.</value>
|
||||
public ModuleWriterOptionsBase CurrentModuleWriterOptions { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the writer event listener of the current module.
|
||||
/// </summary>
|
||||
/// <value>The writer event listener.</value>
|
||||
public ModuleWriterListener CurrentModuleWriterListener { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets output <c>byte[]</c> of the current module
|
||||
/// </summary>
|
||||
|
@ -165,17 +159,17 @@ namespace Confuser.Core {
|
|||
if (CurrentModule == null)
|
||||
return null;
|
||||
if (CurrentModuleWriterOptions == null)
|
||||
CurrentModuleWriterOptions = new NativeModuleWriterOptions(CurrentModule);
|
||||
CurrentModuleWriterOptions = new NativeModuleWriterOptions(CurrentModule, true);
|
||||
|
||||
if (CurrentModuleWriterOptions is NativeModuleWriterOptions)
|
||||
return (NativeModuleWriterOptions)CurrentModuleWriterOptions;
|
||||
var newOptions = new NativeModuleWriterOptions(CurrentModule, CurrentModuleWriterOptions.Listener);
|
||||
var newOptions = new NativeModuleWriterOptions(CurrentModule, true);
|
||||
// Clone the current options to the new options
|
||||
newOptions.AddCheckSum = CurrentModuleWriterOptions.AddCheckSum;
|
||||
newOptions.Cor20HeaderOptions = CurrentModuleWriterOptions.Cor20HeaderOptions;
|
||||
newOptions.Logger = CurrentModuleWriterOptions.Logger;
|
||||
newOptions.MetaDataLogger = CurrentModuleWriterOptions.MetaDataLogger;
|
||||
newOptions.MetaDataOptions = CurrentModuleWriterOptions.MetaDataOptions;
|
||||
newOptions.MetadataLogger = CurrentModuleWriterOptions.MetadataLogger;
|
||||
newOptions.MetadataOptions = CurrentModuleWriterOptions.MetadataOptions;
|
||||
newOptions.ModuleKind = CurrentModuleWriterOptions.ModuleKind;
|
||||
newOptions.PEHeadersOptions = CurrentModuleWriterOptions.PEHeadersOptions;
|
||||
newOptions.ShareMethodBodies = CurrentModuleWriterOptions.ShareMethodBodies;
|
||||
|
@ -186,4 +180,4 @@ namespace Confuser.Core {
|
|||
return newOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -179,7 +179,7 @@ namespace Confuser.Core {
|
|||
PrintEnvironmentInfo(context);
|
||||
}
|
||||
catch (TypeResolveException ex) {
|
||||
context.Logger.ErrorException("Failed to resolve a type, check if all dependencies are present in the correct version.", ex);
|
||||
context.Logger.ErrorException("Failed to resolve a type, check if all dependencies are present in the correct version.", ex);
|
||||
PrintEnvironmentInfo(context);
|
||||
}
|
||||
catch (MemberRefResolveException ex) {
|
||||
|
@ -219,11 +219,9 @@ namespace Confuser.Core {
|
|||
pipeline.ExecuteStage(PipelineStage.Inspection, Inspection, () => getAllDefs(), context);
|
||||
|
||||
var options = new ModuleWriterOptionsBase[context.Modules.Count];
|
||||
var listeners = new ModuleWriterListener[context.Modules.Count];
|
||||
for (int i = 0; i < context.Modules.Count; i++) {
|
||||
context.CurrentModuleIndex = i;
|
||||
context.CurrentModuleWriterOptions = null;
|
||||
context.CurrentModuleWriterListener = null;
|
||||
|
||||
pipeline.ExecuteStage(PipelineStage.BeginModule, BeginModule, () => getModuleDefs(context.CurrentModule), context);
|
||||
pipeline.ExecuteStage(PipelineStage.ProcessModule, ProcessModule, () => getModuleDefs(context.CurrentModule), context);
|
||||
|
@ -231,20 +229,17 @@ namespace Confuser.Core {
|
|||
pipeline.ExecuteStage(PipelineStage.EndModule, EndModule, () => getModuleDefs(context.CurrentModule), context);
|
||||
|
||||
options[i] = context.CurrentModuleWriterOptions;
|
||||
listeners[i] = context.CurrentModuleWriterListener;
|
||||
}
|
||||
|
||||
for (int i = 0; i < context.Modules.Count; i++) {
|
||||
context.CurrentModuleIndex = i;
|
||||
context.CurrentModuleWriterOptions = options[i];
|
||||
context.CurrentModuleWriterListener = listeners[i];
|
||||
|
||||
pipeline.ExecuteStage(PipelineStage.WriteModule, WriteModule, () => getModuleDefs(context.CurrentModule), context);
|
||||
|
||||
context.OutputModules[i] = context.CurrentModuleOutput;
|
||||
context.OutputSymbols[i] = context.CurrentModuleSymbol;
|
||||
context.CurrentModuleWriterOptions = null;
|
||||
context.CurrentModuleWriterListener = null;
|
||||
context.CurrentModuleOutput = null;
|
||||
context.CurrentModuleSymbol = null;
|
||||
}
|
||||
|
@ -262,7 +257,7 @@ namespace Confuser.Core {
|
|||
static void Inspection(ConfuserContext context) {
|
||||
context.Logger.Info("Resolving dependencies...");
|
||||
foreach (var dependency in context.Modules
|
||||
.SelectMany(module => module.GetAssemblyRefs().Select(asmRef => Tuple.Create(asmRef, module)))) {
|
||||
.SelectMany(module => module.GetAssemblyRefs().Select(asmRef => Tuple.Create(asmRef, module)))) {
|
||||
try {
|
||||
AssemblyDef assembly = context.Resolver.ResolveThrow(dependency.Item1, dependency.Item2);
|
||||
}
|
||||
|
@ -280,7 +275,7 @@ namespace Confuser.Core {
|
|||
else if (snKey != null && !module.IsStrongNameSigned)
|
||||
context.Logger.WarnFormat("[{0}] SN Key is provided for an unsigned module, the output may not be working.", module.Name);
|
||||
else if (snKey != null && module.IsStrongNameSigned &&
|
||||
!module.Assembly.PublicKey.Data.SequenceEqual(snKey.PublicKey))
|
||||
!module.Assembly.PublicKey.Data.SequenceEqual(snKey.PublicKey))
|
||||
context.Logger.WarnFormat("[{0}] Provided SN Key and signed module's public key do not match, the output may not be working.", module.Name);
|
||||
}
|
||||
|
||||
|
@ -328,7 +323,7 @@ namespace Confuser.Core {
|
|||
}
|
||||
|
||||
static void CopyPEHeaders(PEHeadersOptions writerOptions, ModuleDefMD module) {
|
||||
var image = module.MetaData.PEImage;
|
||||
var image = module.Metadata.PEImage;
|
||||
writerOptions.MajorImageVersion = image.ImageNTHeaders.OptionalHeader.MajorImageVersion;
|
||||
writerOptions.MajorLinkerVersion = image.ImageNTHeaders.OptionalHeader.MajorLinkerVersion;
|
||||
writerOptions.MajorOperatingSystemVersion = image.ImageNTHeaders.OptionalHeader.MajorOperatingSystemVersion;
|
||||
|
@ -342,14 +337,13 @@ namespace Confuser.Core {
|
|||
static void BeginModule(ConfuserContext context) {
|
||||
context.Logger.InfoFormat("Processing module '{0}'...", context.CurrentModule.Name);
|
||||
|
||||
context.CurrentModuleWriterListener = new ModuleWriterListener();
|
||||
context.CurrentModuleWriterListener.OnWriterEvent += (sender, e) => context.CheckCancellation();
|
||||
context.CurrentModuleWriterOptions = new ModuleWriterOptions(context.CurrentModule, context.CurrentModuleWriterListener);
|
||||
context.CurrentModuleWriterOptions = new ModuleWriterOptions(context.CurrentModule);
|
||||
context.CurrentModuleWriterOptions.WriterEvent += (sender, e) => context.CheckCancellation();
|
||||
CopyPEHeaders(context.CurrentModuleWriterOptions.PEHeadersOptions, context.CurrentModule);
|
||||
|
||||
if (!context.CurrentModule.IsILOnly || context.CurrentModule.VTableFixups != null)
|
||||
context.RequestNative();
|
||||
|
||||
|
||||
var snKey = context.Annotations.Get<StrongNameKey>(context.CurrentModule, Marker.SNKey);
|
||||
context.CurrentModuleWriterOptions.InitializeStrongNameSigning(context.CurrentModule, snKey);
|
||||
|
||||
|
@ -451,11 +445,11 @@ namespace Confuser.Core {
|
|||
|
||||
Type mono = Type.GetType("Mono.Runtime");
|
||||
context.Logger.InfoFormat("Running on {0}, {1}, {2} bits",
|
||||
Environment.OSVersion,
|
||||
mono == null ?
|
||||
".NET Framework v" + Environment.Version :
|
||||
mono.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null),
|
||||
IntPtr.Size * 8);
|
||||
Environment.OSVersion,
|
||||
mono == null ?
|
||||
".NET Framework v" + Environment.Version :
|
||||
mono.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, null),
|
||||
IntPtr.Size * 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,7 +458,7 @@ namespace Confuser.Core {
|
|||
|
||||
using (RegistryKey ndpKey =
|
||||
RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "").
|
||||
OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\")) {
|
||||
OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\")) {
|
||||
foreach (string versionKeyName in ndpKey.GetSubKeyNames()) {
|
||||
if (!versionKeyName.StartsWith("v"))
|
||||
continue;
|
||||
|
@ -496,7 +490,7 @@ namespace Confuser.Core {
|
|||
|
||||
using (RegistryKey ndpKey =
|
||||
RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "").
|
||||
OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\")) {
|
||||
OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\")) {
|
||||
if (ndpKey.GetValue("Release") == null)
|
||||
yield break;
|
||||
var releaseKey = (int)ndpKey.GetValue("Release");
|
||||
|
@ -535,4 +529,4 @@ namespace Confuser.Core {
|
|||
context.Logger.Error("---END DEBUG INFO---");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,8 +98,8 @@ namespace Confuser.Core {
|
|||
/// <returns><c>true</c> if specified type is COM import; otherwise, <c>false</c>.</returns>
|
||||
public static bool IsComImport(this TypeDef type) {
|
||||
return type.IsImport ||
|
||||
type.HasAttribute("System.Runtime.InteropServices.ComImportAttribute") ||
|
||||
type.HasAttribute("System.Runtime.InteropServices.TypeLibTypeAttribute");
|
||||
type.HasAttribute("System.Runtime.InteropServices.ComImportAttribute") ||
|
||||
type.HasAttribute("System.Runtime.InteropServices.TypeLibTypeAttribute");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -375,84 +375,4 @@ namespace Confuser.Core {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="Stream" /> wrapper of <see cref="IImageStream" />.
|
||||
/// </summary>
|
||||
public class ImageStream : Stream {
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImageStream" /> class.
|
||||
/// </summary>
|
||||
/// <param name="baseStream">The base stream.</param>
|
||||
public ImageStream(IImageStream baseStream) {
|
||||
BaseStream = baseStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the base stream of this instance.
|
||||
/// </summary>
|
||||
/// <value>The base stream.</value>
|
||||
public IImageStream BaseStream { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanRead {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanSeek {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanWrite {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override long Length {
|
||||
get { return BaseStream.Length; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override long Position {
|
||||
get { return BaseStream.Position; }
|
||||
set { BaseStream.Position = value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Flush() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int Read(byte[] buffer, int offset, int count) {
|
||||
return BaseStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override long Seek(long offset, SeekOrigin origin) {
|
||||
switch (origin) {
|
||||
case SeekOrigin.Begin:
|
||||
BaseStream.Position = offset;
|
||||
break;
|
||||
case SeekOrigin.Current:
|
||||
BaseStream.Position += offset;
|
||||
break;
|
||||
case SeekOrigin.End:
|
||||
BaseStream.Position = BaseStream.Length + offset;
|
||||
break;
|
||||
}
|
||||
return BaseStream.Position;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void SetLength(long value) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(byte[] buffer, int offset, int count) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,7 +120,6 @@ namespace Confuser.Core.Helpers {
|
|||
var newLocal = new Local(ctx.Importer.Import(local.Type));
|
||||
newMethodDef.Body.Variables.Add(newLocal);
|
||||
newLocal.Name = local.Name;
|
||||
newLocal.PdbAttributes = local.PdbAttributes;
|
||||
|
||||
bodyMap[local] = newLocal;
|
||||
}
|
||||
|
@ -302,4 +301,4 @@ namespace Confuser.Core.Helpers {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
using System;
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Writer;
|
||||
|
||||
namespace Confuser.Core {
|
||||
/// <summary>
|
||||
/// The listener of module writer event.
|
||||
/// </summary>
|
||||
public class ModuleWriterListener : IModuleWriterListener {
|
||||
/// <inheritdoc />
|
||||
void IModuleWriterListener.OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) {
|
||||
if (evt == ModuleWriterEvent.PESectionsCreated)
|
||||
NativeEraser.Erase(writer as NativeModuleWriter, writer.Module as ModuleDefMD);
|
||||
if (OnWriterEvent != null) {
|
||||
OnWriterEvent(writer, new ModuleWriterListenerEventArgs(evt));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a module writer event is triggered.
|
||||
/// </summary>
|
||||
public event EventHandler<ModuleWriterListenerEventArgs> OnWriterEvent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the triggered writer event.
|
||||
/// </summary>
|
||||
public class ModuleWriterListenerEventArgs : EventArgs {
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ModuleWriterListenerEventArgs" /> class.
|
||||
/// </summary>
|
||||
/// <param name="evt">The triggered writer event.</param>
|
||||
public ModuleWriterListenerEventArgs(ModuleWriterEvent evt) {
|
||||
WriterEvent = evt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the triggered writer event.
|
||||
/// </summary>
|
||||
/// <value>The triggered writer event.</value>
|
||||
public ModuleWriterEvent WriterEvent { get; private set; }
|
||||
}
|
||||
}
|
|
@ -35,19 +35,19 @@ namespace Confuser.Core {
|
|||
uint f = sect.Item3[methodOffset - sect.Item1];
|
||||
uint size;
|
||||
switch ((f & 7)) {
|
||||
case 2:
|
||||
case 6:
|
||||
size = (f >> 2) + 1;
|
||||
break;
|
||||
case 2:
|
||||
case 6:
|
||||
size = (f >> 2) + 1;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
f |= (uint)((sect.Item3[methodOffset - sect.Item1 + 1]) << 8);
|
||||
size = (f >> 12) * 4;
|
||||
uint codeSize = BitConverter.ToUInt32(sect.Item3, (int)(methodOffset - sect.Item1 + 4));
|
||||
size += codeSize;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
case 3:
|
||||
f |= (uint)((sect.Item3[methodOffset - sect.Item1 + 1]) << 8);
|
||||
size = (f >> 12) * 4;
|
||||
uint codeSize = BitConverter.ToUInt32(sect.Item3, (int)(methodOffset - sect.Item1 + 4));
|
||||
size += codeSize;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
Erase(sect, methodOffset, size);
|
||||
}
|
||||
|
@ -64,9 +64,9 @@ namespace Confuser.Core {
|
|||
var sectHdr = origSect.PESection;
|
||||
|
||||
s.SetLength(0);
|
||||
oldChunk.WriteTo(new BinaryWriter(s));
|
||||
oldChunk.WriteTo(new DataWriter(s));
|
||||
var buf = s.ToArray();
|
||||
var newChunk = new BinaryReaderChunk(MemoryImageStream.Create(buf), oldChunk.GetVirtualSize());
|
||||
var newChunk = new DataReaderChunk(oldChunk.CreateReader());
|
||||
newChunk.SetOffset(oldChunk.FileOffset, oldChunk.RVA);
|
||||
|
||||
origSect.Chunk = newChunk;
|
||||
|
@ -77,14 +77,15 @@ namespace Confuser.Core {
|
|||
buf));
|
||||
}
|
||||
|
||||
var md = module.MetaData;
|
||||
var md = module.Metadata;
|
||||
|
||||
var row = md.TablesStream.MethodTable.Rows;
|
||||
for (uint i = 1; i <= row; i++) {
|
||||
var method = md.TablesStream.ReadMethodRow(i);
|
||||
var codeType = ((MethodImplAttributes)method.ImplFlags & MethodImplAttributes.CodeTypeMask);
|
||||
if (codeType == MethodImplAttributes.IL)
|
||||
Erase(sections, (uint)md.PEImage.ToFileOffset((RVA)method.RVA));
|
||||
if (md.TablesStream.TryReadMethodRow(i, out var method)) {
|
||||
var codeType = ((MethodImplAttributes)method.ImplFlags & MethodImplAttributes.CodeTypeMask);
|
||||
if (codeType == MethodImplAttributes.IL)
|
||||
Erase(sections, (uint)md.PEImage.ToFileOffset((RVA)method.RVA));
|
||||
}
|
||||
}
|
||||
|
||||
var res = md.ImageCor20Header.Resources;
|
||||
|
@ -92,9 +93,9 @@ namespace Confuser.Core {
|
|||
Erase(sections, (uint)res.StartOffset, res.Size);
|
||||
|
||||
Erase(sections, md.ImageCor20Header);
|
||||
Erase(sections, md.MetaDataHeader);
|
||||
Erase(sections, md.MetadataHeader);
|
||||
foreach (var stream in md.AllStreams)
|
||||
Erase(sections, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,49 +145,49 @@ namespace Confuser.Core {
|
|||
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 "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 "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 "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;
|
||||
case "Feature":
|
||||
Debug.Assert(prop.Type.ElementType == ElementType.String);
|
||||
string feature = (UTF8String)prop.Value;
|
||||
|
||||
var match = OrderPattern.Match(feature);
|
||||
if (match.Success) {
|
||||
var orderStr = match.Groups[1].Value;
|
||||
var f = match.Groups[2].Value;
|
||||
int o;
|
||||
if (!int.TryParse(orderStr, out o))
|
||||
throw new NotSupportedException(string.Format("Failed to parse feature '{0}' in {1} ", feature, item));
|
||||
order = o;
|
||||
feature = f;
|
||||
}
|
||||
var match = OrderPattern.Match(feature);
|
||||
if (match.Success) {
|
||||
var orderStr = match.Groups[1].Value;
|
||||
var f = match.Groups[2].Value;
|
||||
int o;
|
||||
if (!int.TryParse(orderStr, out o))
|
||||
throw new NotSupportedException(string.Format("Failed to parse feature '{0}' in {1} ", feature, item));
|
||||
order = o;
|
||||
feature = f;
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
default:
|
||||
throw new NotSupportedException("Unsupported property: " + prop.Name);
|
||||
}
|
||||
}
|
||||
if (strip)
|
||||
|
@ -417,7 +417,7 @@ namespace Confuser.Core {
|
|||
}
|
||||
}
|
||||
|
||||
if (project.Debug) {
|
||||
if (project.Debug && module.PdbState == null) {
|
||||
module.LoadPdb();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using dnlib.DotNet.Writer;
|
||||
|
||||
namespace Confuser.Core.Services {
|
||||
/// <summary>
|
||||
|
@ -154,6 +155,13 @@ namespace Confuser.Core.Services {
|
|||
return BitConverter.ToUInt32(NextBytes(4), 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a nonnegative random integer that is less than the specified maximum.
|
||||
/// </summary>
|
||||
/// <param name="max">The exclusive upper bound.</param>
|
||||
/// <returns>Requested random number.</returns>
|
||||
public uint NextUInt32(uint max) => NextUInt32() % max;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random double floating pointer number from 0 (inclusive) to 1 (exclusive).
|
||||
/// </summary>
|
||||
|
@ -187,6 +195,22 @@ namespace Confuser.Core.Services {
|
|||
list[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuffles the element in the specified metadata table.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="table">The metadata table to shuffle.</param>
|
||||
public void Shuffle<T>(MDTable<T> table) where T : struct {
|
||||
if (table.IsEmpty) return;
|
||||
|
||||
for (uint i = (uint)(table.Rows - 1); i > 1; i--) {
|
||||
uint k = NextUInt32(i + 1);
|
||||
var tmp = table[k];
|
||||
table[k] = table[i];
|
||||
table[i] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -227,4 +251,4 @@ namespace Confuser.Core.Services {
|
|||
/// <exception cref="System.ArgumentNullException"><paramref name="id" /> is <c>null</c>.</exception>
|
||||
RandomGenerator GetRandomGenerator(string id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,47 +47,47 @@ namespace Confuser.Protections.AntiTamper {
|
|||
return GetFileLength();
|
||||
}
|
||||
|
||||
public void WriteTo(BinaryWriter writer) {
|
||||
writer.Write((uint)(Body.Length >> 2));
|
||||
writer.Write(Body);
|
||||
public void WriteTo(DataWriter writer) {
|
||||
writer.WriteUInt32((uint)(Body.Length >> 2));
|
||||
writer.WriteBytes(Body);
|
||||
}
|
||||
|
||||
public void Serialize(uint token, uint key, byte[] fieldLayout) {
|
||||
using (var ms = new MemoryStream()) {
|
||||
var writer = new BinaryWriter(ms);
|
||||
var writer = new DataWriter(ms);
|
||||
foreach (byte i in fieldLayout)
|
||||
switch (i) {
|
||||
case 0:
|
||||
writer.Write((uint)ILCode.Length);
|
||||
writer.WriteUInt32((uint)ILCode.Length);
|
||||
break;
|
||||
case 1:
|
||||
writer.Write(MaxStack);
|
||||
writer.WriteUInt32(MaxStack);
|
||||
break;
|
||||
case 2:
|
||||
writer.Write((uint)EHs.Length);
|
||||
writer.WriteUInt32((uint)EHs.Length);
|
||||
break;
|
||||
case 3:
|
||||
writer.Write((uint)LocalVars.Length);
|
||||
writer.WriteUInt32((uint)LocalVars.Length);
|
||||
break;
|
||||
case 4:
|
||||
writer.Write(Options);
|
||||
writer.WriteUInt32(Options);
|
||||
break;
|
||||
case 5:
|
||||
writer.Write(MulSeed);
|
||||
writer.WriteUInt32(MulSeed);
|
||||
break;
|
||||
}
|
||||
|
||||
writer.Write(ILCode);
|
||||
writer.Write(LocalVars);
|
||||
writer.WriteBytes(ILCode);
|
||||
writer.WriteBytes(LocalVars);
|
||||
foreach (JITEHClause clause in EHs) {
|
||||
writer.Write(clause.Flags);
|
||||
writer.Write(clause.TryOffset);
|
||||
writer.Write(clause.TryLength);
|
||||
writer.Write(clause.HandlerOffset);
|
||||
writer.Write(clause.HandlerLength);
|
||||
writer.Write(clause.ClassTokenOrFilterOffset);
|
||||
writer.WriteUInt32(clause.Flags);
|
||||
writer.WriteUInt32(clause.TryOffset);
|
||||
writer.WriteUInt32(clause.TryLength);
|
||||
writer.WriteUInt32(clause.HandlerOffset);
|
||||
writer.WriteUInt32(clause.HandlerLength);
|
||||
writer.WriteUInt32(clause.ClassTokenOrFilterOffset);
|
||||
}
|
||||
writer.WriteZeros(4 - ((int)ms.Length & 3)); // pad to 4 bytes
|
||||
writer.WriteZeroes(4 - ((int)ms.Length & 3)); // pad to 4 bytes
|
||||
Body = ms.ToArray();
|
||||
}
|
||||
Debug.Assert(Body.Length % 4 == 0);
|
||||
|
@ -104,15 +104,15 @@ namespace Confuser.Protections.AntiTamper {
|
|||
counter ^= (state >> 5) | (state << 27);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class JITMethodBodyWriter : MethodBodyWriterBase {
|
||||
readonly CilBody body;
|
||||
readonly JITMethodBody jitBody;
|
||||
readonly bool keepMaxStack;
|
||||
readonly MetaData metadata;
|
||||
readonly Metadata metadata;
|
||||
|
||||
public JITMethodBodyWriter(MetaData md, CilBody body, JITMethodBody jitBody, uint mulSeed, bool keepMaxStack) :
|
||||
public JITMethodBodyWriter(Metadata md, CilBody body, JITMethodBody jitBody, uint mulSeed, bool keepMaxStack) :
|
||||
base(body.Instructions, body.ExceptionHandlers) {
|
||||
metadata = md;
|
||||
this.body = body;
|
||||
|
@ -136,11 +136,13 @@ namespace Confuser.Protections.AntiTamper {
|
|||
else
|
||||
jitBody.LocalVars = new byte[0];
|
||||
|
||||
using (var ms = new MemoryStream()) {
|
||||
uint _codeSize = WriteInstructions(new BinaryWriter(ms));
|
||||
Debug.Assert(codeSize == _codeSize);
|
||||
jitBody.ILCode = ms.ToArray();
|
||||
}
|
||||
{
|
||||
var newCode = new byte[codeSize];
|
||||
var writer = new ArrayWriter(newCode);
|
||||
uint _codeSize = WriteInstructions(ref writer);
|
||||
Debug.Assert(codeSize == _codeSize);
|
||||
jitBody.ILCode = newCode;
|
||||
}
|
||||
|
||||
jitBody.EHs = new JITEHClause[exceptionHandlers.Count];
|
||||
if (exceptionHandlers.Count > 0) {
|
||||
|
@ -173,28 +175,28 @@ namespace Confuser.Protections.AntiTamper {
|
|||
}
|
||||
}
|
||||
|
||||
protected override void WriteInlineField(BinaryWriter writer, Instruction instr) {
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
protected override void WriteInlineField(ref ArrayWriter writer, Instruction instr) {
|
||||
writer.WriteUInt32(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
|
||||
protected override void WriteInlineMethod(BinaryWriter writer, Instruction instr) {
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
protected override void WriteInlineMethod(ref ArrayWriter writer, Instruction instr) {
|
||||
writer.WriteUInt32(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
|
||||
protected override void WriteInlineSig(BinaryWriter writer, Instruction instr) {
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
protected override void WriteInlineSig(ref ArrayWriter writer, Instruction instr) {
|
||||
writer.WriteUInt32(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
|
||||
protected override void WriteInlineString(BinaryWriter writer, Instruction instr) {
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
protected override void WriteInlineString(ref ArrayWriter writer, Instruction instr) {
|
||||
writer.WriteUInt32(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
|
||||
protected override void WriteInlineTok(BinaryWriter writer, Instruction instr) {
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
protected override void WriteInlineTok(ref ArrayWriter writer, Instruction instr) {
|
||||
writer.WriteUInt32(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
|
||||
protected override void WriteInlineType(BinaryWriter writer, Instruction instr) {
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
protected override void WriteInlineType(ref ArrayWriter writer, Instruction instr) {
|
||||
writer.WriteUInt32(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,14 +224,14 @@ namespace Confuser.Protections.AntiTamper {
|
|||
return GetFileLength();
|
||||
}
|
||||
|
||||
public void WriteTo(BinaryWriter writer) {
|
||||
public void WriteTo(DataWriter writer) {
|
||||
uint length = GetFileLength() - 4; // minus length field
|
||||
writer.Write((uint)bodies.Count);
|
||||
writer.WriteUInt32((uint)bodies.Count);
|
||||
foreach (var entry in bodies.OrderBy(entry => entry.Key)) {
|
||||
writer.Write(entry.Key);
|
||||
writer.WriteUInt32(entry.Key);
|
||||
Debug.Assert(entry.Value != null);
|
||||
Debug.Assert((length + entry.Value.Offset) % 4 == 0);
|
||||
writer.Write((length + entry.Value.Offset) >> 2);
|
||||
writer.WriteUInt32((length + entry.Value.Offset) >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ using Confuser.Core.Services;
|
|||
using Confuser.Renamer;
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Emit;
|
||||
using dnlib.DotNet.MD;
|
||||
using dnlib.DotNet.Writer;
|
||||
|
||||
namespace Confuser.Protections.AntiTamper {
|
||||
|
@ -147,16 +148,16 @@ namespace Confuser.Protections.AntiTamper {
|
|||
cctor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
|
||||
|
||||
methods = parameters.Targets.OfType<MethodDef>().Where(method => method.HasBody).ToList();
|
||||
context.CurrentModuleWriterListener.OnWriterEvent += OnWriterEvent;
|
||||
context.CurrentModuleWriterOptions.WriterEvent += OnWriterEvent;
|
||||
}
|
||||
|
||||
void OnWriterEvent(object sender, ModuleWriterListenerEventArgs e) {
|
||||
void OnWriterEvent(object sender, ModuleWriterEventArgs e) {
|
||||
var writer = (ModuleWriterBase)sender;
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDBeginWriteMethodBodies) {
|
||||
if (e.Event == ModuleWriterEvent.MDBeginWriteMethodBodies) {
|
||||
context.Logger.Debug("Extracting method bodies...");
|
||||
CreateSection(writer);
|
||||
}
|
||||
else if (e.WriterEvent == ModuleWriterEvent.BeginStrongNameSign) {
|
||||
else if (e.Event == ModuleWriterEvent.BeginStrongNameSign) {
|
||||
context.Logger.Debug("Encrypting method section...");
|
||||
EncryptSection(writer);
|
||||
}
|
||||
|
@ -205,7 +206,7 @@ namespace Confuser.Protections.AntiTamper {
|
|||
newSection.Add(new ByteArrayChunk(random.NextBytes(0x10)), 0x10);
|
||||
|
||||
// create index
|
||||
var bodyIndex = new JITBodyIndex(methods.Select(method => writer.MetaData.GetToken(method).Raw));
|
||||
var bodyIndex = new JITBodyIndex(methods.Select(method => writer.Metadata.GetToken(method).Raw));
|
||||
newSection.Add(bodyIndex, 0x10);
|
||||
|
||||
// save methods
|
||||
|
@ -213,16 +214,24 @@ namespace Confuser.Protections.AntiTamper {
|
|||
if (!method.HasBody)
|
||||
continue;
|
||||
|
||||
MDToken token = writer.MetaData.GetToken(method);
|
||||
MDToken token = writer.Metadata.GetToken(method);
|
||||
|
||||
var jitBody = new JITMethodBody();
|
||||
var bodyWriter = new JITMethodBodyWriter(writer.MetaData, method.Body, jitBody, random.NextUInt32(), writer.MetaData.KeepOldMaxStack || method.Body.KeepOldMaxStack);
|
||||
var bodyWriter = new JITMethodBodyWriter(writer.Metadata, method.Body, jitBody, random.NextUInt32(), writer.Metadata.KeepOldMaxStack || method.Body.KeepOldMaxStack);
|
||||
bodyWriter.Write();
|
||||
jitBody.Serialize(token.Raw, key, fieldLayout);
|
||||
bodyIndex.Add(token.Raw, jitBody);
|
||||
|
||||
method.Body = NopBody;
|
||||
writer.MetaData.TablesHeap.MethodTable[token.Rid].ImplFlags |= (ushort)MethodImplAttributes.NoInlining;
|
||||
RawMethodRow methodRow = writer.Metadata.TablesHeap.MethodTable[token.Rid];
|
||||
writer.Metadata.TablesHeap.MethodTable[token.Rid] = new RawMethodRow(
|
||||
methodRow.RVA,
|
||||
(ushort)(methodRow.ImplFlags | (ushort)MethodImplAttributes.NoInlining),
|
||||
methodRow.Flags,
|
||||
methodRow.Name,
|
||||
methodRow.Signature,
|
||||
methodRow.ParamList);
|
||||
|
||||
context.CheckCancellation();
|
||||
}
|
||||
bodyIndex.PopulateSection(newSection);
|
||||
|
@ -246,7 +255,7 @@ namespace Confuser.Protections.AntiTamper {
|
|||
uint encLoc = 0, encSize = 0;
|
||||
int origSects = -1;
|
||||
if (writer is NativeModuleWriter && writer.Module is ModuleDefMD)
|
||||
origSects = ((ModuleDefMD)writer.Module).MetaData.PEImage.ImageSectionHeaders.Count;
|
||||
origSects = ((ModuleDefMD)writer.Module).Metadata.PEImage.ImageSectionHeaders.Count;
|
||||
for (int i = 0; i < sections; i++) {
|
||||
uint nameHash;
|
||||
if (origSects > 0) {
|
||||
|
|
|
@ -96,15 +96,15 @@ namespace Confuser.Protections.AntiTamper {
|
|||
|
||||
public void HandleMD(AntiTamperProtection parent, ConfuserContext context, ProtectionParameters parameters) {
|
||||
methods = parameters.Targets.OfType<MethodDef>().ToList();
|
||||
context.CurrentModuleWriterListener.OnWriterEvent += OnWriterEvent;
|
||||
context.CurrentModuleWriterOptions.WriterEvent += WriterEvent;
|
||||
}
|
||||
|
||||
void OnWriterEvent(object sender, ModuleWriterListenerEventArgs e) {
|
||||
void WriterEvent(object sender, ModuleWriterEventArgs e) {
|
||||
var writer = (ModuleWriterBase)sender;
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDEndCreateTables) {
|
||||
if (e.Event == ModuleWriterEvent.MDEndCreateTables) {
|
||||
CreateSections(writer);
|
||||
}
|
||||
else if (e.WriterEvent == ModuleWriterEvent.BeginStrongNameSign) {
|
||||
else if (e.Event == ModuleWriterEvent.BeginStrongNameSign) {
|
||||
EncryptSection(writer);
|
||||
}
|
||||
}
|
||||
|
@ -124,8 +124,8 @@ namespace Confuser.Protections.AntiTamper {
|
|||
|
||||
uint alignment;
|
||||
|
||||
alignment = writer.TextSection.Remove(writer.MetaData).Value;
|
||||
writer.TextSection.Add(writer.MetaData, alignment);
|
||||
alignment = writer.TextSection.Remove(writer.Metadata).Value;
|
||||
writer.TextSection.Add(writer.Metadata, alignment);
|
||||
|
||||
alignment = writer.TextSection.Remove(writer.NetResources).Value;
|
||||
writer.TextSection.Add(writer.NetResources, alignment);
|
||||
|
@ -163,7 +163,7 @@ namespace Confuser.Protections.AntiTamper {
|
|||
foreach (MethodDef method in methods) {
|
||||
if (!method.HasBody)
|
||||
continue;
|
||||
MethodBody body = writer.MetaData.GetMethodBody(method);
|
||||
MethodBody body = writer.Metadata.GetMethodBody(method);
|
||||
bool ok = writer.MethodBodies.Remove(body);
|
||||
encryptedChunk.Add(body);
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ namespace Confuser.Protections.AntiTamper {
|
|||
uint encLoc = 0, encSize = 0;
|
||||
int origSects = -1;
|
||||
if (writer is NativeModuleWriter && writer.Module is ModuleDefMD)
|
||||
origSects = ((ModuleDefMD)writer.Module).MetaData.PEImage.ImageSectionHeaders.Count;
|
||||
origSects = ((ModuleDefMD)writer.Module).Metadata.PEImage.ImageSectionHeaders.Count;
|
||||
for (int i = 0; i < sections; i++) {
|
||||
uint nameHash;
|
||||
if (origSects > 0) {
|
||||
|
|
|
@ -84,24 +84,31 @@ namespace Confuser.Protections {
|
|||
|
||||
var snKey = context.Annotations.Get<StrongNameKey>(originModule, Marker.SNKey);
|
||||
using (var ms = new MemoryStream()) {
|
||||
stubModule.Write(ms, new ModuleWriterOptions(stubModule, new KeyInjector(ctx)) {
|
||||
StrongNameKey = snKey
|
||||
});
|
||||
var options = new ModuleWriterOptions(stubModule)
|
||||
{
|
||||
StrongNameKey = snKey
|
||||
};
|
||||
var injector = new KeyInjector(ctx);
|
||||
options.WriterEvent += injector.WriterEvent;
|
||||
|
||||
stubModule.Write(ms, options);
|
||||
context.CheckCancellation();
|
||||
ProtectStub(context, context.OutputPaths[ctx.ModuleIndex], ms.ToArray(), snKey, new StubProtection(ctx, originModule));
|
||||
}
|
||||
}
|
||||
|
||||
static string GetId(byte[] module) {
|
||||
var md = MetaDataCreator.CreateMetaData(new PEImage(module));
|
||||
var assemblyRow = md.TablesStream.ReadAssemblyRow(1);
|
||||
var assembly = new AssemblyNameInfo();
|
||||
assembly.Name = md.StringsStream.ReadNoNull(assemblyRow.Name);
|
||||
assembly.Culture = md.StringsStream.ReadNoNull(assemblyRow.Locale);
|
||||
assembly.PublicKeyOrToken = new PublicKey(md.BlobStream.Read(assemblyRow.PublicKey));
|
||||
assembly.HashAlgId = (AssemblyHashAlgorithm)assemblyRow.HashAlgId;
|
||||
assembly.Version = new Version(assemblyRow.MajorVersion, assemblyRow.MinorVersion, assemblyRow.BuildNumber, assemblyRow.RevisionNumber);
|
||||
assembly.Attributes = (AssemblyAttributes)assemblyRow.Flags;
|
||||
var md = MetadataFactory.CreateMetadata(new PEImage(module));
|
||||
var assembly = new AssemblyNameInfo();
|
||||
if (md.TablesStream.TryReadAssemblyRow(1, out var assemblyRow))
|
||||
{
|
||||
assembly.Name = md.StringsStream.ReadNoNull(assemblyRow.Name);
|
||||
assembly.Culture = md.StringsStream.ReadNoNull(assemblyRow.Locale);
|
||||
assembly.PublicKeyOrToken = new PublicKey(md.BlobStream.Read(assemblyRow.PublicKey));
|
||||
assembly.HashAlgId = (AssemblyHashAlgorithm)assemblyRow.HashAlgId;
|
||||
assembly.Version = new Version(assemblyRow.MajorVersion, assemblyRow.MinorVersion, assemblyRow.BuildNumber, assemblyRow.RevisionNumber);
|
||||
assembly.Attributes = (AssemblyAttributes)assemblyRow.Flags;
|
||||
}
|
||||
return GetId(assembly);
|
||||
}
|
||||
|
||||
|
@ -296,11 +303,16 @@ namespace Confuser.Protections {
|
|||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
public void WriterEvent(object sender, ModuleWriterEventArgs args)
|
||||
{
|
||||
OnWriterEvent(args.Writer, args.Event);
|
||||
}
|
||||
|
||||
public void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) {
|
||||
if (evt == ModuleWriterEvent.MDBeginCreateTables) {
|
||||
// Add key signature
|
||||
uint sigBlob = writer.MetaData.BlobHeap.Add(ctx.KeySig);
|
||||
uint sigRid = writer.MetaData.TablesHeap.StandAloneSigTable.Add(new RawStandAloneSigRow(sigBlob));
|
||||
uint sigBlob = writer.Metadata.BlobHeap.Add(ctx.KeySig);
|
||||
uint sigRid = writer.Metadata.TablesHeap.StandAloneSigTable.Add(new RawStandAloneSigRow(sigBlob));
|
||||
Debug.Assert(sigRid == 1);
|
||||
uint sigToken = 0x11000000 | sigRid;
|
||||
ctx.KeyToken = sigToken;
|
||||
|
@ -309,28 +321,28 @@ namespace Confuser.Protections {
|
|||
else if (evt == ModuleWriterEvent.MDBeginAddResources && !ctx.CompatMode) {
|
||||
// Compute hash
|
||||
byte[] hash = SHA1.Create().ComputeHash(ctx.OriginModule);
|
||||
uint hashBlob = writer.MetaData.BlobHeap.Add(hash);
|
||||
uint hashBlob = writer.Metadata.BlobHeap.Add(hash);
|
||||
|
||||
MDTable<RawFileRow> fileTbl = writer.MetaData.TablesHeap.FileTable;
|
||||
MDTable<RawFileRow> fileTbl = writer.Metadata.TablesHeap.FileTable;
|
||||
uint fileRid = fileTbl.Add(new RawFileRow(
|
||||
(uint)FileAttributes.ContainsMetaData,
|
||||
writer.MetaData.StringsHeap.Add("koi"),
|
||||
(uint)FileAttributes.ContainsMetadata,
|
||||
writer.Metadata.StringsHeap.Add("koi"),
|
||||
hashBlob));
|
||||
uint impl = CodedToken.Implementation.Encode(new MDToken(Table.File, fileRid));
|
||||
|
||||
// Add resources
|
||||
MDTable<RawManifestResourceRow> resTbl = writer.MetaData.TablesHeap.ManifestResourceTable;
|
||||
MDTable<RawManifestResourceRow> resTbl = writer.Metadata.TablesHeap.ManifestResourceTable;
|
||||
foreach (var resource in ctx.ManifestResources)
|
||||
resTbl.Add(new RawManifestResourceRow(resource.Item1, resource.Item2, writer.MetaData.StringsHeap.Add(resource.Item3), impl));
|
||||
resTbl.Add(new RawManifestResourceRow(resource.Item1, resource.Item2, writer.Metadata.StringsHeap.Add(resource.Item3), impl));
|
||||
|
||||
// Add exported types
|
||||
var exTbl = writer.MetaData.TablesHeap.ExportedTypeTable;
|
||||
var exTbl = writer.Metadata.TablesHeap.ExportedTypeTable;
|
||||
foreach (var type in ctx.OriginModuleDef.GetTypes()) {
|
||||
if (!type.IsVisibleOutside())
|
||||
continue;
|
||||
exTbl.Add(new RawExportedTypeRow((uint)type.Attributes, 0,
|
||||
writer.MetaData.StringsHeap.Add(type.Name),
|
||||
writer.MetaData.StringsHeap.Add(type.Namespace), impl));
|
||||
writer.Metadata.StringsHeap.Add(type.Name),
|
||||
writer.Metadata.StringsHeap.Add(type.Namespace), impl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace Confuser.Protections.Compress {
|
|||
context.CurrentModule.Kind = ModuleKind.NetModule;
|
||||
}
|
||||
|
||||
context.CurrentModuleWriterListener.OnWriterEvent += new ResourceRecorder(ctx, context.CurrentModule).OnWriterEvent;
|
||||
context.CurrentModuleWriterOptions.WriterEvent += new ResourceRecorder(ctx, context.CurrentModule).WriterEvent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,14 +65,18 @@ namespace Confuser.Protections.Compress {
|
|||
targetModule = module;
|
||||
}
|
||||
|
||||
public void OnWriterEvent(object sender, ModuleWriterListenerEventArgs e) {
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDEndAddResources) {
|
||||
public void WriterEvent(object sender, ModuleWriterEventArgs e) {
|
||||
if (e.Event == ModuleWriterEvent.MDEndAddResources) {
|
||||
var writer = (ModuleWriterBase)sender;
|
||||
ctx.ManifestResources = new List<Tuple<uint, uint, string>>();
|
||||
Dictionary<uint, byte[]> stringDict = writer.MetaData.StringsHeap.GetAllRawData().ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
foreach (RawManifestResourceRow resource in writer.MetaData.TablesHeap.ManifestResourceTable)
|
||||
ctx.ManifestResources.Add(Tuple.Create(resource.Offset, resource.Flags, Encoding.UTF8.GetString(stringDict[resource.Name])));
|
||||
ctx.EntryPointToken = writer.MetaData.GetToken(ctx.EntryPoint).Raw;
|
||||
Dictionary<uint, byte[]> stringDict = writer.Metadata.StringsHeap.GetAllRawData().ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
MDTable<RawManifestResourceRow> manifestResourceTable = writer.Metadata.TablesHeap.ManifestResourceTable;
|
||||
for (uint i = 1; i <= manifestResourceTable.Rows; i++)
|
||||
{
|
||||
RawManifestResourceRow resource = manifestResourceTable[i];
|
||||
ctx.ManifestResources.Add(Tuple.Create(resource.Offset, resource.Flags, Encoding.UTF8.GetString(stringDict[resource.Name])));
|
||||
}
|
||||
ctx.EntryPointToken = writer.Metadata.GetToken(ctx.EntryPoint).Raw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,13 +88,13 @@ namespace Confuser.Protections.Compress {
|
|||
Debug.Assert(field != null);
|
||||
context.Registry.GetService<INameService>().SetCanRename(field, true);
|
||||
|
||||
context.CurrentModuleWriterListener.OnWriterEvent += (sender, e) => {
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDBeginCreateTables) {
|
||||
context.CurrentModuleWriterOptions.WriterEvent += (sender, e) => {
|
||||
if (e.Event == ModuleWriterEvent.MDBeginCreateTables) {
|
||||
// Add key signature
|
||||
var writer = (ModuleWriterBase)sender;
|
||||
var prot = (StubProtection)Parent;
|
||||
uint blob = writer.MetaData.BlobHeap.Add(prot.ctx.KeySig);
|
||||
uint rid = writer.MetaData.TablesHeap.StandAloneSigTable.Add(new RawStandAloneSigRow(blob));
|
||||
uint blob = writer.Metadata.BlobHeap.Add(prot.ctx.KeySig);
|
||||
uint rid = writer.Metadata.TablesHeap.StandAloneSigTable.Add(new RawStandAloneSigRow(blob));
|
||||
Debug.Assert((0x11000000 | rid) == prot.ctx.KeyToken);
|
||||
|
||||
if (prot.ctx.CompatMode)
|
||||
|
@ -102,12 +102,12 @@ namespace Confuser.Protections.Compress {
|
|||
|
||||
// Add File reference
|
||||
byte[] hash = SHA1.Create().ComputeHash(prot.ctx.OriginModule);
|
||||
uint hashBlob = writer.MetaData.BlobHeap.Add(hash);
|
||||
uint hashBlob = writer.Metadata.BlobHeap.Add(hash);
|
||||
|
||||
MDTable<RawFileRow> fileTbl = writer.MetaData.TablesHeap.FileTable;
|
||||
MDTable<RawFileRow> fileTbl = writer.Metadata.TablesHeap.FileTable;
|
||||
uint fileRid = fileTbl.Add(new RawFileRow(
|
||||
(uint)FileAttributes.ContainsMetaData,
|
||||
writer.MetaData.StringsHeap.Add("koi"),
|
||||
(uint)FileAttributes.ContainsMetadata,
|
||||
writer.Metadata.StringsHeap.Add("koi"),
|
||||
hashBlob));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@ using Confuser.DynCipher.AST;
|
|||
using Confuser.DynCipher.Generation;
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Emit;
|
||||
using dnlib.DotNet.MD;
|
||||
using dnlib.DotNet.Writer;
|
||||
using MethodBody = dnlib.DotNet.Writer.MethodBody;
|
||||
|
||||
|
@ -118,19 +119,28 @@ namespace Confuser.Protections.Constants {
|
|||
.Compile<Func<int, int>>();
|
||||
|
||||
|
||||
ctx.Context.CurrentModuleWriterListener.OnWriterEvent += InjectNativeCode;
|
||||
ctx.Context.CurrentModuleWriterOptions.WriterEvent += InjectNativeCode;
|
||||
}
|
||||
|
||||
void InjectNativeCode(object sender, ModuleWriterListenerEventArgs e) {
|
||||
var writer = (ModuleWriterBase)sender;
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDEndWriteMethodBodies) {
|
||||
void InjectNativeCode(object sender, ModuleWriterEventArgs e) {
|
||||
var writer = e.Writer;
|
||||
switch (e.Event) {
|
||||
case ModuleWriterEvent.MDEndWriteMethodBodies:
|
||||
codeChunk = writer.MethodBodies.Add(new MethodBody(code));
|
||||
}
|
||||
else if (e.WriterEvent == ModuleWriterEvent.EndCalculateRvasAndFileOffsets) {
|
||||
uint rid = writer.MetaData.GetRid(native);
|
||||
writer.MetaData.TablesHeap.MethodTable[rid].RVA = (uint)codeChunk.RVA;
|
||||
break;
|
||||
case ModuleWriterEvent.EndCalculateRvasAndFileOffsets:
|
||||
uint rid = writer.Metadata.GetRid(native);
|
||||
var methodRow = writer.Metadata.TablesHeap.MethodTable[rid];
|
||||
writer.Metadata.TablesHeap.MethodTable[rid] = new RawMethodRow(
|
||||
(uint)codeChunk.RVA,
|
||||
methodRow.ImplFlags,
|
||||
methodRow.Flags,
|
||||
methodRow.Name,
|
||||
methodRow.Signature,
|
||||
methodRow.ParamList);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ namespace Confuser.Protections.ControlFlow {
|
|||
instrs.Add(Instruction.Create(OpCodes.Ldarg, new Parameter(0xff)));
|
||||
break;
|
||||
case 4:
|
||||
instrs.Add(Instruction.Create(OpCodes.Ldloc, new Local(null) { Index = 0xff }));
|
||||
instrs.Add(Instruction.Create(OpCodes.Ldloc, new Local(null, null, 0xff)));
|
||||
break;
|
||||
case 5:
|
||||
instrs.Add(Instruction.Create(OpCodes.Ldtoken, Method));
|
||||
|
@ -100,4 +100,4 @@ namespace Confuser.Protections.ControlFlow {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using Confuser.DynCipher;
|
|||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Emit;
|
||||
using dnlib.DotNet.MD;
|
||||
using dnlib.DotNet.Pdb;
|
||||
using dnlib.DotNet.Writer;
|
||||
|
||||
namespace Confuser.Protections.ControlFlow {
|
||||
|
@ -99,6 +100,14 @@ namespace Confuser.Protections.ControlFlow {
|
|||
|
||||
body.Instructions.Clear();
|
||||
root.ToBody(body);
|
||||
if (body.PdbMethod != null) {
|
||||
body.PdbMethod = new PdbMethod() {
|
||||
Scope = new PdbScope() {
|
||||
Start = body.Instructions.First(),
|
||||
End = body.Instructions.Last()
|
||||
}
|
||||
};
|
||||
}
|
||||
foreach (ExceptionHandler eh in body.ExceptionHandlers) {
|
||||
var index = body.Instructions.IndexOf(eh.TryEnd) + 1;
|
||||
eh.TryEnd = index < body.Instructions.Count ? body.Instructions[index] : null;
|
||||
|
@ -108,4 +117,4 @@ namespace Confuser.Protections.ControlFlow {
|
|||
body.KeepOldMaxStack = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ using Confuser.DynCipher.Generation;
|
|||
using Confuser.Renamer;
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Emit;
|
||||
using dnlib.DotNet.MD;
|
||||
using dnlib.DotNet.Writer;
|
||||
using MethodBody = dnlib.DotNet.Writer.MethodBody;
|
||||
|
||||
|
@ -88,19 +89,29 @@ namespace Confuser.Protections.ControlFlow {
|
|||
.Compile<Func<int, int>>();
|
||||
|
||||
|
||||
ctx.Context.CurrentModuleWriterListener.OnWriterEvent += InjectNativeCode;
|
||||
ctx.Context.CurrentModuleWriterOptions.WriterEvent += InjectNativeCode;
|
||||
}
|
||||
|
||||
void InjectNativeCode(object sender, ModuleWriterListenerEventArgs e) {
|
||||
var writer = (ModuleWriterBase)sender;
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDEndWriteMethodBodies) {
|
||||
void InjectNativeCode(object sender, ModuleWriterEventArgs e) {
|
||||
var writer = e.Writer;
|
||||
switch (e.Event) {
|
||||
case ModuleWriterEvent.MDEndWriteMethodBodies:
|
||||
codeChunk = writer.MethodBodies.Add(new MethodBody(code));
|
||||
}
|
||||
else if (e.WriterEvent == ModuleWriterEvent.EndCalculateRvasAndFileOffsets) {
|
||||
uint rid = writer.MetaData.GetRid(native);
|
||||
writer.MetaData.TablesHeap.MethodTable[rid].RVA = (uint)codeChunk.RVA;
|
||||
break;
|
||||
case ModuleWriterEvent.EndCalculateRvasAndFileOffsets:
|
||||
uint rid = writer.Metadata.GetRid(native);
|
||||
|
||||
var methodRow = writer.Metadata.TablesHeap.MethodTable[rid];
|
||||
writer.Metadata.TablesHeap.MethodTable[rid] = new RawMethodRow(
|
||||
(uint)codeChunk.RVA,
|
||||
methodRow.ImplFlags,
|
||||
methodRow.Flags,
|
||||
methodRow.Name,
|
||||
methodRow.Signature,
|
||||
methodRow.ParamList);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,21 +57,15 @@ namespace Confuser.Protections {
|
|||
protected override void Execute(ConfuserContext context, ProtectionParameters parameters) {
|
||||
if (parameters.Targets.Contains(context.CurrentModule)) {
|
||||
random = context.Registry.GetService<IRandomService>().GetRandomGenerator(_FullId);
|
||||
context.CurrentModuleWriterListener.OnWriterEvent += OnWriterEvent;
|
||||
context.CurrentModuleWriterOptions.WriterEvent += OnWriterEvent;
|
||||
}
|
||||
}
|
||||
|
||||
void Randomize<T>(MDTable<T> table) where T : IRawRow {
|
||||
List<T> rows = table.ToList();
|
||||
random.Shuffle(rows);
|
||||
table.Reset();
|
||||
foreach (T row in rows)
|
||||
table.Add(row);
|
||||
}
|
||||
void Randomize<T>(MDTable<T> table) where T : struct => random.Shuffle(table);
|
||||
|
||||
void OnWriterEvent(object sender, ModuleWriterListenerEventArgs e) {
|
||||
void OnWriterEvent(object sender, ModuleWriterEventArgs e) {
|
||||
var writer = (ModuleWriterBase)sender;
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDEndCreateTables) {
|
||||
if (e.Event == ModuleWriterEvent.MDEndCreateTables) {
|
||||
// These hurts reflection
|
||||
|
||||
/*
|
||||
|
@ -93,46 +87,46 @@ namespace Confuser.Protections {
|
|||
0, 0, ns, 0x3FFFD, fieldLen, methodLen));
|
||||
writer.MetaData.TablesHeap.NestedClassTable.Add(new RawNestedClassRow(root, type));
|
||||
}
|
||||
|
||||
|
||||
foreach (var row in writer.MetaData.TablesHeap.ParamTable)
|
||||
row.Name = 0x7fff7fff;
|
||||
*/
|
||||
|
||||
writer.MetaData.TablesHeap.ModuleTable.Add(new RawModuleRow(0, 0x7fff7fff, 0, 0, 0));
|
||||
writer.MetaData.TablesHeap.AssemblyTable.Add(new RawAssemblyRow(0, 0, 0, 0, 0, 0, 0, 0x7fff7fff, 0));
|
||||
writer.Metadata.TablesHeap.ModuleTable.Add(new RawModuleRow(0, 0x7fff7fff, 0, 0, 0));
|
||||
writer.Metadata.TablesHeap.AssemblyTable.Add(new RawAssemblyRow(0, 0, 0, 0, 0, 0, 0, 0x7fff7fff, 0));
|
||||
|
||||
int r = random.NextInt32(8, 16);
|
||||
for (int i = 0; i < r; i++)
|
||||
writer.MetaData.TablesHeap.ENCLogTable.Add(new RawENCLogRow(random.NextUInt32(), random.NextUInt32()));
|
||||
writer.Metadata.TablesHeap.ENCLogTable.Add(new RawENCLogRow(random.NextUInt32(), random.NextUInt32()));
|
||||
r = random.NextInt32(8, 16);
|
||||
for (int i = 0; i < r; i++)
|
||||
writer.MetaData.TablesHeap.ENCMapTable.Add(new RawENCMapRow(random.NextUInt32()));
|
||||
writer.Metadata.TablesHeap.ENCMapTable.Add(new RawENCMapRow(random.NextUInt32()));
|
||||
|
||||
//Randomize(writer.MetaData.TablesHeap.NestedClassTable);
|
||||
Randomize(writer.MetaData.TablesHeap.ManifestResourceTable);
|
||||
Randomize(writer.Metadata.TablesHeap.ManifestResourceTable);
|
||||
//Randomize(writer.MetaData.TablesHeap.GenericParamConstraintTable);
|
||||
|
||||
writer.TheOptions.MetaDataOptions.TablesHeapOptions.ExtraData = random.NextUInt32();
|
||||
writer.TheOptions.MetaDataOptions.TablesHeapOptions.UseENC = false;
|
||||
writer.TheOptions.MetaDataOptions.MetaDataHeaderOptions.VersionString += "\0\0\0\0";
|
||||
writer.TheOptions.MetadataOptions.TablesHeapOptions.ExtraData = random.NextUInt32();
|
||||
writer.TheOptions.MetadataOptions.TablesHeapOptions.UseENC = false;
|
||||
writer.TheOptions.MetadataOptions.MetadataHeaderOptions.VersionString += "\0\0\0\0";
|
||||
|
||||
/*
|
||||
We are going to create a new specific '#GUID' Heap to avoid UnConfuserEX to work.
|
||||
<sarcasm>UnConfuserEX is so well coded, it relies on static cmp between values</sarcasm>
|
||||
If you deobfuscate this tool, you can see that it check for #GUID size and compare it to
|
||||
'16', so we have to create a new array of byte wich size is exactly 16 and put it into
|
||||
'16', so we have to create a new array of byte wich size is exactly 16 and put it into
|
||||
our brand new Heap
|
||||
*/
|
||||
//
|
||||
writer.TheOptions.MetaDataOptions.OtherHeapsEnd.Add(new RawHeap("#GUID", Guid.NewGuid().ToByteArray()));
|
||||
writer.TheOptions.MetadataOptions.CustomHeaps.Add(new RawHeap("#GUID", Guid.NewGuid().ToByteArray()));
|
||||
//
|
||||
writer.TheOptions.MetaDataOptions.OtherHeapsEnd.Add(new RawHeap("#Strings", new byte[1]));
|
||||
writer.TheOptions.MetaDataOptions.OtherHeapsEnd.Add(new RawHeap("#Blob", new byte[1]));
|
||||
writer.TheOptions.MetaDataOptions.OtherHeapsEnd.Add(new RawHeap("#Schema", new byte[1]));
|
||||
writer.TheOptions.MetadataOptions.CustomHeaps.Add(new RawHeap("#Strings", new byte[1]));
|
||||
writer.TheOptions.MetadataOptions.CustomHeaps.Add(new RawHeap("#Blob", new byte[1]));
|
||||
writer.TheOptions.MetadataOptions.CustomHeaps.Add(new RawHeap("#Schema", new byte[1]));
|
||||
}
|
||||
else if (e.WriterEvent == ModuleWriterEvent.MDOnAllTablesSorted) {
|
||||
writer.MetaData.TablesHeap.DeclSecurityTable.Add(new RawDeclSecurityRow(
|
||||
unchecked(0x7fff), 0xffff7fff, 0xffff7fff));
|
||||
else if (e.Event == ModuleWriterEvent.MDOnAllTablesSorted) {
|
||||
writer.Metadata.TablesHeap.DeclSecurityTable.Add(new RawDeclSecurityRow(
|
||||
unchecked(0x7fff), 0xffff7fff, 0xffff7fff));
|
||||
/*
|
||||
writer.MetaData.TablesHeap.ManifestResourceTable.Add(new RawManifestResourceRow(
|
||||
0x7fff7fff, (uint)ManifestResourceAttributes.Private, 0x7fff7fff, 2));
|
||||
|
@ -158,8 +152,8 @@ namespace Confuser.Protections {
|
|||
return (uint)content.Length;
|
||||
}
|
||||
|
||||
protected override void WriteToImpl(BinaryWriter writer) {
|
||||
writer.Write(content);
|
||||
protected override void WriteToImpl(DataWriter writer) {
|
||||
writer.WriteBytes(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -330,19 +330,19 @@ namespace Confuser.Protections.ReferenceProxy {
|
|||
ctx.Name.SetCanRename(cctor, false);
|
||||
}
|
||||
|
||||
ctx.Context.CurrentModuleWriterOptions.MetaDataOptions.Flags |= MetaDataFlags.PreserveExtraSignatureData;
|
||||
ctx.Context.CurrentModuleWriterListener.OnWriterEvent += EncodeField;
|
||||
ctx.Context.CurrentModuleWriterOptions.MetadataOptions.Flags |= MetadataFlags.PreserveExtraSignatureData;
|
||||
ctx.Context.CurrentModuleWriterOptions.WriterEvent += EncodeField;
|
||||
encodeCtx = ctx;
|
||||
}
|
||||
|
||||
void EncodeField(object sender, ModuleWriterListenerEventArgs e) {
|
||||
void EncodeField(object sender, ModuleWriterEventArgs e) {
|
||||
var writer = (ModuleWriterBase)sender;
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDMemberDefRidsAllocated && keyAttrs != null) {
|
||||
if (e.Event == ModuleWriterEvent.MDMemberDefRidsAllocated && keyAttrs != null) {
|
||||
Dictionary<TypeDef, Func<int, int>> keyFuncs = keyAttrs
|
||||
.Where(entry => entry != null)
|
||||
.ToDictionary(entry => entry.Item1, entry => entry.Item2);
|
||||
foreach (FieldDesc desc in fieldDescs) {
|
||||
uint token = writer.MetaData.GetToken(desc.Method).Raw;
|
||||
uint token = writer.Metadata.GetToken(desc.Method).Raw;
|
||||
uint key = encodeCtx.Random.NextUInt32() | 1;
|
||||
|
||||
// CA
|
||||
|
@ -371,7 +371,7 @@ namespace Confuser.Protections.ReferenceProxy {
|
|||
|
||||
// Field sig
|
||||
FieldSig sig = desc.Field.FieldSig;
|
||||
uint encodedToken = (token - writer.MetaData.GetToken(((CModOptSig)sig.Type).Modifier).Raw) ^ encodedNameKey;
|
||||
uint encodedToken = (token - writer.Metadata.GetToken(((CModOptSig)sig.Type).Modifier).Raw) ^ encodedNameKey;
|
||||
|
||||
|
||||
var extra = new byte[8];
|
||||
|
|
|
@ -8,6 +8,7 @@ using Confuser.DynCipher.Generation;
|
|||
using Confuser.Renamer;
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Emit;
|
||||
using dnlib.DotNet.MD;
|
||||
using dnlib.DotNet.Writer;
|
||||
using MethodBody = dnlib.DotNet.Writer.MethodBody;
|
||||
|
||||
|
@ -63,24 +64,31 @@ namespace Confuser.Protections.ReferenceProxy {
|
|||
|
||||
nativeCodes.Add(Tuple.Create(native, code, (MethodBody)null));
|
||||
if (!addedHandler) {
|
||||
ctx.Context.CurrentModuleWriterListener.OnWriterEvent += InjectNativeCode;
|
||||
ctx.Context.CurrentModuleWriterOptions.WriterEvent += InjectNativeCode;
|
||||
addedHandler = true;
|
||||
}
|
||||
}
|
||||
|
||||
void InjectNativeCode(object sender, ModuleWriterListenerEventArgs e) {
|
||||
void InjectNativeCode(object sender, ModuleWriterEventArgs e) {
|
||||
var writer = (ModuleWriterBase)sender;
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDEndWriteMethodBodies) {
|
||||
if (e.Event == ModuleWriterEvent.MDEndWriteMethodBodies) {
|
||||
for (int n = 0; n < nativeCodes.Count; n++)
|
||||
nativeCodes[n] = new Tuple<MethodDef, byte[], MethodBody>(
|
||||
nativeCodes[n].Item1,
|
||||
nativeCodes[n].Item2,
|
||||
writer.MethodBodies.Add(new MethodBody(nativeCodes[n].Item2)));
|
||||
}
|
||||
else if (e.WriterEvent == ModuleWriterEvent.EndCalculateRvasAndFileOffsets) {
|
||||
else if (e.Event == ModuleWriterEvent.EndCalculateRvasAndFileOffsets) {
|
||||
foreach (var native in nativeCodes) {
|
||||
uint rid = writer.MetaData.GetRid(native.Item1);
|
||||
writer.MetaData.TablesHeap.MethodTable[rid].RVA = (uint)native.Item3.RVA;
|
||||
uint rid = writer.Metadata.GetRid(native.Item1);
|
||||
RawMethodRow methodRow = writer.Metadata.TablesHeap.MethodTable[rid];
|
||||
writer.Metadata.TablesHeap.MethodTable[rid] = new RawMethodRow(
|
||||
(uint)native.Item3.RVA,
|
||||
methodRow.ImplFlags,
|
||||
methodRow.Flags,
|
||||
methodRow.Name,
|
||||
methodRow.Signature,
|
||||
methodRow.ParamList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ using Confuser.Core.Helpers;
|
|||
using Confuser.Core.Services;
|
||||
using Confuser.Renamer;
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.MD;
|
||||
using dnlib.DotNet.Writer;
|
||||
|
||||
namespace Confuser.Protections.Resources {
|
||||
|
@ -20,12 +21,12 @@ namespace Confuser.Protections.Resources {
|
|||
}
|
||||
|
||||
public void Hook() {
|
||||
ctx.Context.CurrentModuleWriterListener.OnWriterEvent += OnWriterEvent;
|
||||
ctx.Context.CurrentModuleWriterOptions.WriterEvent += OnWriterEvent;
|
||||
}
|
||||
|
||||
void OnWriterEvent(object sender, ModuleWriterListenerEventArgs e) {
|
||||
void OnWriterEvent(object sender, ModuleWriterEventArgs e) {
|
||||
var writer = (ModuleWriterBase)sender;
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDBeginAddResources) {
|
||||
if (e.Event == ModuleWriterEvent.MDBeginAddResources) {
|
||||
ctx.Context.CheckCancellation();
|
||||
ctx.Context.Logger.Debug("Encrypting resources...");
|
||||
bool hasPacker = ctx.Context.Packer != null;
|
||||
|
@ -53,7 +54,7 @@ namespace Confuser.Protections.Resources {
|
|||
}
|
||||
byte[] moduleBuff;
|
||||
using (var ms = new MemoryStream()) {
|
||||
module.Write(ms, new ModuleWriterOptions { StrongNameKey = writer.TheOptions.StrongNameKey });
|
||||
module.Write(ms, new ModuleWriterOptions(e.Writer.Module) { StrongNameKey = writer.TheOptions.StrongNameKey });
|
||||
moduleBuff = ms.ToArray();
|
||||
}
|
||||
|
||||
|
@ -93,20 +94,28 @@ namespace Confuser.Protections.Resources {
|
|||
Debug.Assert(buffIndex == compressedBuff.Length);
|
||||
var size = (uint)encryptedBuffer.Length;
|
||||
|
||||
TablesHeap tblHeap = writer.MetaData.TablesHeap;
|
||||
tblHeap.ClassLayoutTable[writer.MetaData.GetClassLayoutRid(ctx.DataType)].ClassSize = size;
|
||||
tblHeap.FieldTable[writer.MetaData.GetRid(ctx.DataField)].Flags |= (ushort)FieldAttributes.HasFieldRVA;
|
||||
TablesHeap tblHeap = writer.Metadata.TablesHeap;
|
||||
|
||||
uint classLayoutRid = writer.Metadata.GetClassLayoutRid(ctx.DataType);
|
||||
RawClassLayoutRow classLayout = tblHeap.ClassLayoutTable[classLayoutRid];
|
||||
tblHeap.ClassLayoutTable[classLayoutRid] = new RawClassLayoutRow(classLayout.PackingSize, size, classLayout.Parent);
|
||||
|
||||
uint dataFieldRid = writer.Metadata.GetRid(ctx.DataField);
|
||||
RawFieldRow dataField = tblHeap.FieldTable[dataFieldRid];
|
||||
tblHeap.FieldTable[dataFieldRid] = new RawFieldRow((ushort)(dataField.Flags | (ushort)FieldAttributes.HasFieldRVA), dataField.Name, dataField.Signature);
|
||||
encryptedResource = writer.Constants.Add(new ByteArrayChunk(encryptedBuffer), 8);
|
||||
|
||||
// inject key values
|
||||
MutationHelper.InjectKeys(ctx.InitMethod,
|
||||
new[] { 0, 1 },
|
||||
new[] { (int)(size / 4), (int)(keySeed) });
|
||||
new[] { 0, 1 },
|
||||
new[] { (int)(size / 4), (int)(keySeed) });
|
||||
}
|
||||
else if (e.WriterEvent == ModuleWriterEvent.EndCalculateRvasAndFileOffsets) {
|
||||
TablesHeap tblHeap = writer.MetaData.TablesHeap;
|
||||
tblHeap.FieldRVATable[writer.MetaData.GetFieldRVARid(ctx.DataField)].RVA = (uint)encryptedResource.RVA;
|
||||
else if (e.Event == ModuleWriterEvent.EndCalculateRvasAndFileOffsets) {
|
||||
TablesHeap tblHeap = writer.Metadata.TablesHeap;
|
||||
uint fieldRvaRid = writer.Metadata.GetFieldRVARid(ctx.DataField);
|
||||
RawFieldRVARow fieldRva = tblHeap.FieldRVATable[fieldRvaRid];
|
||||
tblHeap.FieldRVATable[fieldRvaRid] = new RawFieldRVARow((uint)encryptedResource.RVA, fieldRva.Field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,10 +45,16 @@ namespace Confuser.Renamer.Analyzers {
|
|||
// CustomAttribute
|
||||
table = module.TablesStream.Get(Table.CustomAttribute);
|
||||
len = table.Rows;
|
||||
IEnumerable<CustomAttribute> attrs = Enumerable.Range(1, (int)len)
|
||||
.Select(rid => module.ResolveHasCustomAttribute(module.TablesStream.ReadCustomAttributeRow((uint)rid).Parent))
|
||||
.Distinct()
|
||||
.SelectMany(owner => owner.CustomAttributes);
|
||||
var attrs = Enumerable.Range(1, (int)len)
|
||||
.Select(rid => {
|
||||
if (module.TablesStream.TryReadCustomAttributeRow((uint)rid, out var row)) {
|
||||
return module.ResolveHasCustomAttribute(row.Parent);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.Where(a => a != null)
|
||||
.Distinct()
|
||||
.SelectMany(owner => owner.CustomAttributes);
|
||||
foreach (CustomAttribute attr in attrs) {
|
||||
if (attr.Constructor is MemberRef)
|
||||
AnalyzeMemberRef(context, service, (MemberRef)attr.Constructor);
|
||||
|
@ -126,7 +132,7 @@ namespace Confuser.Renamer.Analyzers {
|
|||
Debug.Assert(!(inst.GenericType.TypeDefOrRef is TypeSpec));
|
||||
TypeDef openType = inst.GenericType.TypeDefOrRef.ResolveTypeDefThrow();
|
||||
if (!context.Modules.Contains((ModuleDefMD)openType.Module) ||
|
||||
memberRef.IsArrayAccessors())
|
||||
memberRef.IsArrayAccessors())
|
||||
return;
|
||||
|
||||
IDnlibDef member;
|
||||
|
@ -138,4 +144,4 @@ namespace Confuser.Renamer.Analyzers {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,10 +64,10 @@ namespace Confuser.Renamer.Analyzers {
|
|||
#region Niks patch fix
|
||||
|
||||
/*
|
||||
* Nik's patch for maintaining relative paths. If the xaml file is referenced in this manner
|
||||
* "/some.namespace;component/somefolder/somecontrol.xaml"
|
||||
* then we want to keep the relative path and namespace intact. We should be obfuscating it like this - /some.namespace;component/somefolder/asjdjh2398498dswk.xaml
|
||||
* */
|
||||
* Nik's patch for maintaining relative paths. If the xaml file is referenced in this manner
|
||||
* "/some.namespace;component/somefolder/somecontrol.xaml"
|
||||
* then we want to keep the relative path and namespace intact. We should be obfuscating it like this - /some.namespace;component/somefolder/asjdjh2398498dswk.xaml
|
||||
* */
|
||||
|
||||
string[] completePath = newName.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
string newShinyName = string.Empty;
|
||||
|
@ -108,6 +108,8 @@ namespace Confuser.Renamer.Analyzers {
|
|||
if (wpfResInfo == null)
|
||||
return;
|
||||
|
||||
var newResources = new List<EmbeddedResource>();
|
||||
|
||||
foreach (EmbeddedResource res in module.Resources.OfType<EmbeddedResource>()) {
|
||||
Dictionary<string, BamlDocument> resInfo;
|
||||
|
||||
|
@ -117,8 +119,7 @@ namespace Confuser.Renamer.Analyzers {
|
|||
var stream = new MemoryStream();
|
||||
var writer = new ResourceWriter(stream);
|
||||
|
||||
res.Data.Position = 0;
|
||||
var reader = new ResourceReader(new ImageStream(res.Data));
|
||||
var reader = new ResourceReader(res.CreateReader().AsStream());
|
||||
IDictionaryEnumerator enumerator = reader.GetEnumerator();
|
||||
while (enumerator.MoveNext()) {
|
||||
var name = (string)enumerator.Key;
|
||||
|
@ -140,7 +141,12 @@ namespace Confuser.Renamer.Analyzers {
|
|||
writer.AddResourceData(name, typeName, data);
|
||||
}
|
||||
writer.Generate();
|
||||
res.Data = MemoryImageStream.Create(stream.ToArray());
|
||||
newResources.Add(new EmbeddedResource(res.Name, stream.ToArray(), res.Attributes));
|
||||
}
|
||||
|
||||
foreach (EmbeddedResource res in newResources) {
|
||||
int index = module.Resources.IndexOfEmbeddedResource(res.Name);
|
||||
module.Resources[index] = res;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,11 +159,11 @@ namespace Confuser.Renamer.Analyzers {
|
|||
var regMethod = (IMethod)instr.Operand;
|
||||
|
||||
if (regMethod.DeclaringType.FullName == "System.Windows.DependencyProperty" &&
|
||||
regMethod.Name.String.StartsWith("Register")) {
|
||||
regMethod.Name.String.StartsWith("Register")) {
|
||||
dpRegInstrs.Add(Tuple.Create(regMethod.Name.String.StartsWith("RegisterAttached"), instr));
|
||||
}
|
||||
else if (regMethod.DeclaringType.FullName == "System.Windows.EventManager" &&
|
||||
regMethod.Name.String == "RegisterRoutedEvent") {
|
||||
regMethod.Name.String == "RegisterRoutedEvent") {
|
||||
routedEvtRegInstrs.Add(instr);
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +171,7 @@ namespace Confuser.Renamer.Analyzers {
|
|||
var methodRef = (IMethod)instr.Operand;
|
||||
|
||||
if (methodRef.DeclaringType.FullName == "System.Windows.Data.PropertyGroupDescription" &&
|
||||
methodRef.Name == ".ctor" && i - 1 >= 0 && method.Body.Instructions[i - 1].OpCode.Code == Code.Ldstr) {
|
||||
methodRef.Name == ".ctor" && i - 1 >= 0 && method.Body.Instructions[i - 1].OpCode.Code == Code.Ldstr) {
|
||||
foreach (var property in analyzer.LookupProperty((string)method.Body.Instructions[i - 1].Operand))
|
||||
service.SetCanRename(property, false);
|
||||
}
|
||||
|
@ -249,10 +255,10 @@ namespace Confuser.Renamer.Analyzers {
|
|||
if (!found) {
|
||||
if (instrInfo.Item1)
|
||||
context.Logger.WarnFormat("Failed to find the accessors of attached dependency property '{0}' in type '{1}'.",
|
||||
name, declType.FullName);
|
||||
name, declType.FullName);
|
||||
else
|
||||
context.Logger.WarnFormat("Failed to find the CLR property of normal dependency property '{0}' in type '{1}'.",
|
||||
name, declType.FullName);
|
||||
name, declType.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,7 +285,7 @@ namespace Confuser.Renamer.Analyzers {
|
|||
EventDef eventDef = null;
|
||||
if ((eventDef = declType.FindEvent(name)) == null) {
|
||||
context.Logger.WarnFormat("Failed to find the CLR event of routed event '{0}' in type '{1}'.",
|
||||
name, declType.FullName);
|
||||
name, declType.FullName);
|
||||
continue;
|
||||
}
|
||||
service.SetCanRename(eventDef, false);
|
||||
|
@ -315,8 +321,7 @@ namespace Confuser.Renamer.Analyzers {
|
|||
|
||||
var resInfo = new Dictionary<string, BamlDocument>();
|
||||
|
||||
res.Data.Position = 0;
|
||||
var reader = new ResourceReader(new ImageStream(res.Data));
|
||||
var reader = new ResourceReader(res.CreateReader().AsStream());
|
||||
IDictionaryEnumerator enumerator = reader.GetEnumerator();
|
||||
while (enumerator.MoveNext()) {
|
||||
var name = (string)enumerator.Key;
|
||||
|
@ -338,4 +343,4 @@ namespace Confuser.Renamer.Analyzers {
|
|||
context.Annotations.Set(module, BAMLKey, wpfResInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Confuser.Core;
|
||||
using dnlib.DotNet;
|
||||
using dnlib.DotNet.Pdb;
|
||||
|
||||
namespace Confuser.Renamer {
|
||||
internal class RenamePhase : ProtectionPhase {
|
||||
|
@ -55,7 +56,7 @@ namespace Confuser.Renamer {
|
|||
if (!string.IsNullOrEmpty(local.Name))
|
||||
local.Name = service.ObfuscateName(local.Name, mode);
|
||||
}
|
||||
method.Body.Scope = null;
|
||||
method.Body.PdbMethod.Scope = new PdbScope();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,4 +104,4 @@ namespace Confuser.Renamer {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Confuser.Renamer {
|
|||
if (other == null)
|
||||
return false;
|
||||
return new SigComparer().Equals(MethodSig, other.MethodSig) &&
|
||||
Name.Equals(other.Name, StringComparison.Ordinal);
|
||||
Name.Equals(other.Name, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
|
@ -53,7 +53,7 @@ namespace Confuser.Renamer {
|
|||
}
|
||||
|
||||
public override string ToString() {
|
||||
return FullNameCreator.MethodFullName("", Name, MethodSig);
|
||||
return FullNameFactory.MethodFullName("", Name, MethodSig);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,10 +136,10 @@ namespace Confuser.Renamer {
|
|||
var ret = new VTable(typeDef.ToTypeSig());
|
||||
|
||||
var virtualMethods = typeDef.Methods
|
||||
.Where(method => method.IsVirtual)
|
||||
.ToDictionary(
|
||||
method => VTableSignature.FromMethod(method),
|
||||
method => method
|
||||
.Where(method => method.IsVirtual)
|
||||
.ToDictionary(
|
||||
method => VTableSignature.FromMethod(method),
|
||||
method => method
|
||||
);
|
||||
|
||||
// See Partition II 12.2 for implementation algorithm
|
||||
|
@ -221,7 +221,7 @@ namespace Confuser.Renamer {
|
|||
var targetSlot = vTbl.AllSlots.Single(slot => slot.MethodDef == targetMethod);
|
||||
CheckKeyExist(storage, vTbl.SlotsMap, targetSlot.Signature, "MethodImpl Normal Sig");
|
||||
targetSlot = vTbl.SlotsMap[targetSlot.Signature]; // Use the most derived slot
|
||||
// Maybe implemented by above processes --- this process should take priority
|
||||
// Maybe implemented by above processes --- this process should take priority
|
||||
while (targetSlot.MethodDef.DeclaringType == typeDef)
|
||||
targetSlot = targetSlot.Overrides;
|
||||
vTbl.SlotsMap[targetSlot.Signature] = targetSlot.OverridedBy(method.Value);
|
||||
|
@ -246,7 +246,7 @@ namespace Confuser.Renamer {
|
|||
Func<VTableSlot, VTableSlot> implLookup = slot => {
|
||||
MethodDef impl;
|
||||
if (virtualMethods.TryGetValue(slot.Signature, out impl) &&
|
||||
impl.IsNewSlot && !impl.DeclaringType.IsInterface) {
|
||||
impl.IsNewSlot && !impl.DeclaringType.IsInterface) {
|
||||
// Interface methods cannot implements base interface methods.
|
||||
// The Overrides of interface slots should directly points to the root interface slot
|
||||
var targetSlot = slot;
|
||||
|
@ -286,7 +286,7 @@ namespace Confuser.Renamer {
|
|||
// when a derived type shadow the base type using newslot.
|
||||
// In this case, use the derived type's slot in SlotsMap.
|
||||
|
||||
// The derived type's slots are always at a later position
|
||||
// The derived type's slots are always at a later position
|
||||
// than the base type, so it would naturally 'override'
|
||||
// their position in SlotsMap.
|
||||
vTbl.SlotsMap[slot.Signature] = slot;
|
||||
|
@ -376,9 +376,9 @@ namespace Confuser.Renamer {
|
|||
}
|
||||
foreach (var iface in vTable.InterfaceSlots) {
|
||||
ret.InterfaceSlots.Add(GenericArgumentResolver.Resolve(iface.Key, genInst.GenericArguments),
|
||||
iface.Value.Select(slot => ResolveSlot(openType, slot, genInst.GenericArguments)).ToList());
|
||||
iface.Value.Select(slot => ResolveSlot(openType, slot, genInst.GenericArguments)).ToList());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче