7 个稳定版本
1.1.1 | 2023 年 3 月 31 日 |
---|---|
1.0.9 | 2023 年 3 月 25 日 |
1.0.6 | 2023 年 3 月 24 日 |
1.0.5 | 2023 年 3 月 22 日 |
1.0.4 | 2023 年 3 月 17 日 |
196 在 日期和时间
86 每月下载量
315KB
3K SLoC
ClrOxide
ClrOxide
是一个 Rust 库,允许您托管 CLR 并动态执行 dotnet 二进制文件。
我本来想叫它 Kepler
,但 Cargo 中已经有一个名为 kepler
的包。:(
我已经断断续续地用 Rust 托管 CLR 两年了,但直到两周前才有所突破!
这个库的实现离不开以下项目
- NimPlant 及其 执行汇编 实现
- winim/clear 允许重写 Console.Write 的输出缓冲区并获取输出,其优雅性是本库用了两年才达到的原因。我如何让 Cas 玩 Rust,如果他不复制这个!?我的 Rust 实现为 NimPlant 的工作也是我最初进入这个迷宫的原因。
- go-clr by ropnop
- 在此特别感谢 ropnop!这个库完全是由于
go-clr
中的一个功能,使我一切都豁然开朗,三天内完成了整个库!
- 在此特别感谢 ropnop!这个库完全是由于
- dinvoke_rs by Kudaes
- 类似于
go-clr
,Kurosh 的dinvoke_rs
项目也让 Rust/win32 的复杂性变得清晰,并使项目得以继续进行。
- 类似于
- 各种 CLR 相关的 Rust 库
架构限制
ClrOxide
ClrOxide
仅在编译为 x86_64-pc-windows-gnu
或 x86_64-pc-windows-msvc
时才能正常工作。
针对 i686-pc-windows-gnu
的编译失败,因为存在已知的 rust panic unwinding 问题。它可能使用 i686-pc-windows-msvc
可以工作,但我自己还没有尝试。
汇编
尽管我自己没有遇到过这个问题,但可能存在需要将汇编专门编译为 x64
而不是 Any CPU
的情况。
使用
您可以在 examples/
文件夹中找到更多示例。
运行汇编并捕获其输出
ClrOxide
将在当前进程中加载 CLR,解析 mscorlib
并重定向 System.Console
的输出,最后加载并运行您的可执行文件,并以字符串的形式返回其输出。
目前不支持输出流,尽管我相信用于重定向输出的 CLR 策略魔法可以为愿意实现它的人提供很好的指导。
use clroxide::clr::Clr;
use std::{env, fs, process::exit};
fn main() -> Result<(), String> {
let (path, args) = prepare_args();
let contents = fs::read(path).expect("Unable to read file");
let mut clr = Clr::new(contents, args)?;
let results = clr.run()?;
println!("[*] Results:\n\n{}", results);
Ok(())
}
fn prepare_args() -> (String, Vec<String>) {
let mut args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("Please provide a path to a dotnet executable");
exit(1)
}
let mut command_args: Vec<String> = vec![];
if args.len() > 2 {
command_args = args.split_off(2)
}
let path = args[1].clone();
println!("[+] Running `{}` with given args: {:?}", path, command_args);
return (path, command_args);
}
使用自定义应用域
您可以通过更新上下文来使用自定义应用域。如果您想避免 DefaultDomain
,这可能会很有用。有关更多详细信息,请参阅 examples/custom_app_domain.rs
。
...
let app_domain = clr.using_runtime_host(|host| {
let app_domain = unsafe { (*host).create_domain("CustomDomain")? };
Ok(app_domain)
})?;
clr.use_app_domain(app_domain)?;
...
为 mscoree.dll
使用自定义加载器
我们需要从 mscoree.dll
加载 CreateInterface
函数以启动 CLR。您可以通过禁用默认功能来提供自定义加载器。
首先,将 default-features = false
添加到您的依赖声明中。
clroxide = { version = "1.0.6", default-features = false }
然后提供一个具有以下签名的函数,它返回在创建 Clr 实例时指向 CreateInterface
函数的指针:fn() -> Result<isize, String>
litcrypt::use_litcrypt!();
fn load_function() -> Result<isize, String> {
let library = custom_load_library_a(lc!("mscoree.dll\0"));
if library == 0 {
return Err("Failed".into());
}
let function = custom_get_process_address(library, lc!("CreateInterface\0"));
if function == 0 {
return Err("Failed".into());
}
Ok(function)
}
fn main() -> Result<(), String> {
// ...
let mut context = Clr::new(contents, args, load_function)?;
// ...
}
修改 System.Environment.Exit
以不退出
您可以使用 ClrOxide
提供的构建块来修改 System.Environment.Exit
,如 MDSec 在 Massaging your CLR: Preventing Environment.Exit in In-Process .NET Assemblies 中所述。
您可以在 examples/patch_exit.rs
中查看参考实现。由于这需要使用 VirtualProtect
或 NtProtectVirtualMemory
,所以我打算不将其添加为 ClrOxide
的功能。
依赖项
~130MB
~2M SLoC