مشاكل استخدام دالة NtQuerySystemInformation مع وسيطات غير موثقة

بدأ صباح ذلك اليوم بحقيقة "كسر". لقد تم صياغته هذا التعبير من قبل أحد زملائي الذين أظهروا كيف ينتقل مصحح الأخطاء الخاص به إلى كتلة if عند التنقل عبر الرمز ، في حين أن الشرط الذي تم التحقق منه كان خاطئًا تمامًا. اتضح أن المشكلة في ذلك الوقت كانت تافهة - فقد استخدم إصدارًا محسنًا من الإصدار ، وفي هذا السيناريو ، الثقة في تصحيح الأخطاء خطوة بخطوة ، بالطبع ، أمر مستحيل. لكن تعبير "ifs break" ذاته قد ترسخ واستخدم هنا منذ ذلك الحين للإشارة إلى موقف توقف فيه شيء ما عن العمل لدرجة أنه لم يكن يؤمن به.

لذلك ، في ذلك اليوم ، تعطلت وظيفة NtQuerySystemInformation - واحدة من أهم وظائف نظام التشغيل Windows ، والتي تُرجع معلومات حول العمليات ، مؤشرات الترابط ، واصفات النظام ، إلخ. حول فوائد استخدام هذه الميزة ، كتبت مرة هذا المقال . ولكن اتضح أنه حتى مثل هذه الركائز الأساسية للنظام يمكن أن تفشل في بعض الأحيان.

إذن ماذا حدث.

لفترة طويلة (منذ عدة سنوات بالفعل) ، استخدمنا استدعاء الدالة NtQuerySystemInformation مع وسيطة SystemHandleInformation للحصول على معلومات حول جميع الواصفات في النظام. نعم ، تشير هذه الوسيطة رسميًا إلى تلك غير الموثقة ، ولكن إذا بدأت البحث عن معلومات حول كيفية سرد جميع الواصفات في جميع تطبيقات Windows التي تعمل حاليًا ، فإن مجموعة NtQuerySystemInformation + SystemHandleInformation هي الخيار الأكثر شيوعًا المقترح. وهو يعمل حقًا ، على جميع أنظمة التشغيل بدءًا من Windows NT.

لماذا قد تحتاج إلى البحث عن الواصفات في جميع العمليات؟ حسنا ، لأسباب مختلفة. تظهر الأدوات المساعدة مثل Process Hacker للأغراض الإعلامية. هناك برامج تقوم بذلك للبحث عن مورد تم حظره حاليًا بواسطة شخص ما (على سبيل المثال ، ملف). ويمكنك ، على سبيل المثال ، العثور على كائن مزامنة في عملية شخص آخر ، والذي يُستخدم للسماح بنسخة واحدة فقط من البرنامج لإغلاقه وإغلاقه والسماح بتشغيل مثيلين من هذا التطبيق. أو اذكر الواصفات لتكرارها من أجل تنظيم صندوق الحماية. بشكل عام ، هناك العديد من المهام.

لن أقدم وصفًا كاملاً لتعداد الواصف هنا ، سأقول فقط أنه ، بشكل عام ، يشبه الأمثلة الشائعة ، مثل هذا :

while ((status = NtQuerySystemInformation( SystemHandleInformation, handleInfo, handleInfoSize, NULL )) == STATUS_INFO_LENGTH_MISMATCH) handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2); // NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH. if (!NT_SUCCESS(status)) { printf("NtQuerySystemInformation failed!\n"); return 1; } for (i = 0; i < handleInfo->HandleCount; i++) { ... } 

لكن بعد ذلك ، قمت بتشغيل التطبيق الخاص بنا - وفجأة اتضح أن الواصف الذي أحتاجه (وأنا أعلم بالتأكيد أنه موجود!) ليس في القائمة التي تم إرجاعها بواسطة الدالة NtQuerySystemInformation (). هذا كل شيء ، لقد جاءوا - "إذا ما تم كسر".

