Skip to content
تم إنشاء هذه الصفحة وترجمتها بمساعدة الذكاء الاصطناعي. إذا لاحظت أي أخطاء، لا تتردد في المساهمة في تحسينها. تعديل على GitHub

تطوير إضافات WASM

يتضمن PRX-SD نظام إضافات مدعوم بـ Wasmtime يتيح لك توسيع محرك الكشف بماسحات مخصصة مكتوبة بأي لغة تُترجَم إلى WebAssembly (Rust وGo وC وAssemblyScript وغيرها). تعمل الإضافات في بيئة WASM آمنة بحدود موارد قابلة للتهيئة.

البنية المعمارية

~/.prx-sd/plugins/
  my-scanner/
    plugin.json          # Plugin manifest
    my_scanner.wasm      # Compiled WASM module
  another-plugin/
    plugin.json
    another_plugin.wasm

عند بدء تشغيل محرك الفحص، يمشي PluginRegistry عبر دليل الإضافات، ويُحمِّل كل دليل فرعي يحتوي على plugin.json، ويُجمِّع وحدة WASM، ويستدعي تصدير on_load للإضافة. أثناء الفحص، يُستدعى كل إضافة تتطابق file_types وplatforms الخاصة بها مع الملف الحالي بالتسلسل.

تدفق التنفيذ

  1. الاكتشاف -- يجد PluginRegistry ملفات plugin.json في ~/.prx-sd/plugins/
  2. التجميع -- يُجمِّع Wasmtime وحدة .wasm مع قياس الوقود وحدود الذاكرة
  3. التهيئة -- يُستدعى on_load()؛ تُقرأ plugin_name() وplugin_version()
  4. الفحص -- لكل ملف، يُستدعى scan(ptr, len) -> score مع بيانات الملف
  5. التقرير -- تستدعي الإضافات report_finding() لتسجيل التهديدات، أو تُعيد درجة غير صفرية

بيان الإضافة (plugin.json)

يجب أن يحتوي كل دليل إضافة على plugin.json يصف الإضافة وقيود بيئتها الآمنة:

json
{
  "name": "Example Scanner",
  "version": "0.1.0",
  "author": "prx-sd",
  "description": "Example plugin that detects MALICIOUS_MARKER string",
  "wasm_file": "example_plugin.wasm",
  "platforms": ["all"],
  "file_types": ["all"],
  "min_engine_version": "0.1.0",
  "permissions": {
    "network": false,
    "filesystem": false,
    "max_memory_mb": 64,
    "max_exec_ms": 5000
  }
}

حقول البيان

الحقلالنوعمطلوبالوصف
namestringنعماسم الإضافة القابل للقراءة
versionstringنعمالإصدار الدلالي للإضافة
authorstringنعممؤلف الإضافة أو المنظمة
descriptionstringنعموصف موجز لما تكتشفه الإضافة
wasm_filestringنعماسم ملف وحدة WASM المُجمَّعة (نسبي لدليل الإضافة)
platformsstring[]نعمالمنصات المستهدفة: "linux"، "macos"، "windows"، أو "all"
file_typesstring[]نعمأنواع الملفات للفحص: "pe"، "elf"، "macho"، "pdf"، أو "all"
min_engine_versionstringنعمالحد الأدنى لإصدار محرك PRX-SD المطلوب
permissions.networkbooleanلاهل يمكن للإضافة الوصول إلى الشبكة (الافتراضي: false)
permissions.filesystembooleanلاهل يمكن للإضافة الوصول إلى نظام الملفات المضيف عبر WASI (الافتراضي: false)
permissions.max_memory_mbintegerلاالحد الأقصى للذاكرة الخطية بالميجابايت (الافتراضي: 64)
permissions.max_exec_msintegerلاالحد الأقصى لوقت التنفيذ الجداري بالملليثانية (الافتراضي: 5000)

صادرات WASM المطلوبة

يجب أن تُصدِّر وحدة WASM الوظائف التالية:

scan(ptr: i32, len: i32) -> i32

نقطة دخول الفحص الرئيسية. تستقبل مؤشراً وطولاً لبيانات الملف في ذاكرة الضيف. تُعيد درجة تهديد من 0 إلى 100:

  • 0 = نظيف
  • 1-29 = معلوماتي
  • 30-59 = مشبوه
  • 60-100 = ضار

memory

يجب أن تُصدِّر الوحدة ذاكرتها الخطية كـ memory حتى يتمكن المضيف من كتابة بيانات الملف وقراءة النتائج.

صادرات WASM الاختيارية

الصادرالتوقيعالوصف
on_load() -> i32() -> i32يُستدعى مرة واحدة بعد التجميع. أعِد 0 للنجاح.
plugin_name(buf: i32, len: i32) -> i32(i32, i32) -> i32اكتب اسم الإضافة في المخزن المؤقت. أعِد الطول الفعلي.
plugin_version(buf: i32, len: i32) -> i32(i32, i32) -> i32اكتب إصدار الإضافة في المخزن المؤقت. أعِد الطول الفعلي.
alloc(size: i32) -> i32(i32) -> i32خصِّص size بايت من ذاكرة الضيف. أعِد المؤشر.

وظائف المضيف المتاحة للإضافات

يوفر المضيف هذه الوظائف في مساحة الاسم "env":

report_finding(name_ptr, name_len, score, detail_ptr, detail_len)

الإبلاغ عن نتيجة تهديد. يمكن استدعاؤها عدة مرات أثناء فحص واحد.

  • name_ptr / name_len -- مؤشر وطول سلسلة اسم التهديد (مثل "Trojan.Marker")
  • score -- درجة التهديد (0-100، مقيَّدة)
  • detail_ptr / detail_len -- مؤشر وطول سلسلة تفاصيل

