معهد ماساتشوستس للتكنولوجيا. دورة محاضرة # 6.858. "أمن أنظمة الكمبيوتر." نيكولاي زيلدوفيتش ، جيمس ميكينز. 2014 سنة
أمان أنظمة الكمبيوتر هو دورة حول تطوير وتنفيذ أنظمة الكمبيوتر الآمنة. تغطي المحاضرات نماذج التهديد والهجمات التي تهدد الأمن وتقنيات الأمان القائمة على العمل العلمي الحديث. تشمل الموضوعات أمان نظام التشغيل (OS) ، والميزات ، وإدارة تدفق المعلومات ، وأمن اللغات ، وبروتوكولات الشبكة ، وأمن الأجهزة ، وأمن تطبيق الويب.
المحاضرة 1: "مقدمة: نماذج التهديد"
الجزء 1 /
الجزء 2 /
الجزء 3محاضرة 2: "السيطرة على هجمات القراصنة"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 3: "تجاوزات المخزن المؤقت: المآثر والحماية"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 4: "الفصل بين الامتيازات"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 5: "من أين تأتي أنظمة الأمن؟"
الجزء 1 /
الجزء 2المحاضرة 6: "الفرص"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 7: "صندوق حماية العميل الأصلي"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 8: "نموذج أمان الشبكة"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 9: "أمان تطبيق الويب"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 10: "الإعدام الرمزي"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 11: "أور / لغة برمجة الويب"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 12:
الجزء 1 من أمان الشبكة /
الجزء 2 /
الجزء 3المحاضرة 13: "بروتوكولات الشبكة"
الجزء 1 /
الجزء 2 /
الجزء 3محاضرة 14: "SSL و HTTPS"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 15: "البرامج الطبية"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 16: "هجمات القناة الجانبية"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 17: "مصادقة المستخدم"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 18: "تصفح الإنترنت الخاص"
الجزء 1 /
الجزء 2 /
الجزء 3محاضرة 19: "شبكات مجهولة"
الجزء 1 /
الجزء 2 /
الجزء 3المحاضرة 20: "أمن الهاتف المحمول"
الجزء 1 /
الجزء 2 /
الجزء 3محاضرة 21: "تتبع البيانات"
الجزء 1 /
الجزء 2 /
الجزء 3 الطالب: لماذا من المستحيل ببساطة مسح الرمز وعدم التحقق منه يدويًا؟
أستاذ: في الممارسة العملية ، هذا ما يحدث. يعرف المطورون أنه عندما يقوم المترجم بهذا النوع من العمل ، عند إرجاع قيمة الإرجاع ، يتم استخدام كود خاص يقوم تلقائيًا بتعيين قيمة النظام المصابة إلى system.arraycopy () ، والتي يجب أن ترتبط بها.
الطالب: صحيح ، لكن ما هو الجزء اليدوي من العمل؟
أستاذ: الجزء اليدوي هو أساسا لمعرفة ما ينبغي أن تكون سياسة تنفيذ التدقيق. بمعنى آخر ، إذا نظرت فقط إلى TaintDroid القياسي أو Android القياسي ، فسوف يفعلون شيئًا لك ، لكنهم لن يتمكنوا من تعيين Taint تلقائيًا بالطريقة الصحيحة. لذلك يجب على شخص ما تعيين سياسة التتبع يدويًا.

