【发布时间】:2021-07-11 13:18:42
【问题描述】:
我有 2 个项目:
Main (Console)
Util (Class library)
我想要两全其美,但我不确定这是否可能。
假设我的 Util 库中有这个类:
public static class Helper
{
public static int AnswerToUniverse()
{
return 42;
}
}
我通过 Visual Studio Project -> Add Reference 将类库 Util 添加为 Main 的依赖项。这会将其放入 Main 的清单中,并允许我静态使用 Util 库中公开的所有类型,以及所有 Intellisense 优点。
我一直认为运行时会在启动时立即加载这些静态链接的程序集,但似乎如果我在我的 Main 项目中从 Util 中删除所有使用但保留它作为参考,然后删除 .dll 程序集文件从Main 的工作目录中,它仍然运行良好,所以我得出结论,它在第一次使用时就被加载了。
现在,我的工作目录中不会有程序集文件 Util,但我确实有它的原始字节,所以我想将 Util 程序集的内容作为原始字节动态加载到应用程序域在第一次使用其任何方法之前在运行时。
我可以删除静态依赖,然后使用反射,例如:
var assembly = AppDomain.CurrentDomain.Load(rawBytes);
assembly.GetType("Util.Helper").GetMethod("AnswerToUniverse") // etc.. etc..
但我仍然非常希望能够做到:
var answer = Helper.AnswerToUniverse();
我已经尝试过挂钩 AppDomain.CurrentDomain.AssemblyResolve,但这似乎不会在静态引用的程序集上被调用。
测试代码:
Util、Helper.cs:
namespace Util
{
public static class Helper
{
public static int AnswerToUniverse()
{
return 42;
}
}
}
主要,Program.cs:
using Util;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Main
{
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
Console.WriteLine(Helper.AnswerToUniverse());
}
private static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
File.WriteAllText("test.txt", "assemblyresolved");
Console.WriteLine("resolved.");
Console.Out.Flush();
return null;
}
}
}
每次我在工作目录中没有Util 程序集文件的情况下运行Main 时,我都会得到一个FileNotFoundException,这是否可以以某种方式拦截,所以我可以返回从原始字节加载的程序集,还是我使用反射卡住了如上图?
【问题讨论】:
-
@HansPassant 这是团队正在创建的 CTF 挑战。我知道这不是最佳实践。
Main应该从字节数组中动态加载Util,而字节数组又来自 CTF 的先前步骤。如果我在不删除静态引用的情况下无法加载它,因此必须使用GetMethod等,那么就这样吧,但我想知道是否有办法保持静态类型检查并从字节加载。 -
@HansPassant 是的,大卫的回答似乎符合您的描述,谢谢!
标签: c# .net windows visual-studio