Przewodnik: Emitowanie kodu w scenariuszach częściowo zaufanych

Emisja odbicia używa tego samego zestawu interfejsu API w pełnym lub częściowym zaufaniu, ale niektóre funkcje wymagają specjalnych uprawnień w częściowo zaufanym kodzie. Ponadto emisja odbicia ma funkcję, anonimowo hostowaną metodę dynamiczną, która jest przeznaczona do użycia z częściowym zaufaniem i przez zestawy przezroczyste dla zabezpieczeń.

Uwaga

Przed .NET Framework 3.5 emitowanie kodu wymaganego ReflectionPermission za pomocą flagi ReflectionPermissionFlag.ReflectionEmit . To uprawnienie jest domyślnie uwzględniane w FullTrust zestawach uprawnień i Intranet nazwanych, ale nie w Internet zestawie uprawnień. W związku z tym można użyć biblioteki z częściowego zaufania tylko wtedy, gdy miał SecurityCriticalAttribute atrybut , a także wykonał metodę Assert dla ReflectionEmit. Takie biblioteki wymagają starannego przeglądu zabezpieczeń, ponieważ błędy kodowania mogą powodować luki w zabezpieczeniach. .NET Framework 3.5 umożliwia emitowanie kodu w scenariuszach częściowego zaufania bez wystawiania żadnych wymagań dotyczących zabezpieczeń, ponieważ generowanie kodu nie jest z natury operacją uprzywilejowaną. Oznacza to, że wygenerowany kod nie ma więcej uprawnień niż zestaw, który go emituje. Dzięki temu biblioteki emitujące kod są niewidoczne dla zabezpieczeń i eliminuje konieczność potwierdzenia ReflectionEmit, dzięki czemu pisanie bezpiecznej biblioteki nie wymaga takiego dokładnego przeglądu zabezpieczeń.

W instruktażu przedstawiono następujące zagadnienia:

Aby uzyskać więcej informacji na temat emitowania kodu w scenariuszach częściowego zaufania, zobacz Problemy z zabezpieczeniami w emisji odbicia.

Aby uzyskać pełną listę kodu pokazanego w tych procedurach, zobacz sekcję Przykład na końcu tego przewodnika.

Konfigurowanie częściowo zaufanych lokalizacji

W poniższych dwóch procedurach pokazano, jak skonfigurować lokalizacje, z których można przetestować kod z częściowym zaufaniem.

  • Pierwsza procedura pokazuje, jak utworzyć domenę aplikacji w trybie piaskownicy, w której kod ma przyznane uprawnienia internetowe.

  • Druga procedura pokazuje, jak dodać ReflectionPermission flagę ReflectionPermissionFlag.RestrictedMemberAccess do częściowo zaufanej domeny aplikacji, aby umożliwić dostęp do danych prywatnych w zestawach o równym lub mniejszym zaufaniu.

Tworzenie domen aplikacji w trybie piaskownicy

Aby utworzyć domenę aplikacji, w której zestawy są uruchamiane z częściowym zaufaniem, należy określić zestaw uprawnień, które mają zostać przyznane zestawom przy użyciu AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) przeciążenia metody w celu utworzenia domeny aplikacji. Najprostszym sposobem określenia zestawu udzielania jest pobranie nazwanego zestawu uprawnień z zasad zabezpieczeń.

Poniższa procedura tworzy domenę aplikacji w trybie piaskownicy, która uruchamia kod z częściowym zaufaniem, aby przetestować scenariusze, w których emitowany kod może uzyskiwać dostęp tylko do publicznych elementów członkowskich typów publicznych. W kolejnej procedurze pokazano, jak dodać RestrictedMemberAccessmetodę , aby przetestować scenariusze, w których emitowany kod może uzyskiwać dostęp do typów niepublicowych i elementów członkowskich w zestawach, którym przyznano równe lub mniejsze uprawnienia.