محاولة إعادة إنتاج المشكلة على أجهزة الكمبيوتر الأخرى في المكتب. على بعض يتم استنساخه ، على الأغلبية - لا. نحاول أن نفهم كيف تختلف تلك التي تتكاثر عليها عن تلك التي كل شيء جيد. إصدار Windows هو نفسه في كل مكان ، والتحديثات ، وبناء برنامجنا - كل شيء مماثل. فجأة ، لاحظ شخص ما أن جميع أجهزة الكمبيوتر المحمولة التي تم إنتاج المشكلة عليها هي من نفس الطراز. عدم توافق الأجهزة؟ ولكن لماذا فجأة الآن ، كانت تعمل ... بالإضافة إلى ذلك ، هناك أجهزة كمبيوتر محمولة أخرى من نفس الطراز في المكتب تعمل الآن. تمت مقارنة إصدارات برامج تشغيل الأجهزة - يبدو أن كل شيء هو نفسه. ولكن كل شيء يعمل على بعض أجهزة الكمبيوتر المحمولة ، ولكن ليس على غيرها.

استمر شد الشعر على الرأس حوالي نصف يوم ، حتى لاحظت بطريق الخطأ شيئين:

  1. PIDs العملية ، والتي عادة ما تكون من ثلاثة أرقام أو أربعة أو خمسة أرقام على جهاز الكمبيوتر الخاص بي لسبب ما تصبح ستة أرقام. كان من الغريب أن أرى معرف PID من النوع 780936. لم ألاحظ ذلك من قبل. علاوة على ذلك ، كان العدد الإجمالي للعمليات الجارية مناسبًا جدًا (يصل إلى مائة).
  2. أظهر مدير المهام في علامة تبويب وحدة المعالجة المركزية إجمالي عدد الواصفات في النظام - وكان ضخمًا ، أكثر من 800000.

بالنسبة للتطبيق العادي ، من الطبيعي فتح مائة أو واصفين. حسنا ، الف. مع الاستخدام النشط ، يمكن فتح chrome حوالي عام 2000 ، يمكن لـ Visual Studio فتح 3000 على المشاريع الكبيرة ، لكن من الذي فتح 800000؟ لحسن الحظ ، يتيح لك Process Hacker المذكور سابقًا إظهار عدد الواصفات لكل عملية وحتى فرز قائمة العمليات حسب عدد الواصفات المستخدمة.

وماذا نرى؟ ونحن نرى شيئا مثل هذه الصورة:



يجب أن أقول إنني قمت للتو بتصوير لقطة الشاشة المذكورة أعلاه ، لذا فإن أول قائمة في قائمة العمليات بها "فقط" حوالي 20.000 واصف. وبعد ذلك ، عندما رأيت المشكلة لأول مرة ، كان هناك حوالي 650.000. ومن هو بطلنا؟ البنغو! هذه هي العملية SynTPEnhService.exe.

ثم يتطور اللغز كله في رأسي. يعد SynTPEnhService.exe جزءًا من برنامج تشغيل لوحة اللمس Synaptics. تم تثبيته فقط على أجهزة الكمبيوتر المحمولة من طراز معين في مكتبنا ، والتي حدثت المشكلة. أظهرت ملاحظة قصيرة أن كل 5 ثوانٍ تبدأ هذه العملية في تشغيل العملية الفرعية SynTPEnh.exe ، والتي تغلق بعد 1-2 ثانية. في الوقت نفسه ، تستمر العملية الأصل في الاحتفاظ بواصف العملية الفرعية ، مما يؤدي إلى تسرب الواصفات. واحد في وقت واحد كل 5 ثوان. هذا هو 17280 واصف في اليوم الواحد. اترك الكمبيوتر قيد التشغيل لمدة أسبوع ، والآن لديك أكثر من مائة ألف واصف تعليق. لم تتم إعادة تشغيل جهاز الكمبيوتر الشخصي الخاص بي لأكثر من شهر - ومن هنا فإن أرقام التعريف الشخصية الخاصة بالعمليات الجديدة التي تزيد أعدادها عن نصف مليون. وهذا يفسر أيضًا سبب تكرار المشكلة على بعض أجهزة الكمبيوتر المحمولة في مكتبنا ، ولكنها لم تحدث على أجهزة الكمبيوتر المحمولة الأخرى: قام بعض زملائي بإعادة تشغيل أجهزة الكمبيوتر الخاصة بهم كل يوم ، وتركهم شخص مثلي في وضع التشغيل طوال الليل. .

