
एक Rust लाइब्रेरी जो आपको CLR को होस्ट करने और dotnet बाइनरी निष्पादित करने की अनुमति देती है।
ClrOxide एक rust लाइब्रेरी है जो आपको CLR होस्ट करने और dotnet बाइनरीज़ को डायनामिक रूप से निष्पादित करने की अनुमति देती है।
मैं इसे बिना किसी विशेष कारण के Kepler कहना चाहता था, लेकिन cargo में पहले से ही kepler नाम का एक पैकेज है। :(
मैं पिछले 2 वर्षों से rust के साथ CLR होस्टिंग पर रुक-रुक कर काम कर रहा हूँ, और आखिरकार दो सप्ताह पहले कुछ समझ में आया!
यह लाइब्रेरी निम्नलिखित प्रोजेक्ट्स के बिना संभव नहीं होती:
winim/clr Console.Write के लिए आउटपुट बफर को ओवरराइट करने और आउटपुट प्राप्त करने की अनुमति देता है! उसी सुंदरता के लिए प्रयास करना ही इस लाइब्रेरी को दो साल लगने का एकमात्र कारण है।
अगर वह इसे दोहरा नहीं सकता तो मैं Cas को rust के साथ प्रयोग करने के लिए कैसे मना सकता हूँ!? NimPlant के लिए rust इम्प्लांट पर मेरा काम भी वही है जिसने मुझे शुरू में इस उलझन में डाला।go-clr में किसी चीज़ के कारण जिसने मेरे लिए सब कुछ स्पष्ट कर दिया!go-clr के समान, Kurosh का dinvoke_rs प्रोजेक्ट भी कुछ rust/win32 जटिलताओं को स्पष्ट करता है और प्रोजेक्ट को आगे बढ़ाने में सक्षम बनाता है।ClrOxide केवल तभी काम करता है जब इसे x86_64-pc-windows-gnu या x86_64-pc-windows-msvc के लिए संकलित किया जाए।
i686-pc-windows-gnu के लिए संकलन rust panic unwinding की ज्ञात समस्याओं के कारण विफल रहता है। यह i686-pc-windows-msvc के साथ काम कर सकता है, लेकिन मैंने इसे स्वयं नहीं आज़माया है।
हालाँकि मुझे स्वयं यह समस्या नहीं आई है, ऐसे मामले हो सकते हैं जहाँ आपको अपनी असेंबली को Any CPU के बजाय विशेष रूप से x64 के रूप में संकलित करने की आवश्यकता हो।
windows crate में कुछ सप्ताह पहले तक mscoree.dll के लिए कोई प्रकार परिभाषाएँ नहीं थीं। ऐसा लगता है कि mscoree.dll की परिभाषाएँ windows crate के संस्करण 0.48.0 में शामिल हो गई हैं। हालाँकि, ये परिभाषाएँ सही ढंग से काम करती नहीं दिख रही हैं। एक उदाहरण के रूप में; एक vtable प्रविष्टि जो CLR थ्रेड के भीतर किसी फ़ंक्शन की ओर इंगित करनी चाहिए (मान लीजिए पते 0x7ffef16821a0 पर), किसी तरह एक ऐसा पता लौटाती है जो सीमा से काफी बाहर है (0x750003cac9053b48)।
windows crate सुरक्षा के लिए vtables के साथ बहुत सारी आकर्षक चीज़ें करता है, लेकिन विडंबना यह है कि ये संभवतः उपरोक्त access violation का कारण बन रही हैं। या कुछ और हो रहा है... मेरा इरादा रखरखाव का बोझ कम करने के लिए V2 के लिए आधिकारिक परिभाषाओं का उपयोग करने का था, लेकिन यह एक अड़चन है।
आप 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 के लिए कस्टम लोडर का उपयोग करेंCLR को आरंभ करने के लिए हमें mscoree.dll से CreateInterface फ़ंक्शन को लोड करना होगा। आप डिफ़ॉल्ट सुविधाओं को अक्षम करके एक कस्टम लोडर प्रदान कर सकते हैं।
सबसे पहले, अपनी निर्भरता घोषणा में default-features = false जोड़ें।
clroxide = { version = "1.0.6", default-features = false }
और फिर Clr इंस्टेंस बनाते समय fn() -> Result<isize, String> हस्ताक्षर वाला एक फ़ंक्शन प्रदान करें जो CreateInterface फ़ंक्शन के लिए एक पॉइंटर लौटाता है।
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 में एक सुविधा के रूप में जोड़ने का इरादा नहीं रखता।