Skip to content

Commit

Permalink
Fix handling of fully foreign vtable slots
Browse files Browse the repository at this point in the history
Implemented handling for the renamer in case all methods of a VTable slot don't belong to the type, the slots belongs to.
This happens in case a type implicitly implements an interface by inheriting another class.
  • Loading branch information
mkaring committed Jan 27, 2021
1 parent b29ff42 commit b3c2281
Show file tree
Hide file tree
Showing 15 changed files with 245 additions and 13 deletions.
24 changes: 19 additions & 5 deletions Confuser.Renamer/Analyzers/VTableAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ public static void Analyze(INameService service, ICollection<ModuleDefMD> module
else if (baseUnderCtrl && !ifaceUnderCtrl || !service.CanRename(slot.Overrides.MethodDef)) {
service.SetCanRename(slot.MethodDef, false);
}

// Now it is possible that the method implementing the interface, belongs to the base class.
// If that happens the methods analyzing the methods will not pick up on this. We'll mark that
// case here.
if (!TypeEqualityComparer.Instance.Equals(slot.MethodDef.DeclaringType, type)) {
SetupOverwriteReferences(service, modules, slot, type);
//CreateOverrideReference(service, slot.MethodDef, slot.Overrides.MethodDef);
}
}
}
}
Expand Down Expand Up @@ -103,7 +111,7 @@ public static void Analyze(INameService service, ICollection<ModuleDefMD> module
if (slot.Overrides == null)
continue;

SetupOverwriteReferences(service, modules, slot, method.Module);
SetupOverwriteReferences(service, modules, slot, method.DeclaringType);
}
}
else if (!doesOverridePropertyOrEvent) {
Expand Down Expand Up @@ -258,7 +266,8 @@ private static void SetupSignatureReferences(INameService service, ICollection<M
}
}