Aby utworzyć domenę aplikacji z częściowym zaufaniem

  1. Utwórz zestaw uprawnień, aby udzielić zestawom w domenie aplikacji w trybie piaskownicy. W tym przypadku jest używany zestaw uprawnień strefy internetowej.

    Evidence ev = new Evidence();
    ev.AddHostEvidence(new Zone(SecurityZone.Internet));
    PermissionSet pset = new NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev));
    
    Dim ev As New Evidence()
    ev.AddHostEvidence(new Zone(SecurityZone.Internet))
    Dim pset As New NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev))
    
  2. AppDomainSetup Utwórz obiekt, aby zainicjować domenę aplikacji przy użyciu ścieżki aplikacji.

    Ważne

    Dla uproszczenia w tym przykładzie kodu jest używany bieżący folder. Aby uruchomić kod, który faktycznie pochodzi z Internetu, użyj oddzielnego folderu dla niezaufanego kodu, zgodnie z opisem w temacie Instrukcje: Uruchamianie częściowo zaufanego kodu w piaskownicy.

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
  3. Utwórz domenę aplikacji, określając informacje o konfiguracji domeny aplikacji i zestaw dotacji dla wszystkich zestawów wykonywanych w domenie aplikacji.

    AppDomain ad = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, null);
    
    Dim ad As AppDomain = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, Nothing)
    

    Ostatni parametr AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) przeciążenia metody umożliwia określenie zestawu zestawów, które mają zostać przyznane pełne zaufanie, zamiast zestawu dotacji domeny aplikacji. Nie trzeba określać zestawów .NET Framework używanych przez aplikację, ponieważ te zestawy znajdują się w globalnej pamięci podręcznej zestawów. Zestawy w globalnej pamięci podręcznej zestawów są zawsze w pełni zaufane. Tego parametru można użyć do określenia zestawów o silnych nazwach, które nie znajdują się w globalnej pamięci podręcznej zestawów.

Dodawanie funkcji RestrictedMemberAccess do domen w trybie piaskownicy

Aplikacje hosta mogą zezwalać anonimowo hostowanym metodom dynamicznym na dostęp do danych prywatnych w zestawach, które mają poziomy zaufania równe lub mniejsze niż poziom zaufania zestawu, który emituje kod. Aby włączyć tę ograniczoną możliwość pomijania kontroli widoczności just in time (JIT), aplikacja hosta dodaje ReflectionPermission obiekt z ReflectionPermissionFlag.RestrictedMemberAccess flagą (RMA) do zestawu dotacji.

Na przykład host może przyznać aplikacjom internetowym uprawnienia internetowe plus RMA, dzięki czemu aplikacja internetowa może emitować kod, który uzyskuje dostęp do prywatnych danych we własnych zestawach. Ponieważ dostęp jest ograniczony do zestawów o równym lub mniejszym zaufaniu, aplikacja internetowa nie może uzyskać dostępu do elementów członkowskich w pełni zaufanych zestawów, takich jak zestawy .NET Framework.

Uwaga

Aby zapobiec podwyższeniu uprawnień, informacje o stosie dla zestawu emitowanego są uwzględniane podczas konstruowania anonimowo hostowanych metod dynamicznych. Po wywołaniu metody informacje o stosie są sprawdzane. W związku z tym anonimowo hostowana metoda dynamiczna wywoływana z w pełni zaufanego kodu jest nadal ograniczona do poziomu zaufania emitowania zestawu.

Aby utworzyć domenę aplikacji z częściowym zaufaniem plus RMA

  1. Utwórz nowy ReflectionPermission obiekt z RestrictedMemberAccess flagą (RMA) i użyj PermissionSet.SetPermission metody , aby dodać uprawnienie do zestawu udzielania.

    pset.SetPermission(
        new ReflectionPermission(
            ReflectionPermissionFlag.RestrictedMemberAccess));
    
    pset.SetPermission( _
        New ReflectionPermission( _
            ReflectionPermissionFlag.RestrictedMemberAccess))
    

    Metoda AddPermission dodaje uprawnienie do zestawu udzielania, jeśli nie jest jeszcze dołączone. Jeśli uprawnienie jest już uwzględnione w zestawie dotacji, określone flagi są dodawane do istniejącego uprawnienia.

    Uwaga

    RMA to funkcja anonimowo hostowanych metod dynamicznych. Gdy zwykłe metody dynamiczne pomijają sprawdzanie widoczności JIT, emitowany kod wymaga pełnego zaufania.

  2. Utwórz domenę aplikacji, określając informacje o konfiguracji domeny aplikacji i zestaw dotacji.

    ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, null);
    
    ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, Nothing)
    

Uruchamianie kodu w domenach aplikacji w trybie piaskownicy

Poniższa procedura wyjaśnia, jak zdefiniować klasę przy użyciu metod, które można wykonać w domenie aplikacji, jak utworzyć wystąpienie klasy w domenie i jak wykonać jej metody.

