연습: 부분 신뢰 시나리오에서 코드 내보내기

리플렉션 내보내기에는 완전 또는 부분 신뢰에서 동일한 API 집합이 사용되지만 일부 기능의 경우 부분적으로 신뢰할 수 있는 코드에 특수 권한이 필요합니다. 또한 리플렉션 내보내기에는 부분 신뢰와 함께 보안 투명 어셈블리에서 사용되도록 디자인된 익명으로 호스트되는 동적 메서드의 기능이 있습니다.

참고

.NET Framework 3.5 이전에는 코드 내보내기에는 ReflectionPermissionFlag.ReflectionEmit 플래그가 있는 ReflectionPermission이 필요했습니다. 이 권한은 기본적으로 FullTrustIntranet 명명된 권한 집합에 포함되지만 Internet 권한 집합에는 포함되지 않습니다. 따라서 SecurityCriticalAttribute 특성이 있고 ReflectionEmit에 대해 Assert 메서드를 실행한 경우에만 부분 신뢰 영역에서 라이브러리를 사용할 수 있었습니다. 코딩 오류가 있을 경우 보안 허점이 발생할 수 있으므로 이러한 라이브러리는 신중한 보안 검토가 필요합니다. .NET Framework 3.5에서는 코드 생성이 기본적으로 권한 있는 작업이 아니기 때문에 보안 요구를 실행하지 않고 부분 신뢰 시나리오에서 코드를 내보낼 수 있습니다. 즉, 생성된 코드에 코드를 내보내는 어셈블리보다 많은 권한이 없습니다. 따라서 코드를 내보내는 라이브러리가 보안상 투명할 수 있으며 ReflectionEmit를 어설션할 필요가 없으므로 보안 라이브러리 작성 시 철저한 보안 검토가 필요하지 않습니다.

이 연습에서는 다음 작업을 수행합니다.

부분 신뢰 시나리오의 코드 내보내기에 대한 자세한 내용은 리플렉션 내보내기의 보안 문제점을 참조하세요.

이러한 절차에 표시된 코드의 전체 목록을 보려면 이 연습의 끝부분에 있는 예제 섹션을 참조하세요.

부분적으로 신뢰할 수 있는 위치 설정

다음 두 절차는 부분 신뢰를 사용하여 코드를 테스트할 수 있는 위치를 설정하는 방법을 보여 줍니다.

  • 첫 번째 절차는 코드에 인터넷 권한이 부여되는 샌드박스가 적용된 애플리케이션 도메인을 만드는 방법을 보여 줍니다.

  • 두 번째 절차는 동일하거나 낮은 신뢰 수준 어셈블리의 전용 데이터에 액세스할 수 있도록 ReflectionPermissionFlag.RestrictedMemberAccess 플래그와 함께 ReflectionPermission을 부분적으로 신뢰할 수 있는 애플리케이션 도메인에 추가하는 방법을 보여 줍니다.

샌드박스가 적용된 애플리케이션 도메인 만들기

어셈블리가 부분 신뢰로 실행되는 애플리케이션 도메인을 만들려면 AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) 메서드 오버로드를 사용하여 애플리케이션 도메인을 만드는 방식으로 어셈블리에 부여되는 권한 집합을 지정해야 합니다. 권한 집합을 지정하는 가장 쉬운 방법은 보안 정책에서 명명된 권한 집합을 검색하는 것입니다.

다음 절차에서는 코드를 부분 신뢰로 실행하는 샌드박스가 적용된 애플리케이션 도메인을 만들어 내보낸 코드가 public 형식의 public 멤버에만 액세스할 수 있는 시나리오를 테스트합니다. 이후 절차에서는 RestrictedMemberAccess를 추가하여 내보낸 코드가 동일하거나 낮은 수준의 권한이 부여된 어셈블리의 public이 아닌 형식 및 멤버에 액세스할 수 있는 시나리오를 테스트하는 방법을 보여 줍니다.

