سؤال

كيف يقوم الجهاز الظاهري بإنشاء رمز الجهاز الأصلي بسرعة وتنفيذه؟

بافتراض أنه يمكنك معرفة ما هي أكواد تشغيل الجهاز الأصلية التي تريد إصدارها، كيف يمكنك تشغيلها فعليًا؟

هل هو شيء مبتكر مثل تعيين تعليمات ذاكري للرموز الثنائية، وحشوها في مؤشر char* وتحويلها إلى وظيفة وتنفيذها؟

أو هل يمكنك إنشاء مكتبة مشتركة مؤقتة (.dll أو .so أو أي شيء آخر) وتحميلها إلى الذاكرة باستخدام وظائف قياسية مثل LoadLibrary ?

هل كانت مفيدة؟

المحلول

يمكنك فقط أن تجعل عداد البرنامج أشر إلى الكود الذي تريد تنفيذه.تذكر أن البيانات يمكن أن تكون بيانات أو تعليمات برمجية.على نظام التشغيل x86، عداد البرنامج هو سجل EIP.يرمز جزء IP من EIP إلى مؤشر التعليمات.يتم استدعاء تعليمات JMP للانتقال إلى عنوان ما.بعد القفزة، سيحتوي EIP على هذا العنوان.

هل هو شيء مبتكر مثل تعيين تعليمات ذاكري للرموز الثنائية، وحشوها في مؤشر char* وتحويلها إلى وظيفة وتنفيذها؟

نعم.هذه هي إحدى الطرق للقيام بذلك.سيتم إرسال الكود الناتج إلى a المؤشر للعمل شركة.

نصائح أخرى

هل هو شيء مبتكر مثل تعيين تعليمات ذاكري للرموز الثنائية، وحشوها في مؤشر char* وتحويلها إلى وظيفة وتنفيذها؟

نعم، إذا كنت تفعل ذلك باستخدام لغة C أو C++ (أو شيء مشابه)، فهذا بالضبط ما ستفعله.

يبدو الأمر مبتكرًا، لكنه في الواقع قطعة أثرية من تصميم اللغة.تذكر أن الخوارزمية الفعلية التي تريد استخدامها بسيطة جدًا:حدد التعليمات التي تريد استخدامها، وقم بتحميلها في مخزن مؤقت في الذاكرة، ثم انتقل إلى بداية ذلك المخزن المؤقت.

إذا كنت تحاول حقًا القيام بذلك، فتأكد من حصولك على اصطلاح الاتصال بشكل صحيح عند العودة إلى برنامج C الخاص بك.أعتقد أنه إذا أردت إنشاء كود فسأبحث عن مكتبة لتهتم بهذا الجانب من أجلي.لقد ظهر نانوجيت في الأخبار مؤخرًا؛يمكنك أن تنظر إلى ذلك.

نعم.كل ما عليك فعله هو إنشاء char* وتنفيذه.ومع ذلك، عليك أن تلاحظ بعض التفاصيل.يجب أن يكون الحرف* في قسم قابل للتنفيذ من الذاكرة ويجب أن يكون بمحاذاة مناسبة.

بالإضافة إلى nanojit، يمكنك أيضًا الاطلاع على LLVM وهي مكتبة أخرى قادرة على تجميع تمثيلات البرامج المتنوعة وصولاً إلى مؤشر الوظيفة.واجهته نظيفة والكود الذي تم إنشاؤه يميل إلى أن يكون فعالاً.

بقدر ما أعرف فإنه يجمع كل شيء في الذاكرة لأنه يجب عليه تشغيل بعض الاستدلالات لتحسين الكود (على سبيل المثال:التضمين مع مرور الوقت) ولكن يمكنك إلقاء نظرة على المصدر المشترك البنية التحتية للغة المشتركة 2.0 الافراج عن الدوار.قاعدة التعليمات البرمجية بأكملها مماثلة لـ .NET باستثناء Jitter وGC.

بالإضافة إلى Rotor 2.0 - يمكنك أيضًا إلقاء نظرة على آلة هوت سبوت الافتراضية في OpenJDK.

حول إنشاء DLL:إن الإدخال / الإخراج الإضافي المطلوب لذلك، بالإضافة إلى الارتباط، بالإضافة إلى تعقيد إنشاء تنسيق DLL، من شأنه أن يجعل ذلك أكثر تعقيدًا، وقبل كل شيء سيقتل الأداء؛بالإضافة إلى ذلك، في النهاية لا تزال تستدعي مؤشر دالة للكود الذي تم تحميله، لذلك...أيضًا، يمكن أن يتم تجميع JIT بطريقة واحدة في كل مرة، وإذا كنت تريد القيام بذلك، فستقوم بإنشاء الكثير من ملفات DLL الصغيرة.

فيما يتعلق بمتطلبات "القسم القابل للتنفيذ"، فإن استدعاء mprotect() على أنظمة POSIX يمكن أن يصلح الأذونات (توجد واجهة برمجة تطبيقات مشابهة على Win32).يتعين عليك القيام بذلك لشريحة ذاكرة كبيرة بدلاً من ذلك مرة واحدة لكل طريقة لأنها ستكون بطيئة جدًا بخلاف ذلك.

في نظام x86 العادي، لن تلاحظ المشكلة، أما في نظام x86 مع PAE أو أجهزة AMD64/Intel 64 بت 64 بت، فستحصل على خطأ segfault.

هل هو شيء مخترق مثل رسم خرائط للإرشادات ذاكري للرموز الثنائية ، وحشوها في مؤشر char* وتلقيها كدالة وتنفيذ؟

نعم، هذا يعمل.

للقيام بذلك في نظام التشغيل Windows، يجب عليك تعيين PAGE_EXECUTE_READWRITE على الكتلة المخصصة:

void (*MyFunc)() = (void (*)()) VirtualAlloc(NULL, sizeofblock,  MEM_COMMIT, PAGE_EXECUTE_READWRITE);

//Now fill up the block with executable code and issue-

MyFunc();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top