بالمناسبة ، في هذا المكان ، تذكرت أنني قد قرأت بالفعل عن مشكلة ما في برامج تشغيل لوحة اللمس Synaptics. بعد قليل من الحفر ، وجدت هذا المقال الذي كتبه بروس داوسون (نُشرت ترجمات كثيرة لمقالاته في أوقات مختلفة على Habré ، ولكن ليس هذا التفسير المحدد). هناك يصف مشكلة تسرب الذاكرة بسبب إعادة التشغيل التي لا تنتهي لعملية SynTPEnh.exe ، لكنه لا يقول شيئًا عن مشكلة تسرب المقبض ، لذلك لا يزال اكتشافي مختلفًا عنها.

حل المشكلات


لذا ، فإن برنامج تشغيل لوحة اللمس "يأكل" مئات الآلاف من الواصفات - وماذا في ذلك؟ وحقيقة أن الدالة NtQuerySystemInformation (SystemHandleInformation، ...) المكتوبة مرة أخرى في أيام Windows NT لديها (ولديها) بعض المخزن المؤقت الداخلي محدود للغاية. لم أتمكن من العثور على مؤشر دقيق لحجمها في أي مكان ، لكن من الواضح أنه لم يكن مصممًا لوصف مليون واصف. ونتيجة لذلك ، تُرجعها الدالة "قدر الإمكان" ، مما يعني أنه من المحتمل أن تكون هناك الوظيفة المطلوبة أو لا تكون.

ماذا تفعل؟ كما قال ريك من سلسلة الرسوم المتحركة "ريك ومورتي": "عندما تخترع النقل عن بعد ، تكتشف على الفور شيئًا غير سارة: أنت آخر شخص في الكون ابتكره". كما اتضح فيما بعد ، أدركت Microsoft هذه المشكلة باستخدام المخزن المؤقت المحدود في NtQuerySystemInformation عند استدعاءها باستخدام وسيطة SystemHandleInformation بالفعل قبل 20 عامًا ، وبالتالي ، بدءًا من WindowsXP ، أضافوا وسيطة NtQuerySystemInformation وظيفة أخرى (وأيضًا غير موثقة) وسيطة SystemExtendedHandleInformation. عند استدعاء NtQuerySystemInformation (SystemExtendedHandleInformation ، ...) ، سيتم إرجاع جميع الواصفات في النظام إليك ، بغض النظر عن عددها. حسنًا ، أو بالأحرى ، لا أعرف هذا بالتأكيد ، ربما هناك بعض القيود على هذه الحجة ، لكن من المؤكد أنه يمكنه إرجاع 800000 واصف في إحدى الولايات.

على شبكة الإنترنت ، يمكنك العثور على أمثلة لاستخدام SystemExtendedHandleInformation ، على سبيل المثال ، هذا واحد . بشكل عام ، كل شيء مشابه هناك ، يتم استخدام هياكل أخرى ، وهذا كل شيء.

لقد كانت قصة مفيدة حول استخدام الوسائط غير الموثقة لنظام التشغيل Widnows ، والتي يمكن أن تكون مفيدة للغاية ، ولكنها تتطلب اختبارًا دقيقًا والاستعداد للمشاكل غير القياسية.

Source: https://habr.com/ru/post/ar433906/


All Articles