Passo a passo: Emitindo o código em cenários de confiança parcial

A emissão de reflexão usa a mesma API definida na confiança total ou parcial, porém alguns recursos exigem permissões especiais em código parcialmente confiável. Além disso, a emissão de reflexão tem um recurso, os métodos dinâmicos hospedados anonimamente, que é projetado para ser usado com confiança parcial e por assemblies transparentes de segurança.

Observação

Antes do .NET Framework 3.5, a emissão de código necessitava de ReflectionPermission com o sinalizador ReflectionPermissionFlag.ReflectionEmit. Essa permissão é incluída por padrão nos conjuntos de permissões denominados FullTrust e Intranet, mas não no conjunto de permissões Internet. Portanto, uma biblioteca poderia ser usada da confiança parcial somente se tivesse o atributo SecurityCriticalAttribute e também executasse um método Assert para ReflectionEmit. Tais bibliotecas exigem uma análise atenta da segurança, pois erros de código poderiam resultar em falhas de segurança. O .NET Framework 3.5 permite que o código seja emitido em cenários de confiança parcial sem a emissão de nenhuma demanda de segurança, pois a geração de código não é uma operação inerentemente privilegiada. Ou seja, o código gerado não tem mais permissões que o assembly que o emite. Isso permite que bibliotecas que emitem código sejam transparentes de segurança e elimina a necessidade de declarar ReflectionEmit, de modo que escrever uma biblioteca de segurança não exige uma análise minuciosa da segurança.

Este passo a passo ilustra as seguintes tarefas:

Para obter mais informações sobre como emitir código em cenários de confiança parcial, consulte Problemas de segurança na emissão de reflexão.

Para obter uma lista completa do código mostrado nesses procedimentos, consulte a Seção de exemplos no final deste passo a passo.

Configurar locais parcialmente confiáveis

Os dois procedimentos a seguir mostram como configurar locais de onde você pode testar o código com confiança parcial.

  • O primeiro procedimento mostra como criar um domínio do aplicativo em área restrita no qual o código recebe permissões da Internet.

  • O segundo procedimento mostra como adicionar ReflectionPermission com o sinalizador ReflectionPermissionFlag.RestrictedMemberAccess para um domínio do aplicativo parcialmente confiável, a fim de habilitar o acesso aos dados particulares em assemblies de confiança iguais ou inferior.

Criar domínios do aplicativo em área restrita

Para criar um domínio do aplicativo no qual seus assemblies são executados com confiança parcial, você deve especificar o conjunto de permissões a serem concedidas aos assemblies usando a sobrecarga de método AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) para criar o domínio do aplicativo. A maneira mais fácil de especificar o conjunto de concessões é recuperar um conjunto de permissões nomeadas da política de segurança.

O procedimento a seguir cria um domínio do aplicativo em área restrita que executa seu código com confiança parcial para testar cenários em que o código emitido pode acessar somente membros públicos de tipos públicos. Um procedimento subsequente mostra como adicionar RestrictedMemberAccess para testar cenários em que o código emitido pode acessar tipos não públicos e membros em assemblies que recebem permissões iguais ou inferiores.

Criar um domínio do aplicativo com confiança parcial

  1. Crie um conjunto de permissões que serão concedidas aos assemblies no domínio do aplicativo em área restrita. Nesse caso, o conjunto de permissões da zona da Internet é usado.

    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. Crie um objeto AppDomainSetup para inicializar o domínio do aplicativo com um caminho de aplicativo.

    Importante

    Para simplificar, este exemplo de código usa a pasta atual. Para executar um código que realmente vem da Internet, use uma pasta separada para o código não confiável, conforme descrito em Como executar código parcialmente confiável em uma área restrita.

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
  3. Crie o domínio do aplicativo especificando as informações de configuração de domínio do aplicativo e o conjunto de concessões para todos os assemblies que são executadas no domínio do aplicativo.

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

    O último parâmetro da sobrecarga do método AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) permite que você especifique um conjunto de assemblies que devem receber confiança total, em vez do conjunto de concessões do domínio do aplicativo. Você não precisa especificar os assemblies do .NET Framework que o aplicativo usa, pois tais assemblies estão no cache de assembly global. Assemblies no cache de assembly global sempre são totalmente confiáveis. Você pode usar esse parâmetro para especificar os assemblies de nome forte que não estão no cache de assembly global.