Aby zdefiniować i wykonać metodę w domenie aplikacji

  1. Zdefiniuj klasę pochodzącą z klasy MarshalByRefObject. Dzięki temu można tworzyć wystąpienia klasy w innych domenach aplikacji i wykonywać wywołania metod w granicach domeny aplikacji. Klasa w tym przykładzie nosi nazwę Worker.

    public class Worker : MarshalByRefObject
    {
    
    Public Class Worker
        Inherits MarshalByRefObject
    
  2. Zdefiniuj metodę publiczną zawierającą kod, który chcesz wykonać. W tym przykładzie kod emituje prostą metodę dynamiczną, tworzy delegata do wykonania metody i wywołuje delegata.

    public void SimpleEmitDemo()
    {
        DynamicMethod meth = new DynamicMethod("", null, null);
        ILGenerator il = meth.GetILGenerator();
        il.EmitWriteLine("Hello, World!");
        il.Emit(OpCodes.Ret);
    
        Test1 t1 = (Test1) meth.CreateDelegate(typeof(Test1));
        t1();
    }
    
    Public Sub SimpleEmitDemo()
    
        Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
        Dim il As ILGenerator = meth.GetILGenerator()
        il.EmitWriteLine("Hello, World!")
        il.Emit(OpCodes.Ret)
    
        Dim t1 As Test1 = CType(meth.CreateDelegate(GetType(Test1)), Test1)
        t1()
    End Sub
    
  3. W głównym programie pobierz nazwę wyświetlaną zestawu. Ta nazwa jest używana podczas tworzenia wystąpień Worker klasy w domenie aplikacji w trybie piaskownicy.

    String asmName = typeof(Worker).Assembly.FullName;
    
    Dim asmName As String = GetType(Worker).Assembly.FullName
    
  4. W głównym programie utwórz domenę aplikacji w trybie piaskownicy, zgodnie z opisem w pierwszej procedurze w tym przewodniku. Nie musisz dodawać żadnych uprawnień do Internet zestawu uprawnień, ponieważ SimpleEmitDemo metoda używa tylko metod publicznych.

  5. W głównym programie utwórz wystąpienie Worker klasy w domenie aplikacji w trybie piaskownicy.

    Worker w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");
    
    Dim w As Worker = _
        CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)
    

    Metoda CreateInstanceAndUnwrap tworzy obiekt w domenie aplikacji docelowej i zwraca serwer proxy, który może służyć do wywoływania właściwości i metod obiektu.

    Uwaga

    Jeśli używasz tego kodu w programie Visual Studio, musisz zmienić nazwę klasy, aby uwzględnić przestrzeń nazw. Domyślnie przestrzeń nazw jest nazwą projektu. Jeśli na przykład projekt ma wartość "PartialTrust", nazwa klasy musi mieć wartość "PartialTrust.Worker".

  6. Dodaj kod, aby wywołać metodę SimpleEmitDemo . Wywołanie jest wykonywane przez granicę domeny aplikacji, a kod jest wykonywany w domenie aplikacji w trybie piaskownicy.

    w.SimpleEmitDemo();
    
    w.SimpleEmitDemo()
    

Używanie anonimowo hostowanych metod dynamicznych

Anonimowe hostowane metody dynamiczne są skojarzone z przezroczystym zestawem dostarczanym przez system. W związku z tym kod, który zawiera, jest przezroczysty. Z drugiej strony zwykłe metody dynamiczne muszą być skojarzone z istniejącym modułem (określonym bezpośrednio lub wywnioskowany ze skojarzonego typu) i pobrać poziom zabezpieczeń z tego modułu.

Uwaga

Jedynym sposobem skojarzenia metody dynamicznej z zestawem, który zapewnia hosting anonimowy, jest użycie konstruktorów opisanych w poniższej procedurze. Nie można jawnie określić modułu w anonimowym zestawie hostingu.

Zwykłe metody dynamiczne mają dostęp do wewnętrznych elementów członkowskich modułu, z którymi są skojarzone, lub do prywatnych elementów członkowskich typu, z którymi są skojarzone. Ponieważ metody dynamiczne hostowane anonimowo są odizolowane od innego kodu, nie mają dostępu do danych prywatnych. Jednak mają ograniczoną możliwość pomijania kontroli widoczności JIT w celu uzyskania dostępu do danych prywatnych. Ta możliwość jest ograniczona do zestawów, które mają poziomy zaufania równe lub mniejsze niż poziom zaufania zestawu, który emituje kod.

Aby zapobiec podwyższeniu uprawnień, informacje o stosie dla zestawu emitowanego są uwzględniane podczas konstruowania anonimowo hostowanych metod dynamicznych. Po wywołaniu metody informacje o stosie są sprawdzane. Anonimowo hostowana metoda dynamiczna wywoływana z w pełni zaufanego kodu jest nadal ograniczona do poziomu zaufania zestawu, który go emitował.

