Share via


Panduan: Memancarkan Kode dalam Skenario Kepercayaan Parsial

Pancaran refleksi menggunakan set API yang sama dalam kepercayaan penuh atau parsial, tetapi beberapa fitur memerlukan izin khusus dalam kode yang dipercaya sebagian. Selain itu, pancaran refleksi memiliki fitur, metode dinamis yang dihosting secara anonim, yang dirancang untuk digunakan dengan kepercayaan parsial dan oleh rakitan transparan keamanan.

Catatan

Sebelum .NET Framework 3.5, memancarkan kode diperlukan ReflectionPermission dengan bendera ReflectionPermissionFlag.ReflectionEmit. Izin ini disertakan secara default dalam kumpulan izin bernama FullTrust dan Intranet, tetapi tidak dalam kumpulan izin Internet. Oleh karena itu, pustaka dapat digunakan dari kepercayaan parsial hanya jika memiliki atribut SecurityCriticalAttribute dan juga menjalankan metode Assert untuk ReflectionEmit. Pustaka tersebut memerlukan tinjauan keamanan yang cermat karena kesalahan pengodean dapat mengakibatkan lubang keamanan. .NET Framework 3.5 memungkinkan kode untuk dipancarkan dalam skenario kepercayaan parsial tanpa mengeluarkan permintaan keamanan apa pun, karena menghasilkan kode secara inheren bukanlah operasi hak istimewa. Artinya, kode yang dihasilkan tidak memiliki izin lebih dari perakitan yang memancarkannya. Ini memungkinkan pustaka yang memancarkan kode menjadi transparan keamanan dan menghapus kebutuhan untuk menegaskan ReflectionEmit, sehingga menulis pustaka aman tidak memerlukan tinjauan keamanan menyeluruh.

Panduan ini mengilustrasikan tugas-tugas berikut:

Untuk informasi selengkapnya tentang memancarkan kode dalam skenario kepercayaan parsial, lihat Masalah Keamanan di Pancaran Refleksi.

Untuk daftar lengkap kode yang diperlihatkan dalam prosedur ini, lihat bagian Contoh di akhir panduan ini.

Menyiapkan Lokasi Tepercaya Sebagian

Dua prosedur berikut menunjukkan cara menyiapkan lokasi tempat Anda dapat menguji kode dengan kepercayaan parsial.

  • Prosedur pertama menunjukkan cara membuat domain aplikasi sandbox tempat kode diberikan izin Internet.

  • Prosedur kedua menunjukkan cara menambahkan ReflectionPermission dengan bendera ReflectionPermissionFlag.RestrictedMemberAccess ke domain aplikasi yang tepercaya sebagian, untuk memungkinkan akses ke data privat dalam rakitan dengan kepercayaan yang sama atau kurang.

Membuat Domain Aplikasi Sandbox

Untuk membuat domain aplikasi tempat rakitan Anda berjalan dengan kepercayaan parsial, Anda harus menentukan sekumpulan izin yang akan diberikan ke rakitan dengan menggunakan kelebihan beban metode AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) untuk membuat domain aplikasi. Cara termudah untuk menentukan set hibah adalah dengan mengambil kumpulan izin dari kebijakan keamanan.

Prosedur berikut membuat domain aplikasi sandbox yang menjalankan kode Anda dengan kepercayaan parsial, untuk menguji skenario di mana kode yang dipancarkan hanya dapat mengakses anggota publik dari jenis publik. Prosedur berikutnya menunjukkan cara menambahkan RestrictedMemberAccess, untuk menguji skenario di mana kode yang dipancarkan dapat mengakses jenis nonpublik dan anggota dalam rakitan yang diberikan izin yang sama atau lebih sedikit.

Untuk membuat domain aplikasi dengan kepercayaan parsial

  1. Buat kumpulan izin untuk diberikan ke rakitan di domain aplikasi sandbox. Dalam hal ini, kumpulan izin zona Internet digunakan.

    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. Buat objek AppDomainSetup untuk menginisialisasi domain aplikasi dengan jalur aplikasi.

    Penting

    Untuk kesederhanaan, contoh kode ini menggunakan folder saat ini. Untuk menjalankan kode yang sebenarnya berasal dari Internet, gunakan folder terpisah untuk kode yang tidak tepercaya, seperti yang dijelaskan dalam Cara: Menjalankan Kode Tepercaya Sebagian di Sandbox.

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
  3. Buat domain aplikasi, menentukan informasi penyiapan domain aplikasi dan hibah yang ditetapkan untuk semua rakitan yang dijalankan di domain aplikasi.

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

    Parameter terakhir dari kelebihan beban metode AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) memungkinkan Anda menentukan sekumpulan rakitan yang akan diberikan kepercayaan penuh, alih-alih set hibah domain aplikasi. Anda tidak perlu menentukan rakitan .NET Framework yang digunakan aplikasi Anda, karena rakitan tersebut berada dalam singgahan perakitan global. Rakitan dalam singgahan perakitan global selalu dipercaya sepenuhnya. Anda dapat menggunakan parameter ini untuk menentukan rakitan dengan nama yang kuat yang tidak ada dalam singgahan perakitan global.

