Skip to main content
Version: 2023.4

5.4. Private Protected Visibility

.NET languages offer a few keywords for visibility control between assemblies, classes and members. For example, C# has public, internal, protected, protected internal and private access modifiers.

Sometimes you may need a special private protected accessibility level. It exists in Managed C++ but absent in older VB.NET and C# versions. It corresponds to FamANDAssem visibility scope in terms of .NET CLR.

Tip

C# starting with version 7.2 provides private protected access modifier. Visual Basic starting with version 15.5 provides Private Protected access modifier. This is a preferred way to go, instead of relying on Eazfuscator.NET to achieve the very same functionality.

Availability of private protected accessibility level is pretty rare requirement, so let's take a look on specific example. Suppose you have a DLL assembly written in older C# version (before 7.2) that does XML serialization for some entities:

Example 5.5. Original code

using System;
using System.Xml.Serialization;

// This class is used by System.Xml.Serialization.XmlSerializer.
public class Card
{
public string ID { get; set; }

protected virtual void Validate()
{
}
}

// This class is used by System.Xml.Serialization.XmlSerializer.
public class VerticalCard : Card
{
public int Height { get; set; }

protected override void Validate()
{
if (Height <= 0)
throw new Exception("Vertical card height should be a positive number greater than zero.");
}
}

See that Validate method? It won't be renamed after obfuscation despite the wish of a developer. But why? The answer is: because assembly is DLL, the class is public and Validate method is protected. This means that Validate method can be reached by a third-party assembly and Eazfuscator.NET leaves its name intact.

That's ok for most situations.

Still, let's imagine that one picky developer decides to rename Validate method whatever it costs. Potential workarounds are:

  • Make Validate methods private. Won't work because it wouldn't be possible to override Validate method in VerticalCard class

  • Make Card and VerticalCard classes internal. Won't work because XmlSerializer works on public classes only

  • Make Validate methods internal. Will work but will break the visibility borders inside the assembly. This may be unfeasible if you work in a team with established responsibility borders between its members

  • Make Validate methods private protected. Will perfectly work, but only in Managed C++. Older VB.NET and C# versions have no corresponding access modifier

  • Move validation away to a separate set of classes. Will work, but it requires code refactoring. It may be risky for a large code base and thus not always suitable

So we are stuck if our code is in C# or VB.NET.

Fortunately Eazfuscator.NET can change the visibility of class members to FamANDAssem level. This is the exact same thing as protected private in Managed C++. Having that, we can now solve the dilemma (C#):

Example 5.6. Modified code to allow family and assembly visibility for specified methods

using System;
using System.Xml.Serialization;
using System.Reflection;

// This class is used by System.Xml.Serialization.XmlSerializer.
public class Card
{
public string ID { get; set; }

[Obfuscation(Feature = "family and assembly visibility", Exclude = false)]
protected virtual void Validate()
{
}
}

// This class is used by System.Xml.Serialization.XmlSerializer.
public class VerticalCard : Card
{
public int Height { get; set; }

[Obfuscation(Feature = "family and assembly visibility", Exclude = false)]
protected override void Validate()
{
if (Height <= 0)
throw new Exception("Vertical card height should be a positive number greater than zero.");
}
}

Once that in place, Validate methods will be renamed and will no longer be visible to other assemblies.

Instructions on changing visibility to FamANDAssem level for a class member

  1. Open the source code of a class member that should have a visibility change

  2. Add a custom attribute as shown below (C#):

    using System;
    using System.Reflection;

    class YourClass
    {
    [Obfuscation(Feature = "family and assembly visibility", Exclude = false)]
    protected void YourMethod()
    {
    ...
    }
    }

    For Visual Basic .NET:

    Imports System
    Imports System.Reflection

    Class YourClass

    <Obfuscation(Feature:="family and assembly visibility", Exclude:=False)>
    Protected Sub YourMethod()
    ...
    End Sub

    End Class
Tip

If you change visibility of a virtual method then it is beneficial to ensure that the whole inheritance hierarchy has the corresponding change. This will improve renaming coverage during obfuscation.

Tip

It may be a good idea to turn on code verification for your assembly when visibility changes are applied to ensure that the generated code conforms to the industrial standard of quality.