如何保护我的私有函数免受反射执行?

发布于 2024-12-18 23:50:52 字数 253 浏览 2 评论 0原文

看到这个之后: 访问修饰符也会影响反射吗?

我尝试使用这个,但它不起作用: 在此处输入图像描述

如何防止反射执行我的私有方法?

After seeing this: Do access modifiers affect reflection also?

I tried using this, but it doesn't work:
enter image description here

How can I prevent reflection from executing my private methods?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

倒数 2024-12-25 23:50:52

如果某人当前可以对您的私有方法使用反射,那么他们已经有足够的访问权限来避开您放置在他们的方式中的任何其他内容。以较少的信任运行可能是一种选择,但这只是为了防止插件等拥有过多的访问权限 - 它不会阻止具有(例如)管理员访问权限的用户,他们可以简单地提升访问权限。

如果您不希望代码运行,请不要将其放在恶意用户的物理接触范围内;将其保存在网络服务或类似服务中。用户可用的任何代码都可以直接使用,也可以通过反编译(并在需要时对其进行反混淆)来间接使用。您可以使用一些技巧来阻止他们(通过堆栈跟踪等检查调用者),但这不会阻止某些人的决心。

If someone can currently use reflection on your private methods, then they already have enough access to sidestep anything else you place in their way. Running with less trust may be an option, but that is only to prevent things like plugins from having too much access - it won't stop a user with (say) admin access to the box, who can simply elevate the access.

If you don't want code running, don't put it in physical reach of the malicious user; keep it at a web-service or similar. Any code available to a user can be used directly, or indirectly by decompiling it (and deobfuscating it if needed). You can use some tricks to get in their way (checking the caller via the stacktrace etc), but that will not stop someone determined.

岁月无声 2024-12-25 23:50:52

这是一个迟来的答案,但我认为这是一个更新,因为所有答案都是在 2015 年中期 .NET 4.6 发布之前编写的,该版本引入了一个名为 禁用PrivateReflection

通过在 AssemblyInfo.cs 中标记该属性,您可以禁用对该程序集的私有成员的反射。

示例:

namespace DisablingPrivateReflection
{
    public class Singleton
    {
        private Singleton()
        {

        }
    }
}

AssemblyInfo.cs 中添加以下行:

[assembly: DisablePrivateReflection]

然后在引用上述程序集的客户端程序集中,此代码将在运行时失败:

var singleton = Activator.CreateInstance(typeof(Singleton), true);

抛出的异常类型为 MethodAccessException 并显示消息:

尝试通过方法“Program.Main(System.String[])”访问方法
“DisablingPrivateReflection.Singleton..ctor()”失败。

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.

风吹短裙飘 2024-12-25 23:50:52

如何保护我的私有函数免受反射执行?

您可以更改安全策略,以便代码在运行时没有执行“私有反射”的权限。

当然,这只会影响您的机器。如果你想影响别人的机器,发送电子邮件给他们的机器管理员并要求管理员更改用户的安全策略,使其没有权限进行“私人反射”。那是拥有机器及其运行网络的人;显然,您无法更改不属于您的网络上的安全设置。

当然,请注意,比私人反思更强大的权利也必须受到限制。制定一项政策没有任何好处,例如“拒绝私人反映权,但授予更改安全政策的权利”。然后,用户只需更改安全策略即可重新授予自己私有反射。

您还必须限制访问磁盘的能力。可以访问磁盘的人可以简单地从程序集中读取代码,将私有元数据更改为公共,然后正常加载程序集。

因此,您的任务是说服世界上所有的计算机管理员不允许他们的用户访问他们自己的磁盘。我怀疑你不会成功;我建议您找到一种不同的方法来保护您的功能免遭滥用。

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.

无尽的现实 2024-12-25 23:50:52

访问修饰符不是一种安全机制。

如果如果你可以阻止你的函数通过反射被调用,用户可以反编译你的程序,提取该函数,将其放入一个新的程序集并执行它。

Access modifiers are not a security mechanism.

If if you could prevent your function from being called via reflection, the user can just decompile your program, extract that function, put it in a new assembly and execute it.

揪着可爱 2024-12-25 23:50:52
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);
    }
}
}
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);
    }
}
}
尤怨 2024-12-25 23:50:52

没有办法做到这一点。为什么要阻止执行私有函数?通常,如果有人使用反射,他就知道自己在做什么。

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.

十秒萌定你 2024-12-25 23:50:52