Menambahkan RestrictedMemberAccess ke Domain Sandbox

Aplikasi host dapat memungkinkan metode dinamis yang dihosting secara anonim untuk memiliki akses ke data privat dalam rakitan yang memiliki tingkat kepercayaan yang sama dengan atau kurang dari tingkat kepercayaan rakitan yang memancarkan kode. Untuk mengaktifkan kemampuan terbatas ini untuk melewati pemeriksaan visibilitas just-in-time (JIT), aplikasi host menambahkan objek ReflectionPermission dengan bendera ReflectionPermissionFlag.RestrictedMemberAccess (RMA) ke set hibah.

Misalnya, host mungkin memberikan izin Internet aplikasi Internet ditambah RMA, sehingga aplikasi Internet dapat memancarkan kode yang mengakses data privat di rakitannya sendiri. Karena akses terbatas pada rakitan dengan kepercayaan yang sama atau kurang, aplikasi Internet tidak dapat mengakses anggota rakitan tepercaya sepenuhnya seperti rakitan .NET Framework.

Catatan

Untuk mencegah elevasi hak istimewa, informasi tumpukan untuk perakitan pemancar disertakan ketika metode dinamis yang dihosting secara anonim dibangun. Ketika metode dipanggil, informasi tumpukan diperiksa. Dengan demikian, metode dinamis yang dihosting secara anonim yang dipanggil dari kode yang sepenuhnya tepercaya masih terbatas pada tingkat kepercayaan rakitan pemancar.

Untuk membuat domain aplikasi dengan kepercayaan parsial ditambah RMA

  1. Buat objek ReflectionPermission baru dengan bendera RestrictedMemberAccess (RMA), dan gunakan metode PermissionSet.SetPermission untuk menambahkan izin ke set hibah.

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

    Metode AddPermission menambahkan izin ke set hibah jika belum disertakan. Jika izin sudah disertakan dalam set hiah, bendera yang ditentukan ditambahkan ke izin yang ada.

    Catatan

    RMA adalah fitur metode dinamis yang dihosting secara anonim. Ketika metode dinamis biasa melewati pemeriksaan visibilitas JIT, kode yang dipancarkan memerlukan kepercayaan penuh.

  2. Buat domain aplikasi, menentukan informasi penyiapan domain aplikasi dan set hibah.

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

Menjalankan Kode di Domain Aplikasi Sandbox

Prosedur berikut menjelaskan cara menentukan kelas dengan menggunakan metode yang dapat dijalankan di domain aplikasi, cara membuat instans kelas di domain, dan cara menjalankan metodenya.