Aby używać anonimowo hostowanych metod dynamicznych

  • Utwórz anonimowo hostowaną metodę dynamiczną przy użyciu konstruktora, który nie określa skojarzonego modułu ani typu.

    DynamicMethod meth = new DynamicMethod("", null, null);
    ILGenerator il = meth.GetILGenerator();
    il.EmitWriteLine("Hello, World!");
    il.Emit(OpCodes.Ret);
    
    Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
    Dim il As ILGenerator = meth.GetILGenerator()
    il.EmitWriteLine("Hello, World!")
    il.Emit(OpCodes.Ret)
    

    Jeśli metoda dynamiczna hostowana anonimowo używa tylko typów publicznych i metod, nie wymaga ograniczonego dostępu do składowych i nie musi pomijać kontroli widoczności JIT.

    Do emitowania metody dynamicznej nie są wymagane żadne specjalne uprawnienia, ale emitowany kod wymaga uprawnień wymaganych przez typy i metody, których używa. Jeśli na przykład emitowany kod wywołuje metodę, która uzyskuje dostęp do pliku, wymaga .FileIOPermission Jeśli poziom zaufania nie zawiera tego uprawnienia, podczas wykonywania emitowanego kodu jest zgłaszany wyjątek zabezpieczeń. Pokazany tutaj kod emituje metodę dynamiczną, która używa tylko Console.WriteLine metody . W związku z tym kod można wykonać z częściowo zaufanych lokalizacji.

  • Alternatywnie utwórz anonimowo hostowaną metodę dynamiczną z ograniczoną możliwością pomijania kontroli widoczności JIT przy użyciu konstruktora DynamicMethod(String, Type, Type[], Boolean) i określania true parametru restrictedSkipVisibility .

    DynamicMethod meth = new DynamicMethod("",
                                           typeof(char),
                                           new Type[] { typeof(String) },
                                           true);
    
    Dim meth As New DynamicMethod("", _
                                  GetType(Char), _
                                  New Type() {GetType(String)}, _
                                  True)
    

    Ograniczenie polega na tym, że anonimowo hostowana metoda dynamiczna może uzyskiwać dostęp do danych prywatnych tylko w zestawach z poziomami zaufania równymi lub mniejszym niż poziom zaufania emitowania zestawu. Jeśli na przykład metoda dynamiczna jest uruchamiana za pomocą zaufania internetowego, może uzyskać dostęp do danych prywatnych w innych zestawach, które są również wykonywane za pomocą zaufania internetowego, ale nie może uzyskać dostępu do prywatnych danych .NET Framework zestawów. .NET Framework zestawy są instalowane w globalnej pamięci podręcznej zestawów i są zawsze w pełni zaufane.

    Metody dynamiczne hostowane anonimowo mogą używać tej ograniczonej możliwości pomijania widoczności JIT tylko wtedy, gdy aplikacja hosta przyznaje ReflectionPermission flagę ReflectionPermissionFlag.RestrictedMemberAccess . Żądanie tego uprawnienia jest wykonywane po wywołaniu metody.

    Uwaga

    Informacje o stosie wywołań dla zestawu emitowania są uwzględniane podczas konstruowania metody dynamicznej. W związku z tym zapotrzebowanie jest wykonywane względem uprawnień do emitowania zestawu zamiast zestawu, który wywołuje metodę. Zapobiega to wykonywaniu emitowanego kodu z podwyższonym poziomem uprawnień.

    Kompletny przykład kodu na końcu tego przewodnika przedstawia użycie i ograniczenia ograniczonego dostępu do składowych. Jej Worker klasa zawiera metodę, która umożliwia tworzenie anonimowo hostowanych metod dynamicznych z ograniczoną możliwością pomijania kontroli widoczności, a przykład pokazuje wynik wykonywania tej metody w domenach aplikacji, które mają różne poziomy zaufania.

    Uwaga

    Ograniczona możliwość pomijania kontroli widoczności jest funkcją anonimowo hostowanych metod dynamicznych. Gdy zwykłe metody dynamiczne pomijają sprawdzanie widoczności trybu JIT, muszą mieć pełne zaufanie.

Przykład

Opis

W poniższym przykładzie kodu pokazano użycie RestrictedMemberAccess flagi w celu umożliwienia anonimowo hostowanych metod dynamicznych pomijania kontroli widoczności JIT, ale tylko wtedy, gdy element docelowy znajduje się na równym lub niższym poziomie zaufania niż zestaw emitujący kod.

