2

I am trying to create a Windows sandbox application, building upon the "How to" found here: "https://msdn.microsoft.com/en-us/library/bb763046(v=vs.110).aspx"

In the example it loads a specific type from a DLL whereas I would like to be able to execute an assembly from its entry point with restricted permissions.

The program I am using for testing purposes is a simple hello world application.

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            Console.Read();
        }
    }
}

I have tried two different methods to try and achieve this.

Method 1.

Use the "MethodInfo.Invoke" method on the entry point of the assembly.

MethodInfo target = Assembly.Load(assemblyName).EntryPoint;
target.Invoke(null, parameters);

This produces a Method Access Exception due to the main method being non-public. A simple way around this would be to make the main method public but I will not have this sort of access to the assemblies that are intended to be used with this application.

Method 2.

Use the "AppDomain.ExecuteAssembly" method as shown below.

newDomain.ExecuteAssembly(filePath, parameters);

This requires that the app domain has both File IO Permission and UI Permission for the assembly to be executed but I want to be able to restrict the assembly from having these permissions.

Is there a way to execute an assembly from it's entry point within a permission restricted app domain?

EDIT: The assembly's location is provided from an Open File Dialog and is then passed to the following method.

public int RunAssembly(string filePath, string[] parameters)
{
    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = Path.GetDirectoryName(filePath);

    PermissionSet permSet = new PermissionSet(PermissionState.None);
    permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

    StrongName fullTrustAssembly = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<StrongName>();

    newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);

    return newDomain.ExecuteAssembly(filePath, parameters);
}

As you can see the only permission I would like to give the new app domain is the ability to run. Whereas it required File IO and UI permissions for the ExecuteAssembly method to work correctly.

Phil
  • 23
  • 2
  • 5
  • Please post the code for your loader too. Method #1 works fine from a normal appdomain. – Jester Feb 11 '15 at 14:05
  • Out of curiosity, did you start playing with Code Access Security after reading a recent post on the Space Engineers modding forum? (I don't see questions about this topic too often and I just did a big post about it on that site a day or two ago) – Scott Chamberlain Feb 11 '15 at 15:08
  • I have added the loading code for Method #2. Jester: What do you mean by "normal" appdomain? Scott: No I've picked this up due to a need for it within a university project. – Phil Feb 11 '15 at 16:29

3 Answers3

1

You wrote: "This produces a Method Access Exception due to the main method being non-public." Yes, you shouldn't call a method which is not intended to be called from outside. You try to "override" the protection level: I hope it's not possible as it means a big hole in the system.

Peter Krassoi
  • 571
  • 3
  • 11
  • Yes I understand why the entry point of an assembly should not be public as it is not designed to be called from anything but the CLR. This leaves the question as to what is the best method to programmatically invoke an assembly with a limited specific permission set e.g. the permission set that is present within the first edit. – Phil Feb 11 '15 at 16:56
  • you can invoke a non-public method using reflections call with `BindingFlags.NonPublic` (take a look at: https://stackoverflow.com/questions/135443/how-do-i-use-reflection-to-invoke-a-private-method) – Tomer W Mar 08 '20 at 11:24
0

Using Method #1 and adding the reflection permission RestrictedMemberAccess so that non-public members can be invoked is a way of invoking an assembly with fully restricted permissions.

MethodInfo target = Assembly.Load(assemblyName).EntryPoint;
(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess)).Assert();
target.Invoke(null, parameters);

The full loading code:

public int RunAssembly(string filePath, Object[] parameters)
{
    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = Path.GetDirectoryName(filePath);

    PermissionSet permSet = new PermissionSet(PermissionState.None);
    permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

    StrongName fullTrustAssembly = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<StrongName>();

    newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);

    ObjectHandle handle = Activator.CreateInstanceFrom(
        _newDomain, typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,
        typeof(Sandboxer).FullName
        );

    newDomainInstance = (Sandboxer)handle.Unwrap();

    string assemblyName = Path.GetFileNameWithoutExtension(filePath);

    return newDomainInstance.ExecuteAssembly(assemblyName, parameters);
}

public int ExecuteAssembly(string assemblyName, Object[] parameters)
{
    MethodInfo target = Assembly.Load(assemblyName).EntryPoint;
    (new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess)).Assert();

    return target.Invoke(null, parameters);
}

Sorry for the ambiguous method name, these should be changed if it to be used.

Phil
  • 23
  • 2
  • 5
0

I know it has been a while but I came to this question and here what I ended up with.

first, import system.security

using System.Security;
using System.Security.Permissions;

And here is the execution using DomainApp.

public static void ExecuteAssemblyLoadFileAppDomain(string file, string[] param)
{
    Console.WriteLine("[*] Using ExecuteAssemblyLoadFileAppDomain1:");
    PermissionSet permission = new PermissionSet(PermissionState.Unrestricted);
    AppDomainSetup setup = new AppDomainSetup();

    setup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
    AppDomain domain = AppDomain.CreateDomain("King AppDomain", null, setup, permission);

    try
    {
        Console.WriteLine($"[+] Executing '{Path.GetFileName(file)}' in '{domain.FriendlyName}' AppDomain.");
        domain.ExecuteAssembly(file, param);
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }
    finally
    {
        AppDomain.Unload(domain);
    }
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
KING SABRI
  • 775
  • 7
  • 18