不可以,修饰符只是为了开发者进行适当的封装。在运行时,一切都处于同一水平可能会令人难过。

反射机制通常由需要调用一些预配置方法(旧的 ORM)或显示它们(IDE)的应用程序使用。如果这个机制做不到这一点,那就真的很难了。

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.

沉睡月亮 2024-12-25 23:50:52

虽然我绝对同意访问修饰符不是安全功能的想法,但为了编程,我一直在思考这个问题,并且我有一个简单的、没有多大用处的机制,用 Reflection 对抗 Reflection : -)

请注意,这只是一个愚蠢的概念证明,我没有考虑通用方法,它需要对此进行更改...

这个想法是,在您想要保护的每个私有方法的开始处“非法”调用,您只需检查反映您是从该类中的另一个方法调用的,而不是从外部调用的。所以你会使用:
new StackTrace().GetFrame(1).GetMethod();
获取调用者的 MethodBase 并将其与类的 MethodInfos 列表进行比较。

您可以将其添加到辅助类中(无论如何,您需要一个 IEqualityComparer 来比较 MethodBases...

一个问题是您还会阻止一些正确的调用,例如通过委托或通过另一个方法的反射来调用它。 ..所以你在使用它时应该小心,

你可以我的实现此处

Though I absolutely agree with the idea of access modifiers not being a security feature, just for the sake of programming I've been thinking a bit about this, and I've got a simple, not much useful mechanism, fight Reflection with Reflection :-)

Be advised, it's just a silly proof of concept, I'm not taking into account Generic methods, it would need changes for that...

The idea is, at the start of every private method that you want to secure from being "illegally" invoked, you just check via Reflection that you're being invoked from another method in that class, not from outside. So you would use:
new StackTrace().GetFrame(1).GetMethod();
to get the MethodBase of your invoker and would compare it against the list of MethodInfos for your class.

