mirror of
https://github.com/yamakadi/clroxide
synced 2026-06-08 18:28:14 +00:00
allow creating and using a custom app domain
This commit is contained in:
@@ -85,6 +85,28 @@ fn prepare_args() -> (String, Vec<String>) {
|
||||
}
|
||||
```
|
||||
|
||||
### Use a custom app domain
|
||||
|
||||
<img width="563" alt="assembly_arch" src="./docs/images/using_custom_app_domain.png">
|
||||
|
||||
You can update the context to use a custom app domain. This can be useful if you want to avoid `DefaultDomain`. Check out [`examples/custom_app_domain.rs`](examples/custom_app_domain.rs) for more details.
|
||||
|
||||
```rust
|
||||
...
|
||||
|
||||
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)?;
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Use a custom loader for `mscoree.dll`
|
||||
|
||||
We need to load the `CreateInterface` function from `mscoree.dll` to kickstart the CLR. You can provide a custom loader by disabling default features.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
@@ -0,0 +1,45 @@
|
||||
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 app_domain = clr.using_runtime_host(|host| {
|
||||
let app_domain = unsafe { (*host).create_domain("CustomDomain")? };
|
||||
|
||||
Ok(app_domain)
|
||||
})?;
|
||||
|
||||
clr.use_app_domain(app_domain)?;
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -86,6 +86,28 @@ impl Clr {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn using_runtime_host<T>(
|
||||
&mut self,
|
||||
callback: fn(*mut ICorRuntimeHost) -> Result<T, String>,
|
||||
) -> Result<T, String> {
|
||||
let context = self.get_context()?;
|
||||
let runtime_host = context.runtime_host;
|
||||
|
||||
callback(runtime_host)
|
||||
}
|
||||
|
||||
pub fn use_app_domain(&mut self, app_domain: *mut _AppDomain) -> Result<(), String> {
|
||||
if self.context.is_none() {
|
||||
return Err("CLR Context has not been initialized".into());
|
||||
}
|
||||
|
||||
let context = self.context.as_mut().unwrap();
|
||||
|
||||
context.app_domain = app_domain;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Result<String, String> {
|
||||
self.redirect_output()?;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::{ffi::c_void, ops::Deref, ptr};
|
||||
use windows::core::BSTR;
|
||||
|
||||
use crate::primitives::{
|
||||
Class, IUnknown, IUnknownVtbl, Interface, _AppDomain, GUID, HANDLE, HINSTANCE, HRESULT,
|
||||
@@ -116,6 +117,53 @@ impl ICorRuntimeHost {
|
||||
Ok(app_domain)
|
||||
}
|
||||
|
||||
pub fn create_domain(&self, domain: &str) -> Result<*mut _AppDomain, String> {
|
||||
let domain_name = BSTR::from(domain);
|
||||
let mut unknown_array: *mut IUnknown = ptr::null_mut();
|
||||
let mut unknown: *mut IUnknown = ptr::null_mut();
|
||||
|
||||
let hr = unsafe {
|
||||
(*self).CreateDomain(
|
||||
domain_name.into_raw() as *const _ as *const u16,
|
||||
unknown_array,
|
||||
&mut unknown,
|
||||
)
|
||||
};
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!(
|
||||
"Could not create app domain `{}`: {:?}",
|
||||
domain, hr
|
||||
));
|
||||
}
|
||||
|
||||
if unknown.is_null() {
|
||||
return Err(format!("Could not create app domain `{}`", domain));
|
||||
}
|
||||
|
||||
let mut app_domain: *mut _AppDomain = ptr::null_mut();
|
||||
|
||||
let hr = unsafe {
|
||||
(*unknown).QueryInterface(
|
||||
&_AppDomain::IID,
|
||||
&mut app_domain as *mut *mut _ as *mut *mut c_void,
|
||||
)
|
||||
};
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!(
|
||||
"Could not create app domain `{}`: {:?}",
|
||||
domain, hr
|
||||
));
|
||||
}
|
||||
|
||||
if app_domain.is_null() {
|
||||
return Err(format!("Could not create app domain `{}`", domain));
|
||||
}
|
||||
|
||||
Ok(app_domain)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn CreateLogicalThreadState(&self) -> HRESULT {
|
||||
((*self.vtable).CreateLogicalThreadState)(self as *const _ as *mut _)
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace WithArgs
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine($"[*] Hello World from `{Assembly.GetExecutingAssembly().FullName}`!");
|
||||
Console.WriteLine($"[*] I am running in `{AppDomain.CurrentDomain}`!");
|
||||
Console.WriteLine($"[*] I was given {args.Length} arguments");
|
||||
|
||||
foreach (var s in args)
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace WithExit
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine($"[*] Hello World from `{Assembly.GetExecutingAssembly().FullName}`!");
|
||||
Console.WriteLine($"[*] I am running in `{AppDomain.CurrentDomain}`!");
|
||||
Console.WriteLine("[*] I very much hope to live past `System.Environment.Exit`!");
|
||||
Console.WriteLine();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace WithoutArgs
|
||||
public static void Main()
|
||||
{
|
||||
Console.WriteLine($"[*] Hello World from `{Assembly.GetExecutingAssembly().FullName}`!");
|
||||
Console.WriteLine($"[*] I am running in `{AppDomain.CurrentDomain}`!");
|
||||
Console.WriteLine("[*] I have no arguments and live a happy life!");
|
||||
Console.WriteLine("[*] Bye!");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user