لا يبدو أنها ستكون مشكلة كبيرة في الممارسة. ولكن إذا زاد عدد التطبيقات التي تستخدم أساليب موجهة نحو الآلة بشكل مطرد ، فقد تكون لدينا مشاكل صغيرة.
نوع آخر من البيانات يدعو للقلق من حيث تعيين العدوى هو رسائل IPC. تعامل رسائل IPC بشكل أساسي كصفائف. لذلك ، سيتم ربط كل من هذه الرسائل بصمة واحدة شائعة ، وهي اتحاد الالتهابات في جميع الأجزاء المكونة لها.
يساهم هذا في أداء النظام لأننا نحتاج فقط إلى تخزين علامة تلوين واحدة لكل من هذه الرسائل. في الحالة القصوى ، سيتم إعادة تقييم درجة من العدوى ، لكنها لن تؤدي أبدًا إلى انخفاض مستوى الأمان. أسوأ شيء يمكن أن يحدث في نفس الوقت هو أن الشبكة لن تحصل على البيانات التي يمكن الوصول إليها دون أي عواقب وخيمة على الخصوصية.
لذلك ، عندما تقوم بإنشاء رسالة IPC ، فإنها تستقبل المادة المختلطة. عندما تقرأ ما تلقيته في هذه الرسالة ، فإن البيانات المستخرجة تصاب بالعدوى من الرسالة نفسها ، وهذا أمر منطقي. هكذا يتم التعامل مع رسائل IPC.
يجدر أيضًا القلق حول كيفية معالجة الملف. لذلك ، يستقبل كل ملف علامة واحدة ، ويتم تخزين هذه العلامة مع الملف في البيانات التعريفية الخاصة به على وسيط تخزين ثابت ، مثل بطاقة ذاكرة SD. هنا نفس النهج المحافظ للعدوى يحدث كما في الحالات السابقة. الفكرة الرئيسية هي أن التطبيق يمكنه الوصول إلى بعض البيانات السرية ، على سبيل المثال ، موقع GPS ، ومن المحتمل أن يكتب هذه البيانات إلى ملف ، لذلك يقوم TaintDroid بتحديث العلامة الملوثة لهذا الملف بعلامة GPS ، وبعد ذلك يغلق التطبيق. في وقت لاحق ، قد يتم تضمين بعض التطبيقات الأخرى التي تقرأ هذا الملف.

عندما يصل إلى الجهاز الظاهري ، إلى التطبيق ، يرى TaintDroid أن لديه هذا العلم ، وبالتالي فإن أي بيانات مستخرجة أثناء قراءة هذا الملف سيكون لها علامة GPS أيضًا. اعتقد انه بسيط جدا.
لذا ، ما الأشياء التي يمكن أن نتسبب فيها من منظور جافا؟ هناك أساسا خمسة أنواع من الكائنات جافا التي تحتاج إلى أعلام ملوثة. أولاً ، هذه هي المتغيرات المحلية المتغيرات المحلية المستخدمة في الأسلوب. بالعودة إلى الأمثلة السابقة ، يمكننا افتراض أن char c هو مثل هذا المتغير.
لذلك ، يجب علينا تعيين الأعلام لهذه العناصر. النوع الثاني هو وسيطات طريقة وسيطات الطريقة ؛ ويجب أن تحتوي أيضًا على علامات الإصابة. كل من هذه الأشياء تعيش على المكدس ، لذلك يجب على TaintDroid تتبع الغرض من الأعلام وأكثر من ذلك بكثير لهذه الأنواع من الكائنات.
نحتاج أيضًا إلى تعيين علامات لحقول مثيل لحقول مثيل الكائن. تخيل أن هناك كائنًا معينًا C ، إنها دائرة ، وأريد أن أعرف نصف قطرها. وبالتالي ، لدينا حقل c.radius ، ويجب أن نربط معلومات العدوى لكل من هذه الحقول: بـ و radius.
النوع الرابع من كائن Java هو حقول الفئة الثابتة لحقول الفئة الثابتة ، والتي تتطلب أيضًا معلومات غير دقيقة. يمكن أن يكون شيء مثل circle.property ، أي وصف لخصائص الدائرة التي نخصص لها بعض المعلومات للتلوث.
النوع الخامس هو صفائف Arrays ، التي تحدثنا عنها سابقًا ، ونقوم بتعيين قطعة واحدة شائعة من معلومات الإصابة للصفيف بأكمله.
تتمثل الفكرة الأساسية لتطبيق علامات التمييز في هذه الأنواع من كائنات Java في محاولة تخزين علامات التمييز على متغير بجوار المتغير نفسه.

