[Part 1] Is c# safe? Are Internal class accessible only from the same assembly?

Hi

I was wondering for some time about encapsulation in C#. Are internal class accessible only from the same assembly? Are private fields accessible only from inside class?

Quoting the Microsoft website:
"Private access is the least permissive access level. Private members are accessible only within the body of the class or the struct in which they are declared...."
"Internal types or members are accessible only within files in the same assembly..."
It looks like true. I believed it, but I decided to check it out.

There is a possibility to read and modify private fields and create instances of internal classes when reflection is used.

Reflection is the built-in mechanizm allowing to dynamically create instance of class or invoke methods.

Unfortunately it allows access to private fields and much more...

I wrote a simple example showing how powerful is reflection.
Code is uploaded to github. GITHUB - PrivateFieldsInternalClass


My solution contains 5 projects.
First one InternalClasses contains internal classes with private field and public classes with internal or private fields, e.g InternalClassInternalConstructorPrivateField looks like this:


namespace InternalClasses
{
  internal class InternalClassInternalConstructorPrivateField
  {
    internal InternalClassInternalConstructorPrivateField()
    {
      privateInt = 668;
    }
    private int privateInt;
  }
}

Second one is simple console application showing that using reflection you can create classes from InternalClasses project. You can see it on github.
IsCsharpSafeTests contains unit tests confirming my assumption.
WindowsFormsWithSafeKey is a simple Windows Forms application containing "private key" in private field.

namespace WindowsFormsWithSafeKey
{
  public partial class Form1 : Form
  {
    private string key = "PRIVATE KEY";
    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      textBox1.Text = key;
    }
  }
}

The last one is ReflectionHelper which contains my code which allows to change private property or create internal class.

In System.Reflection namespace you can find interesting classes e.q 
  Assembly
  FieldInfo
  MethodInfo

Assembly class lets load and explore .net assemblies, e.q you can load assembly and get all public types.
  Assembly assembly = Assembly.Load(assemblyName);
  assembly.GetExportedTypes(); 
...yes only public... but when you use 
  assembly.GetTypes();     
you get all types from assembly, public, protected and internal. Assembly class contains much more powerful methods like "CreateInstance". Now I show you  example allowing create instance of public and nonpublic classes.
  public static object CreateInstanceOfInternalClass(string assemblyName, string classNamespace, 
  string className)
    {
      Assembly assembly = Assembly.Load(assemblyName);
      return assembly.CreateInstance($"{classNamespace}.{className}", false, 
             BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | 
             BindingFlags.CreateInstance, null, null, null, null);
    }
 
The one of the parameters of the CreateInstance method are binding flags. As you can see, you can use the NonPublic flag. Below is the unit test that shows that there is possible to create instance of internal class with public/internal/private constructor. 

Earlier, I mentioned that reflection allows to get and set private fields, so now I show you example.
Class "Type" contains GetField method. When you call it with default parameters it returns only public fields. As earlier you can call it with BindingFlags.NonPublic. My method GetNonPublicIntFiledValue returns value of public, private and static fields and it looks like:
public static object GetNonPublicIntFiledValue(object obj, string fieldName, Type type)
    {
      FieldInfo field = type.GetField(fieldName, BindingFlags.NonPublic 
         | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
      return field.GetValue(obj);
    } 

The most dangerous is what I checked at the end whether another application can be launched with changed private fields.
I wrote unit test which loads Form1 from WindowsFormsWithSafeKey, change private field and call private method. 
    [TestMethod]
    public void RunProgramMainWithDifferentValue()
    {

      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      Form1 program = new Form1();
     object val= ReflectionHelper.GetNonPublicIntFiledValue(program, "key", program.GetType());

      Assert.AreEqual(val, "PRIVATE KEY");

      Task.Run(async () =>
      {
        await Task.Delay(2000);
        MethodInvoker del = delegate
        {
          ReflectionHelper.InvokeNonPublicMethod(program, "button1_Click", program.GetType(), new object[] 
          { new object(), new EventArgs() });
        };

        program.Invoke(del);
        await Task.Delay(2000);
        program.Close();
      });

      program.ShowDialog();
      program = new Form1();

      ReflectionHelper.SetNonPublicIntFiledValue(program, "666", "key", program.GetType());

       val = ReflectionHelper.GetNonPublicIntFiledValue(program, "key", program.GetType());

      Assert.AreEqual(val, "666");

      Task.Run(async () =>
      {
       await Task.Delay(2000);
        MethodInvoker del = delegate
        {
          ReflectionHelper.InvokeNonPublicMethod(program, "button1_Click", program.GetType(), new object[] 
          { new object(), new EventArgs() });
        };

        program.Invoke(del);
        await Task.Delay(2000);
        program.Close();
      });

      program.ShowDialog();    
    }

After run this test you'll see simple windows forms app
after 2 seconds you'll see private key inside textbox, because called InvokeNonPublicMethod invokes private method button1_Click and simulates click on button.
Then my test closes this window and creates it again. Next it sets the value "666" to private field named "key" and shows window again.

I think that it is very dangerous and it is loophole for the hackers.

Komentarze

Prześlij komentarz

Popularne posty z tego bloga

Czarna lista produktów zawierających utwardzony tłuszcz roślinny. Aktualizacja 03.08.2013

Olej palmowy w produktach