You can add it to a helper class (anyway you'll need a IEqualityComparer to compare MethodBases...

One problem is that you would also be preventing some correct invocations, like invoking it through a delegate or through Reflection from another of your methods... so you should be careful with when you use it.

You can my implementation here

风追烟花雨 2024-12-25 23:50:52

我使用 eazfuscator ,它使方法虚拟化似乎可以很好地隐藏方法。

然后在方法中,我喜欢保护,我将在发布模式下更改代码以提供空指针异常,以启动一个将生成空指针的任务并在没有调用堆栈的代码的情况下执行它。

没有很多开发人员可以在不进行调试的情况下使用您的生产代码...

#if !DEBUG
    #pragma warning disable CS8618 
    
    [System.Diagnostics.DebuggerStepThrough, System.Diagnostics.DebuggerNonUserCode]
    [System.ComponentModel.Browsable(false)]
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
#endif

namespace MyApp.Infrastructure.LicenseManager
{
    [Obfuscation(Feature = "apply to member * when method or constructor: virtualization", Exclude = false)]
    internal sealed class LicenseManager(ISomeClass parameter, ILoggerFactory? factory = null)
    {
       //hide the name space for reverse engineering the naming scheme
       _logger = factory?.CreateLogger("MyApp.LicenseManager") 

    #if !DEBUG
        if (System.Diagnostics.Debugger.IsAttached)
        {
            //send computer information for license violation and prosecution then crash
            System.Threading.ThreadPool.UnsafeQueueUserWorkItem(SystemCrasher.SendAbuseAndCrash);
            
            //send a log entry, of don't if you wish to give no warning
           _logger?.LogWarning(Walter.BOM.LogEvents.FireWall_Warning, "Debugging will cause the developer to generate null pointer exceptions in administration context");
           return;
           
           //all class initiolizers will stay null
         }
    #endif

        _myClass= parameter;

}

#if !DEBUG
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
#endif

如果您的代码被共享 DLL 中的其他代码(例如 NuGet 包中)使用,那么上述方法将阻止您受到同事的欢迎,您需要一个“调试”友好的方法,使用方法代理结合混淆可能会为您解决问题。

[Obfuscation(Feature = "virtualization", Exclude = false)]
private void MyMethod(int parameter)
{
    MyMethodProxy();
    //do some code
}

private void MyMethodProxy([CallerMemberName] string? calledBy = null)
{
    if (!string.Equals(nameof(MyMethod), calledBy, StringComparison.Ordinal))
    {
        throw new LordOfTheRingsException("You shall not pass!!");
    }
}

通过使用 NameOf 方法,您可以保留混淆器重命名方案中的不可打印字符。

我使用了一些其他选项,但这会限制您自动化和使用面向方面的框架,例如 postsharp

希望它有所帮助在此处输入代码

I use eazfuscator and it making methods virtual seems to do a good job hiding the method.

Then in methods, I like to protect I will alter the code in release mode to give null pointer exceptions to start a task that will generate a null pointer and execute it without the code having a callstack.

There are not a lot of developers that can work with your production code without debugging...

#if !DEBUG
    #pragma warning disable CS8618 
    
    [System.Diagnostics.DebuggerStepThrough, System.Diagnostics.DebuggerNonUserCode]
    [System.ComponentModel.Browsable(false)]
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
#endif

namespace MyApp.Infrastructure.LicenseManager
{
    [Obfuscation(Feature = "apply to member * when method or constructor: virtualization", Exclude = false)]
    internal sealed class LicenseManager(ISomeClass parameter, ILoggerFactory? factory = null)
    {
       //hide the name space for reverse engineering the naming scheme
       _logger = factory?.CreateLogger("MyApp.LicenseManager") 

    #if !DEBUG
        if (System.Diagnostics.Debugger.IsAttached)
        {
            //send computer information for license violation and prosecution then crash
            System.Threading.ThreadPool.UnsafeQueueUserWorkItem(SystemCrasher.SendAbuseAndCrash);
            
            //send a log entry, of don't if you wish to give no warning
           _logger?.LogWarning(Walter.BOM.LogEvents.FireWall_Warning, "Debugging will cause the developer to generate null pointer exceptions in administration context");
           return;
           
           //all class initiolizers will stay null
         }
    #endif

        _myClass= parameter;

}

#if !DEBUG
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
#endif

If your code is consumed by other code in a shared DLL (like in NuGet packages) then the above method will prevent you from being popular with your colleagues, you need a "Debug" friendly method, using a method proxy may do the trick for you in combination with obfuscation.

[Obfuscation(Feature = "virtualization", Exclude = false)]
private void MyMethod(int parameter)
{
    MyMethodProxy();
    //do some code
}

private void MyMethodProxy([CallerMemberName] string? calledBy = null)
{
    if (!string.Equals(nameof(MyMethod), calledBy, StringComparison.Ordinal))
    {
        throw new LordOfTheRingsException("You shall not pass!!");
    }
}

By using the NameOf method you are able to survive the non-printable characters from the Obfuscator's renaming scheme.

I use a few other options but this would limit you automate and use Aspect-oriented frameworks like postsharp

Hope it helpsenter code here

蹲在坟头点根烟 2024-12-25 23:50:52

我知道这已经很旧了,但是基本上在 .NET 中做你所要求的事情是相对不可能的,但是你可以做一些事情来减少表面积,并且它们通常需要更多的工作。最终你想要阻止的是类型的句柄,对吗?考虑以下场景。

public class OuterView
{
   protected internal class HiddenMethods
   {
       public static void DoMoreWork(string msg)
       {
            Console.WriteLine(msg);
       }
   }

   public void DoWork(string msg)
   {
       HiddenMethods.DoMoreWork(msg);
   }
}

假设这是在一个库中,您不想授予对底层方法的直接访问权限 - Assembly.GetTypes() 将不会返回嵌套类,并且您有权访问的类中的 HiddenMethods 中没有引用到(外部视图)。将状态保存在 OuterView 中,并在每次静态调用时将其传递到 HiddenMethods 中。最终,任何拥有足够访问权限来创建 PEReader 的人仍然可以访问您的 HiddenMethods。但上述方法适用于十分之九的情况。

I know this is old, but basically to do what you are asking is relatively imposible in .NET, but there are some things you can do to lessen the surface area, and they generally require more work. Ultimately what you are trying to prevent is a handle to a type, right? Consider the following scenario.

public class OuterView
{
   protected internal class HiddenMethods
   {
       public static void DoMoreWork(string msg)
       {
            Console.WriteLine(msg);
       }
   }

   public void DoWork(string msg)
   {
       HiddenMethods.DoMoreWork(msg);
   }
}

Assuming this is in a library that you don't want to grant direct access to the underlying methods - Assembly.GetTypes() won't return the nested class, and there is no reference from the HiddenMethods in the class that you do have access to (OuterView). Save the state in the OuterView, and pass it into the HiddenMethods with each static call. Ultimately, anyone with enough access to create a PEReader can still access your HiddenMethods. But the above works for 9 out of 10 scenarios.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文