دعنا نقول أن لدينا بعض الأعداد الصحيحة ، ونريد أن نضع نوعًا من التلوث الملوث بها. نريد أن نحاول إبقاء هذه الحالة أقرب ما تكون إلى المتغير ، ربما لأسباب ضمان تشغيل ذاكرة التخزين المؤقت على مستوى المعالج. إذا ظللنا بعيدًا عن هذا المتغير ، فقد يتسبب ذلك في حدوث مشكلات ، لأنه بعد أن يبحث المترجم في قيمة الذاكرة لمتغير Java الفعلي ، فسوف يرغب في التعرف على المعلومات المتعلقة بالعدوى في أسرع وقت ممكن.
إذا نظرنا إلى عملية النقل ، نلاحظ أنه في هذه الأماكن في الكود ، dst و src ، عندما يأخذ المترجم الشفهي في الاعتبار القيم ، فإنه يأخذ في الاعتبار أيضًا الإصابات الملوثة المقابلة.
وبالتالي ، بوضع هذه الأشياء بالقرب من بعضها البعض ، فإنك تحاول ضمان استخدام أكثر كفاءة لذاكرة التخزين المؤقت. هذا بسيط جدا. إذا نظرت إلى ما يفعله المطورون للوسيطات الخاصة بالطرق والمتغيرات المحلية التي تعيش على المكدس ، يمكنك أن ترى أنهم يسلطون الضوء بشكل أساسي على الأعلام الملوثة بجانب مكان المتغيرات.
لنفترض أن لدينا شيئًا مفضلاً في محاضراتنا ، وهو مخطط مكدس ربما تكرهه قريبًا للتكرار المتكرر. دع المتغير المحلي 0 موجودًا في مجموعتنا ، ثم يخزن TaintDroid في الذاكرة علامة حول إصابة هذا المتغير أسفله مباشرة. إذا كان لديك بعد ذلك متغير آخر ، فسيتم وضع العلامة أيضًا أسفله مباشرةً ، وهكذا. انها بسيطة جدا. ستكون كل هذه الأشياء موجودة على نفس خط ذاكرة التخزين المؤقت ، مما سيجعل الوصول إلى الذاكرة أقل تكلفة.
الطالب: أتساءل كيف يمكن أن يكون لديك علامة واحدة لمجموعة كاملة وأعلام مختلفة لكل خاصية لكائن. ماذا لو كانت إحدى طرق الكائن يمكنها الوصول إلى البيانات المخزنة في خصائصها؟ سيكون ... أنت تعرف ماذا أقصد؟
الأستاذ: هل تسأل عن سبب تطبيق هذه السياسة فقط؟
الطالب: نعم ، عن سبب استخدام مثل هذه السياسة.
أستاذ: أعتقد أن هذا يتم لضمان فعالية التنفيذ. ربما تكون هناك قواعد أخرى - على سبيل المثال ، لا يُبلغون عن طول صفيف البيانات ، لأن تسرب المعلومات ممكن ، وبالتالي فهي لا تمد العدوى إلى هذا المؤشر. لذلك أعتقد أن بعض القرارات يتم اتخاذها ببساطة لأسباب الكفاءة. من حيث المبدأ ، لا يوجد شيء يمكن أن يعوقه عند إتاحة الوصول إلى كل عنصر من عناصر المصفوفة للإشارة إلى أن الشيء الموجود على اليسار لا يتأثر إلا من أي عناصر محددة.
ومع ذلك ، ليس من الواضح ما إذا كان هذا سيكون صحيحًا ، لأنه ، على ما يبدو ، إذا وضعت شيئًا ما في الصفيف ، فيجب أن يعرف هذا الشيء شيئًا عن هذه المجموعة. لذلك ، أعتقد أن المطورين يستخدمون مزيجًا من كلا النهجين. كونك متحفظًا بشكل مفرط ، يجب ألا تسمح بتسريب البيانات التي تريد حمايتها ، ولكن في نفس الوقت ، لكي تتمكن من الوصول إلى المصفوفة ، يجب أن تعرف شيئًا عنها. وعندما تريد أن تتعلم شيئًا ما عن شيء ما ، فهذا يعني عادةً أنك تستخدم الملوث.
لذلك ، هذا هو المخطط الأساسي الذي يستخدمونه لتخزين كل هذه المعلومات بجانب بعضهم البعض. يمكن للمرء أن يتخيل أن الشيء نفسه يتم لحقول الفصل ولحقول الكائن. عند الإعلان عن فئة ، لديك بعض ذاكرة الفتحة لمتغير معين ، وبجانب هذه الفتحة هي معلومات شائعة لهذا المتغير. لذلك أعتقد أن كل هذا معقول جدا.
هذا هو مبدأ TaintDroid. عندما تتم تهيئة النظام أو في أوقات أخرى أثناء تشغيل النظام ، يبحث TaintDroid في جميع مصادر المعلومات التي يحتمل أن تكون مصابة ويعين إشارة لكل من هذه الأشياء - مستشعر GPS والكاميرا وما إلى ذلك. أثناء تشغيل البرنامج ، سيقوم باستخراج معلومات سرية من هذه المصادر ، وبعد ذلك سينظر المترجم الشفهي في جميع أنواع الوظائف وفقًا للجدول الوارد في المقالة لمعرفة كيفية نشر العدوى الملوثة عبر النظام.
يحدث الشيء الأكثر إثارة للاهتمام عندما تحاول البيانات اختراق النظام. يمكن لـ TaintDroid التحكم في واجهات الشبكة ومشاهدة كل ما يحاول المرور عبرها. إنه يبحث عن العلامات الملوثة ، وإذا كانت البيانات التي تحاول اختراق الشبكة تحتوي على واحد أو أكثر من هذه العلامات ، فسيتم حظرها من استخدام الشبكة. ما يحدث في هذه اللحظة يعتمد في الواقع على التطبيق.

