Crate rustclr

Source
Expand description

§rustclr 🦀

Rust crate docs Forks Stars License

rustclr is a powerful library for hosting the Common Language Runtime (CLR) and executing .NET binaries directly with Rust, among other operations.

§Table of Contents

§Features

  • ✅ Run .NET binaries in memory with full control over runtime configurations
  • ✅ Fine-grained control over the CLR environment and runtime initialization
  • ✅ Configure output redirection to capture .NET program output

§Installation

Add rustclr to your project by updating your Cargo.toml:

cargo add rustclr

Or manually add the dependency:

[dependencies]
rustclr = "<version>"

§Usage

§Running a .NET Assembly with Configured Flags

The following flags provide full control over your CLR environment and the execution of your .NET assemblies:

  • .with_runtime_version(RuntimeVersion::V4): Sets the .NET runtime version (e.g., RuntimeVersion::V2, RuntimeVersion::V3, RuntimeVersion::V4). This flag ensures that the assembly runs with the specified CLR version.
  • .with_output_redirection(true): Redirects the output from the .NET assembly’s console to the Rust environment, capturing all console output.
  • .with_domain("DomainName"): Sets a custom AppDomain name, which is useful for isolating different .NET assemblies.
  • .with_args(vec!["arg1", "arg2"]): Passes arguments to the .NET application, useful for parameterized entry points in the assembly.

Using rustclr to load and execute a .NET assembly, redirect its output and customize the CLR runtime environment.

use std::fs;
use rustclr::{RustClr, RuntimeVersion};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load a sample .NET assembly into a buffer
    let buffer = fs::read("examples/sample.exe")?;

    // Create and configure a RustClr instance with runtime version and output redirection
    let output = RustClr::new(&buffer)?
        .with_runtime_version(RuntimeVersion::V4) // Specify .NET runtime version
        .with_output_redirection(true) // Redirect output to capture it in Rust
        .with_domain("CustomDomain") // Optionally set a custom application domain
        .with_args(vec!["arg1", "arg2"]) // Pass arguments to the .NET assembly's entry point
        .run()?; // Execute the assembly

    println!("Captured output: {}", output);

    Ok(())
}

§Configuration with RustClrEnv and ClrOutput

For more fine-grained control, rustclr provides the RustClrEnv and ClrOutput components:

  • RustClrEnv: Allows for low-level customization and initialization of the .NET runtime environment, which is useful if you need to manually control the CLR version, MetaHost, runtime information, and application domain. This struct provides an alternative way to initialize a CLR environment without executing an assembly immediately.
use rustclr::{RustClrEnv, RuntimeVersion};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a new environment for .NET with a specific runtime version
    let clr_env = RustClrEnv::new(Some(RuntimeVersion::V4))?;
    println!("CLR environment initialized successfully with version {:?}", clr_env.runtime_version);

    Ok(())
}
  • ClrOutput: Manages redirection of standard output and error streams from .NET to Rust. This is especially useful if you need to capture and process all output produced by .NET code within a Rust environment.
use rustclr::{
    RustClrEnv, ClrOutput, 
    Invocation, Variant
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create and initialize the CLR environment
    let clr = RustClrEnv::new(None)?;
    let mscorlib = clr.app_domain.load_lib("mscorlib")?;
    let console = mscorlib.resolve_type("System.Console")?;

    // Set up output redirection
    let mut clr_output = ClrOutput::new(&mscorlib);
    clr_output.redirect()?;

    // Prepare the arguments
    let args = vec!["Hello World".to_variant()];

    // Invoke the WriteLine method
    console.invoke("WriteLine", None, Some(args), Invocation::Static)?;

    // Restore the original output and capture redirected content
    clr_output.restore()?;
    let output = clr_output.capture()?;

    print!("{output}");

    Ok(())
}

§Additional Resources

For more examples, check the examples folder in the repository.

§CLI

rustclr also includes a command-line interface (CLI) for running .NET assemblies with various configuration options. Below is a description of the available flags and usage examples.

The CLI accepts the following options:

  • -f, --file: Specifies the path to the .NET assembly file to be executed (required).
  • -i, --inputs: Provides string arguments to be passed to the .NET program’s entry point. This flag can be repeated to add multiple arguments.
  • -r, --runtime-version: Sets the .NET runtime version to use. Accepted values include "v2", "v3", and "v4". Defaults to "v4".
  • -d, --domain: Allows setting a custom name for the application domain (optional).

§Example Command

clr.exe -f Rubeus.exe -i "triage" -i "/consoleoutfile:C:\Path" -r v4 -d "CustomDomain"

§Contributing to rustclr

To contribute to rustclr, follow these steps:

  1. Fork this repository.
  2. Create a branch: git checkout -b <branch_name>.
  3. Make your changes and commit them: git commit -m '<commit_message>'.
  4. Push your changes to your branch: git push origin <branch_name>.
  5. Create a pull request.

Alternatively, consult the GitHub documentation on how to create a pull request.

§References

§License

This project is licensed under the MIT License. See the LICENSE file for details.

Modules§

com
Contains definitions for COM interoperability, making it easier to call methods and manipulate COM interfaces.
data
Defines data structures and descriptions for manipulating and interacting with the CLR.
error
Manages specific error types used when interacting with the CLR and COM APIs.

Structs§

ClrOutput
Manages output redirection in the CLR by using a StringWriter.
RustClr
Represents a Rust interface to the Common Language Runtime (CLR).
RustClrEnv
Represents a simplified interface to the CLR components without loading assemblies.

Enums§

Invocation
Specifies the invocation type for a method, indicating if it is static or instance-based.
RuntimeVersion
Represents the .NET runtime versions supported by RustClr.

Traits§

Variant
Trait to convert various Rust types to Windows COM-compatible VARIANT types.
WinStr
The WinStr trait provides methods for working with BSTRs (Binary String), a format commonly used in Windows API. BSTRs are wide strings (UTF-16) with specific memory layouts, used for interoperation with COM (Component Object Model) and other Windows-based APIs.

Functions§

create_safe_args
Creates a SAFEARRAY from a vector of VARIANT elements.
create_safe_array_args
Creates a SAFEARRAY from a vector of elements implementing the Variant trait.
create_safe_array_buffer
Creates a SAFEARRAY from a byte buffer for loading assemblies.