부분 신뢰를 사용하여 애플리케이션 도메인을 만들려면

  1. 샌드박스가 적용된 애플리케이션 도메인에서 어셈블리에 부여할 권한 집합을 만듭니다. 이 경우 인터넷 영역의 권한 집합이 사용됩니다.

    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 개체를 만들어 애플리케이션 경로를 통해 애플리케이션 도메인을 초기화합니다.

    중요

    간단히 설명하기 위해 이 코드 예제에서는 현재 폴더를 사용합니다. 실제로 인터넷에서 나오는 코드를 실행하려면 방법: 샌드박스에서 부분적으로 신뢰할 수 있는 코드 실행의 설명대로 신뢰할 수 없는 코드에 별도의 폴더를 사용합니다.

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
  3. 애플리케이션 도메인을 만들어 애플리케이션 도메인 설정 정보 및 애플리케이션 도메인에서 실행되는 모든 어셈블리의 권한 집합을 지정합니다.

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

    AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) 메서드 오버로드의 마지막 매개 변수를 사용하여 애플리케이션 도메인의 권한 집합이 아닌 완전 신뢰가 부여되는 어셈블리 집합을 지정할 수 있습니다. 애플리케이션에서 사용하는 .NET Framework 어셈블리는 글로벌 어셈블리 캐시에 있으므로 해당 어셈블리를 지정할 필요가 없습니다. 전역 어셈블리 캐시의 어셈블리는 항상 완전히 신뢰할 수 있습니다. 이 매개 변수를 사용하여 전역 어셈블리 캐시에 없는 강력한 이름의 어셈블리를 지정할 수 있습니다.

샌드박스가 적용된 도메인에 RestrictedMemberAccess 추가

호스트 애플리케이션에서는 익명으로 호스트된 동적 메서드가 코드를 내보내는 어셈블리의 신뢰 수준과 같거나 낮은 신뢰 수준을 가진 어셈블리의 전용 데이터에 액세스할 수 있습니다. JIT(Just-In-Time) 표시 유형 확인을 건너뛰는 이 제한된 기능을 사용할 수 있도록 호스트 애플리케이션에서는 ReflectionPermissionFlag.RestrictedMemberAccess(RMA) 플래그가 있는 ReflectionPermission 개체를 권한 집합에 추가합니다.

예를 들어 호스트에서는 인터넷 애플리케이션에 인터넷 권한과 RMA를 부여할 수 있으므로 인터넷 애플리케이션은 자체 어셈블리의 전용 데이터에 액세스하는 코드를 내보낼 수 있습니다. 액세스는 같거나 낮은 신뢰 수준의 어셈블리로 제한되므로 인터넷 애플리케이션은 .NET Framework 어셈블리와 같이 완전히 신뢰할 수 있는 어셈블리의 멤버에 액세스할 수 없습니다.

참고

권한 상승을 방지하기 위해 익명으로 호스트된 동적 메서드가 생성될 때 내보내는 어셈블리에 대한 스택 정보가 포함됩니다. 메서드가 호출되면 스택 정보가 확인됩니다. 따라서 완전히 신뢰할 수 있는 코드에서 호출되는 익명으로 호스트된 동적 메서드는 계속해서 내보내는 어셈블리의 신뢰 수준으로 제한됩니다.

부분 신뢰 및 RMA를 사용하여 애플리케이션 도메인을 만들려면

  1. RestrictedMemberAccess(RMA) 플래그가 있는 새 ReflectionPermission 개체를 만들고 PermissionSet.SetPermission 메서드를 사용하여 권한 집합에 권한을 추가합니다.

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

    AddPermission 메서드는 권한 집합에 권한을 추가합니다(권한이 포함되지 않은 경우). 권한이 이미 권한 집합에 포함된 경우 지정된 플래그가 기존 권한에 추가됩니다.

    참고

    RMA는 익명으로 호스트된 동적 메서드의 기능입니다. 일반 동적 메서드가 JIT 표시 유형 확인을 건너뛰면 내보낸 코드에 완전 신뢰가 필요합니다.

  2. 애플리케이션 도메인을 만들어 애플리케이션 도메인 설정 정보 및 권한 집합을 지정합니다.

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

샌드박스가 적용된 애플리케이션 도메인에서 코드 실행

다음 절차에서는 애플리케이션 도메인에서 실행할 수 있는 메서드를 사용하여 클래스를 정의하는 방법, 도메인에서 클래스 인스턴스를 만드는 방법 및 해당 메서드를 실행하는 방법을 설명합니다.

