قياسات دفاع VM وردود أفعاله
أبلِغ خادمك الخلفي باكتشافات دفاع VM باستخدام vmDefenseHook، واضبط كيفية استجابة كل فئة اكتشاف عبر vmDefenseReaction - من بناءٍ للقياس عن بُعد فقط لا يكسر شيئًا إطلاقًا، إلى بناءٍ يكسر فورًا عند سرقة الحزمة.
شاهد
Obfuscator.io Defense Reactions: Break, Decoy, and the VM Defense Hook
المشكلة
تعمل دفاعات VM - vmSelfDefending وvmDebugProtection وvmDomainLock - محليًا: فعند اكتشاف مُنقِّح أو أداة أتمتة أو بيئة متلاعَب بها أو نطاق غير مصرَّح به، يتعطّل الكود المحمي أو يُفسِد نتائجه بصمت. يوقف ذلك المهاجم، لكنك افتراضيًا لا تسمع بالأمر أبدًا. فلا يمكنك معرفة عدد مرات فحص حزمتك، ولا أيُّ كاشفٍ أُطلِق، ولا ما إذا كان أحد الدفاعات يعطّل مستخدمًا شرعيًا.
يسدّ خياران هذه الفجوة. ولا يُفعِّل أيٌّ منهما أيَّ دفاع - فهما يراقبان الدفاعات التي فعّلتها بالفعل ويوجّهانها فقط:
vmDefenseHook- دالة رد نداء عامة تتلقّى كائن إشارة في كل مرة يكتشف فيها أحد الدفاعات شيئًا. استخدمه لإرسال بيانات القياس عن بُعد إلى خادمك الخلفي.vmDefenseReaction- خريطة لكل فئة تحدّد كيف يستجيب دفاعٌ مُفعَّل: الكسر، أو التضليل، أو عدم فعل أي شيء محليًا.
قُدِّم الخياران كلاهما في الإصدار v7.1.0، لكن كل الأمثلة هنا تستخدم صيغة الكائن vmDefenseHook: { name }، التي تتطلب
v7.4.0. أما الإصدارات الأقدم فكانت تقبل نصًا مجردًا (vmDefenseHook: '__vmDetection')؛ وهذه الصيغة مرفوضة بدءًا من v8.0.0، لذا
استخدم صيغة الكائن في كل الحالات.
الوصفة 1 - أبلِغ خادمك الخلفي بالاكتشافات
الخطوة 1 - سجِّل دالة خطّاف عامة قبل أن تُحمَّل الحزمة المشوَّشة
تعمل بيئة تشغيل VM ودفاعاتها قبل برنامجك المحمي، لذا تُطلَق كثير من الاكتشافات أثناء بدء التشغيل. عرِّف الخطّاف كمتغيّر عام عادي في الصفحة المضيفة، قبل وسم السكربت المشوَّش:
الخطوة 2 - وجِّه vmDefenseHook إليه
الخيار كائنٌ يكون فيه name هو الدالة العامة المطلوب استدعاؤها (aliases اختياري - انظر أدناه):
في لوحة التحكم، يظهر حقل VM Defense Hook في قسم الحماية المتقدمة بمجرد تفعيل دفاع واحد على الأقل (vmSelfDefending أو vmDebugProtection أو vmDomainLock).
الخطوة 3 - استقبِل الإشارة على خادمك الخلفي
يستدعي كل اكتشافٍ الخطّافَ بكائن signal واحد:
source- الكاشف المحدَّد:headlessأوnodeأوagentأوagentBrowserأوdomainأوdebuggerأوsandboxأوnativeHookأوtimingأوintegrity. واعتبارًا من الإصدار v7.4.0 صار الكاشفان السابقانenvوinspectorيُبلِّغان تحتsource: 'debugger'. ويُبلِّغagentBrowserتحتcategory: 'automation'، ويعمل مع أهداف المتصفح عند تفعيلvmDebugProtection(v7.9.0+).category-automationأوdebuggerأوsandboxأوdomainأوtamperأوintegrity. ويُبلِّغ المصدرnodeتحتcategory: 'debugger'(v7.4.0+).scoreوthreshold- درجة الاكتشاف والعتبة التي تجاوزها
نقطة نهاية استقبال بسيطة (المعروض هنا Express؛ لكن أيَّ خادم خلفي يقبل طلب POST يعمل). وهي تُطبِّع الجسم إلى مصفوفة كي تتعامل أيضًا مع الصيغة المجمَّعة التي يرسلها نمط العازل أدناه:
الخطّاف للإبلاغ فقط - تُتجاهَل قيمته المُعادة، والخطّاف الغائب أو الذي يُطلِق استثناءً هو عملية لا شيء صامتة. ولا يمكنه أبدًا تعطيل دفاع، فلا يكسب المهاجم شيئًا من حذف خطّافك أو إعطابه. ولتغيير ما يفعله الدفاع، استخدم vmDefenseReaction (الوصفة 2).
عرِّف الخطّاف في الصفحة المضيفة، لا داخل المصدر المشوَّش
في القياس عن بُعد تريد التقاط كل اكتشاف، وكثيرٌ منها يُطلَق عند بدء التشغيل - والخطّاف المعرَّف داخل الحزمة المشوَّشة يُسجَّل متأخرًا جدًا بحيث لا يلتقط تلك الاكتشافات، وإذا تُرجِم إلى بايت كود VM فلن يكون قابلًا للوصول حتى يعمل برنامجك. ويظل آمنًا في كلتا الحالتين (الخطّاف الغائب لا يفعل شيئًا، والخطّاف الذي يُطلِق هو نفسه اكتشافًا لا يُستدعى مجددًا بشكل متكرر)، لكن للتغطية الكاملة سجِّله مقدَّمًا في الصفحة المضيفة.
الاستثناء الوحيد هو خطّاف يستجيب فقط لاكتشافٍ وقت التشغيل - مثل التنظيف عند فتح مُنقِّح أثناء الاستخدام. فذلك الخطّاف يمكن أن يعيش داخل الحزمة المشوَّشة؛ انظر الوصفة 3.
ولحماية منطق الإبلاغ لديك رغم ذلك، أبقِ الخطّاف المسجَّل عازلًا من سطر واحد وأفرِغه من كودك المشوَّش:
إعادة تسمية حقول الإشارة (الأسماء البديلة)
القيم الافتراضية للحقلين source / category أسماء وصفية، فيستطيع أيُّ شخص يُجهِّز رد النداء (أو يقرأ الناتج) أن يتعرّف على الحماية وعلى الكاشف الذي أُطلِق. يعيد aliases تسمية حقول الإشارة إلى رموز مبهمة من اختيارك، تُطبَّق داخل الآلة الافتراضية قبل إصدار الإشارة، بحيث لا تظهر تلك الأسماء أبدًا في الناتج ولا تصل إلى رد النداء. ويعرف تطبيقك التعيين الخاص به ويمرِّر الرموز إلى خادمك الخلفي.
الأسماء البديلة لكل حقل على حدة: يأخذ كلُّ حقلٍ key (اسم الخاصية الذي يتلقّاه رد النداء)؛ ويأخذ الحقلان النصيّان source وcategory أيضًا خريطة values، بينما score / threshold رقمان ويأخذان key فقط. والمدخلات غير المضبوطة تبقى بأسمائها الافتراضية.
في لوحة التحكم، يقع قسم أسماء بديلة للإشارات أسفل حقل VM Defense Hook.
هذا تجنُّبٌ للبصمة، لا سرِّية - إذ لا يزال بالإمكان استنتاج التعيين بالاختبار المتكرِّر، فمنفعته الوحيدة هي عدم كشف أسماء ثابتة تشرح نفسها.
الوصفة 2 - عدِّل ردود الأفعال الافتراضية
يضبط vmDefenseReaction كيفية استجابة كل فئة اكتشاف. وهو لا يُفعِّل شيئًا - فالدفاعات نفسها تُشغَّل عبر الخيارات vmSelfDefending وvmDebugProtection وvmDomainLock؛ وهذا الخيار يختار فقط كيف يستجيب دفاعٌ مُفعَّل. والفئة هي وحدة التحكم: فكل كاشفٍ في فئةٍ يُنفِّذ ردَّ فعل تلك الفئة، وردُّ الفعل المضبوط لفئةٍ يكون خيارها مُطفأً لا أثر له ببساطة.
| الفئة | يُفعِّلها | تستجيب عندما |
|---|---|---|
automation | vmSelfDefending أو vmDebugProtection | يُقاد الكود ببرمجيات بدلًا من شخص: متصفح مقطوع الرأس أو مُؤتمَت، أو إطار عمل للكشط / الاختبار، أو وكيل برمجة بالذكاء الاصطناعي يخطو عبر الصفحة. |
debugger | vmDebugProtection أو vmSelfDefending | شخصٌ ما يفتح مُنقِّحًا أو أداة الفحص في أدوات المطوِّر بالمتصفح ويخطو عبر الكود العامل ليفهمه. |
sandbox | vmDebugProtection | الكود لا يعمل في متصفح حقيقي إطلاقًا - فقد نُقِل إلى بيئة JavaScript مُحاكاة أو مُبرمَجة كي يُنفَّذ ويُدرَس دون اتصال. |
domain | vmDomainLock | الكود يعمل على موقع لم تصرِّح به: مُضيف ليس في قائمة السماح vmDomainLock لديك (مثلًا، حزمتك منسوخة على نطاق شخص آخر). |
tamper | vmSelfDefending | بيئة JavaScript المحيطة بالآلة الافتراضية جرى تعديلها لمراقبتها أو اختطافها، مثل استبدال أدوات المتصفح المدمجة الأصلية بنسخ مُجهَّزة. |
integrity | vmSelfDefending | كود الحزمة المحمية نفسه جرى تعديله أو ترقيعه منذ أن ولّدتها. |
المفاتيح هي أسماء الفئات الست هذه، أو default (احتياطي للفئات غير المحدَّدة). والقيم هي:
break- يكسر فورًاdecoy- يستمر في العمل على حالة مسمَّمة، مُنتجًا نتائج خاطئة بصمت. يتطلبdecoyتفعيلvmDebugProtectionأوvmDomainLockمع هدف متصفح؛ وإلا فإنه يتصرف مثلbreak.none- لا يفعل شيئًا محليًا (قياس عن بُعد فقط)
الفئة التي لا تضبطها ترجع إلى الإعدادات الافتراضية المدمجة:
يصل default إلى كل فئة، بما فيها integrity وtamper، لذا فإن { default: 'none' } بناءٌ للقياس عن بُعد فقط لا يكسر شيئًا حقًا:
في لوحة التحكم، تظهر قوائم VM Defense Reactions في قسم الحماية المتقدمة بمجرد تفعيل دفاع؛ وتكون كل فئة قابلة للتحرير فقط أثناء تشغيل دفاعٍ يُصدِر كواشفها.
الوصفة 3 - شغّل منطقك الخاص قبل أن يكسر الدفاع
الخطّاف ليس للإبلاغ فقط - بل هو أيضًا المكان الموثوق الوحيد لتشغيل استجابتك الخاصة قبل أن يستجيب الدفاع. فعندما يُفتح مُنقِّح على صفحة عاملة، قد ترغب في مسح ما على الشاشة، أو استبدال العرض بصفحة 404، قبل أن يتعطّل الكود.
لماذا الخطّاف بدلًا من كودٍ في مكان آخر من تطبيقك: يوقف break كل بايت كود لاحق، فأيُّ تفكيكٍ يعمل بعد أن يُطلَق الدفاع - خصوصًا حين يكون هو نفسه مشوَّشًا باستخدام VM - هو بالضبط ما يمنع الكسرُ تنفيذَه. يُطلَق الخطّاف عند موضع الاكتشاف قبل أن يُنفَّذ رد الفعل، بشكل متزامن - فالدالة المتزامنة التي يستدعيها تنتهي أولًا، ثم يوقف break الآلة الافتراضية.
عرِّف الاستجابة بوصفها vmDefenseHook الخاص بك. وبما أن اكتشاف debugger يُطلَق وقت التشغيل - بعد أن يكون برنامجك قد حُمِّل وعرّف الخطّاف - يمكن أن يكون الخطّاف جزءًا من مصدرك المشوَّش ويُرمَّز بالبايت كود مع بقية الحزمة. تفرّع على signal.category كي تحصل كل حالة على الاستجابة الصحيحة، وأبقِ العمل متزامنًا، ثم دع رد الفعل يعمل:
هذا ينطبق على الاكتشافات التي تُطلَق أثناء عمل تطبيقك - راجع متى يعمل ترميز الخطّاف إلى بايت كود أدناه.
ضع هذه النقاط في اعتبارك:
- العمل المتزامن وحده مضمونٌ أن ينتهي أولًا. يعمل رد الفعل على العبارة التالية مباشرةً لعودة الخطّاف. والاستدعاءات من نوع "أطلِق وانسَ" التي تُسلِّم فورًا لا بأس بها (
navigator.sendBeacon، والتعديلات المتزامنة على DOM وعنصر canvas)؛ أما العمل الذي تجدوله لوقت لاحق -setTimeout، أو استكمال وعد، أوawait- فليس كذلك، وأيُّ شيء يحتاج مزيدًا من بايت كود VM لن يعمل، لأن ذلك هو ما يوقفهbreak. - الخطّاف يعمل قبل رد الفعل؛ ولا يحل محله. تُتجاهَل قيمته المُعادة، ولا يمكنه إلغاء ما يفعله رد الفعل أو تأخيره أو تغييره. استخدمه للتصرّف قبل الكسر، لا للاعتراض عليه - ولتغيير رد الفعل نفسه، استخدم
vmDefenseReaction(الوصفة 2).
متى يعمل ترميز الخطّاف إلى بايت كود
وضع الخطّاف داخل الحزمة المشوَّشة على هذا النحو يعمل فقط لأن اكتشاف debugger يُطلَق وقت التشغيل. فالآلة الافتراضية تُطلِق vmDefenseHook بينما لا تزال حيّة، بعد أن يكون برنامجك قد حُمِّل وعرّف الخطّاف، فيُفكَّك ترميز الخطّاف المُرمَّز بالبايت كود ويُشغَّل أولًا، ثم break. وهذا ما يحمي مصدر الخطّاف نفسه.
وهو لا يعمل مع الاكتشافات التي تُطلَق عند بدء التشغيل - automation أو sandbox أو domain، أو مُنقِّح مفتوح أصلًا حين تُحمَّل الصفحة - لأن الخطّاف المُرمَّز بالبايت كود لا يكون معرَّفًا بعدُ في تلك اللحظة، فلا يجد الدفاع دالةً يستدعيها. ولأجل تلك الحالات، سجِّل الخطّاف بدلًا من ذلك كمتغيّر عام عادي في الصفحة المضيفة، كما في الوصفة 1. وعند الشك، يغطّي المتغيّر العام العادي في الصفحة المضيفة كل اكتشافٍ يصل إلى الخطّاف؛ والترميز بالبايت كود لا يضيف سوى حماية مصدر الخطّاف نفسه، ولاكتشافات وقت التشغيل فقط.
من القياس عن بُعد إلى الإنفاذ
لا يلزم أن تُطلَق الرؤية والإنفاذ معًا. انشُر الدفاعات على مرحلتين: أولًا بناءٌ يُبلِّغ فقط، ثم - بمجرد أن تبدو بيانات القياس عن بُعد نظيفة - بناءٌ يتفاعل.
الخطوة 1 - أطلِق بناءً للملاحظة فقط
فعِّل كل دفاعٍ تنوي استخدامه، ووجِّه vmDefenseHook إلى نقطة نهايتك، وأطفئ جميع ردود الأفعال. سيظل كل كاشفٍ يعمل ويُبلِّغ عن كل إصابة إلى خادمك الخلفي، لكن لا يُكسَر شيء:
الخطوة 2 - راجِع الإشارات المجموعة
بعد أن يرى البناء حركةً حقيقية، ابحث عن الاكتشافات التي أطلقها الاستخدام الشرعي. وأكثرها شيوعًا اثنان:
- إصابات
automationمن اختباراتك الشاملة أو من مراقبة التشغيل - ابنِ تلك المُخرَجات دون الدفاعات بدلًا من التسامح مع الفئة في الإنتاج. - إصابات
domainمن مُضيف تجهيزي أو معاينة نسيت تضمينه في قائمة السماحvmDomainLock- أضِف المُضيف.
فضِّل إصلاح السبب على تخفيف رد الفعل: فكل فئةٍ تُترَك على none هي كاشفٌ يستطيع المهاجم تجاهله بأمان.
الخطوة 3 - شغّل ردود الأفعال
أزِل التجاوز default: 'none' كي تُطبَّق ردود الأفعال المدمجة لكل فئة؛ فذلك السطر الواحد هو التغيير كله. وإذا ظلّت فئةٌ تُنتِج نتائج إيجابية كاذبة لا يمكنك التخلّص منها، فاترُك تلك الفئة وحدها على none (مثل vmDefenseReaction: { automation: 'none' }) وأنفِذ البقية.
أبقِ vmDefenseHook مضبوطًا بعد تشغيل الإنفاذ - فالخطّاف يُطلَق بصرف النظر عن رد الفعل، فتحتفظ بالرؤية لمن يفحص حزمتك بينما تعمل الدفاعات.