W przykładzie zdefiniowano klasę Worker , którą można marshalled przekraczać granice domeny aplikacji. Klasa ma dwa AccessPrivateMethod przeciążenia metody, które emitują i wykonują metody dynamiczne. Pierwsze przeciążenie emituje metodę dynamiczną, która wywołuje prywatną PrivateMethod metodę Worker klasy i może emitować metodę dynamiczną z funkcjami widoczności JIT lub bez niej. Drugie przeciążenie emituje metodę dynamiczną internal , która uzyskuje dostęp do właściwości (Friend właściwości w Visual Basic) String klasy .

W przykładzie użyto metody pomocniczej w celu utworzenia zestawu uprawnień ograniczonego do Internet uprawnień, a następnie utworzenia domeny aplikacji przy użyciu AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) przeciążenia metody w celu określenia, że cały kod wykonywany w domenie używa tego zestawu uprawnień. Przykład tworzy wystąpienie Worker klasy w domenie aplikacji i wykonuje metodę AccessPrivateMethod dwa razy.

  • Przy pierwszym wykonaniu AccessPrivateMethod metody są wymuszane kontrole widoczności JIT. Metoda dynamiczna kończy się niepowodzeniem po wywołaniu metody, ponieważ sprawdzanie widoczności trybu JIT uniemożliwia uzyskanie dostępu do metody prywatnej.

  • Przy drugim wykonaniu AccessPrivateMethod metody sprawdzanie widoczności trybu JIT jest pomijane. Metoda dynamiczna kończy się niepowodzeniem podczas kompilowania, ponieważ Internet zestaw dotacji nie udziela wystarczających uprawnień do pomijania kontroli widoczności.

Przykład dodaje ReflectionPermission element z elementem ReflectionPermissionFlag.RestrictedMemberAccess do zestawu dotacji. W tym przykładzie tworzona jest druga domena, określając, że cały kod wykonywany w domenie ma przyznane uprawnienia w nowym zestawie dotacji. Przykład tworzy wystąpienie Worker klasy w nowej domenie aplikacji i wykonuje oba przeciążenia AccessPrivateMethod metody.

  • Pierwsze przeciążenie AccessPrivateMethod metody jest wykonywane, a kontrole widoczności JIT są pomijane. Metoda dynamiczna kompiluje i wykonuje pomyślnie, ponieważ zestaw emitujący kod jest taki sam jak zestaw zawierający metodę prywatną. W związku z tym poziomy zaufania są równe. Jeśli aplikacja zawierająca klasę Worker zawiera kilka zestawów, ten sam proces zakończy się pomyślnie dla każdego z tych zestawów, ponieważ wszystkie one byłyby na tym samym poziomie zaufania.

  • Drugie przeciążenie AccessPrivateMethod metody jest wykonywane, a ponownie sprawdzanie widoczności JIT jest pomijane. Tym razem metoda dynamiczna kończy się niepowodzeniem podczas kompilowania, ponieważ próbuje uzyskać dostęp do internalFirstChar właściwości String klasy. Zestaw zawierający klasę String jest w pełni zaufany. W związku z tym jest na wyższym poziomie zaufania niż zestaw, który emituje kod.

To porównanie pokazuje, jak ReflectionPermissionFlag.RestrictedMemberAccess umożliwia częściowe zaufanemu kodowi pomijanie sprawdzania widoczności dla innego częściowo zaufanego kodu bez naruszania zabezpieczeń zaufanego kodu.

Kod

using System;
using System.Reflection.Emit;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Collections;
using System.Diagnostics;

// This code example works properly only if it is run from a fully
// trusted location, such as your local computer.

// Delegates used to execute the dynamic methods.
//
public delegate void Test(Worker w);
public delegate void Test1();
public delegate char Test2(String instance);

// The Worker class must inherit MarshalByRefObject so that its public
// methods can be invoked across application domain boundaries.
//
public class Worker : MarshalByRefObject
{
    private void PrivateMethod()
    {
        Console.WriteLine("Worker.PrivateMethod()");
    }

    public void SimpleEmitDemo()
    {
        DynamicMethod meth = new DynamicMethod("", null, null);
        ILGenerator il = meth.GetILGenerator();
        il.EmitWriteLine("Hello, World!");
        il.Emit(OpCodes.Ret);

        Test1 t1 = (Test1) meth.CreateDelegate(typeof(Test1));
        t1();
    }