애플리케이션 도메인에서 메서드를 정의 및 실행하려면

  1. MarshalByRefObject에서 파생된 클래스를 정의합니다. 이 작업을 통해 다른 애플리케이션 도메인에서 클래스 인스턴스를 만들고 애플리케이션 도메인 경계에 걸쳐 메서드 호출을 실행할 수 있습니다. 이 예제에서 클래스 이름은 Worker입니다.

    public class Worker : MarshalByRefObject
    {
    
    Public Class Worker
        Inherits MarshalByRefObject
    
  2. 실행할 코드가 포함된 public 메서드를 정의합니다. 이 예제에서 코드는 간단한 동적 메서드를 내보내고, 대리자를 만들어 메서드를 실행하고, 대리자를 호출합니다.

    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. 기본 프로그램에서 어셈블리의 표시 이름을 가져옵니다. 이 이름은 샌드박스가 적용된 애플리케이션 도메인에서 Worker 클래스의 인스턴스를 만들 때 사용됩니다.

    String asmName = typeof(Worker).Assembly.FullName;
    
    Dim asmName As String = GetType(Worker).Assembly.FullName
    
  4. 기본 프로그램에서 이 연습의 첫 번째 절차에 설명된 대로 샌드박스가 적용된 애플리케이션 도메인을 만듭니다. SimpleEmitDemo 메서드는 public 메서드만 사용하므로 Internet 권한 집합에 권한을 추가할 필요가 없습니다.

  5. 기본 프로그램에서 샌드박스가 적용된 애플리케이션 도메인에서 Worker 클래스의 인스턴스를 만듭니다.

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

    CreateInstanceAndUnwrap 메서드는 대상 애플리케이션 도메인에서 개체를 만들고 개체의 속성과 메서드를 호출하는 데 사용될 수 있는 프록시를 반환합니다.

    참고

    Visual Studio에서 이 코드를 사용하는 경우 네임스페이스를 포함하도록 클래스의 이름을 변경해야 합니다. 기본적으로 네임스페이스는 프로젝트의 이름입니다. 예를 들어 프로젝트가 "PartialTrust"이면 클래스 이름은 "PartialTrust.Worker"입니다.

  6. SimpleEmitDemo 메서드를 호출하는 코드를 추가합니다. 호출은 애플리케이션 도메인 경계에서 마샬링되고 코드는 샌드박스가 적용된 애플리케이션 도메인에서 실행됩니다.

    w.SimpleEmitDemo();
    
    w.SimpleEmitDemo()
    

익명으로 호스트된 동적 메서드 사용

익명으로 호스트된 동적 메서드는 시스템에서 제공되는 투명 어셈블리와 연결됩니다. 따라서 메서드에 포함된 코드는 투명합니다. 반면, 일반 동적 메서드는 기존 모듈과 연결되고(직접 지정되거나 연결된 형식에서 유추됨) 해당 모듈의 보안 수준을 사용해야 합니다.

참고

익명 호스팅을 제공하는 어셈블리와 동적 메서드를 연결하는 유일한 방법은 다음 절차에 설명된 생성자를 사용하는 것입니다. 익명 호스팅 어셈블리에서는 모듈을 명시적으로 지정할 수 없습니다.

일반 동적 메서드는 연결된 모듈의 internal 멤버 또는 연결된 형식의 private 멤버에 액세스할 수 있습니다. 익명으로 호스트된 동적 메서드는 다른 코드에서 분리되므로 전용 데이터에 액세스할 수 없습니다. 하지만 JIT 표시 유형 확인을 건너뛰어 전용 데이터에 대한 액세스 권한을 얻는 제한된 기능이 있습니다. 이 기능은 코드를 내보내는 어셈블리의 신뢰 수준과 같거나 낮은 신뢰 수준을 가진 어셈블리로 제한됩니다.

권한 상승을 방지하기 위해 익명으로 호스트된 동적 메서드가 생성될 때 내보내는 어셈블리에 대한 스택 정보가 포함됩니다. 메서드가 호출되면 스택 정보가 확인됩니다. 완전히 신뢰할 수 있는 코드에서 호출되는 익명으로 호스트된 동적 메서드는 계속해서 메서드를 내보낸 어셈블리의 신뢰 수준으로 제한됩니다.

익명으로 호스트된 동적 메서드를 사용하려면

  • 연결된 모듈 또는 형식을 지정하지 않는 생성자를 사용하여 익명으로 호스트된 동적 메서드를 만듭니다.

    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)
    

    public 형식 및 메서드만 사용하는 익명으로 호스트된 동적 메서드의 경우 제한된 멤버 액세스가 필요하지 않고 JIT 표시 유형 확인을 건너뛸 필요가 없습니다.

    동적 메서드를 내보내기 위한 특수 권한이 필요하지 않지만, 내보낸 코드에는 코드에서 사용하는 형식 및 메서드에 필요한 권한이 있어야 합니다. 예를 들어 내보낸 코드가 파일에 액세스하는 메서드를 호출할 경우 FileIOPermission이 필요합니다. 신뢰 수준에 권한이 포함되지 않은 경우 내보낸 코드가 실행될 때 보안 예외가 throw됩니다. 여기 표시된 코드는 Console.WriteLine 메서드만 사용하는 동적 메서드를 내보냅니다. 따라서 코드는 부분적으로 신뢰할 수 있는 위치에서 실행할 수 있습니다.

  • 또는 DynamicMethod(String, Type, Type[], Boolean) 생성자를 사용하고 restrictedSkipVisibility 매개 변수를 true로 지정하여 JIT 표시 유형 확인을 건너뛰는 제한된 기능을 가진 익명으로 호스트된 동적 메서드를 만듭니다.

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

    익명으로 호스트된 동적 메서드는 내보내는 어셈블리의 신뢰 수준과 같거나 낮은 신뢰 수준을 가진 어셈블리의 전용 데이터에만 액세스할 수 있도록 제한됩니다. 예를 들어 인터넷 신뢰로 실행되고 있는 동적 메서드는 인터넷 신뢰로 실행되고 있는 다른 어셈블리의 전용 데이터에 액세스할 수 있지만 .NET Framework 어셈블리의 전용 데이터에는 액세스할 수 없습니다. .NET Framework 어셈블리는 글로벌 어셈블리 캐시에 설치되고 항상 완전히 신뢰할 수 있습니다.

    익명으로 호스트된 동적 메서드는 호스트 애플리케이션에서 ReflectionPermissionFlag.RestrictedMemberAccess 플래그로 ReflectionPermission을 부여하는 경우에만 JIT 표시 유형 확인을 건너뛰는 이 제한된 기능을 사용할 수 있습니다. 메서드가 호출될 때 이 권한이 필요합니다.

    참고

    동적 메서드가 생성될 때 내보내는 어셈블리의 호출 스택 정보가 포함됩니다. 따라서 메서드를 호출하는 어셈블리가 아닌 내보내는 어셈블리에 대한 권한이 필요합니다. 이렇게 하면 내보낸 코드가 높은 권한으로 실행되지 않습니다.

    이 연습의 끝부분에 있는 전체 코드 예제는 제한된 멤버 액세스의 사용 및 제한 사항을 보여 줍니다. Worker 클래스에는 표시 유형 확인을 건너뛰는 제한된 기능을 사용하거나 사용하지 않고 익명으로 호스트된 동적 메서드를 만들 수 있는 메서드가 포함되며 예제에서는 다양한 신뢰 수준을 가진 애플리케이션 도메인에서 이 메서드를 실행한 결과를 보여 줍니다.

    참고

    표시 유형 확인을 건너뛰는 제한된 기능은 익명으로 호스트된 동적 메서드의 기능입니다. 일반 동적 메서드가 JIT 표시 유형 확인을 건너뛸 경우 완전 신뢰가 부여되어야 합니다.