Adicionando RestrictedMemberAccess a domínios em área restrita

Aplicativos host podem permitir que os métodos dinâmicos hospedados anonimamente tenham acesso aos dados particulares em assemblies com níveis de confiança iguais ou inferior ao nível de confiança do assembly que emite o código. Para habilitar essa capacidade restrita de ignorar as verificações de visibilidade JIT (Just-In-Time), o aplicativo host adiciona um objeto ReflectionPermission com o sinalizador ReflectionPermissionFlag.RestrictedMemberAccess (ADM) para o conjunto de concessões.

Por exemplo, um host pode conceder permissões da Internet a aplicativos da Internet mais ADM para que um aplicativo da Internet possa emitir código que acessa dados particulares em seus próprios assemblies. Como o acesso é limitado aos assemblies de confiança igual ou inferior, um aplicativo da Internet não pode acessar membros de assemblies totalmente confiáveis, como assemblies do .NET Framework.

Observação

Para evitar a elevação de privilégio, as informações de pilha para o assembly de emissão são incluídas quando ps métodos dinâmicos hospedados anonimamente são construídos. Quando o método é invocado, as informações de pilha são verificadas. Dessa forma, um método dinâmico hospedado anonimamente que é invocado do código totalmente confiável ainda é limitado ao nível de confiança do assembly de emissão.

Criar um domínio do aplicativo com confiança parcial mais ADM

  1. Crie um novo objeto ReflectionPermission com o sinalizador RestrictedMemberAccess (ADM) e use o método PermissionSet.SetPermission para adicionar a permissão ao conjunto de concessões.

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

    O método AddPermission adiciona a permissão ao conjunto de concessões se ele não já estiver incluído. Se a permissão já estiver incluída no conjunto de concessões, os sinalizadores especificados serão adicionados à permissão existente.

    Observação

    O ADM é um recurso de métodos dinâmicos hospedados anonimamente. Quando métodos dinâmicos comuns ignoram verificações de visibilidade JIT, o código emitido requer confiança total.

  2. Crie o domínio do aplicativo especificando as informações de configuração do domínio do aplicativo e o conjunto de concessões.

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

Executando código em domínios do aplicativo em área restrita

O procedimento a seguir explica como definir uma classe com métodos que podem ser executados em um domínio do aplicativo, como criar uma instância da classe do domínio e como executar seus métodos.