Untuk menentukan dan menjalankan metode dalam domain aplikasi

  1. Tentukan kelas yang berasal dari MarshalByRefObject. Ini memungkinkan Anda membuat instans kelas di domain aplikasi lain dan melakukan panggilan metode di seluruh batas domain aplikasi. Dalam contoh ini, kelas diberi nama Worker.

    public class Worker : MarshalByRefObject
    {
    
    Public Class Worker
        Inherits MarshalByRefObject
    
  2. Tentukan metode publik yang berisi kode yang ingin Anda jalankan. Dalam contoh ini, kode memancarkan metode dinamis sederhana, membuat delegasi untuk menjalankan metode, dan memanggil delegasi.

    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. Dalam program utama Anda, dapatkan nama tampilan assembly Anda. Nama ini digunakan saat Anda membuat instans kelas Worker di domain aplikasi sandbox.

    String asmName = typeof(Worker).Assembly.FullName;
    
    Dim asmName As String = GetType(Worker).Assembly.FullName
    
  4. Dalam program utama Anda, buat domain aplikasi sandbox, seperti yang dijelaskan dalam prosedur pertama dalam panduan ini. Anda tidak perlu menambahkan izin apa pun ke Internet kumpulan izin, karena metode SimpleEmitDemo hanya menggunakan metode publik.

  5. Dalam program utama Anda, buat instans kelas Worker di domain aplikasi sandbox.

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

    Metode CreateInstanceAndUnwrap ini membuat objek di domain aplikasi target dan mengembalikan proksi yang dapat digunakan untuk memanggil properti dan metode objek.

    Catatan

    Jika Anda menggunakan kode ini di Visual Studio, Anda harus mengubah nama kelas untuk menyertakan namespace layanan. Secara default, namespace layanan adalah nama proyek. Misalnya, jika proyek adalah "PartialTrust", nama kelas harus "PartialTrust.Worker".

  6. Tambahkan kode untuk memanggil metode SimpleEmitDemo. Panggilan ini disusun di seluruh batas domain aplikasi, dan kode dijalankan di domain aplikasi sandbox.

    w.SimpleEmitDemo();
    
    w.SimpleEmitDemo()
    

Metode Dinamis yang di-Hosting secara Anonim

Metode dinamis yang dihosting secara anonim dikaitkan dengan rakitan transparan yang disediakan oleh sistem. Oleh karena itu, kode yang dikandungnya transparan. Metode dinamis biasa, di sisi lain, harus dikaitkan dengan modul yang ada (baik secara langsung ditentukan atau disimpulkan dari jenis terkait), dan mengambil tingkat keamanannya dari modul tersebut.

Catatan

Satu-satunya cara untuk mengaitkan metode dinamis dengan perakitan yang menyediakan hosting anonim adalah dengan menggunakan konstruktor yang dijelaskan dalam prosedur berikut. Anda tidak dapat secara eksplisit menentukan modul di rakitan hosting anonim.

Metode dinamis biasa memiliki akses ke anggota internal modul yang dikaitkan dengan mereka, atau ke anggota privat dari jenis yang terkait dengan mereka. Karena metode dinamis yang dihosting secara anonim diisolasi dari kode lain, metode tersebut tidak memiliki akses ke data privat. Namun, mereka memang memiliki kemampuan terbatas untuk melewati pemeriksaan visibilitas JIT untuk mendapatkan akses ke data privat. Kemampuan ini terbatas pada rakitan yang memiliki tingkat kepercayaan sama dengan atau kurang dari tingkat kepercayaan rakitan yang memancarkan kode.

Untuk mencegah elevasi hak istimewa, informasi tumpukan untuk perakitan pemancar disertakan ketika metode dinamis yang dihosting secara anonim dibangun. Ketika metode dipanggil, informasi tumpukan diperiksa. Dengan demikian, metode dinamis yang dihosting secara anonim yang dipanggil dari kode yang sepenuhnya tepercaya masih terbatas pada tingkat kepercayaan rakitan yang memancarkannya.

Untuk menggunakan metode dinamis yang di-hosting secara anonim

  • Buat metode dinamis yang dihosting secara anonim dengan menggunakan konstruktor yang tidak menentukan modul atau jenis terkait.

    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)
    

    Jika metode dinamis yang dihosting secara anonim hanya menggunakan jenis dan metode publik, metode tidak memerlukan akses anggota terbatas dan tidak harus melewati pemeriksaan visibilitas JIT.

    Tidak ada izin khusus yang diperlukan untuk memancarkan metode dinamis, tetapi kode yang dipancarkan memerlukan izin yang diminta oleh jenis dan metode yang digunakannya. Misalnya, jika kode yang dipancarkan memanggil metode yang mengakses file, kode tersebut memerlukan FileIOPermission. Jika tingkat kepercayaan tidak menyertakan izin tersebut, pengecualian keamanan akan dilemparkan saat kode yang dipancarkan dijalankan. Kode yang ditampilkan di sini memancarkan metode dinamis yang hanya menggunakan metode Console.WriteLine. Oleh karena itu, kode dapat dieksekusi dari lokasi tepercaya sebagian.

  • Atau, buat metode dinamis yang dihosting secara anonim dengan kemampuan terbatas untuk melewati pemeriksaan visibilitas JIT, dengan menggunakan konstruktor DynamicMethod(String, Type, Type[], Boolean) dan menentukan true parameter restrictedSkipVisibility.

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

    Pembatasannya adalah bahwa metode dinamis yang dihosting secara anonim hanya dapat mengakses data privat dalam rakitan dengan tingkat kepercayaan yang sama dengan atau kurang dari tingkat kepercayaan perakitan yang memancarkan. Misalnya, jika metode dinamis dijalankan dengan kepercayaan Internet, metode ini dapat mengakses data privat di rakitan lain yang juga dijalankan dengan kepercayaan Internet, tetapi tidak dapat mengakses data privat rakitan .NET Framework. .NET Framework rakitan dipasang di singgahan perakitan global dan selalu dipercaya sepenuhnya.

    Metode dinamis yang dihosting secara anonim dapat menggunakan kemampuan terbatas ini untuk melewati pemeriksaan visibilitas JIT hanya jika aplikasi host diberikan ReflectionPermission dengan bendera ReflectionPermissionFlag.RestrictedMemberAccess. Permintaan untuk izin ini dibuat ketika metode dipanggil.

    Catatan

    Informasi tumpukan panggilan untuk perakitan pemancaran disertakan ketika metode dinamis dibangun. Oleh karena itu, permintaan dibuat terhadap izin perakitan pemancaran alih-alih perakitan yang memanggil metode. Ini mencegah kode yang dipancarkan dijalankan dengan izin yang dielevasi.

    Contoh kode lengkap di akhir panduan ini menunjukkan penggunaan dan batasan akses anggota terbatas. Kelas Worker-nya mencakup metode yang dapat membuat metode dinamis yang dihosting secara anonim dengan atau tanpa kemampuan terbatas untuk melewati pemeriksaan visibilitas, dan contoh menunjukkan hasil menjalankan metode ini di domain aplikasi yang memiliki tingkat kepercayaan yang berbeda.

    Catatan

    Kemampuan terbatas untuk melewati pemeriksaan visibilitas adalah fitur metode dinamis yang dihosting secara anonim. Ketika metode dinamis biasa melewati pemeriksaan visibilitas JIT, metode tersebut harus diberikan kepercayaan penuh.