على سبيل المثال ، يمكن لـ TaintDroid أن يُظهر للمستخدم تحذيراً يقول إن شخصًا ما يحاول إرسال بيانات حول موقعه إلى الجانب. من المحتمل أن يحتوي TaintDroid على سياسات مضمنة تسمح للتطبيق بالوصول إلى الشبكة ، ولكن في الوقت نفسه ستعيد تعيين جميع البيانات الحساسة التي سيحاول نقلها ، وما إلى ذلك. في هذه المقالة ، لم يتم وصف هذه الآلية بتفاصيل كافية ، لأن المؤلفين كانوا مهتمين بشكل أساسي بمسألة "تسرب" البيانات إلى الشبكة.
يناقش قسم من المقالة بعنوان "التقييم" بعض الأشياء الموجودة في عملية دراسة تشغيل النظام. لذلك ، وجد مؤلفو المقالة أن تطبيقات Android ستحاول استخراج البيانات بطرق غير مرئية للمستخدم. لنفترض أنهم سيحاولون استخدام موقعك للإعلان ، وسيقومون بإرسال رقمك إلى خادم بعيد ، وهكذا. من المهم ملاحظة أن هذه التطبيقات ، كقاعدة عامة ، لا "تكسر" نموذج أمان Android ، بمعنى أنه يجب على المستخدم السماح له بالوصول إلى الشبكة أو السماح له باستخدام قائمة جهات الاتصال. ومع ذلك ، لا تنص التطبيقات في اتفاقية ترخيص EULA على أنها تنوي إرسال رقم هاتف إلى خادم Silk Road 8 أو شيء من هذا القبيل. في الواقع ، يعد هذا خداعًا وتضليلًا للمستخدمين حول النوايا الحقيقية للتطبيق ، لأنهم إذا رأوا متطلبات اتفاقية ترخيص المستخدم النهائي هذه وعرفوا ما الذي كانوا محفوفين به ، فيمكنهم التفكير فيما إذا كان سيتم تثبيت مثل هذا التطبيق على هواتفهم الذكية أم لا.
الطالب: يمكن افتراض أنه حتى لو وضعوا هذه المتطلبات في اتفاقية الترخيص ، فلن ينجح ذلك ، لأن الأشخاص عادةً ما لا يقرأون اتفاقية ترخيص المستخدم النهائي.
البروفيسور: هذا افتراض معقول للغاية ، لأنه حتى علماء الكمبيوتر لا يتحققون دائمًا من اتفاقية الترخيص. ومع ذلك ، فإن مثل هذا الصدق في اتفاقية ترخيص المستخدم النهائي لا يزال مفيدًا ، لأن هناك أشخاصًا يقرؤون حقًا اتفاقية الترخيص. لكنك محق تمامًا في افتراض أن المستخدمين لن يقرأوا مجموعة من الصفحات المكتوبة بخط صغير ، فهم فقط ينقرون "موافق" ويثبتون التطبيق.
لذلك ، أعتقد أن قواعد تمرير المعلومات عبر النظام بسيطة للغاية ، كما قلنا سابقًا ، تنتقل العناصر الضارة ببساطة من الجانب الأيمن إلى الجانب الأيسر. ومع ذلك ، في بعض الأحيان قد يكون لهذه القواعد لحركة تدفق المعلومات نتائج متضاربة إلى حد ما.
تخيل أن التطبيق ينفذ فئة خاصة به من القوائم المرتبطة. لدينا فئة بسيطة تسمى ListNode ، سيكون لها حقل كائن لبيانات الكائن وكائن ListNode التالي الذي يمثل القائمة التالية.
افترض أن التطبيق يعين البيانات المصابة إلى حقل بيانات الكائن - المعلومات السرية الواردة من جهاز استشعار GPS أو أي شيء آخر. والسؤال هو ، عندما نحسب طول هذه القائمة ، هل يجب أن تكون مصابة؟ ستندهش من أن إجابة الإجابة على السؤال ستكون "لا" ، وهو ما يفسر كيف يحدد TaintDroid وبعض هذه الأنظمة تدفق المعلومات. دعونا نلقي نظرة على ما يعنيه إضافة عقدة إلى قائمة مرتبطة.
إضافة عقدة تتكون من 3 خطوات. لذلك ، فإن أول ما تفعله هو تحديد عقدة قائمة جديدة تحتوي على البيانات التي تريد إضافتها - Alloc ListNode. الخطوة الثانية هي تعيين حقل بيانات لهذه العقدة الجديدة. والشيء الثالث الذي تقوم به هو استخدام نوع من التصحيح لـ ListNode بجانب دمج العقد في قائمة - هذا هو مؤشر ptr "التالي".

