簡體   English   中英

受限 AppDomain 中的 C# 類繼承自位於主 AppDomain 中的其他類

[英]C# Class in a restricted AppDomain inherit from an other class located in the main AppDomain

我嘗試在 C# 中創建一個簡單的控制台修改項目,其中我的程序包含一個名為ElementInGame的抽象類列表 我希望能夠創建從 .txt 文件繼承 ElementInGame 的其他類 ElementInGame 類將包含一些基本方法(虛擬和非虛擬)。 但是我不希望這些其他修改過的類執行惡意代碼,我希望它們只能訪問繼承類的方法/屬性。 這是我的 ElementInGame 代碼:

(我的 C# 程序 #1)

using System;

namespace Modding
{
    //The class itself inherit from MarshalByRefObject to be available in 2 differents Domains
    public abstract class ElementInGame : MarshalByRefObject
    {
        public ElementInGame()
        {
            Console.WriteLine("ElementInGame class created");
        }

        public virtual int GetNumber()
        {
            return 10;
        }

        public void CountToTen()
        {
            for (int i = 0; i <= 10; i++)
            {
                Console.WriteLine(i);
            }
        }
    }
}

然后我將我的 .txt 文件存儲在“C:\\program.txt”

(我原來的 .txt 文件)

using System;

namespace Test
{   
    public class HelloWorld
    {
        public HelloWorld()
        {
            Console.WriteLine("Called Constructor() !");
        }

        public static int TestMethod()
        {
            Console.WriteLine("Called TestMethod() !");
            return 11;
        }
    }
}

所以我編寫主程序來讀取 .txt 文件,在有限制的情況下編譯它,然后執行它:

(我的 C# 程序 #2 在第二個 .cs 文件中,長代碼警告)

using System;
using System.CodeDom.Compiler;
using System.IO;
using Microsoft.CSharp;
using System.Reflection;
using System.Security.Permissions;
using System.Security;
using System.Security.Policy;
using System.Runtime.Remoting;
using System.Collections.Generic;

namespace Modding
{
    public class Program : MarshalByRefObject
    {
        public static void Main(string[] args)
        {

            string assemblyPath = @"C:\program.txt"; // Where the .txt file is stored
            string code = File.ReadAllText(assemblyPath); //The code to compile

            CompilerResults compile = CompileFromCode(code); //Compile the code in the temporary files

            string fullPath = compile.PathToAssembly;                           //sample : C:\Users\MY_USER_NAME\AppData\Local\Temp\5v2p3qki.dll
            string pathWithoutFile = Path.GetDirectoryName(fullPath);           //sample : C:\Users\MY_USER_NAME\AppData\Local\Temp
            string pathNameOnly = Path.GetFileNameWithoutExtension(fullPath);   //sample : 5v2p3qki

            Program newDomainInstance = GetOtherProtectedDomainInstance(pathWithoutFile);

            newDomainInstance.CallMethod(pathNameOnly, "Test.HelloWorld", "TestMethod", null, null);
            newDomainInstance.CreateObject(pathNameOnly,"Test.HelloWorld");

            List<ElementInGame> allElement = new List<ElementInGame>();
            //allElement.Add ***?***

            Console.ReadKey();
        }

        public static Program GetOtherProtectedDomainInstance(string pathWithoutFile)
        {
            AppDomainSetup adSetup = new AppDomainSetup();
            adSetup.ApplicationBase = pathWithoutFile;

            //Set some permissions to avoid malicious code
            PermissionSet permSet = new PermissionSet(PermissionState.None);
            permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

            StrongName fullTrustAssembly = new StrongName(
                new StrongNamePublicKeyBlob(typeof(Program).Assembly.GetName().GetPublicKey()),
                typeof(Program).Assembly.GetName().Name,
                typeof(Program).Assembly.GetName().Version);

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

            ObjectHandle handle = Activator.CreateInstanceFrom(
                newDomain, typeof(Program).Assembly.ManifestModule.FullyQualifiedName,
                typeof(Program).FullName
                );

            Program newDomainInstance = (Program)handle.Unwrap();
            return newDomainInstance;
        }

        public static CompilerResults CompileFromCode(string code)
        {
            //Compile the code in a .dll locate in the temporary files
            //The following code is based on https://stackoverflow.com/questions/10314815/trying-to-compile-and-execute-c-sharp-code-programmatically
            CompilerParameters CompilerParams = new CompilerParameters();
            string outputDirectory = Directory.GetCurrentDirectory();

            CompilerParams.GenerateInMemory = false;
            CompilerParams.TreatWarningsAsErrors = false;
            CompilerParams.GenerateExecutable = false;
            CompilerParams.CompilerOptions = "/optimize";

            //Adding a reference to the current project to allow the .txt file to inherit the class "ElementInGame" later
            string[] references = { "System.dll", Assembly.GetEntryAssembly().Location };
            CompilerParams.ReferencedAssemblies.AddRange(references);

            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerResults compile = provider.CompileAssemblyFromSource(CompilerParams, code);

            if (compile.Errors.HasErrors)
            {
                string text = "Compile error: ";
                foreach (CompilerError ce in compile.Errors)
                {
                    text += "rn" + ce.ToString();
                }
                throw new Exception(text);
            }

            return compile;
        }

        public static void DisplaySomething()//Useful for later
        {
            Console.WriteLine("This isn't supposed to be display");
        }

        //Calling a method from the restricted Domain
        public void CallMethod(string assemblyName, string typeName, string entryPoint, object objectToExecute = null, object[] parameters = null)
        {
            MethodInfo target = Assembly.Load(assemblyName).GetType(typeName).GetMethod(entryPoint);
            try
            {
                target.Invoke(objectToExecute, parameters);
            }
            catch
            {
                Console.WriteLine("Security Error with Method " + assemblyName + " namespace : " + typeName + " method : " + entryPoint);
            }
        }

        //Create an instance from the restricted Domain
        public void CreateObject(string assemblyName, string typeName)
        {
            try
            {
                object o = Assembly.Load(assemblyName).CreateInstance(typeName);
            }
            catch
            {
                Console.WriteLine("Security Error with Constructor " + assemblyName + " namespace : " + typeName);
            }
        }
    }
}

目前.txt 文件與我的 C# 程序根本沒有任何鏈接 代碼工作正常,我得到以下輸出:

Called TestMethod() !
Called Constructor() !

然后我在我的 .txt 文件中編輯我的代碼以從 Modding.ElementInGame 繼承:

(我編輯過的.txt 文件)

using System;

namespace Test
{   
    public class HelloWorld : Modding.ElementInGame
    {
        public HelloWorld() : base()
        {
            Console.WriteLine("Called Constructor() !");
        }

        public static int TestMethod()
        {
            Console.WriteLine("Called TestMethod() !");
            return 11;
        }
    }
}

所以我期望輸出如下:

Called TestMethod() !
ElementInGame class created
Called Constructor() !

但是在此更改之后,程序在調用 TestMethod 時崩潰並出現System.NullReferenceExceptionnewDomainInstance.CallMethod(pathNameOnly, "Test.HelloWorld", "TestMethod", null, null);

然而,創建一個 HelloWorld 實例(.txt 文件): newDomainInstance.CreateObject(pathNameOnly,"Test.HelloWorld"); 似乎有效(沒有崩潰,執行 try/catch 時代碼保留在 try 部分),但是我的控制台中沒有打印任何內容,所以我猜它不起作用?

更改 AppDomain 的權限不會改變任何內容。

PermissionSet permSet = new PermissionSet(PermissionState.Unrestricted);
permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.AllFlags));

所以我的問題是:如何在我的程序中創建存儲從 ElementInGame 繼承的 .txt 文件的實例(並將其添加到 ElementInGame 的列表中)?

這樣我就可以從我的程序中使用虛擬方法 GetNumber()。 我不希望 .txt 文件訪問程序本身(如調用 DisplaySomething() 方法),只需與 ElementInGame通信

您正在從不同位置生成和加載參考程序集。 您確實為輸出設置了當前目錄,但忘記將其分配給編譯器參數。

string outputDirectory = Directory.GetCurrentDirectory();
CompilerParams.OutputAssembly = Path.Combine(outputDirectory, "Test.dll");

這應該可以解決問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM