
مكتبة Rust تسمح لك باستضافة CLR وتنفيذ ملفات dotnet الثنائية.
ClrOxide هي مكتبة رست تتيح لك استضافة CLR وتنفيذ ملفات dotnet الثنائية ديناميكيًا.
أردت تسميتها Kepler من دون سبب معين، لكن هناك بالفعل حزمة باسم kepler في cargo. :(
لقد عملت على استضافة CLR باستخدام رست بشكل متقطع لمدة عامين، وأخيرًا اتضحت الأمور منذ أسبوعين!
لم تكن هذه المكتبة ممكنة لولا المشاريع التالية:
winim/clr استبدال المخزن المؤقت للمخرجات لـ Console.Write والحصول على المخرجات! السعي لتحقيق نفس الأناقة هو السبب الوحيد الذي جعل هذه المكتبة تستغرق عامين. كيف يمكنني إقناع Cas بخوض تجربة رست إذا كان لا يستطيع تكرار هذا!؟ إن عملي على أداة رست لـ NimPlant هو أيضًا ما قادني إلى هذه المتاهة في المقام الأول.go-clr جعل كل شيء يتضح لدي فجأة!go-clr، فإن مشروع Kurosh dinvoke_rs جعل أيضًا بعض التعقيدات في rust/win32 أكثر وضوحًا وساعد المشروع على المضي قدمًا.تعمل ClrOxide فقط عند ترجمتها لـ x86_64-pc-windows-gnu أو x86_64-pc-windows-msvc.
تفشل الترجمة لـ i686-pc-windows-gnu بسبب مشكلات معروفة في آلية unwinding عند panic في رست. قد تعمل مع i686-pc-windows-msvc، لكنني لم أجرّبها بنفسي.
على الرغم من أنني لم أواجه هذه المشكلة بنفسي، فقد تكون هناك حالات تحتاج فيها إلى ترجمة التجميعة الخاصة بك تحديدًا كـ x64 بدلاً من Any CPU.
لم تكن حزمة windows (crate) تحتوي على تعريفات أنواع لـ mscoree.dll حتى بضعة أسابيع مضت. يبدو أن تعريفات mscoree.dll قد وجدت طريقها إلى حزمة windows في الإصدار 0.48.0. ومع ذلك، لا يبدو أن هذه التعريفات تعمل بشكل صحيح. فقط كمثال؛ إدخال vtable من المفترض أن يشير إلى دالة داخل خيط (thread) CLR (لنقل عند العنوان 0x7ffef16821a0)، يعيد بطريقة ما عنوانًا بعيدًا جدًا عن النطاق (0x750003cac9053b48).
تقوم حزمة windows (crate) بالكثير من الأمور المتقنة مع vtables من أجل السلامة، ولكن من المفارقة أن هذه الأمور على الأرجح تسبب انتهاك الوصول المذكور أعلاه. أو أن شيئًا آخر يحدث... كنت أنوي استخدام التعريفات الرسمية للإصدار 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نحتاج إلى تحميل دالة CreateInterface من mscoree.dll لبدء تشغيل CLR. يمكنك توفير محمّل مخصص عن طريق تعطيل الميزات الافتراضية.
أولاً، أضف default-features = false إلى تعريف اعتماديتك.
clroxide = { version = "1.0.6", default-features = false }
ثم وفر دالة بتوقيع fn() -> Result<isize, String> تُرجع مؤشرًا إلى دالة CreateInterface عند إنشاء مثيل Clr.
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 كما هو موصوف في Massaging your CLR: Preventing Environment.Exit in In-Process .NET Assemblies من إعداد MDSec.
يمكنك الاطلاع على التنفيذ المرجعي في examples/patch_exit.rs. نظرًا لأن هذا يتطلب استخدام VirtualProtect أو NtProtectVirtualMemory، فلا أنوي إضافة هذه الميزة إلى ClrOxide.