ومن المثير للاهتمام ، أن الخطوة الثالثة لا تتعلق بمجال البيانات على الإطلاق ، فهي تأخذ فقط في الاعتبار القيمة التالية. بمجرد إصابة بيانات الكائن ، نبدأ في حساب طول القائمة ، بدءًا من بعض العقدة الرأسية ، ونستعرض جميع مؤشرات ptr "التالية" ونحسب فقط عدد المؤشرات التي مرت. لذلك لا تلمس خوارزمية العد البيانات المصابة.
ومن المثير للاهتمام ، إذا كان لديك قائمة مرتبطة مليئة بالبيانات المصابة ثم تقوم بحساب طولها ، فلن يؤدي ذلك إلى إنشاء قيمة مصابة. قد يبدو هذا غير منطقي بعض الشيء ، على الرغم من أنه عند النظر في المصفوفات ، قلنا بالفعل أن طول المصفوفة أيضًا لا يحتوي على مواد ملوثة. هناك نفس السبب. قرب نهاية المحاضرة ، سنناقش كيف يمكنك استخدام لغة تسمح لك كمبرمج لتحديد أنواع العدوى الخاصة بك ، ومن ثم يمكنك تطوير سياستك الخاصة لمثل هذه الأشياء.
هناك ميزة جيدة في TaintDroid وهي أنك ، كمطور ، لا يتعين عليك تسمية أي شيء ، ولكن TaintDroid يقوم بذلك نيابة عنك. يلاحظ كل الأشياء السرية التي يمكن أن تكون مصدرًا للمعلومات ، وكل الأشياء التي يمكن أن تكون "مغاسل" من المعلومات ، بحيث تكون أنت كمطور جاهزًا للعمل. ولكن إذا كنت تريد التحكم في إضافة العقد ، فقد تضطر إلى إنشاء بعض السياسات بنفسك.
كيف يؤثر TaintDroid على أداء النظام؟ النفقات العامة الحالية في الواقع تبدو معقولة جدا. الحمل الذاكرة هو لتخزين جميع علامات العدوى. يتكون حمل المعالج بشكل أساسي من وجهة هذه الإصابات وتوزيعها والتحقق منها ، وتجدر الإشارة إلى أن استخدام الجهاز الظاهري Dalvik هو عمل إضافي. لذلك ، بالنظر إلى المصدر ، وبالنظر إلى معلومات العدوى هذه ذات 32 بت ، فإننا نقوم بتنفيذ عمليات نظرنا فيها بالفعل. هذا هو النفقات العامة الحسابية.
هذه النفقات العامة تبدو معتدلة جدا. وفقًا لمؤلفي المقال ، يتطلب تخزين العلامات الملوثة 3٪ إلى 5٪ من الذاكرة الإضافية ، لذلك هذا ليس سيئًا للغاية. تحميل المعالج أعلى قليلاً ويمكن أن يصل إلى 3٪ إلى 29٪ من الطاقة الحاسوبية. ويرجع ذلك إلى حقيقة أنه في كل مرة يتم تنفيذ الحلقة ، يحتاج المترجم إلى إلقاء نظرة على هذه العلامات وتنفيذ العمليات المقابلة. على الرغم من أن هذه مجرد عمليات bitwise ، إلا أنها تحتاج إلى تنفيذها طوال الوقت. هذا ليس بالأمر السيء حتى في حالة الحمل بنسبة 29 ٪ ، لأن المطورين من وادي السيليكون يتحدثون باستمرار عن حقيقة أن الهواتف الحديثة تحتاج إلى معالجات رباعية النواة. قد تنشأ المشكلة الوحيدة في البطارية ، لأنه حتى لو كان لديك نوى إضافية للمعالجات ، فمن غير المحتمل أن ترغب في امتلاك هاتف ساخن في جيبك يبدأ في "الانفجار" عند محاولة حساب هذه الأشياء. ولكن إذا كانت بطاريتك لا تتأثر بشكل خاص بهذه الحسابات ، فكل شيء ليس سيئًا للغاية.

