After seeing this: Do access modifiers affect reflection also?
I tried using this, but it doesn\'t work:
using System;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
class Person
{
private string SayInternalSecure()
{
if (!PrivacyHelper.IsInvocationAllowed<Person>())
throw new Exception("you can't invoke this private method");
return "Internal Secure";
}
private string SayInternal()
{
return "Internal";
}
public string SaySomething()
{
return "Hi " + this.SayInternal();
}
public string SaySomethingSecure()
{
return "Hi " + this.SayInternalSecure();
}
public void BeingCalledBy()
{
Console.WriteLine("I'm being called by: " + new StackTrace().GetFrame(1).GetMethod().Name);
}
}
public class MethodBaseComparer : IEqualityComparer<MethodBase>
{
private string GetMethodIdentifier(MethodBase mb)
{
return mb.Name + ":" + String.Join(";", mb.GetParameters().Select(paramInfo=>paramInfo.Name).ToArray());
}
public bool Equals(MethodBase m1, MethodBase m2)
{
//we need something more here, comparing just by name is not enough, need to take parameters into account
return this.GetMethodIdentifier(m1) == this.GetMethodIdentifier(m2);
}
public int GetHashCode(MethodBase mb)
{
return this.GetMethodIdentifier(mb).GetHashCode();
}
}
class PrivacyHelper
{
static Dictionary<Type, MethodBase[]> cache = new Dictionary<Type, MethodBase[]>();
public static bool IsInvocationAllowed<T>()
{
Type curType = typeof(T);
if (!cache.ContainsKey(curType))
{
cache[curType] = curType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToArray();
}
//StackTrace.GetFrame returns a MethodBase, not a MethodInfo, that's why we're falling back to MethodBody
MethodBase invoker = new StackTrace().GetFrame(2).GetMethod();
return cache[curType].Contains(invoker, new MethodBaseComparer());
}
}
public class App
{
public static void CheckCaller()
{
Person p = new Person();
Console.WriteLine("- calling via delegate");
Action action = p.BeingCalledBy;
action();
Console.WriteLine("- calling via reflection");
MethodInfo method = typeof(Person).GetMethod("BeingCalledBy", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
Console.WriteLine(method.Invoke(p, null));
Console.WriteLine("- calling via delegate again");
action = (Action)(Delegate.CreateDelegate(typeof(Action), p, method));
action();
}
public static void Main()
{
Console.WriteLine("Press key to run");
Console.ReadLine();
CheckCaller();
Person p = new Person();
Console.WriteLine(p.SaySomething());
Console.WriteLine(p.SaySomethingSecure());
MethodInfo privateMethod = typeof(Person).GetMethod("SayInternal", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
Console.WriteLine("invoking private method via Reflection:");
Console.WriteLine(privateMethod.Invoke(p, null));
Console.WriteLine("----------------------");
privateMethod = typeof(Person).GetMethod("SayInternalSecure", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
Console.WriteLine("invoking secured private method via Reflection:");
try
{
Console.WriteLine(privateMethod.Invoke(p, null));
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
How can I protect my private funcs against reflection executing?
You can change your security policy so that the code does not have permission to do "private reflection" when you run it.
Of course, that will only affect your machine. If you want to affect someone else's machine, send an email to their machine administrator and ask the administrator to change the user's security policy so that it does not have permission to do "private reflection". That's the person who owns the machine and the network it runs on; obviously you do not have the ability to change the security settings on a network you don't own.
Note of course that rights more powerful than private reflection also have to be restricted. It does no good to set a policy that says, for example "private reflection rights are denied, but the right to change security policy is granted". The user could then just change security policy to re-grant private reflection to themselves.
You'll also have to restrict ability to access the disk. Someone who can access the disk can simply read the code out of the assembly, change the private metadata to public, and load the assembly normally.
So, your mission is to convince all of the machine administrators of the world to not allow their users to access their own disks. I suspect you will be unsuccessful; I suggest that you find a different way to protect your functions from abuse.
There is no way to do that. Why do you want to prevent execution of your private funcs? Usually, if someone uses reflection, he knows what he's doing.
You can not, the modifiers are only for developers to have proper encapsulation. At the runtime it could be sad that everything is on the same level.
The reflection mechanics, is used usually by application that need to call some pre-configured methods (older ORM) or display them (IDE). It wold be really hard if this mechanism would not be able to do that.
This is a late answer, but I consider it an update since all the answers were written before the release of .NET 4.6 in mid of 2015 which introduces a new assembly attribute called DisablePrivateReflection.
With that attribute tagged in your AssemblyInfo.cs
, you can disable reflection over private members of that assembly.
Example:
namespace DisablingPrivateReflection
{
public class Singleton
{
private Singleton()
{
}
}
}
And in your AssemblyInfo.cs
add this line:
[assembly: DisablePrivateReflection]
Then in your client assembly that is referencing the above assembly, this code would fail at run-time:
var singleton = Activator.CreateInstance(typeof(Singleton), true);
The exception thrown is of type MethodAccessException with message:
Attempt by method 'Program.Main(System.String[])' to access method 'DisablingPrivateReflection.Singleton..ctor()' failed.
I would try to parse stack trace (https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics?redirectedfrom=MSDN&view=netframework-4.7.2) and check for dynamic invocation...