    // This overload of AccessPrivateMethod emits a dynamic method and
    // specifies whether to skip JIT visiblity checks. It creates a
    // delegate for the method and invokes the delegate. The dynamic
    // method calls a private method of the Worker class.
    public void AccessPrivateMethod(bool restrictedSkipVisibility)
    {
        // Create an unnamed dynamic method that has no return type,
        // takes one parameter of type Worker, and optionally skips JIT
        // visiblity checks.
        DynamicMethod meth = new DynamicMethod(
            "",
            null,
            new Type[] { typeof(Worker) },
            restrictedSkipVisibility);

        // Get a MethodInfo for the private method.
        MethodInfo pvtMeth = typeof(Worker).GetMethod("PrivateMethod",
            BindingFlags.NonPublic | BindingFlags.Instance);

        // Get an ILGenerator and emit a body for the dynamic method.
        ILGenerator il = meth.GetILGenerator();

        // Load the first argument, which is the target instance, onto the
        // execution stack, call the private method, and return.
        il.Emit(OpCodes.Ldarg_0);
        il.EmitCall(OpCodes.Call, pvtMeth, null);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method, and
        // invoke it.
        try
        {
            Test t = (Test) meth.CreateDelegate(typeof(Test));
            try
            {
                t(this);
            }
            catch (Exception ex)
            {
                Console.WriteLine("{0} was thrown when the delegate was invoked.",
                    ex.GetType().Name);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("{0} was thrown when the delegate was compiled.",
                ex.GetType().Name);
        }
    }

    // This overload of AccessPrivateMethod emits a dynamic method that takes
    // a string and returns the first character, using a private field of the
    // String class. The dynamic method skips JIT visiblity checks.
    public void AccessPrivateMethod()
    {
        DynamicMethod meth = new DynamicMethod("",
                                               typeof(char),
                                               new Type[] { typeof(String) },
                                               true);

        // Get a MethodInfo for the 'get' accessor of the private property.
        PropertyInfo pi = typeof(System.String).GetProperty(
            "FirstChar",
            BindingFlags.NonPublic | BindingFlags.Instance);
        MethodInfo pvtMeth = pi.GetGetMethod(true);

        // Get an ILGenerator and emit a body for the dynamic method.
        ILGenerator il = meth.GetILGenerator();

        // Load the first argument, which is the target string, onto the
        // execution stack, call the 'get' accessor to put the result onto
        // the execution stack, and return.
        il.Emit(OpCodes.Ldarg_0);
        il.EmitCall(OpCodes.Call, pvtMeth, null);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method, and
        // invoke it.
        try
        {
            Test2 t = (Test2) meth.CreateDelegate(typeof(Test2));
            char first = t("Hello, World!");
            Console.WriteLine("{0} is the first character.", first);
        }
        catch (Exception ex)
        {
            Console.WriteLine("{0} was thrown when the delegate was compiled.",
                ex.GetType().Name);
        }
    }

    // The entry point for the code example.
    static void Main()
    {
        // Get the display name of the executing assembly, to use when
        // creating objects to run code in application domains.
        String asmName = typeof(Worker).Assembly.FullName;

        // Create the permission set to grant to other assemblies. In this
        // case they are the permissions found in the Internet zone.
        Evidence ev = new Evidence();
        ev.AddHostEvidence(new Zone(SecurityZone.Internet));
        PermissionSet pset = new NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev));

        // For simplicity, set up the application domain to use the
        // current path as the application folder, so the same executable
        // can be used in both trusted and untrusted scenarios. Normally
        // you would not do this with real untrusted code.
        AppDomainSetup adSetup = new AppDomainSetup();
        adSetup.ApplicationBase = ".";

        // Create an application domain in which all code that executes is
        // granted the permissions of an application run from the Internet.
        AppDomain ad = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, null);

        // Create an instance of the Worker class in the partially trusted
        // domain. Note: If you build this code example in Visual Studio,
        // you must change the name of the class to include the default
        // namespace, which is the project name. For example, if the project
        // is "AnonymouslyHosted", the class is "AnonymouslyHosted.Worker".
        Worker w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");

        // Emit a simple dynamic method that prints "Hello, World!"
        w.SimpleEmitDemo();

        // Emit and invoke a dynamic method that calls a private method
        // of Worker, with JIT visibility checks enforced. The call fails
        // when the delegate is invoked.
        w.AccessPrivateMethod(false);

        // Emit and invoke a dynamic method that calls a private method
        // of Worker, skipping JIT visibility checks. The call fails when
        // the method is invoked.
        w.AccessPrivateMethod(true);

        // Unload the application domain. Add RestrictedMemberAccess to the
        // grant set, and use it to create an application domain in which
        // partially trusted code can call private members, as long as the
        // trust level of those members is equal to or lower than the trust
        // level of the partially trusted code.
        AppDomain.Unload(ad);
        pset.SetPermission(
            new ReflectionPermission(
                ReflectionPermissionFlag.RestrictedMemberAccess));
        ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, null);

        // Create an instance of the Worker class in the partially trusted
        // domain.
        w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");

        // Again, emit and invoke a dynamic method that calls a private method
        // of Worker, skipping JIT visibility checks. This time compilation
        // succeeds because of the grant for RestrictedMemberAccess.
        w.AccessPrivateMethod(true);

        // Finally, emit and invoke a dynamic method that calls an internal
        // method of the String class. The call fails, because the trust level
        // of the assembly that contains String is higher than the trust level
        // of the assembly that emits the dynamic method.
        w.AccessPrivateMethod();
    }
}

