在 AppDomain 中启动 .NET 进程
Posted
技术标签:
【中文标题】在 AppDomain 中启动 .NET 进程【英文标题】:Starting a .NET process within an AppDomain 【发布时间】:2016-12-02 10:29:47 【问题描述】:我的问题的标题可能已经暴露了我不确定自己想要什么的事实,因为它可能没有意义。
对于一个项目,我希望能够在我的应用程序中运行可执行文件,同时重定向它们的标准输入和输出,以便我的应用程序可以通过这些流与它们通信。
同时,我不想让这些可执行文件执行某些操作,比如使用网络,或者在他们自己的工作目录之外读/写(基本上我只想让他们从标准中读写进出)。
我在互联网上的不同地方读到,在创建 AppDomain 时可以使用 PermissionStates 设置这些权限,然后您可以在其中执行可执行文件。但是,我没有找到一种方法来通过它们的标准输入和输出与可执行文件进行通信,这是必不可少的。但是,我可以在启动新进程 (Process.Start()
) 时执行此操作,但我无法设置可执行文件允许执行的操作的界限。
我的直觉告诉我应该以某种方式在 AppDomain 中执行进程,以便进程在域中“运行”,尽管我看不到直接执行此操作的方法。
我的一位同事通过创建代理应用程序来实现这一点,它基本上是另一个可执行文件,其中创建了 AppDomain,其中执行实际的可执行文件。然后代理应用程序由主应用程序中的进程启动。我认为这是一个很酷的想法,虽然我觉得我不应该需要这一步。
我可以添加一些代码,其中包含我迄今为止创建进程和 appdomain 所做的工作,尽管这个问题已经很长了。如果你愿意,我会添加它。
【问题讨论】:
这非常复杂,可悲的是——这些安全方法一次又一次地失败是有原因的,他们付出了巨大的努力,没有人能把它们做好。但是,您可以做的是以受限用户的身份运行该进程 - 虽然它没有为您提供 CAS 为您提供的粒度,但它也容易得多,并保持进程隔离。进程内扩展可以很容易地杀死您的应用程序:) 无法在AppDomain
中运行进程,因为它们是完全独立的概念。 AppDomain
s 在进程中运行,反之亦然。当然,它们首先只适用于 .NET 应用程序 :)
@Luaan 那么当我打电话给AppDomain.Create(...).ExecuteAssembly(pathToMyStuff)
时会发生什么?我觉得这开始了一个新的过程,但根据你的说法,情况并非如此......
它在给定的程序集中执行入口点方法,在给定的AppDomain
内(如果我简化,它相当于GetType("Program").GetMethod("Main").Invoke();
)。没有产生新的进程。 AppDomain
确实是一种软件隔离进程的机制,但是使用起来相当棘手,而且隔离对于真正的沙盒来说太有限了。
.NET MSDN 文档实际上相当不错——在ExecuteAssembly
上,它实际上明确指出“此方法不会创建新的进程或应用程序域,并且不会在一个新线程。”我想知道如果我们回到“首先检查文档”模型,我们会节省多少精力,而不是期望我们的假设是正确的,只是因为方法的名称是“执行”:D 对我来说,原来的假设源于“它位于AppDomain
,因此它显然无法启动进程。” - 这可能可能是错误的。
【参考方案1】:
“代理”应用程序听起来是一种非常合理的方法(假设您只想运行 .NET 程序集)。
您可以隔离不同的进程,这允许您通过 stdin/stdout 进行通信,并提供额外的稳健性,即不受信任的可执行文件不会使您的主应用程序崩溃(如果它在您的主应用程序进程内的 AppDomain 中运行,它可能会崩溃。
然后,代理应用程序将设置一个受限的 AppDomain 并执行沙盒代码,类似于此处描述的方法:
How to: Run Partially Trusted Code in a Sandbox
此外,您可以利用操作系统级别的机制来减少进程的攻击面。这可以实现,例如通过启动具有最低完整性的代理进程来删除对大多数资源的写访问(例如,只允许在 AppData\LocalLow 中写入文件)。示例见here。
当然,您需要考虑这种沙盒级别是否足以满足您的需求。一般来说,沙盒很难,而且隔离级别总是只有一定程度。
【讨论】:
我想我真的不明白 AppDomain 在调用 ExecuteAssembly() 时做了什么,对我来说,这听起来像是又开始了另一个进程,但显然如果我与代理应用程序通信,我实际上与我想与之交谈的可执行文件交谈,因为它是通过创建的 appdomain 在代理应用程序中加载的。 @Glubus:ExecuteAssembly
不会启动新进程,而是在同一个进程的 AppDomain 中执行。因此,如果您与“代理”应用程序通信,则通信工作正常。
所以你是说代理应用程序中的 Console.WriteLine() 在 AppDomain 中运行时在执行的程序集中调用它时正在写入同一个流?在阅读了您和 Luaans 的 cmets 之后,我现在似乎已经明白了一半。
@Glubus:我自己没有尝试过,但我希望会是这样,因为访问 stdin/stdout 发生在进程(而不是 AppDomain)级别,并且执行的程序集在该特定程序中运行过程。
我现在看到了你的期望,它开始对我有意义。从这个意义上说,代理应用程序实际上并不是额外的执行层,因为我们要运行的程序实际上是作为代理应用程序的一部分加载的。我觉得我不再需要删除该层了。非常感谢!以上是关于在 AppDomain 中启动 .NET 进程的主要内容,如果未能解决你的问题,请参考以下文章
.NET 进程和 AppDomain 在啥情况下会共享内存中加载的程序集?