لذلك كان هذا لمحة عامة عن عمل TaintDroid. لديك سؤال؟
الطالب: هل تضع علامة فقط على ما هو موجود في كل وقت؟ أو كل متغير الموسومة؟
البروفيسور: كل شيء ملحوظ ، لذلك لا يوجد شيء نظري يمنعك من وضع أي معلومات حول العدوى لأشياء لا تحتوي على أي عدوى على الإطلاق. أعتقد أنه بمجرد حصول شيء ما على الأقل على قطعة صغيرة واحدة ، فأنت بحاجة إلى إنشاء شيء مثل تخطيط التغيير الديناميكي. - , , . taint, , , - , , . , , - . TaintDroid . Dalvik.
– taint x86 ARM? , , , , , , Java . ?
, , , . , , , , , Java- - . x86, , , , , , .
, taint , , , . .

, x86 — . . , - x86, . , , , P, , , !
, taint x86. , , , AD, , .
-, , . -, , . , , , .
, . , . , , , . , « » Taint Explosion.
, , . , Dungeons and Dragons, .
, , - - . , , , .
, - esp esb. , .

, x86, , esp. , , . , , , ebp, , , . , , , taint .
, Linux . , . , - .
: ? , .
: . x86, , . , . Bochs – IBM PC, 86. TaintBochs, x86 . x86, , . , . , , , , , , - .
54:10
MIT « ». 21: « », 3.
, . ? ? ,
30% entry-level , : VPS (KVM) E5-2650 v4 (6 Cores) 10GB DDR4 240GB SSD 1Gbps $20 ? ( RAID1 RAID10, 24 40GB DDR4).
VPS (KVM) E5-2650 v4 (6 Cores) 10GB DDR4 240GB SSD 1Gbps ,
.
Dell R730xd 2 ? لدينا فقط
2 x Intel Dodeca-Core Xeon E5-2650v4 128GB DDR4 6x480GB SSD بسرعة 1 جيجابت في الثانية 100 TV من 249 دولارًا في هولندا والولايات المتحدة الأمريكية!اقرأ عن كيفية بناء البنية التحتية فئة باستخدام خوادم V4 R730xd E5-2650d تكلف 9000 يورو عن بنس واحد؟