كتابة عارية مع وظائف مخصصة حاسوب والخاتمة البرمجية في Visual Studio

StackOverflow https://stackoverflow.com/questions/886836

سؤال

أنا أكتب بعض رمز البرنامج المساعد في dll التي يتم استدعاؤها من قبل مجموعة أكثر من الذي لا نملك السيطرة عليه.

المضيف يفترض أن الإضافات التي يتم تصديرها كما __stdcall وظائف.المضيف هو قال اسم الدالة و تفاصيل الحجج التي يتوقع وحيوي كروفت حتى مكالمة عبر LoadLibrary ، GetProcAddress يدويا دفع الحجج على المكدس.

عادة المساعد dlls فضح ثابت واجهة.بلدي المساعد يعرض واجهة التي يتم تكوينها في dll وقت التحميل.لتحقيق هذا البرنامج المساعد بلدي يعرض مجموعة من معيار نقاط الدخول التي تم تعريفها في وقت dll يتم ترجمة و يخصص لهم حسب الحاجة الداخلية وظيفة هذا التعرض.

كل من الوظائف الداخلية قد يستغرق حجج مختلفة ولكن هذا هو إبلاغ المضيف جنبا إلى جنب مع المادية entrypoint اسم.كل من بلدي المادية dll entrypoints وتعرف أن تأخذ واحدة الفراغ * مؤشر وأنا المشير اللاحقة المعلمات من المكدس نفسي من خلال العمل من تعويضات عن الحجة الأولى و المعروفة الحجة القائمة التي وردت إلى المضيف.

المضيف بنجاح استدعاء وظائف في بلدي المساعد الصحيح الحجج و كل شيء يعمل بشكل جيد...ومع ذلك, أنا على علم أن) مهامي لا تنظيف المكدس كما أنها من المفترض أن كما انهم تعريف __stdcall الوظائف التي تأخذ مؤشر 4 بايت و لذلك هم دائما 'ret 4' في النهاية حتى لو كان المتصل يدفع أكثر الحجج على المكدس.و ب) لا أستطيع التعامل مع الوظائف التي لا تأخذ الحجج ret 4 سوف البوب 4 بايت الكثير من الخروج من كومة على العودة.

بعد أن تتبع من المساعد في المضيف كود الاتصال أستطيع أن أرى ذلك في الواقع) ليس صفقة كبيرة;المضيف يفقد بعض مساحة مكدس حتى تعود من إرسال الدعوة في هذه النقطة أنه ينظف لها إطار المكدس الذي ينظف بلدي القمامة ، ومع ذلك...

أنا يمكن أن تحل ب) عن طريق التحول إلى __cdecl وليس التنظيف على الإطلاق.أعتقد أنني يمكن حل) عن طريق التحول إلى عاريا وظائف والكتابة بلدي عام حجة تنظيف التعليمات البرمجية.

منذ أن أعرف مقدار حجة المساحة المستخدمة من خلال وظيفة التي كان يسمى تمنيت أن تكون بسيطة مثل:

extern "C" __declspec(naked) __declspec(dllexport) void  * __stdcall EntryPoint(void *pArg1)
{                                                                                                        
   size_t argumentSpaceUsed;
   {
      void *pX = RealEntryPoint(
         reinterpret_cast<ULONG_PTR>(&pArg1), 
         argumentSpaceUsed);

      __asm
      {
         mov eax, dword ptr pX
      }
   }
   __asm
   {
      ret argumentSpaceUsed
   }
}

ولكن هذا لا يعمل كما المتقاعد يحتاج إلى وقت الترجمة المستمر...أي اقتراحات ؟

تحديث:

بفضل روب كينيدي اقتراحات علي أن هذا الذي يبدو للعمل...

extern "C" __declspec(naked) __declspec(dllexport) void  * __stdcall EntryPoint(void *pArg1)
{      
   __asm {                                                                                                        
      push ebp          // Set up our stack frame            
      mov ebp, esp  
      mov eax, 0x0      // Space for called func to return arg space used, init to 0            
      push eax          // Set up stack for call to real Entry point
      push esp
      lea eax, pArg1                
      push eax                      
      call RealEntryPoint   // result is left in eax, we leave it there for our caller....         
      pop ecx 
      mov esp,ebp       // remove our stack frame
      pop ebp  
      pop edx           // return address off
      add esp, ecx      // remove 'x' bytes of caller args
      push edx          // return address back on                   
      ret                        
   }
}

هل هذا صحيح ؟

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

المحلول

منذ ret يتطلب الحجة المستمرة ، تحتاج إلى ترتيب وظيفة الخاص بك إلى عدد ثابت من المعلمات ، ولكن هذا الوضع هو المطلوب فقط في نقطة كنت على استعداد للعودة من وظيفة.لذا وقبل نهاية الدالة القيام بذلك:

  1. البوب عنوان قبالة الجزء العلوي من كومة وتخزينها في قاعدة مؤقتة ؛ ECX هو مكان جيد.
  2. إزالة عدد متغير من الحجج من المكدس ، إما ظهرت كل واحد على حدة ، أو عن طريق ضبط ESP مباشرة.
  3. الضغط على عنوان العودة مرة أخرى إلى المكدس.
  4. استخدام ret مع ثابت الحجة.

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

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