Skip to content
KitploitKITPLOIT
أدواتعمليات الاستغلالالمدونة
Log in
إرسال
أدواتعمليات الاستغلالالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

الخلاصاتاتصالالخصوصية© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
Unwinder — استدعاء تزوير مكدس الاستدعاءات لـ Rust | Kitploit
أدوات/GitHubGitHub/kudaes/unwinder
التهرب من IDS/IPSما بعد الاستغلالالفريق الأحمرتطوير الحمولاتالهجوم العدائي
GitHubkudaes/unwinder

Unwinder

استدعاء تزوير مكدس الاستدعاءات لـ Rust

عرض المستودع
3843616منذ سنة واحدةتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

المحتوى

  • SilentMoonWalk
    • الوصف
    • الفضل
    • الاستخدام
      • ماكرو call_function!()
      • ماكرو indirect_syscall!()
      • تمرير الوسائط
    • أمثلة
      • استدعاء kernel32.dll!Sleep()
      • استدعاء kernel32.dll!OpenProcess()
      • استدعاء NtDelayExecution كاستدعاء نظام غير مباشر
      • تسلسل استدعاءات الماكرو
    • اعتبارات
      • الإطار الأولي
      • إثبات المفهوم
  • استبدال المكدس
    • وصف التقنية
    • كيفية الاستخدام
    • مثال عملي
    • ملاحظات

SilentMoonWalk

الوصف

توفر Unwinder تسليحًا كاملًا لتقنية SilentMoonWalk، مما يسمح بالحصول على تزييف كامل ومستقر لمكدس الاستدعاءات في Rust.

تتميز هذه التقنية بالخصائص التالية:

  • دعم تشغيل أي دالة تعسفية بحد أقصى 11 وسيطًا.
  • دعم تنفيذ استدعاءات النظام غير المباشرة (دون تخصيصات إضافية في الكومة) بحد أقصى 11 وسيطًا.
  • تسمح هذه الحزمة (crate) باسترجاع القيمة التي تُرجعها الدوال المستدعاة من خلالها.
  • يمكن تسلسل عملية التزييف أي عدد من المرات دون زيادة حجم مكدس الاستدعاءات.
  • يُستخدم TLS لزيادة الكفاءة أثناء عملية التزييف.
  • يُستخدم dinvoke_rs لإجراء أي استدعاء لواجهة برمجة تطبيقات Windows تتطلبه الحزمة.

الفضل

كل التقدير لمبتكري تقنية SilentMoonWalk:

  • KlezVirus
  • Waldo-IRC
  • Trickster0

وبالطبع تحية كبيرة إلى namazso بفضل السلسلة على تويتر التي ألهمت هذا المشروع بأكمله.

الاستخدام

استورد هذه الحزمة إلى مشروعك بإضافة السطر التالي إلى ملف cargo.toml وقم بالترجمة في وضع release:

[dependencies]
unwinder = "=0.1.4"

تم تغليف الوظيفة الرئيسية لهذه الحزمة في ماكرون:

  • يتيح ماكرو call_function!() تشغيل أي دالة تعسفية بمكدس استدعاءات نظيف.
  • ينفذ ماكرو indirect_syscall!() استدعاء النظام (غير المباشر) المحدد بمكدس استدعاءات نظيف.

لاستخدام أي من هذين الماكروين، يلزم استيراد نوع البيانات std::ffi::c_void.

يعيد كلا الماكروين قيمة من نوع *mut c_void يمكن استخدامها لاسترجاع القيمة التي تُرجعها الدالة المنفذة. معلومات أكثر تفصيلًا في قسم الأمثلة.

ماكرو call_function

يُستخدم هذا الماكرو لاستدعاء أي دالة مرغوبة بمكدس استدعاءات نظيف. يتوقع الماكرو الوسائط التالية:

  • الوسيط الأول هو عنوان الذاكرة الذي سيتم الاستدعاء إليه بعد تزييف مكدس الاستدعاءات. يجب تمرير هذا الوسيط كنوع usize أو isize أو مؤشر.
  • الوسيط الثاني هو قيمة منطقية (bool) تشير إلى ما إذا كان سيتم الاحتفاظ بإطار دالة البداية أم لا. إذا لم تكن متأكدًا من ذلك، فاضبطه على false فهو يضمن دائمًا مكدس استدعاءات سليمًا.
  • الوسائط التالية هي تلك الوسائط التي سيتم إرسالها إلى الدالة بعد تزييف مكدس الاستدعاءات.

ماكرو indirect_syscall

يُستخدم هذا الماكرو لتنفيذ أي استدعاء نظام غير مباشر مرغوب بمكدس استدعاءات نظيف. يتوقع الماكرو الوسائط التالية:

  • الوسيط الأول هو سلسلة نصية تحتوي على اسم دالة NT التي تريد تنفيذ استدعاء النظام الخاص بها.
  • الوسيط الثاني هو قيمة منطقية (bool) تشير إلى ما إذا كان سيتم الاحتفاظ بإطار دالة البداية أم لا. إذا لم تكن متأكدًا من ذلك، فاضبطه على false فهو يضمن دائمًا مكدس استدعاءات سليمًا.
  • الوسائط التالية هي تلك الوسائط التي سيتم إرسالها إلى دالة NT.