/* This code example produces the following output:

Hello, World!
MethodAccessException was thrown when the delegate was invoked.
MethodAccessException was thrown when the delegate was invoked.
Worker.PrivateMethod()
MethodAccessException was thrown when the delegate was compiled.
 */
Imports System.Reflection.Emit
Imports System.Reflection
Imports System.Security
Imports System.Security.Permissions
Imports System.Security.Policy
Imports System.Collections
Imports System.Diagnostics

' This code example works properly only if it is run from a fully 
' trusted location, such as your local computer.

' Delegates used to execute the dynamic methods.
'
Public Delegate Sub Test(ByVal w As Worker)
Public Delegate Sub Test1()
Public Delegate Function Test2(ByVal instance As String) As Char

' The Worker class must inherit MarshalByRefObject so that its public 
' methods can be invoked across application domain boundaries.
'
Public Class Worker
    Inherits MarshalByRefObject

    Private Sub PrivateMethod()
        Console.WriteLine("Worker.PrivateMethod()")
    End Sub

    Public Sub SimpleEmitDemo()

        Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
        Dim il As ILGenerator = meth.GetILGenerator()
        il.EmitWriteLine("Hello, World!")
        il.Emit(OpCodes.Ret)

        Dim t1 As Test1 = CType(meth.CreateDelegate(GetType(Test1)), Test1)
        t1()
    End Sub

    ' This overload of AccessPrivateMethod emits a dynamic method and
    ' specifies whether to skip JIT visiblity checks. It creates a 
    ' delegate for the method and invokes the delegate. The dynamic 
    ' method calls a private method of the Worker class.
    Overloads Public Sub AccessPrivateMethod( _
                       ByVal restrictedSkipVisibility As Boolean)

        ' Create an unnamed dynamic method that has no return type,
        ' takes one parameter of type Worker, and optionally skips JIT
        ' visiblity checks.
        Dim meth As New DynamicMethod("", _
                                      Nothing, _
                                      New Type() {GetType(Worker)}, _
                                      restrictedSkipVisibility)

        ' Get a MethodInfo for the private method.
        Dim pvtMeth As MethodInfo = GetType(Worker).GetMethod( _
            "PrivateMethod", _
            BindingFlags.NonPublic Or BindingFlags.Instance)

        ' Get an ILGenerator and emit a body for the dynamic method.
        Dim il As ILGenerator = meth.GetILGenerator()

        ' Load the first argument, which is the target instance, onto the
        ' execution stack, call the private method, and return.
        il.Emit(OpCodes.Ldarg_0)
        il.EmitCall(OpCodes.Call, pvtMeth, Nothing)
        il.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method, and 
        ' invoke it. 
        Try
            Dim t As Test = CType(meth.CreateDelegate(GetType(Test)), Test)
            Try
                t(Me)
            Catch ex As Exception
                Console.WriteLine("{0} was thrown when the delegate was invoked.", _
                    ex.GetType().Name)
            End Try
        Catch ex As Exception
            Console.WriteLine("{0} was thrown when the delegate was compiled.", _
                ex.GetType().Name)
        End Try

    End Sub


    ' This overload of AccessPrivateMethod emits a dynamic method that takes
    ' a string and returns the first character, using a private field of the 
    ' String class. The dynamic method skips JIT visiblity checks.
    Overloads Public Sub AccessPrivateMethod()

        Dim meth As New DynamicMethod("", _
                                      GetType(Char), _
                                      New Type() {GetType(String)}, _
                                      True)

        ' Get a MethodInfo for the 'get' accessor of the private property.
        Dim pi As PropertyInfo = GetType(String).GetProperty( _
            "FirstChar", _
            BindingFlags.NonPublic Or BindingFlags.Instance)
        Dim pvtMeth As MethodInfo = pi.GetGetMethod(True)

        ' Get an ILGenerator and emit a body for the dynamic method.
        Dim il As ILGenerator = meth.GetILGenerator()

        ' Load the first argument, which is the target string, onto the
        ' execution stack, call the 'get' accessor to put the result onto 
        ' the execution stack, and return.
        il.Emit(OpCodes.Ldarg_0)
        il.EmitCall(OpCodes.Call, pvtMeth, Nothing)
        il.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method, and 
        ' invoke it. 
        Try
            Dim t As Test2 = CType(meth.CreateDelegate(GetType(Test2)), Test2)
            Dim first As Char = t("Hello, World!")
            Console.WriteLine("{0} is the first character.", first)
        Catch ex As Exception
            Console.WriteLine("{0} was thrown when the delegate was compiled.", _
                ex.GetType().Name)
        End Try

    End Sub
