Skip to content

Commit 4c89dc3

Browse files
authored
Merge 5591d4c into b4a67cb
2 parents b4a67cb + 5591d4c commit 4c89dc3

38 files changed

+947
-92
lines changed

Confuser.Core/Utils.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4+
using System.Linq;
45
using System.Security.Cryptography;
56
using System.Text;
67

@@ -223,13 +224,25 @@ public static IList<T> RemoveWhere<T>(this IList<T> self, Predicate<T> match) {
223224
/// <param name="logger">The logger.</param>
224225
/// <returns>A wrapper of the list.</returns>
225226
public static IEnumerable<T> WithProgress<T>(this IEnumerable<T> enumerable, ILogger logger) {
226-
var list = new List<T>(enumerable);
227-
int i;
228-
for (i = 0; i < list.Count; i++) {
229-
logger.Progress(i, list.Count);
230-
yield return list[i];
227+
switch (enumerable) {
228+
case IList<T> list:
229+
return WithProgress(enumerable, list.Count, logger);
230+
case ICollection<T> collection:
231+
return WithProgress(enumerable, collection.Count, logger);
232+
default:
233+
var buffered = enumerable.ToList();
234+
return WithProgress(buffered, buffered.Count, logger);
231235
}
232-
logger.Progress(i, list.Count);
236+
}
237+
238+
public static IEnumerable<T> WithProgress<T>(this IEnumerable<T> enumerable, int totalCount, ILogger logger) {
239+
var counter = 0;
240+
foreach (var obj in enumerable) {
241+
logger.Progress(counter, totalCount);
242+
yield return obj;
243+
counter++;
244+
}
245+
logger.Progress(totalCount, totalCount);
233246
logger.EndProgress();
234247
}
235248
}

Confuser.Renamer/AnalyzePhase.cs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,6 @@ void Analyze(NameService service, ConfuserContext context, ProtectionParameters
239239
else if (property.IsRuntimeSpecialName)
240240
service.SetCanRename(property, false);
241241

242-
else if (property.IsExplicitlyImplementedInterfaceMember())
243-
service.SetCanRename(property, false);
244-
245242
else if (parameters.GetParameter(context, property, "forceRen", false))
246243
return;
247244

@@ -250,9 +247,6 @@ void Analyze(NameService service, ConfuserContext context, ProtectionParameters
250247

251248
else if (property.DeclaringType.Name.String.Contains("AnonymousType"))
252249
service.SetCanRename(property, false);
253-
254-
else if (property.IsAbstract())
255-
service.SetCanRename(property, false);
256250
}
257251

258252
void Analyze(NameService service, ConfuserContext context, ProtectionParameters parameters, EventDef evt) {
@@ -263,12 +257,6 @@ void Analyze(NameService service, ConfuserContext context, ProtectionParameters
263257

264258
else if (evt.IsRuntimeSpecialName)
265259
service.SetCanRename(evt, false);
266-
267-
else if (evt.IsExplicitlyImplementedInterfaceMember())
268-
service.SetCanRename(evt, false);
269-
270-
else if (evt.IsAbstract())
271-
service.SetCanRename(evt, false);
272260
}
273261
}
274262
}

Confuser.Renamer/Analyzers/InterReferenceAnalyzer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void ProcessMemberRef(ConfuserContext context, INameService service, ModuleDefMD
5353

5454
TypeDef declType = memberRef.DeclaringType.ResolveTypeDefThrow();
5555
if (declType.Module != module && context.Modules.Contains((ModuleDefMD)declType.Module)) {
56-
var memberDef = (IDnlibDef)declType.ResolveThrow(memberRef);
56+
var memberDef = (IMemberDef)declType.ResolveThrow(memberRef);
5757
service.AddReference(memberDef, new MemberRefReference(memberRef, memberDef));
5858
}
5959
}
@@ -67,4 +67,4 @@ public void PostRename(ConfuserContext context, INameService service, Protection
6767
//
6868
}
6969
}
70-
}
70+
}

Confuser.Renamer/Analyzers/ReflectionAnalyzer.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Confuser.Core;
55
using Confuser.Core.Services;
66
using Confuser.Renamer.Properties;
7+
using Confuser.Renamer.References;
78
using dnlib.DotNet;
89
using dnlib.DotNet.Emit;
910
using ILogger = Confuser.Core.ILogger;
@@ -57,8 +58,13 @@ MethodTrace GetMethodTrace() {
5758
if (!types.Any())
5859
types = moduleDefs.SelectMany(m => m.GetTypes()).ToArray();
5960

60-
foreach (var possibleMethod in types.SelectMany(getMember).Where(m => names.Contains(m.Name))) {
61-
nameService.SetCanRename(possibleMethod, false);
61+
foreach (var possibleMember in types.SelectMany(GetTypeAndBaseTypes).SelectMany(getMember).Where(m => names.Contains(m.Name))) {
62+
nameService.SetCanRename(possibleMember, false);
63+
if (!(possibleMember is IMethod) && !(possibleMember is PropertyDef) && !(possibleMember is EventDef)) continue;
64+
65+
foreach (var reference in nameService.GetReferences(possibleMember).OfType<MemberOverrideReference>()) {
66+
nameService.SetCanRename(reference.BaseMemberDef, false);
67+
}
6268
}
6369
}
6470
}
@@ -67,6 +73,14 @@ MethodTrace GetMethodTrace() {
6773
}
6874
}
6975

