الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

[ تمت الإجابة ]كيف أعرف نوع مخرجات ومدخلات الدوال في مكتبات الربط الديناميكي ؟

بدأه هدف الشمالي في 27 نوفمبر 2012 · 3 رد · 970 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

أنا أتعرف على اسماء الدوال من خلال برنامج depends ولكن بحثت عن كيفية معرفة نوع مخرجات ومدخلات الدوال في مكتبات الربط الديناميكي ولم لم أجد .

#2

إسماء الدوال تظهر لأن المكتبة تصدّر الإسم فقط، فلايمكن معرفة نوع المتغيرات مباشرة. إذا كانت المكتبة متاحة فإبحث عن توثيق الدالة التي تريدها في الإنترنت، أمّا لو كانت مكتبة خاصة وغير موثقة إذا كانت شهيرة كمكتبة ntdll.dll فجرب أن تبحث في الإنترنت فربما تجد شيء. إذا لم تجد شيء فلا يوجد أمامك الا الهندسة العكسية.

جرب أن تستخدم منقح IDA ففيه decompiler جيد يمكنه تقريب الدالة لك لأقرب كود C، بشع لكنه أفضل من أنك تتبع كود أسمبلي. قم بتحميل المكتبة للبرنامج وإبحث في المستطيل الأيسر عن إسم الدالة، إضغط عليها وإضغط على زر F5 لعمل decompiling.

مثلاً هذا تعريف دالة من أحد دوال مكتبة cairo للرسم:

void cairo_line_to (cairo_t *cr, double x, double y)

الكود الذي ولده IDA:

int __cdecl cairo_line_to(int a1, double a2, double a3)
{
  int result; // eax@1
  int v4; // eax@2
  double v5; // [sp+20h] [bp-18h]@1
  double v6; // [sp+28h] [bp-10h]@1

  v6 = a2;
  v5 = a3;
  result = *(_DWORD *)(a1 + 4);
  if ( !result )
  {
    v4 = *(_DWORD *)(a1 + 28);
    if ( !*(_DWORD *)(v4 + 328) )
      sub_68DD7330(v4, &v6, &v5);
    result = sub_68DE7A5C(a1 + 724, COERCE_UNSIGNED_INT64(v6 + 2.6388279e13), COERCE_UNSIGNED_INT64(v5 + 2.6388279e13));
    if ( result )
      result = sub_68DCD954();
  }
  return result;
}

واضحه الأخطأ لأنه في النهاية توليد آلي لكنه بالتأكيد أفضل من النظر لتعليمات أسمبلي.

في المتغير الأول a1 وضعه int بينما ترى عمليات وصول لمتغيرات مثل a1 + 4 و a1 + 28 و a1 + 724 فالأرجح أنه مؤشر لبنية (قد تكون أحياناً مصفوفة الا أن الأول أرجح لأن تلك الأرقام تقبل القسمة على أربعة والوصول غير منتظم) . ولكن يمكنك الرؤية بوضوح أن المتغير الثاني والثالث double وهذه يعرفها البرنامج لأنه توجد تعليمات خاصة للأعداد العشرية. بالنسبة للقيمة التي تعيدها الدالة فيمكن التحقق منها عن طريق تنقيح دالة تستدعيها بداخل المكتبة أو البرنامج ، إضغط على إسم الدالة وإضغط زر X وسترى الأماكن التي إستدعيت منها الدالة داخل المكتبة.

إذا عرفت المدخلات قم بكتابة تعريف لها ، prototype ، في المتغيرات من المهم أن تختار نوع مطابق في الحجم, لـ8 بت إختر char ولـ32بت إختر int وهكذا, وتأكّد من إستخدام إسلوب الإستدعاء الصحيح (__cdecl أو __stdcall أو __fastcall).

مثال للنوع السابق:

typedef int (__cdecl *cairo_line_to_t)(unsigned int p, double a, double b);

ثم قم بإستدعاءها عن طريق تحميل المكتبة بإستخدام LoadLibrary وإستدع بعدها الدالة عن طريق GetProcAddress :

typedef int (__cdecl *cairo_line_to_t)(unsigned int p, double a, double b);

cairo_line_to_t cairo_line_to =
    (cairo_line_to_t) GetProcAddress(LoadLibrary(TEXT("foo.dll")), "cairo_line_to");

قبل كل هذا تأكد أنك تعرف ماتقوم به الدالة لأنها رايح ستسهل عليك الشغل. وتأكّد من أن الدالة لاتأخذ مقبض. مثلاً في هذا المثال:

typedef struct {
    char *privat;
} Object;

Object *foo_init(void)
{
    Object *ptr = NULL;
    if( (ptr = (Object*) malloc(sizeof(Object))) == NULL )
        return NULL;
    ptr->privat = 'p';
    return ptr;
}

void foo_do_something(Object *ptr)
{
    // ...
}

void foo_destroy(Object *ptr)
{
    if(ptr) free(ptr);
}

لن يمكنك إستدعاء الدالة foo_do_something إلا إذا إستدعيت foo_init وهيأت مؤشر البنية Object.

5
#3

+ 1

رد شامل لجوانب الموضوع , يغني كثيرًا عن البحث .

#4

على ما أتذكر يمكن الإطلاع على API من خلال reflector ، (آه!! هرمنا :) )

لا تنسى إستخدام FreeLibrary للتخلص من Handler و إسترجاع الذاكرة المحجوزة ب LoadLibrary

مواضيع مشابهة

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…