private static void SetupOverwriteReferences(INameService service, ICollection<ModuleDefMD> modules, VTableSlot slot, ModuleDef module) {
private static void SetupOverwriteReferences(INameService service, ICollection<ModuleDefMD> modules, VTableSlot slot, TypeDef thisType) {
var module = thisType.Module;
var methodDef = slot.MethodDef;
var baseSlot = slot.Overrides;
var baseMethodDef = baseSlot.MethodDef;
Expand Down Expand Up @@ -290,10 +299,15 @@ private static void SetupOverwriteReferences(INameService service, ICollection<M
if (target is MemberRef methodRef)
AddImportReference(service, modules, module, baseMethodDef, methodRef);

if (methodDef.Overrides.Any(impl => IsMatchingOverride(impl, target)))
return;
if (TypeEqualityComparer.Instance.Equals(methodDef.DeclaringType, thisType)) {
if (methodDef.Overrides.Any(impl => IsMatchingOverride(impl, target)))
return;

methodDef.Overrides.Add(new MethodOverride(methodDef, target));
methodDef.Overrides.Add(new MethodOverride(methodDef, target));
}
else if (target is IMemberDef targetDef) {
CreateOverrideReference(service, methodDef, targetDef);
}
}

private static bool IsMatchingOverride(MethodOverride methodOverride, IMethodDefOrRef targetMethod) {
Expand Down
45 changes: 45 additions & 0 deletions Confuser2.sln
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "244_ClrProtection", "Tests\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "244_ClrProtection.Test", "Tests\244_ClrProtection.Test\244_ClrProtection.Test.csproj", "{3ADB8BB1-AE14-49DA-A7E1-1C0D9BEB76E9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "306_ComplexClassStructureRename.Lib", "Tests\306_ComplexClassStructureRename.Lib\306_ComplexClassStructureRename.Lib.csproj", "{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "306_ComplexClassStructureRename", "Tests\306_ComplexClassStructureRename\306_ComplexClassStructureRename.csproj", "{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "306_ComplexClassStructureRename.Test", "Tests\306_ComplexClassStructureRename.Test\306_ComplexClassStructureRename.Test.csproj", "{13431429-2DB6-480F-B73F-CA019FE759E3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -685,6 +691,42 @@ Global
{3ADB8BB1-AE14-49DA-A7E1-1C0D9BEB76E9}.Release|x64.Build.0 = Release|Any CPU
{3ADB8BB1-AE14-49DA-A7E1-1C0D9BEB76E9}.Release|x86.ActiveCfg = Release|Any CPU
{3ADB8BB1-AE14-49DA-A7E1-1C0D9BEB76E9}.Release|x86.Build.0 = Release|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Debug|x64.ActiveCfg = Debug|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Debug|x64.Build.0 = Debug|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Debug|x86.ActiveCfg = Debug|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Debug|x86.Build.0 = Debug|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Release|Any CPU.Build.0 = Release|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Release|x64.ActiveCfg = Release|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Release|x64.Build.0 = Release|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Release|x86.ActiveCfg = Release|Any CPU
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35}.Release|x86.Build.0 = Release|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Debug|x64.ActiveCfg = Debug|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Debug|x64.Build.0 = Debug|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Debug|x86.ActiveCfg = Debug|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Debug|x86.Build.0 = Debug|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Release|Any CPU.Build.0 = Release|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Release|x64.ActiveCfg = Release|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Release|x64.Build.0 = Release|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Release|x86.ActiveCfg = Release|Any CPU
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16}.Release|x86.Build.0 = Release|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Debug|x64.ActiveCfg = Debug|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Debug|x64.Build.0 = Debug|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Debug|x86.ActiveCfg = Debug|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Debug|x86.Build.0 = Debug|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Release|Any CPU.Build.0 = Release|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Release|x64.ActiveCfg = Release|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Release|x64.Build.0 = Release|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Release|x86.ActiveCfg = Release|Any CPU
{13431429-2DB6-480F-B73F-CA019FE759E3}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -729,6 +771,9 @@ Global
{2C059FE7-C868-4C6D-AFA0-D62BA3C1B2E1} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{73F11EE8-F565-479E-8366-BD74EE467CE8} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{3ADB8BB1-AE14-49DA-A7E1-1C0D9BEB76E9} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{FD93D181-2EC5-4863-8A8F-5F8C84C06B35} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{1B52A3D9-014C-4CBF-BB98-09080D9A8D16} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{13431429-2DB6-480F-B73F-CA019FE759E3} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0D937D9E-E04B-4A68-B639-D4260473A388}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<RootNamespace>ComplexClassStructureRename.Lib</RootNamespace>
</PropertyGroup>

</Project>
5 changes: 5 additions & 0 deletions Tests/306_ComplexClassStructureRename.Lib/ITestEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace ComplexClassStructureRename.Lib {
public interface ITestEvents {
void FireLog(string message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace ComplexClassStructureRename.Lib {
internal class InternalBaseClass {
public virtual void FireLog(string message) { }
}
}
8 changes: 8 additions & 0 deletions Tests/306_ComplexClassStructureRename.Lib/InternalClass1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System;

namespace ComplexClassStructureRename.Lib {
internal class InternalClass1 : InternalBaseClass {
public new void FireLog(string message) =>
Console.WriteLine("InternalClass1: " + message);
}
}
3 changes: 3 additions & 0 deletions Tests/306_ComplexClassStructureRename.Lib/InternalClass2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace ComplexClassStructureRename.Lib {
internal class InternalClass2 : InternalBaseClass, ITestEvents { }
}
12 changes: 12 additions & 0 deletions Tests/306_ComplexClassStructureRename.Lib/MyTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace ComplexClassStructureRename.Lib {
internal class MyTest {
readonly InternalClass1 _test1 = new InternalClass1();
readonly InternalClass2 _test2 = new InternalClass2();

public void Test() {
_test1.FireLog("test1 Hello");
_test2.FireLog("test2 Hello");
}

}
}
8 changes: 8 additions & 0 deletions Tests/306_ComplexClassStructureRename.Lib/PublicClass1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Reflection;

namespace ComplexClassStructureRename.Lib {
[Obfuscation(Exclude = false, Feature = "-rename")]
public class PublicClass1 : ITestEvents {
public void FireLog(string message) { }
}
}
10 changes: 10 additions & 0 deletions Tests/306_ComplexClassStructureRename.Lib/PublicClass2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Reflection;

namespace ComplexClassStructureRename.Lib {
[Obfuscation(Exclude = false, Feature = "-rename")]
public class PublicClass2 {
readonly MyTest _test = new MyTest();

public void Test() => _test.Test();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<RootNamespace>ComplexClassStructureRename.Test</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Confuser.UnitTest\Confuser.UnitTest.csproj" />
<ProjectReference Include="..\306_ComplexClassStructureRename\306_ComplexClassStructureRename.csproj" />
</ItemGroup>
</Project>
33 changes: 33 additions & 0 deletions Tests/306_ComplexClassStructureRename.Test/ComplexRenameTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Threading.Tasks;
using Confuser.Core;
using Confuser.Core.Project;
using Confuser.UnitTest;
using Xunit;
using Xunit.Abstractions;

namespace ComplexClassStructureRename.Test {
public class ComplexRenameTest : TestBase {
public ComplexRenameTest(ITestOutputHelper outputHelper) : base(outputHelper) { }

[Fact]
[Trait("Category", "Protection")]
[Trait("Protection", "rename")]
[Trait("Issue", "https://github.com/mkaring/ConfuserEx/issues/306")]
public async Task ComplexClassStructureRename() =>
await Run(
new[] {
"306_ComplexClassStructureRename.exe",
"306_ComplexClassStructureRename.Lib.dll"
},
new[] {
"InternalClass1: test1 Hello"
},
new SettingItem<Protection>("rename") {
{ "mode", "sequential" },
{ "renPublic", "true" },
{ "flatten", "false" }
}
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net461</TargetFramework>
<RootNamespace>ComplexClassStructureRename</RootNamespace>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\306_ComplexClassStructureRename.Lib\306_ComplexClassStructureRename.Lib.csproj" />
</ItemGroup>

</Project>
21 changes: 21 additions & 0 deletions Tests/306_ComplexClassStructureRename/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using ComplexClassStructureRename.Lib;

[assembly: Obfuscation(Exclude = false, Feature = "-rename")]

namespace ComplexClassStructureRename {
public class Program {
[SuppressMessage("Style", "IDE0060:Remove unused parameters", Justification = "Required signature")]
static int Main(string[] args) {
Console.WriteLine("START");

var t = new PublicClass2();
t.Test();

Console.WriteLine("END");
return 42;
}
}
}
50 changes: 42 additions & 8 deletions Tests/Confuser.UnitTest/TestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Confuser.Core.Project;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace Confuser.UnitTest {
public abstract class TestBase {
Expand Down Expand Up @@ -98,25 +99,50 @@ protected async Task Run(string[] inputFileNames, string[] expectedOutput, IEnum
// Check if output assemblies is obfuscated
Assert.NotEqual(FileUtilities.ComputeFileChecksum(Path.Combine(baseDir, name)),
FileUtilities.ComputeFileChecksum(outputName));
} else if (IsExternal(inputFileNames[index])) {
}
else if (IsExternal(inputFileNames[index])) {
File.Copy(
Path.Combine(baseDir, GetFileName(inputFileNames[index])),
Path.Combine(outputDir, GetFileName(inputFileNames[index])));
}
}

if (Path.GetExtension(entryInputFileName) == ".exe") {
var info = new ProcessStartInfo(entryOutputFileName) { RedirectStandardOutput = true, UseShellExecute = false };
var info = new ProcessStartInfo(entryOutputFileName) {
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
using (var process = Process.Start(info)) {
var stdout = process.StandardOutput;
Assert.Equal("START", await stdout.ReadLineAsync());
using (var stdout = process.StandardOutput) {
try {
Assert.Equal("START", await stdout.ReadLineAsync());

foreach (string line in expectedOutput) {
Assert.Equal(line, await stdout.ReadLineAsync());
}

Assert.Equal("END", await stdout.ReadLineAsync());
Assert.Empty(await stdout.ReadToEndAsync());
}
catch (XunitException) {
try {
LogRemainingStream("Remaining standard output:", stdout);
using (var stderr = process.StandardError) {
LogRemainingStream("Remaining standard error:", stderr);
}
}
catch {
// ignore
}
throw;
}
}

foreach (string line in expectedOutput) {
Assert.Equal(line, await stdout.ReadLineAsync());
using (var stderr = process.StandardError) {
Assert.Empty(await stderr.ReadToEndAsync());
}

Assert.Equal("END", await stdout.ReadLineAsync());
Assert.Empty(await stdout.ReadToEndAsync());
Assert.True(process.HasExited);
Assert.Equal(42, process.ExitCode);
}
Expand All @@ -126,6 +152,14 @@ protected async Task Run(string[] inputFileNames, string[] expectedOutput, IEnum
await postProcessAction.Invoke(outputDir);
}

private void LogRemainingStream(string header, StreamReader reader) {
var remainingOutput = reader.ReadToEnd();
if (!string.IsNullOrWhiteSpace(remainingOutput)) {
outputHelper.WriteLine(header);
outputHelper.WriteLine(remainingOutput.Trim());
}
}

private static string GetFileName(string name) {
if (IsExternal(name))
return name.Substring(_externalPrefix.Length);
Expand Down

0 comments on commit b3c2281

Please sign in to comment.