76+
private static IEnumerable<TypeDef> GetTypeAndBaseTypes(TypeDef typeDef) {
77+
var currentType = typeDef;
78+
while (currentType != null) {
79+
yield return currentType;
80+
currentType = currentType.BaseType.ResolveTypeDef();
81+
}
82+
}
83+
7084
/// <summary>
7185
/// This method is used to determine the types that are load onto the stack at the referenced instruction.
7286
/// In case the method is unable to determine all the types reliable, it will return a empty list.

Confuser.Renamer/Analyzers/TypeBlobAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ private static void AnalyzeMemberRef(ICollection<ModuleDefMD> modules, INameServ
164164
memberRef.IsArrayAccessors())
165165
return;
166166

167-
IDnlibDef member;
167+
IMemberDef member;
168168
if (memberRef.IsFieldRef) member = memberRef.ResolveFieldThrow();
169169
else if (memberRef.IsMethodRef) member = memberRef.ResolveMethodThrow();
170170
else throw new UnreachableException();

Confuser.Renamer/Analyzers/VTableAnalyzer.cs

Lines changed: 138 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,54 @@ public static void Analyze(INameService service, ICollection<ModuleDefMD> module
4949
return;
5050

5151
var vTbl = service.GetVTables()[method.DeclaringType];
52-
VTableSignature sig = VTableSignature.FromMethod(method);
53-
var slots = vTbl.FindSlots(method);
52+
var slots = vTbl.FindSlots(method).ToArray();
53+
54+
IMemberDef discoveredBaseMemberDef = null;
55+
MethodDef discoveredBaseMethodDef = null;
56+
57+
bool doesOverridePropertyOrEvent = false;
58+
var methodProp = method.DeclaringType.Properties.Where(p => BelongsToProperty(p, method));
59+
foreach (var prop in methodProp) {
60+
foreach (var baseMethodDef in FindBaseDeclarations(service, method)) {
61+
var basePropDef = baseMethodDef.DeclaringType.Properties.
62+
FirstOrDefault(p => BelongsToProperty(p, baseMethodDef) && String.Equals(p.Name, prop.Name, StringComparison.Ordinal));
63+
64+
if (basePropDef is null) continue;
65+
66+
// Name of property has to line up.
67+
CreateOverrideReference(service, prop, basePropDef);
68+
CreateSiblingReference(basePropDef, ref discoveredBaseMemberDef, service);
69+
70+
// Method names have to line up as well (otherwise inheriting attributes does not work).
71+
CreateOverrideReference(service, method, baseMethodDef);
72+
CreateSiblingReference(baseMethodDef, ref discoveredBaseMethodDef, service);
73+
74+
doesOverridePropertyOrEvent = true;
75+
}
76+
}
77+
78+
discoveredBaseMemberDef = null;
79+
discoveredBaseMethodDef = null;
80+
81+
var methodEvent = method.DeclaringType.Events.Where(e => BelongsToEvent(e, method));
82+
foreach (var evt in methodEvent) {
83+
foreach (var baseMethodDef in FindBaseDeclarations(service, method)) {
84+
var baseEventDef = baseMethodDef.DeclaringType.Events.
85+
FirstOrDefault(e => BelongsToEvent(e, baseMethodDef) && String.Equals(e.Name, evt.Name, StringComparison.Ordinal));
86+
87+
if (baseEventDef is null) continue;
88+
89+
// Name of event has to line up.
90+
CreateOverrideReference(service, evt, baseEventDef);
91+
CreateSiblingReference(baseEventDef, ref discoveredBaseMemberDef, service);
92+
93+
// Method names have to line up as well (otherwise inheriting attributes does not work).
94+
CreateOverrideReference(service, method, baseMethodDef);
95+
CreateSiblingReference(baseMethodDef, ref discoveredBaseMethodDef, service);
96+
97+
doesOverridePropertyOrEvent = true;
98+
}
99+
}
54100

55101
if (!method.IsAbstract) {
56102
foreach (var slot in slots) {
@@ -60,17 +106,98 @@ public static void Analyze(INameService service, ICollection<ModuleDefMD> module
60106
SetupOverwriteReferences(service, modules, slot, method.Module);
61107
}
62108
}
109+
else if (!doesOverridePropertyOrEvent) {
110+
foreach (var baseMethodDef in FindBaseDeclarations(service, method)) {
111+
CreateOverrideReference(service, method, baseMethodDef);
112+
}
113+
}
114+
}
115+
116+
static void CreateSiblingReference<T>(T basePropDef, ref T discoveredBaseMemberDef, INameService service) where T : class, IMemberDef {
117+
if (discoveredBaseMemberDef is null)
118+
discoveredBaseMemberDef = basePropDef;
63119
else {
64-
foreach (var slot in slots) {
65-
if (slot.Overrides == null)
66-
continue;
67-
service.SetCanRename(method, false);
68-
service.SetCanRename(slot.Overrides.MethodDef, false);
120+
var references = service.GetReferences(discoveredBaseMemberDef).OfType<MemberSiblingReference>().ToArray();
121+
if (references.Length > 0) {
122+
discoveredBaseMemberDef = (T)references[0].OldestSiblingDef;
123+
foreach (var siblingRef in references.Skip(1)) {
124+
// Redirect all the siblings to the new oldest reference
125+
RedirectSiblingReferences(siblingRef.OldestSiblingDef, discoveredBaseMemberDef, service);
126+
}
127+
}
128+
129+
service.AddReference(basePropDef, new MemberSiblingReference(basePropDef, discoveredBaseMemberDef));
130+
UpdateOldestSiblingReference(discoveredBaseMemberDef, basePropDef, service);
131+
}
132+
}
133+
134+
static void UpdateOldestSiblingReference(IMemberDef oldestSiblingMemberDef, IMemberDef basePropDef, INameService service) {
135+
var reverseReference = service.GetReferences(oldestSiblingMemberDef).OfType<MemberOldestSiblingReference>()
136+
.SingleOrDefault();
137+
if (reverseReference is null)
138+
service.AddReference(oldestSiblingMemberDef, new MemberOldestSiblingReference(oldestSiblingMemberDef, basePropDef));
139+
else if (!reverseReference.OtherSiblings.Contains(basePropDef)) {
140+
reverseReference.OtherSiblings.Add(basePropDef);
141+
}
142+
}
143+
144+
static void RedirectSiblingReferences(IMemberDef oldMemberDef, IMemberDef newMemberDef, INameService service) {
145+
if (ReferenceEquals(oldMemberDef, newMemberDef)) return;
146+
147+
var referencesToUpdate = service.GetReferences(oldMemberDef)
148+
.OfType<MemberOldestSiblingReference>()
149+
.SelectMany(r => r.OtherSiblings)
150+
.SelectMany(service.GetReferences)
151+
.OfType<MemberSiblingReference>()
152+
.Where(r => ReferenceEquals(r.OldestSiblingDef, oldMemberDef));
153+
154+
foreach (var reference in referencesToUpdate) {
155+
reference.OldestSiblingDef = newMemberDef;
156+
UpdateOldestSiblingReference(newMemberDef, reference.ThisMemberDef, service);
157+
}
158+
UpdateOldestSiblingReference(newMemberDef, oldMemberDef, service);
159+
}
160+
161+
static void CreateOverrideReference(INameService service, IMemberDef thisMemberDef, IMemberDef baseMemberDef) {
162+
var overrideRef = new MemberOverrideReference(thisMemberDef, baseMemberDef);
163+
service.AddReference(thisMemberDef, overrideRef);
164+
165+
if (!service.CanRename(thisMemberDef))
166+
service.SetCanRename(baseMemberDef, false);
167+
}
168+
169+
170+
private static IEnumerable<MethodDef> FindBaseDeclarations(INameService service, MethodDef method) {
171+
var unprocessed = new Queue<MethodDef>();
172+
unprocessed.Enqueue(method);
173+
174+
var vTables = service.GetVTables();
175+
176+
while (unprocessed.Any()) {
177+
var currentMethod = unprocessed.Dequeue();
178+
179+
var vTbl = vTables[currentMethod.DeclaringType];
180+
var slots = vTbl.FindSlots(currentMethod).Where(s => s.Overrides != null).ToArray();
181+
if (slots.Any()) {
182+
foreach (var slot in slots) {
183+
unprocessed.Enqueue(slot.Overrides.MethodDef);
184+
}
185+
}
186+
else if (method != currentMethod) {
187+
yield return currentMethod;
69188
}
70189
}
71190
}
72191

73-
private static void AddImportReference(INameService service, ICollection<ModuleDefMD> modules, ModuleDef module, MethodDef method, MemberRef methodRef) {
192+
private static bool BelongsToProperty(PropertyDef propertyDef, MethodDef methodDef) =>
193+
propertyDef.GetMethods.Contains(methodDef) || propertyDef.SetMethods.Contains(methodDef) ||
194+
(propertyDef.HasOtherMethods && propertyDef.OtherMethods.Contains(methodDef));
195+
196+
private static bool BelongsToEvent(EventDef eventDef, MethodDef methodDef) =>
197+
Equals(eventDef.AddMethod, methodDef) || Equals(eventDef.RemoveMethod, methodDef) || Equals(eventDef.InvokeMethod, methodDef) ||
198+
(eventDef.HasOtherMethods && eventDef.OtherMethods.Contains(methodDef));
199+
200+
private static void AddImportReference(INameService service, ICollection<ModuleDefMD> modules, ModuleDef module, MethodDef method, MemberRef methodRef) {
74201
if (method.Module != module && modules.Contains((ModuleDefMD)module)) {
75202
var declType = (TypeRef)methodRef.DeclaringType.ScopeType;
76203
service.AddReference(method.DeclaringType, new TypeRefReference(declType, method.DeclaringType));
@@ -88,8 +215,8 @@ private static void AddImportReference(INameService service, ICollection<ModuleD
88215
private static void SetupTypeReference(INameService service, ICollection<ModuleDefMD> modules, ModuleDef module, ITypeDefOrRef typeDefOrRef) {
89216
if (!(typeDefOrRef is TypeRef typeRef)) return;
90217

91-
var def = typeRef.ResolveTypeDefThrow();
92-
if (def.Module != module && modules.Contains((ModuleDefMD)def.Module))
218+
var def = typeRef.ResolveTypeDef();
219+
if (!(def is null) && def.Module != module && modules.Contains((ModuleDefMD)def.Module))
93220
service.AddReference(def, new TypeRefReference(typeRef, def));
94221
}
95222

@@ -99,7 +226,7 @@ private static GenericInstSig SetupSignatureReferences(INameService service, ICo
99226
return new GenericInstSig(genericType, genericArguments);
100227
}
101228

102-
private static T SetupSignatureReferences<T>(INameService service, ICollection<ModuleDefMD> modules, ModuleDef module, T typeSig) where T : TypeSig {
229+
private static T SetupSignatureReferences<T>(INameService service, ICollection<ModuleDefMD> modules, ModuleDef module, T typeSig) where T : TypeSig {
103230
var asTypeRef = typeSig.TryGetTypeRef();
104231
if (asTypeRef != null) {
105232
SetupTypeReference(service, modules, module, asTypeRef);

Confuser.Renamer/INameReference.cs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,49 @@
1-
using System;
2-
using Confuser.Core;
1+
using Confuser.Core;
32

43
namespace Confuser.Renamer {
54
public interface INameReference {
6-
bool UpdateNameReference(ConfuserContext context, INameService service);
5+
/// <summary>
6+
/// Check if the element with this reference attached should be
7+
/// renamed at all.
8+
/// </summary>
9+
bool ShouldCancelRename { get; }
10+
11+
/// <summary>
12+
/// Check if the renaming has to be delayed, because the referenced objects are not handled yet.
13+
/// </summary>
14+
/// <param name="service">The naming service</param>
15+
/// <returns>
16+
/// <see langword="true" /> in case the reference can't be resolved yet;
17+
/// otherwise <see langword="false" />.</returns>
18+
bool DelayRenaming(INameService service);
719

8-
bool ShouldCancelRename();
20+
/// <summary>
21+
/// Update the name reference.
22+
/// </summary>
23+
/// <param name="context">The confuser context</param>
24+
/// <param name="service">The name service</param>
25+
/// <returns>
26+
/// <see langword="true" /> in case the name was updated;
27+
/// otherwise <see langword="false" />.
28+
/// </returns>
29+
/// <exception cref="ArgumentNullException">
30+
/// <paramref name="context" /> is <see langword="null" />
31+
/// <br />- or -<br />
32+
/// <paramref name="service" /> is <see langword="null" />
33+
/// </exception>
34+
bool UpdateNameReference(ConfuserContext context, INameService service);
35+
36+
/// <summary>
37+
/// Get a description of this reference, containing the original
38+
/// names of the referenced objects.
39+
/// </summary>
40+
/// <param name="nameService">
41+
/// The name service used to get the original names;
42+
/// or <see langword="null"/>
43+
/// </param>
44+
/// <returns>Description of this reference.</returns>
45+
string ToString(INameService nameService);
946
}
1047

1148
public interface INameReference<out T> : INameReference { }
12-
}
49+
}

0 commit comments

Comments
 (0)