Skip to content

Commit 9844573

Browse files
mcpolo99RandomCrocodile
andauthored
chore: upgrade dnlib from 3.6.0 to 4.5.0 (#70) (#87)
* chore: upgrade dnlib from 3.6.0 to 4.5.0 (#70) Evaluated and upgraded dnlib to the latest 4.x. The only breaking API change affecting ConfuserEx: dnlib 4.x added IChunk.CalculateAlignment(). Implemented it on the two custom chunk classes in the AntiTamper JIT mode (JITMethodBody, JITBodyIndex), returning 0 (default/no alignment) to preserve the pre-4.x behaviour. Evaluation notes: - netstandard2.0 target preserved (dnlib 4.5.0 still ships net35/net45/ netstandard2.0/net6.0) — Confuser.Core net48+netstandard2.0 unaffected - DnlibUtils extension methods compile unchanged - Resolve/ResolveThrow, ModuleWriter events, AssemblyResolver: no API changes affecting us - Full suite green: 144 passed, 0 failed (incl. AntiTamper, Compressor, packer, and all cross-framework obfuscation tests) Fixes #70 * perf: route HasAttribute through dnlib IsDefined; test ref-struct generics (#70) Two low-risk wins enabled by the dnlib 4.5 upgrade: - HasAttribute now calls CustomAttributeCollection.IsDefined(fullName) instead of a manual LINQ scan over CustomAttributes. This is the by-full-name lookup dnlib 4.2 optimized, and it benefits all 10 callers (including the per-definition renamer analysis path). Behaviour is identical — full suite stays green. - Add a regression test locking in that obfuscation preserves the 'allows ref struct' generic constraint (GenericParamAttributes. AllowByRefLike, named by dnlib 4.x). The net10 library subject now carries such a constraint, and Library_Net10_PreservesAllowByRefLike loads the obfuscated output and asserts the flag survives. ConfuserEx only renames generic parameters, so the attribute bits are preserved — this guards against a future change silently dropping them. 145 tests pass (was 144). --------- Co-authored-by: RandomCrocodile <mawi@polosab.com>
1 parent ca3faa6 commit 9844573

5 files changed

Lines changed: 52 additions & 2 deletions

File tree

Confuser.Core/Confuser.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
</PropertyGroup>
1616

1717
<ItemGroup Label="Nuget Dependencies">
18-
<PackageReference Include="dnlib" Version="3.6.0" />
18+
<PackageReference Include="dnlib" Version="4.5.0" />
1919
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="1.7.0" />
2020
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.*" />
2121
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />

Confuser.Core/DnlibUtils.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@ public static bool IsVisibleOutside(this TypeDef typeDef, bool exeNonPublic = tr
166166
/// <param name="fullName">The full name of the type of custom attribute.</param>
167167
/// <returns><c>true</c> if the specified object has custom attribute; otherwise, <c>false</c>.</returns>
168168
public static bool HasAttribute(this IHasCustomAttribute obj, string fullName) {
169-
return obj.CustomAttributes.Any(attr => attr.TypeFullName == fullName);
169+
// dnlib's CustomAttributeCollection.IsDefined is the by-full-name lookup that dnlib
170+
// 4.2 optimized — prefer it over a manual LINQ scan.
171+
return obj.CustomAttributes.IsDefined(fullName);
170172
}
171173

172174
/// <summary>

Confuser.Protections/AntiTamper/JITBody.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ public uint GetVirtualSize() {
4747
return GetFileLength();
4848
}
4949

50+
// dnlib 4.x added IChunk.CalculateAlignment. Return 0 for default/no alignment,
51+
// matching the implicit behaviour before the method existed in 3.x.
52+
public uint CalculateAlignment() {
53+
return 0;
54+
}
55+
5056
public void WriteTo(DataWriter writer) {
5157
writer.WriteUInt32((uint)(Body.Length >> 2));
5258
writer.WriteBytes(Body);
@@ -224,6 +230,12 @@ public uint GetVirtualSize() {
224230
return GetFileLength();
225231
}
226232

233+
// dnlib 4.x added IChunk.CalculateAlignment. Return 0 for default/no alignment,
234+
// matching the implicit behaviour before the method existed in 3.x.
235+
public uint CalculateAlignment() {
236+
return 0;
237+
}
238+
227239
public void WriteTo(DataWriter writer) {
228240
uint length = GetFileLength() - 4; // minus length field
229241
writer.WriteUInt32((uint)bodies.Count);

Tests/CrossFramework.Library.Net10/SampleService.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,12 @@ public string Process(string data) {
4040
return new string(chars);
4141
}
4242
}
43+
44+
// Carries a C# 13+ 'allows ref struct' generic constraint, which the compiler emits as
45+
// the GenericParamAttributes.AllowByRefLike flag. Used to verify obfuscation preserves it.
46+
public static class RefStructConsumer {
47+
public static void Consume<T>(T value) where T : allows ref struct {
48+
// Intentionally empty — the 'allows ref struct' constraint is what this exercises.
49+
}
50+
}
4351
}

Tests/CrossFramework.Test/LibraryFrameworkTest.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using System.IO;
2+
using System.Linq;
23
using System.Threading.Tasks;
34
using Confuser.Core;
45
using Confuser.Core.Project;
56
using Confuser.UnitTest;
7+
using dnlib.DotNet;
68
using Xunit;
79
using Xunit.Abstractions;
810

@@ -64,5 +66,31 @@ public Task Library_Net10_RenameProtection() =>
6466
new SettingItem<Protection>("rename"),
6567
outputDirSuffix: "-lib-net10",
6668
checkOutput: false);
69+
70+
// Regression guard: the subject has a 'allows ref struct' generic constraint
71+
// (GenericParamAttributes.AllowByRefLike). Renaming must not drop it — verify the flag
72+
// survives obfuscation on the output assembly. (dnlib 4.x names this flag; ConfuserEx
73+
// only renames generic parameters, so the attribute bits must be preserved.)
74+
[Fact]
75+
[Trait("Category", "CrossFramework")]
76+
[Trait("AppType", "Library")]
77+
[Trait("TFM", "net10.0")]
78+
public Task Library_Net10_PreservesAllowByRefLike() =>
79+
Run("CrossFramework.Library.Net10.dll",
80+
null,
81+
new SettingItem<Protection>("rename"),
82+
outputDirSuffix: "-lib-net10-refstruct",
83+
checkOutput: false,
84+
postProcessAction: outputPath => {
85+
var modulePath = Path.Combine(outputPath, "CrossFramework.Library.Net10.dll");
86+
using var module = ModuleDefMD.Load(modulePath);
87+
var genericParams = module.GetTypes()
88+
.SelectMany(type => type.Methods)
89+
.SelectMany(method => method.GenericParameters)
90+
.Concat(module.GetTypes().SelectMany(type => type.GenericParameters));
91+
Assert.Contains(genericParams,
92+
gp => (gp.Flags & GenericParamAttributes.AllowByRefLike) != 0);
93+
return Task.CompletedTask;
94+
});
6795
}
6896
}

0 commit comments

Comments
 (0)