Definir e executar um método em um domínio do aplicativo

  1. Defina uma classe derivada de MarshalByRefObject. Isso permite criar instâncias da classe em outros domínios do aplicativo e fazer chamadas de método entre limites de domínio do aplicativo. Nesse exemplo, a classe é denominada Worker.

    public class Worker : MarshalByRefObject
    {
    
    Public Class Worker
        Inherits MarshalByRefObject
    
  2. Defina um método público que contém o código que você deseja executar. Neste exemplo, o código emite um método dinâmico simples, cria um delegado para executar o método e invoca o delegado.

    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. Em seu programa principal, obtenha o nome de exibição do seu assembly. Esse nome é usado quando você cria instâncias da classe Worker no domínio do aplicativo em área restrita.

    String asmName = typeof(Worker).Assembly.FullName;
    
    Dim asmName As String = GetType(Worker).Assembly.FullName
    
  4. Em seu programa principal, crie um domínio do aplicativo em área restrita, conforme descrito no primeiro procedimento neste passo a passo. Não é necessário adicionar permissões ao conjunto de permissões Internet, pois o método SimpleEmitDemo usa apenas métodos públicos.

  5. No seu programa principal, crie uma instância da classe Worker no domínio do aplicativo em área restrita.

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

    O método CreateInstanceAndUnwrap cria o objeto no domínio do aplicativo de destino e retorna um proxy pode ser usado para chamar as propriedades e métodos do objeto.

    Observação

    Se você usar esse código em Visual Studio, deverá alterar o nome da classe para incluir o namespace. Por padrão, o namespace é o nome do projeto. Por exemplo, se o projeto for “PartialTrust”, o nome de classe deverá ser “PartialTrust.Worker”.

  6. Adicionar código para chamar o método SimpleEmitDemo. É realizado marshaling na chamada além do limite de domínio do aplicativo e o código é executado no domínio do aplicativo em área restrita.

    w.SimpleEmitDemo();
    
    w.SimpleEmitDemo()
    

Usando métodos dinâmicos hospedados anonimamente

Métodos dinâmicos hospedados anonimamente são associados a um assembly transparente que é fornecido pelo sistema. Portanto, o código que eles contêm é transparente. Métodos dinâmicos comuns, por outro lado, devem ser associados a um módulo existente (especificado diretamente ou inferido de um tipo associado) e usar o nível de segurança desse módulo.

Observação

A única maneira de associar um método dinâmico ao assembly que fornece hospedagem anônima é usar os construtores descritos no procedimento a seguir. Não é possível especificar explicitamente um módulo no assembly hospedagem anônima.

Métodos dinâmicos comuns têm acesso os membros internos do módulo aos quais estão associados ou aos membros privados do tipo aos quais estão associados. Como os métodos dinâmicos hospedados anonimamente são isolados do código, eles não tem acesso a dados particulares. No entanto, eles têm uma capacidade restrita para ignorar verificações de visibilidade JIT para obter acesso aos dados particulares. Essa capacidade é limitada a assemblies com níveis de confiança igual ou inferior ao nível de confiança do assembly que emite o código.

Para evitar a elevação de privilégio, as informações de pilha para o assembly de emissão são incluídas quando ps métodos dinâmicos hospedados anonimamente são construídos. Quando o método é invocado, as informações de pilha são verificadas. Um método dinâmico hospedado anonimamente que é invocado do código totalmente confiável ainda é limitado ao nível de confiança do assembly que o emitiu.

Usar métodos dinâmicos hospedados anonimamente

  • Crie um método dinâmico hospedado anonimamente usando um construtor que não especifica um tipo ou um módulo associado.

    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)
    

    Se um método dinâmico hospedado anonimamente usar apenas métodos e tipos públicos, ele não requer acesso de membro restrito e não precisa ignorar verificações de visibilidade JIT.

    Nenhuma permissão especial é necessária para emitir um método dinâmico, mas o código emitido requer as permissões exigidas por esses tipos e métodos que ele usa. Por exemplo, se o código emitido chama um método que acessa um arquivo, ele requer FileIOPermission. Se o nível de confiança não inclui essa permissão, uma exceção de segurança é gerada quando o código emitido é executado. O código mostrado aqui emite um método dinâmico que usa apenas o método Console.WriteLine. Portanto, o código pode ser executado em locais parcialmente confiáveis.

  • Como alternativa, crie um método dinâmico hospedado anonimamente com capacidade restrita de ignorar as verificações de visibilidade JIT usando o construtor DynamicMethod(String, Type, Type[], Boolean) e especificando true para o parâmetro restrictedSkipVisibility.

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

    A restrição é que o método dinâmico hospedado anonimamente poderá acessar dados particulares somente em assemblies com níveis de confiança igual ou inferior ao nível de confiança do assembly de emissão. Por exemplo, se o método dinâmico estiver em execução com confiança de Internet, ele poderá acessar os dados particulares em outros assemblies que também são executados com confiança de Internet, mas não poderá acessar dados particulares de assemblies do .NET Framework. Assemblies do .NET Framework são instalados no cache de assembly global e sempre são totalmente confiáveis.

    Métodos dinâmicos hospedados anonimamente podem usar essa capacidade restrita para ignorar as verificações de visibilidade JIT somente se o aplicativo host conceder ReflectionPermission com o sinalizador ReflectionPermissionFlag.RestrictedMemberAccess. A demanda por essa permissão é realizada quando o método é invocado.

    Observação

    Informações de pilha de chamadas para o assembly de emissão são incluídas quando o método dinâmico é construído. Portanto, a demanda é feita em relação às permissões do assembly de emissão, em vez do assembly que invoca o método. Isso impede que o código emitido seja executado com permissões elevadas.

    O exemplo de código completo no final dessa instrução passo a passo demonstra o uso e as limitações de acesso de membro restrito. Sua classe Worker inclui um método que pode criar métodos dinâmicos hospedados anonimamente com ou sem o recurso restrito para ignorar as verificações de visibilidade e o exemplo mostra o resultado da execução desse método em domínios do aplicativo com níveis diferentes de confiança.

    Observação

    A capacidade restrita de ignorar as verificações de visibilidade é um recurso de métodos dinâmicos hospedados anonimamente. Quando métodos dinâmicos comuns ignoram verificações de visibilidade JIT, eles devem receber confiança total.