예제

설명

다음 코드 예제는 RestrictedMemberAccess 플래그를 사용하여 대상 멤버가 코드를 내보내는 어셈블리와 같거나 낮은 신뢰 수준에 있는 경우에만 익명으로 호스트된 동적 메서드가 JIT 표시 유형 확인을 건너뛰도록 하는 방법을 보여 줍니다.

예제에서는 애플리케이션 도메인 경계에서 마샬링될 수 있는 Worker 클래스를 정의합니다. 클래스에는 동적 메서드를 내보내고 실행하는 두 개의 AccessPrivateMethod 메서드 오버로드가 있습니다. 첫 번째 오버로드는 Worker 클래스의 private PrivateMethod 메서드를 호출하는 동적 메서드를 내보내며 JIT 표시 유형 확인 여부에 관계없이 동적 메서드를 내보낼 수 있습니다. 두 번째 오버로드는 String 클래스의 internal 속성(Visual Basic의 Friend 속성)에 액세스하는 동적 메서드를 내보냅니다.

예제에서는 도우미 메서드를 사용하여 Internet 권한으로 제한된 권한 집합을 만들고 나서 AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) 메서드 오버로드로 애플리케이션 도메인을 만들어 도메인에서 실행되는 모든 코드가 이 권한 집합을 사용하도록 지정합니다. 예제에서는 애플리케이션 도메인에서 Worker 클래스 인스턴스를 만들고 AccessPrivateMethod 메서드를 두 번 실행합니다.

  • AccessPrivateMethod 메서드가 처음 실행될 때 JIT 표시 유형 확인이 실행됩니다. JIT 표시 유형 확인을 실행하면 동적 메서드가 private 메서드에 액세스할 수 없으므로 동적 메서드는 호출 시 실패합니다.

  • AccessPrivateMethod 메서드가 두 번째로 실행될 때는 JIT 표시 유형 확인을 건너뜁니다. Internet 권한 집합은 표시 유형 확인을 건너뛸 충분한 권한을 부여하지 않으므로 동적 메서드는 컴파일 시 실패합니다.