Contoh

Deskripsi

Contoh kode berikut menunjukkan penggunaan bendera RestrictedMemberAccess untuk memungkinkan metode dinamis yang dihosting secara anonim untuk melewati pemeriksaan visibilitas JIT, tetapi hanya ketika anggota target berada pada tingkat kepercayaan yang sama atau lebih rendah daripada perakitan yang memancarkan kode.

Contohnya mendefinisikan kelas Worker yang dapat di disusun di seluruh batas domain aplikasi. Kelas ini memiliki dua kelebihan beban metode AccessPrivateMethod yang memancarkan dan menjalankan metode dinamis. Kelebihan beban pertama memancarkan metode dinamis yang memanggil metode PrivateMethod privat kelas Worker, dan dapat memancarkan metode dinamis dengan atau tanpa pemeriksaan visibilitas JIT. Kelebihan beban kedua memancarkan metode dinamis yang mengakses properti internal (properti Friend dalam Visual Basic) kelas String.

Contohnya menggunakan metode pembantu untuk membuat set hibah yang terbatas pada izin Internet, lalu membuat domain aplikasi, menggunakan kelebihan beban metode AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) untuk menentukan bahwa semua kode yang dijalankan di domain menggunakan set hibah ini. Contohnya membuat instans kelas Worker di domain aplikasi, dan menjalankan metode AccessPrivateMethod dua kali.

  • Pertama kali metode AccessPrivateMethod dijalankan, pemeriksaan visibilitas JIT diberlakukan. Metode dinamis gagal ketika dipanggil, karena pemeriksaan visibilitas JIT mencegahnya mengakses metode privat.

  • Pertama kali metode AccessPrivateMethod dijalankan, pemeriksaan visibilitas JIT dilewati. Metode dinamis gagal ketika dikompilasi, karena set hibah Internet tidak memberikan izin yang memadai untuk melewati pemeriksaan visibilitas.

Contoh menambahkan ReflectionPermission dengan ReflectionPermissionFlag.RestrictedMemberAccess ke set hibah. Contoh kemudian membuat domain kedua, menentukan bahwa semua kode yang dijalankan di domain diberikan izin dalam set hibah baru. Contohnya membuat instans kelas Worker di domain aplikasi, dan menjalankan metode AccessPrivateMethod dua kali.

  • Kelebihan beban metode AccessPrivateMethod pertama dijalankan, dan pemeriksaan visibilitas JIT dilewati. Metode dinamis mengkompilasi dan menjalankan dengan sukses, karena rakitan yang memancarkan kode sama dengan rakitan yang berisi metode privat. Oleh karena itu, tingkat kepercayaannya sama. Jika aplikasi yang berisi kelas Worker memiliki beberapa rakitan, proses yang sama akan berhasil untuk salah satu rakitan tersebut, karena semuanya akan berada pada tingkat kepercayaan yang sama.

  • Kelebihan beban metode AccessPrivateMethod kedu dijalankan, dan lagi-lagi pemeriksaan visibilitas JIT dilewati. Kali ini metode dinamis gagal ketika dikompilasi, karena mencoba mengakses internalFirstChar properti kelas String. Rakitan yang berisi kelas String sepenuhnya tepercaya. Oleh karena itu, berada pada tingkat kepercayaan yang lebih tinggi daripada perakitan yang memancarkan kode.

Perbandingan ini menunjukkan bagaimana ReflectionPermissionFlag.RestrictedMemberAccess memungkinkan kode tepercaya sebagian untuk melewati pemeriksaan visibilitas untuk kode tepercaya parsial lainnya tanpa mengorbankan keamanan kode tepercaya.

Kode

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

Mengompilasi Kode

  • Jika Anda membuat contoh kode ini di Visual Studio, Anda harus mengubah nama kelas untuk menyertakan namespace layanan saat Anda meneruskannya ke metode CreateInstanceAndUnwrap. Secara default, namespace layanan adalah nama proyek. Misalnya, jika proyek adalah "PartialTrust", nama kelas harus "PartialTrust.Worker".

Lihat juga