关于.NET Core受信任程序集DLL注入及.NET 6.0加载自定义System.Diagnostics.Process.dll的技术问询
嘿,这个需求我太熟了——之前帮好几个开发者解决过类似的.NET框架核心程序集替换问题,直接给你说结论:完全可以实现,但得绕开.NET 6默认的程序集加载安全限制,还要分场景操作。
先给你理清楚核心逻辑:.NET 6的程序集加载器会优先从「受信任平台程序集(TPA)列表」加载框架核心DLL(比如System.Diagnostics.Process.dll),这些DLL要么来自全局共享框架,要么来自独立发布应用自带的框架目录。要让它加载你放在工作目录的自定义DLL,得明确告诉加载器「别用默认的,用我这个本地的」。
下面是具体的可行方案,按操作难度从易到难排序:
方案一:修改.deps.json强制定向到自定义DLL
这是最直接的方法,适合**框架依赖(Framework-Dependent)**的应用:
- 找到你应用根目录下的
[你的应用名].deps.json文件,用文本编辑器打开 - 搜索
"System.Diagnostics.Process"的条目,它默认大概长这样:"System.Diagnostics.Process": { "version": "6.0.0", "serviceable": true, "sha512": "这里是原框架DLL的哈希值" } - 把它改成这样:
"System.Diagnostics.Process": { "version": "6.0.0", "path": "System.Diagnostics.Process.dll", "sha512": "这里换成你自定义DLL的SHA512哈希值" }注意:哈希值必须完全匹配!你可以用
dotnet hash System.Diagnostics.Process.dll命令生成正确的哈希字符串,复制进去就行 - 把你的自定义
System.Diagnostics.Process.dll放到应用的工作目录,和.exe同级别 - 启动应用,加载器就会优先读取你指定的本地DLL了
如果是**独立发布(Self-Contained)**的应用,操作更简单:
- 找到发布目录里的
runtimes/[你的系统RID]/lib/net6.0文件夹(比如Windows x64就是runtimes/win-x64/lib/net6.0) - 把里面原生的
System.Diagnostics.Process.dll替换成你的自定义版本,同样要保证版本号、哈希完全匹配 - 直接启动应用即可
方案二:用启动钩子(Startup Hook)拦截加载
如果修改.deps.json对你来说不太方便(比如应用会自动生成这个文件),可以用.NET的启动钩子机制来动态拦截程序集加载:
- 写一个简单的类库项目,代码如下:
using System; using System.IO; using System.Runtime.Loader; namespace ProcessHook { public class StartupHook { public static void Initialize() { // 拿到自定义DLL的路径 var customDllPath = Path.Combine(Directory.GetCurrentDirectory(), "System.Diagnostics.Process.dll"); // 给默认的程序集加载上下文添加解析钩子 AssemblyLoadContext.Default.Resolving += (ctx, assemblyName) => { if (assemblyName.Name.Equals("System.Diagnostics.Process", StringComparison.OrdinalIgnoreCase)) { return ctx.LoadFromAssemblyPath(customDllPath); } return null; }; } } } - 把这个类库编译成.NET 6的DLL,放到应用工作目录
- 启动应用前,设置环境变量:
set DOTNET_STARTUP_HOOKS=ProcessHook.dll(Windows)或者export DOTNET_STARTUP_HOOKS=ProcessHook.dll(Linux/macOS) - 启动应用,钩子会在应用初始化前拦截Process.dll的加载,转而加载你的自定义版本
要踩的坑和注意事项
- 版本和哈希必须严格匹配:.NET 6的加载器会校验程序集的版本号、哈希值,不匹配直接拒绝加载,别偷懒跳过这一步
- 共享框架的优先级问题:如果是框架依赖的应用,你必须在
.deps.json里明确指定本地路径,否则加载器还是会从全局共享框架拿DLL - 安全限制:如果你的应用跑在有安全策略的环境里(比如企业域、云托管平台),自定义框架DLL可能会被安全软件拦截,或者被.NET的安全机制阻止
- 兼容性风险:替换核心框架DLL可能会导致其他依赖
System.Diagnostics.Process的代码出问题,比如某些第三方库依赖原生行为,建议先在测试环境充分验证
额外的替代思路
其实你要实现的是「把alpha.exe替换成beta.exe」,不一定非要替换Process.dll——如果能修改原应用的代码,直接在调用Process.Start()前替换FileName就行;如果不能改原代码,也可以用IL织入或者反射拦截的方式,在运行时修改ProcessStartInfo.FileName的赋值,这样比替换框架DLL更安全,也不容易出兼容性问题。
比如用反射直接修改私有字段的示例(如果能在自己的辅助DLL里执行的话):
var processStartInfo = new ProcessStartInfo("alpha.exe"); // 用反射拿到私有字段_fileName var fileNameField = typeof(ProcessStartInfo).GetField("_fileName", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); fileNameField.SetValue(processStartInfo, "beta.exe"); new Process { StartInfo = processStartInfo }.Start();
不过如果完全碰不到原应用的代码,那还是回到前面的替换DLL方案最直接。有问题随时问,我再给你补细节!