예제에서는 ReflectionPermissionReflectionPermissionFlag.RestrictedMemberAccess와 함께 권한 집합에 추가합니다. 예제에서는 그다음에 두 번째 도메인을 만들어 도메인에서 실행되는 모든 코드에 새 권한 집합의 권한이 부여되도록 지정합니다. 예제에서는 새 애플리케이션 도메인에서 Worker 클래스 인스턴스를 만들고 AccessPrivateMethod 메서드의 오버로드를 둘 다 실행합니다.

  • AccessPrivateMethod 메서드의 첫 번째 오버로드가 실행되고 JIT 표시 유형 확인을 건너뜁니다. 코드를 내보내는 어셈블리가 private 메서드를 포함하는 어셈블리와 같기 때문에 동적 메서드가 성공적으로 컴파일 및 실행됩니다. 따라서 신뢰 수준이 같습니다. Worker 클래스를 포함하는 애플리케이션에 여러 어셈블리가 있는 경우에는 모든 어셈블리의 신뢰 수준이 같으므로 모든 해당 어셈블리에 대해 동일한 프로세스가 성공합니다.

  • AccessPrivateMethod 메서드의 두 번째 오버로드가 실행되고 다시 JIT 표시 유형 확인을 건너뜁니다. 이때 동적 메서드는 String 클래스의 internalFirstChar 속성에 액세스하려고 하므로 동적 메서드가 컴파일 시 실패합니다. String 클래스를 포함하는 어셈블리는 완전히 신뢰할 수 있습니다. 따라서 이 어셈블리는 코드를 내보내는 어셈블리보다 신뢰 수준이 높습니다.

이 비교는 신뢰할 수 있는 코드의 보안을 손상시키지 않고 ReflectionPermissionFlag.RestrictedMemberAccess를 사용하여 부분적으로 신뢰할 수 있는 코드가 다른 부분적으로 신뢰할 수 있는 코드의 표시 유형 확인을 건너뛰는 방법을 보여 줍니다.

코드

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

코드 컴파일

  • Visual Studio에서 이 코드 예제를 빌드하는 경우 CreateInstanceAndUnwrap 메서드에 클래스를 전달할 때 네임스페이스를 포함하도록 해당 클래스의 이름을 변경해야 합니다. 기본적으로 네임스페이스는 프로젝트의 이름입니다. 예를 들어 프로젝트가 "PartialTrust"이면 클래스 이름은 "PartialTrust.Worker"입니다.

참조