log_message(level, msg_ptr, msg_len)

كتابة رسالة سجل إلى نظام التتبع الخاص بالمحرك.

  • level -- 0=trace، 1=debug، 2=info، 3=warn، 4=error
  • msg_ptr / msg_len -- مؤشر وطول سلسلة الرسالة

get_file_path(buf_ptr, buf_len) -> actual_len

قراءة مسار الملف الجاري فحصه في مخزن مؤقت للضيف.

get_file_type(buf_ptr, buf_len) -> actual_len

قراءة نوع الملف المكتشف (مثل "pe"، "elf"، "pdf") في مخزن مؤقت للضيف.

هيكل PluginFinding

عندما تُبلِّغ إضافة عن نتيجة (إما عبر report_finding() أو بإعادة درجة غير صفرية)، يُنشئ المحرك PluginFinding:

rust
pub struct PluginFinding {
    pub plugin_name: String,   // Name of the plugin
    pub threat_name: String,   // e.g. "Trojan.Marker"
    pub score: u32,            // 0-100
    pub detail: String,        // Free-form detail string
}

إذا أعادت الإضافة درجة غير صفرية ولم تستدعِ report_finding()، يُنشئ المحرك نتيجة تلقائياً:

threat_name: "Plugin.<plugin_name>"
detail: "Plugin '<name>' returned threat score <score>"

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

1. إنشاء دليل الإضافة

bash
mkdir -p ~/.prx-sd/plugins/my-scanner

2. كتابة البيان

bash
cat > ~/.prx-sd/plugins/my-scanner/plugin.json << 'EOF'
{
  "name": "My Custom Scanner",
  "version": "0.1.0",
  "author": "your-name",
  "description": "Detects custom threat patterns",
  "wasm_file": "my_scanner.wasm",
  "platforms": ["all"],
  "file_types": ["all"],
  "min_engine_version": "0.1.0",
  "permissions": {
    "network": false,
    "filesystem": false,
    "max_memory_mb": 64,
    "max_exec_ms": 5000
  }
}
EOF

3. كتابة الإضافة (مثال بـ Rust)

إنشاء مشروع مكتبة Rust جديد:

bash
cargo new --lib my-scanner
cd my-scanner

إضافة إلى Cargo.toml:

toml
[lib]
crate-type = ["cdylib"]

[profile.release]
opt-level = "s"
lto = true

كتابة src/lib.rs:

rust
// Host function imports
extern "C" {
    fn report_finding(
        name_ptr: *const u8, name_len: u32,
        score: u32,
        detail_ptr: *const u8, detail_len: u32,
    );
    fn log_message(level: u32, msg_ptr: *const u8, msg_len: u32);
}

#[no_mangle]
pub extern "C" fn on_load() -> i32 {
    let msg = b"My Custom Scanner loaded";
    unsafe { log_message(2, msg.as_ptr(), msg.len() as u32) };
    0 // success
}

#[no_mangle]
pub extern "C" fn scan(ptr: *const u8, len: u32) -> i32 {
    let data = unsafe { core::slice::from_raw_parts(ptr, len as usize) };

    // Example: look for a known malicious marker
    let marker = b"MALICIOUS_MARKER";
    if data.windows(marker.len()).any(|w| w == marker) {
        let name = b"Custom.MaliciousMarker";
        let detail = b"Found MALICIOUS_MARKER string in file data";
        unsafe {
            report_finding(
                name.as_ptr(), name.len() as u32,
                85,
                detail.as_ptr(), detail.len() as u32,
            );
        }
        return 85;
    }

    0 // clean
}

4. التجميع إلى WASM

bash
rustup target add wasm32-wasip1
cargo build --release --target wasm32-wasip1
cp target/wasm32-wasip1/release/my_scanner.wasm ~/.prx-sd/plugins/my-scanner/

5. اختبار الإضافة

bash
# إنشاء ملف اختبار مع العلامة
echo "MALICIOUS_MARKER" > /tmp/test-marker.txt

# الفحص مع تسجيل debug لرؤية نشاط الإضافة
sd --log-level debug scan /tmp/test-marker.txt

TIP

استخدم --log-level debug لرؤية رسائل تحميل وتنفيذ تفصيلية للإضافة، بما فيها استهلاك الوقود واستخدام الذاكرة.

أمان البيئة الآمنة

تعمل الإضافات داخل بيئة Wasmtime الآمنة مع القيود التالية:

القيدالتطبيق
حد الذاكرةmax_memory_mb في البيان؛ يُطبِّق Wasmtime حد الذاكرة الخطية
حد CPUmax_exec_ms مُحوَّل إلى وحدات وقود؛ يتوقف التنفيذ عند نفاد الوقود
الشبكةمُعطَّلة افتراضياً؛ تتطلب permissions.network: true
نظام الملفاتمُعطَّل افتراضياً؛ يتطلب permissions.filesystem: true (WASI preopens)
فحص المنصةتُتخطى الإضافات ذات platforms غير المتطابقة عند وقت التحميل
مرشح نوع الملفتُتخطى الإضافات ذات file_types غير المتطابقة لكل ملف

WARNING

حتى مع network: true أو filesystem: true، تقيِّد بيئة WASI الوصول إلى دلائل ونقاط نهاية محددة. هذه الأذونات إعلان عن نية، وليست منح وصول شاملة.

إعادة التحميل الساخن

أفلِت دليل إضافة جديدة في ~/.prx-sd/plugins/ وسيلتقطه السجل في الفحص التالي. بالنسبة للـ daemon، شغِّل إعادة تحميل باستدعاء sd update أو إعادة تشغيل الـ daemon.

الخطوات التالية

Released under the Apache-2.0 License.