End Class

Friend Class Example

    ' The entry point for the code example.
    Shared Sub Main()

        ' Get the display name of the executing assembly, to use when
        ' creating objects to run code in application domains.
        Dim asmName As String = GetType(Worker).Assembly.FullName

        ' Create the permission set to grant to other assemblies. In this
        ' case they are the permissions found in the Internet zone.
        Dim ev As New Evidence()
        ev.AddHostEvidence(new Zone(SecurityZone.Internet))
        Dim pset As New NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev))

        ' For simplicity, set up the application domain to use the 
        ' current path as the application folder, so the same executable
        ' can be used in both trusted and untrusted scenarios. Normally
        ' you would not do this with real untrusted code.
        Dim adSetup As New AppDomainSetup()
        adSetup.ApplicationBase = "."

        ' Create an application domain in which all code that executes is 
        ' granted the permissions of an application run from the Internet.
        Dim ad As AppDomain = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, Nothing)

        ' Create an instance of the Worker class in the partially trusted 
        ' domain. Note: If you build this code example in Visual Studio, 
        ' you must change the name of the class to include the default 
        ' namespace, which is the project name. For example, if the project
        ' is "AnonymouslyHosted", the class is "AnonymouslyHosted.Worker".
        Dim w As Worker = _
            CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)

        ' Emit a simple dynamic method that prints "Hello, World!"
        w.SimpleEmitDemo()

        ' Emit and invoke a dynamic method that calls a private method
        ' of Worker, with JIT visibility checks enforced. The call fails 
        ' when the delegate is invoked.
        w.AccessPrivateMethod(False)

        ' Emit and invoke a dynamic method that calls a private method
        ' of Worker, skipping JIT visibility checks. The call fails when
        ' the method is compiled.
        w.AccessPrivateMethod(True)


        ' Unload the application domain. Add RestrictedMemberAccess to the
        ' grant set, and use it to create an application domain in which
        ' partially trusted code can call private members, as long as the 
        ' trust level of those members is equal to or lower than the trust 
        ' level of the partially trusted code. 
        AppDomain.Unload(ad)
        pset.SetPermission( _
            New ReflectionPermission( _
                ReflectionPermissionFlag.RestrictedMemberAccess))
        ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, Nothing)

        ' Create an instance of the Worker class in the partially trusted 
        ' domain. 
        w = CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)

        ' Again, emit and invoke a dynamic method that calls a private method
        ' of Worker, skipping JIT visibility checks. This time compilation 
        ' succeeds because of the grant for RestrictedMemberAccess.
        w.AccessPrivateMethod(True)

        ' Finally, emit and invoke a dynamic method that calls an internal 
        ' method of the String class. The call fails, because the trust level
        ' of the assembly that contains String is higher than the trust level
        ' of the assembly that emits the dynamic method.
        w.AccessPrivateMethod()

    End Sub
End Class

' This code example produces the following output:
'
'Hello, World!
'MethodAccessException was thrown when the delegate was invoked.
'MethodAccessException was thrown when the delegate was invoked.
'Worker.PrivateMethod()
'MethodAccessException was thrown when the delegate was compiled.
' 

Kompilowanie kodu

  • Jeśli utworzysz ten przykładowy kod w programie Visual Studio, musisz zmienić nazwę klasy, aby uwzględnić przestrzeń nazw podczas przekazywania jej do CreateInstanceAndUnwrap metody . Domyślnie przestrzeń nazw jest nazwą projektu. Jeśli na przykład projekt ma wartość "PartialTrust", nazwa klasy musi mieć wartość "PartialTrust.Worker".

Zobacz też