تمرير الوسائط

من أجل تمرير وسائط من أنواع مختلفة إلى هذين الماكروين، يجب مراعاة الاعتبارات التالية:

  • يمكن تمرير أي نوع بيانات أساسي يمكن تحويله إلى usize (u8-u64، i8-i64، bool، إلخ) مباشرة إلى الماكروين.
  • يتم تمرير البنى (structs) والاتحادات (unions) ذات الحجم 8 أو 16 أو 32 أو 64 بت كما لو كانت أعدادًا صحيحة بنفس الحجم.
  • يجب تمرير البنى والاتحادات التي يزيد حجمها عن 64 بت كمؤشر.
  • يجب تمرير السلاسل النصية (&str و String) كمؤشر.
  • يتم تمرير المؤشرات الفارغة (ptr::null()، ptr::null_mut()، إلخ) كقيمة 0 (بغض النظر عما إذا كانت u8 أو u16 أو i32 أو غير ذلك).
  • الوسائط ذات الفاصلة العائمة والدقة المزدوجة غير مدعومة حاليًا.
  • يجب تمرير أي نوع بيانات آخر كمؤشر.

أمثلة

استدعاء Sleep

let k32 = dinvoke_rs::dinvoke::get_module_base_address("kernel32.dll");
let sleep = dinvoke_rs::dinvoke::get_function_address(k32, "Sleep"); // Memory address of kernel32.dll!Sleep() 
let miliseconds = 1000i32;
unwinder::call_function!(sleep, false, miliseconds);

استدعاء OpenProcess

let k32 = dinvoke_rs::dinvoke::get_module_base_address("kernel32.dll"); 
let open_process: isize = dinvoke_rs::dinvoke::get_function_address(k32, "Openprocess");
let desired_access: u32 = 0x1000;
let inherit = 0i32;
let pid = 20628i32;
let handle = unwinder::call_function!(open_process, false, desired_access, inherit, pid); // returns *mut c_void
let handle: HANDLE = std::mem::transmute(handle);
println!("Handle id: {:x}", handle.0);

لاحظ أن الماكرو يُرجع قيمة من نوع *mut c_void يمكن تحويلها مباشرة إلى HANDLE نظرًا لأن كلا النوعين لهما نفس الحجم. وهذا يتيح الوصول إلى القيمة التي يُرجعها OpenProcess، وهي المقبض الجديد للعملية الهدف.

استدعاء NtDelayExecution كاستدعاء نظام غير مباشر

let large = 0x8000000000000000 as u64; // Sleep indefinitely
let large: *mut i64 = std::mem::transmute(&large);
let alertable = false;
let ntstatus = unwinder::indirect_syscall!("NtDelayExecution", false, alertable, large); // returns *mut c_void
println!("ntstatus: {:x}", ntstatus as i32);

لاحظ أن الماكرو يُرجع قيمة من نوع *mut c_void يمكن استخدامها لاسترجاع NTSTATUS التي يُرجعها NtDelayExecution.

تسلسل استدعاءات الماكرو

يمكن تسلسل عملية التزييف أي عدد من المرات دون زيادة غير طبيعية في حجم مكدس الاستدعاءات. كما سيتم الحفاظ على تدفق التنفيذ. الكود التالي مثال على ذلك:

fn main()
{
	function_a();
}

fn function_a()
{
	unsafe
	{
		let func_b = function_b as usize;
		call_function!(func_b, false);
		println!("function_a done.");
	}
}

fn function_b()
{
	unsafe
	{
		let func_c = function_c as usize;
		call_function!(func_c, false);
		println!("function_b done.")
	}
}

fn function_c()
{
	unsafe
	{
		let large = 0x0000000000000000 as u64; // Don't sleep so we return to function_b, allowing to check the execution flow preservation.
		let large: *mut i64 = std::mem::transmute(&large);
		let alertable = false;
		let ntstatus = unwinder::indirect_syscall!("NtDelayExecution", false, alertable, large);
		println!("ntstatus: {:x}", (ntstatus as usize) as i32); //NTSTATUS is a i32, although that second casting is not really required in this case.
	}
}

اعتبارات

الإطار الأولي

إذا ضبطت الوسيط الثاني على true (في كلا الماكروين)، فستحاول عملية التزييف الاحتفاظ بإطار عنوان بداية الخيط في مكدس الاستدعاءات لزيادة الشرعية.

مكدس استدعاءات مُزيَّف مع الاحتفاظ بالوحدة الرئيسية.

أحيانًا، لا تنفذ دالة بداية الخيط استدعاء call لدالة لاحقة (على سبيل المثال، يتم تنفيذ تعليمة jmp بدلاً من ذلك)، مما يعني عدم وجود عنوان عودة مدفوع على المكدس. في هذا السيناريو (وأيضًا إذا ضبطت الوسيط الثاني على false)، سيبدأ مكدس الاستدعاءات المُزيَّف من إطار BaseThreadInitThunk.

مكدس استدعاءات مُزيَّف دون الوحدة الرئيسية.

إثبات المفهوم

تنزيل الأداة