Exemplo

Descrição

O exemplo de código a seguir demonstra o uso do sinalizador RestrictedMemberAccess para permitir que métodos dinâmicos hospedados anonimamente ignorem as verificações de visibilidade JIT, mas somente quando o membro de destino tiver um nível de confiança igual ou inferior ao assembly que emite o código.

O exemplo define uma classe Worker que pode passar por marshaling entre limites de domínio do aplicativo. A classe tem duas sobrecargas de método AccessPrivateMethod que emitem e executam métodos dinâmicos. A primeira sobrecarga emite um método dinâmico que chama o método PrivateMethod particular da classe Worker e pode emitir o método dinâmico com ou sem verificações de visibilidade JIT. A segunda sobrecarga emite um método dinâmico que acessa uma propriedade internal (propriedade Friend no Visual Basic) da classe String.

O exemplo usa um método auxiliar para criar um conjunto de concessões limitado a permissões Internet e, em seguida, cria um domínio do aplicativo, usando a sobrecarga do método AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) para especificar que todo o código que é executado no domínio usa esse conjunto de concessões. O exemplo cria uma instância da classe Worker no domínio do aplicativo e executa o método AccessPrivateMethod duas vezes.

  • Na primeira vez que o método AccessPrivateMethod é executado, as verificações de visibilidade JIT são impostas. O método dinâmico falhará quando for invocado, pois as verificações de visibilidade JIT o impedirão de acessar o método particular.

  • Na segunda vez que o método AccessPrivateMethod é executado, as verificações de visibilidade JIT são ignoradas. O método dinâmico falha quando ele é compilado, porque o conjunto de concessões Internet não concede permissões suficientes para ignorar as verificações de visibilidade.

O exemplo adiciona ReflectionPermission com ReflectionPermissionFlag.RestrictedMemberAccess ao conjunto de concessões. O exemplo a seguir cria um segundo domínio, especificando que todo o código que é executado no domínio recebe as permissões no novo conjunto de concessões. O exemplo cria uma instância da classe Worker no domínio do aplicativo e executa ambas as sobrecargas do método AccessPrivateMethod.

  • A primeira sobrecarga do método AccessPrivateMethod é executada e as verificações de visibilidade JIT são ignoradas. O método dinâmico é compilado e executado com êxito, pois o assembly que emite o código é o mesmo que o assembly que contém o método particular. Portanto, os níveis de confiança são iguais. Se o aplicativo que contém a classe Worker tiver vários assemblies, o mesmo processo teria êxito para qualquer um desses assemblies, pois todos estão no mesmo nível de confiança.

  • A segunda sobrecarga do método AccessPrivateMethod é executada e as verificações de visibilidade JIT são ignoradas novamente. Dessa vez, o método dinâmico falha ao ser compilado, pois ele tenta acessar a propriedade internalFirstChar da classe String. O assembly que contém a classe String é totalmente confiável. Portanto, ele está em um nível mais alto que o assembly que emite o código.

Essa comparação mostra como ReflectionPermissionFlag.RestrictedMemberAccess habilita código parcialmente confiável para ignorar as verificações de visibilidade para outros códigos parcialmente confiáveis sem comprometer a segurança do código confiável.

Código

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.
' 

Compilando o código

  • Se você compilar esse exemplo de código no Visual Studio, deverá alterar o nome da classe para incluir o namespace ao passá-lo para o método CreateInstanceAndUnwrap. Por padrão, o namespace é o nome do projeto. Por exemplo, se o projeto for “PartialTrust”, o nome de classe deverá ser “PartialTrust.Worker”.

Confira também