الـ Global Api Hooking - نسخة قابلة للطباعة +- الفريق العربي للهندسة العكسية (https://www.at4re.net/f) +-- قسم : منتديات البرمجة - Programming Forums (https://www.at4re.net/f/forum-5.html) +--- قسم : قسم البرمجة العام - General Programming Section (https://www.at4re.net/f/forum-15.html) +--- الموضوع : الـ Global Api Hooking (/thread-3267.html) |
الـ Global Api Hooking - TeRcO - 11-09-2022 إقتباس :الدرس منقول لــ: Ph-RevIng الدرس 1 : كيف تبرمج Inject Dll / DLL باستعمال الدالة CreateRemoteThread بسم الله الرحمن الرحيم السلام عليكم ورحمة الله تعالى وبركاته سنتكلم اليوم عن موضوع مهم جدا في مجال البرمجة " Api Hooking " اضن ان اغلبكم يعرف ما المقصود بالـApi Hooking , ومن لا يعرف فالمقصود بشكل مبسط هو خطف ( ان صح التعبير ) الدوال او بمعنى اخرلديك برنامج شغال على الويندوز ويستدعي بعضا من دوال الـApi وخطرت لك فكرة ببالك سواء منع دالة (A) من العمل او عمل Filtering او اي شيئ ... اي انه عند استدعاء الدالة ( A ) سيتم استدعاء دالتك (B) بدلا من (A ) ولك القرار . هدا هو المفهوم بشكل اجمالي . ما سنستعلمه في هدا الموضوع هو الـGlobal Api Hooking بمعنى Hook على اي برنامج يعمل على الويندوز او عليها كلها الحكاية طويلة جدا سنتطرق الى عدة امور مع الشرح الدقيق هدا قررت تقسيم الموضوع الى تمانية دروس (وجدت اول اثنين فقط ) : الدرس 1 : كيف تبرمج Inject Dll / DLL باستعمال الدالة CreateRemoteThread الدرس 2 : Inject DLL بالدالة SetWindowsHookEx الدرس 3 : Inject DLL باستعمال Code injecting وتحويل EIP الدرس 4 : Inject DLL باستعمال The IvanOv m4l4ri4 (اسم مخترعها ) الدرس 5 : Unload DLL الدرس 6 : Api Hooking باستعمال الـIAT Patching الدرس 7 : Api Hooking باستعمال الـ Hot Patching الدرس 8 : Api Hooking باستعمال الـInline Patching اللغة المستخدمة : سي / القليل من الاسمبلي ان شاء الله يبقى الموضوع مرجعا لكل عربي باحت في هدا المجال . كيف تبرمج DLL Inject DLL باستعمال الدالة CreateRemoteThreadنبدأ ببرمجة DLL : لن نتكلم كتيرا عن هدا الموضوع لان Dll التي سنربمجها بسيطة جدا لنرى الكود الاتي:
هدا كود DLL بسيط جدا ولن تختلف DLL التي سنربمجها عن هده كما تلاحض في الكود وجود الدالة DllMain وهي تكافئ الدالة Main اي نقطة البدأ Entry Point HInstance وهو مقبض الـDLL dwReason هده الخاصية يتم استلامها من قبل نضام التشغيل فور تحميل الـDLL ولها اربع قيم DLL_PROCESS_ATTACH DLL_PROCESS_DETACH DLL_THREAD_ATTACH DLL_THREAD_DETACH ما يهمنا هو DLL_PROCESS_ATTACH اما البارامتر التالت فهو يخص نضام التشغيل راجعو الرابط :
حسنا يبدو الكود واضحا الان فادا قام Thread بتحميل المكتبة داخل Adress Space للـProcess ستضهر رسالة MessageBox وهده هي النتيجة التي سنصل اليها في درس اليوم كما تلاحضون فقد تم حقن DLL في Process برنامج الميسانجر نمر للمرحلة التانية Inject DLL باستعمال الدالة CreateRemoteThread لعمل الـGlobal Hook نحتاج الى حقن DLL داخل Process البرنامج الهدف وكود الـHook سيكون داخل الـDLL وتعتبر هده التي سنشرحها جيدة لعمل هدا الحقن . ما هي الخطوات التي تتطلبها هده الطريقة ؟ 1 جلب PID للـProcess الهدف (PID = Process Id 2 الحصول على الـProcess Handle 3 حجز مساحة داخل مساحة الـProcess لنتمكن من كتابة مسار الـDLL 4 انشاء Thread جديد داخل الـProcess دوره تحميل الـDLL بعد ان عرفنا الخطوات سنقوم بشرحها واحدا واحدا جلب PID للـProcess الهدف سنستعمل الطريقة الروتينية بالدالة CreateToolhelp32Snapshot تم Process32Next و بما اننا سنترك المستخدم يختار أي Process يريد حقن DLL به فسنعمل EditBox يدخل بها اسم الـ Process ونفس الامر مع الـDLL سنقوم بجلب اسم الـProcess الدي ادخله المستخدم في الـEditBox عبر الدالة GetDlgItemText ودالك باعطائها مقبض الـEditBox وسنعمل دالة نمرر لها الاسم المدخل و تجلب لنا الـPID ولنسمها GetPID الدالة GetPID ستقوم بالدخول في حلقة جلب الـProcess الاول تم التاني تم التالت حتى نمر عليها كلها ودالك بالدالة Process32Next وفي كل مرة نقارن اسم الـProcess الدي ادخله المستخدم بالاسم الحالي الدي حصلنا عليه سيكون الكود كالاتي :
حسنا يبدو الكود واضحا ( اي غموض ارجو طرحه ) الى هنا انتهت المرحلة الاولى . الحصول على الـProcess Handle تدكر ان الدالة السابقة اعادة لنا الـProcess ID (هناك فرق بين الـProcess ID والـProcess Handle ) لكي نجلب الـProcess Handle سنستخدم الدالة OpenProcess
مررنا لها prid وهو الـProcess ID الدي اعادته لنا الدالة السابقة انتهت المرحلة التانية حجز مساحة داخل مساحة الـProcess لنتمكن من كتابة مسار الـDLL سنقوم بحجز المساحة بالدالة VirtualAllocEx هده الدالة تتطلب الـProcess Handle وهو البارامتر الاول لها ( تدكر اننا حصلنا عليه فوق ) , البارامتر التالت للدالة يتطلب حجم المساحة التي سيتم حجزها . حسنا بما ان برنامجنا يسمح للمستخدم بحقن اي DLL شرط ان يدخل مسارها سنقوم باخد هدا المسار كما اخدنا اسم الـProcess تم نحسب طوله بالدالة strlen لكن حداري هنا فهده الدالة تحسب طول الـString دون الـNULL لدا علينا زيادة 1 يصبح الطول الدي سنحجزه يساوي طول المسار الدي ادخله المستخدم + 1
DllPath هو متغير سنخزن فيه مسار DLL الدي ادخل المستخدم نرجع للدالة VirtualAllocEx البارامتر الاخير لها يمتل نوع الحماية , سنضع PAGE_EXECUTE_READWRITE للاننا سنكتب على هدا العنوان
بعد ان تم حجز المساحة بنجاح سنقوم بكتابة مسار DLL داخل المساحة المحجوزة الكتابة تتم بالدالة WriteProcessMemory البارامتر الاول لهده الدالة هو Process Handle ايضا , البارامتر التاني هو العنوان الدي تريد ان تبدأ عنده الكتابة وهنا سنستعمل عنوان المساحة التي قمنا بحجزها البارامتر التالت هي السلسلة او ... التي تريد كتابتها سنقوم نحن هنا بكتابة مسار الـDLL
انتهت المرحلة التالتة انشاء Thread جديد داخل الـProcess دوره تحميل الـDLL قبل ان ننشأ Thread سنحتاج عنوان الدالة LoadLibrary لان هده الدالة هي التي ستحمل الـDLL من داخل البرنامج , لجلب عنوانها سنستعمل الدالة GetProcAdress
حسنا الان بقيت لنا خطوة واحدة وهي انشاء Thread داخل الـDLL بعد تشغيله يقوم بتحمل DLL وتشغيلها لنتمكن من عمل هدا الامر سنستخدم الدالة CreateRemoteThread البارامتر الاول لهده الدالة هو الـProcess Handle والدي حصلنا عليه سابقا في البارامتر الرابع سنضع عنوان الدالة LoadLibrary والبارامتر الخامس عنوان التي String تحمل مسار الـDLL
ما بقي علينا هو استعمال الدالة WaitForSingleObject للانتضار حتى يتم انشاء الـThread تم نقوم بتحرير المساحة وجعلها free تم تحرير المقابض
الكود النهائي للبرنامج :
الدرس 2 : Inject DLL بالدالة SetWindowsHookEx
بسم الله الرحمن الرحيم السلام عليكم ورحمة الله تعالى وبركاته بعد اطلعنا في الدرس السابق عن الطريقة الاولى لحقن ملفات الـDLL اليوم سنتكلم عن طريقة اخرى مهمة جدا باستعمال الدالة SetWindowsHookEx موضوع اليوم يشرح هده الدالة من عدة جوانب اولا اترككم لتتعرفو اكتر على هده الدالة من مكتبة MSDN
يمكننا باستعمال هده الدالة عمل Hook على الرسائل التي يرسلها النضام لمختلف التطبيقات ما المقصود بالرسائل ؟ ان كل تطبيق ( برنامج ) يحتوي على ما يسمى الـ Message Queues يمكن تسميتها بالعربي مكان لتخزين الرسائل , هده الرسائل يتم ارسالها من قبل النضام الى Message Queues فور حدوتها , فمتلا عندما تضغط فوق زر في النافدة فان النضام يرسل الرسالة WM_COMMAND وتقوم الدالة GetMessage بجلب هده الرسالة وتمريرها للدالة DispatchMessage ومن هده الاخيرة الى الـWindow Procedure التي يقوم المستخدم بمعلاجة الرسائل داخلها داخلها (ادا كانت الرسالة ضغطة من الكايبورد تمر الرسالة من GetMessage الى TranslateMessage تم DispatchMessage ) متلا ادا ضغط الزر كدا و كدا تضهر رسالة MessageBox نفترض ان لدينا زر في النافدة والـID الخاص به هو 1005 نريد هدا الزر عند الضغط عليه ان يقوم بعمل ما ... عندما يقوم المستخدم بالضغط فوق الزر فان النضام يولد الرسالة WM_COMAND في الـ Message Queues تم تقوم الدالة GetMessage بجلبها وارسالها الـWindow Procedure حيت يتم تحليلها على انها WM_COMMAND تم تحديد الـID ادا كان هو نفسه للزر الدي وضعنا نقوم بتنفيد ما كنا نود الزر ان يقوم به اضن ان مفهوم الرسائل اصبح واضحا وطبعا مبرمجو الـ Api يعرفون هدا الامر حق المعرفة . لنرجع لموضوعنا حول الدالة SetWindowHookEx ما تقوم به هده الدالة هو خطف هده الرسائل ونحن من سيبني الـWindow Procedure بمعنى ان الرسالة نحن من سيعالجها ولنا القرار نعمل اي شيئ نريده كمتال لاستعمال هده الدالة في الهندسة العكسية لنفترض ان لديك برنامج , زر الدخول معطل Disabled تريد تفعيل هدا الزر طبعا ستستعمل احدى البرامج التي تتعامل مع النوافد متل برنامج الاخ السندباد Window Handler لكن بمجرد غلق البرنامج واعادة فتحه سيتم اعادة الزر الى وضعه السابق لتجاوز هدا المشكل يمكن كسر البرنامج بتعديل بايت واحد فقط كما يمكن عمل هدا برمجيا باستعمال الدالة السابق دكرها . كل ما تكلمنا عنه هو الـHook على رسائل النضام ( وليس Api Hooking ) كما يمكن للدالة عمل Hook على الكايبورد وعلى الماوس ..... لندرس بارامترات الدالة : البارامتر الاول وهو نوع الـHook سنستعمل WH_GETMESSAGE يعني Hook على الرسائل التي يرسلها النضام الى النافدة البارامتر التاني وهو عنوان الـHook Procedure التي سنعالج من خلالها الرسائل ( راجع المقدمة اعلاه ) البارامتر التالت وهو مقبض الـDLL الموجودة بها الـHook Procedure البارامتر الرابع وهو Thread ID للبرنامج الدي تريد ان تعمل عليه الـHook قبل ان ندخل في طريقة حقن DLL بهده الدالة , ليكون الموضوع اكتر وضوحا سوف نعمل Local Hook بمعنى Hook على نافدة برنامجنا حتى نتعود على مفهوم عمل هده الدالة خطوة بخطوة وتكون مكتسباتنا كبيرة من الدرس . سنقوم بعمل برنامج لا يحتوي على شيئ سوى نافدة ادا ضغط المستخدم على زر Entr متلا تضهر له رسالة او اي شيئ تريد ان تبرمجه حين يضغط المستخدم على الزر Entr بما ان الـHook داخلي على برنامجنا فقط فلن نحتاج الى برمجة DLL سنقوم بكتابة Hook Procedure داخل كود برنامجنا نشاهد الكود اولا
نتيجة البرنامج : عند الضغط على زر Enable Hook سيتم تنصيب Hook على نافدة برنامجنا فادا تم الضغط على الزر Entr سيتم التعرف عليه واضهار رسالة MessageBox وادا تم الضغط على Disable Hook سيتم ازالة الـHook وبعدها حتى لو ضغطت Entr لن يتعرف برنامجنا على انك ضغطتها . لنشرح الكود حتى نفهم كيف تتم العملية : البارامتر الاول للدالة SetWindowHookEx يمتل نوع الـHook الدي تريد وضعه اخترت , بما انه على ضغطات الكايبورد فساضع WH_MSGFILTER البارامتر التاني وهو الـ Hook Procedureالتي ستعالج الرسائل وقد سميتها KeyProc البارامتر الثالث مقبض DLL التي تحتوي على الـCall Back بما اننا الان سنعمل Hook على نافدة برناجنا فقط فسنضعه 0 لاننا سنكتبه داخل كود البرنامج البارامتر الرابع هو Thread ID الدي تود ان تضع عليه Hook سنضع Thread ID الخاص لبرنامجنا وهدا ما تقوم به الدالة GetCurrentThreadId نأتي الان الى الـ Hook Procedureالتي ستعالج الرسائل اولا يجب ان تعلم ان اي رسالة (نسبيا) سيتم ارسالها لنافدة برنامجنا ستمر من هنا اولا بارامترات هدا الـCall Back او الـHook Proc مشروحة جيدا في مكتبة MSDN
في حالتنا هده سنستعمل LPARAM وهو يؤشر على Structure من النوع MSG
طبعا الكود اصبح واضحا نبدأ في تحليل البيانات فادا كانت الرسالة هي WM_KEYDOWN يعني ان هده الرسالة التي استقبلناها الان هي ضغطة من الكايبورد ومن WPARAM (الخاص بـMSG ) يمكننا تحديد اي زر تم ضغطه حيت VK_RETURN تمتل الزر Entr بالنسبة للدالة CallNextHookEx فهي لاستمرار في حلقة الـHook وجلب وتحليل الرسائل . يمكنك استعمال هده الطريقة في التحكم ببرناجك عبر الازراركما تستعمل في برامج الـKeyLogger والفايروسات التي تعطل او تبعتر ازرار الكايبورد كما يمكنكا استعمالها في اعادة برمجة لوحة المفاتيح في حالة تعطل لك زر معين وتريد تعويضه بزر اخر لكن ستسعمل Hook شامل على الكايبورد WH_KEYBOARD_LL ( سنرى هدا في دروس لاحقة ) . حسنا الان لنعدل قليلا على برنامجنا ونجعله يحقن ملف DLL في نفسه بمجرد الضغط على Entr DLL التي سيتم حقنها هي نفسها التي استعملنا في الدرس السابق
كود البرنامج
يبدو ان الكود واضح عوض رسالة MessageBox قمت بتحميل الـDLL بالدالة LoadLibrary وستضهر الرسالة Hello World ( الـDLL تم تحميلها داخل Adress Space لبرنامجنا ) حسنا الان نريد من هده DLL ان تحقن فور حدوت اي حدت على مستوى النافدة يعني بمجرد ان تتلقى النافدة رسالة ما تحقن الـDLL وليس بالضرورة ضغط Entr الامر بسيط ، سنزيل فقط كود الفلترة ونضع على WH_GETMESSAGE
ليصبح الكود الجديد
يبدو ان الامر لحد الساعة واضح ، سننتقل الان الى Global Message Hooking وهو نفس الامر بالنسبة لما سبق فقط عوض ان نقوم بـHook على برنامجنا سنقوم به على برنامج اخر كما يمكنك القيام به على جميع البرامج دفعة واحدة , وهو الدي سنستعمله في حقن الـDLL في برنامج خارجي لعمل هدا الامر يجب ان تكون Hook Procedure داخل DLL نرتب عملنا خطوة خطوة : 1 جلب Thread ID للبرنامج الدي نريد تنصيب الـHook عليه ( تنصيب الـHook غرضنا منه هو حقن ملف dllH.dll 2 برمجة DLL التي تحتوي على الـHook Procedure 3 تنصيب الـHook على البرنامج الهدف جلب الـThread ID للبرنامج الهدف تطرقنا الى هده الطريقة في الدرس السابق وكتبنا الكود الاتي
يمكننا استعمال نفس هدا الكود لكن لنتفادى هدا التكرار ساريكم طريقة اخرى للحصول على Thread ID لنشاهد الكود اولا
نلاحظ في بداية الكود انه يشبه الكود الاول فقد استعملنا CreateToolhelp32Snapshot وحلقة ProcessNext/ProcessFirst غيرت قليلا في حلقة While كما اسعملت الدالة StrStrI لكن ان لاحضنا الكود السابق فهو يعيد مباشرة Thread ID عن طريق العنصر th32ProcessID التابع لـPROCESSENTRY32 STRUCTURE والدي يتم ملئها بمعلومات الـProcess في كل دورة الكود الحالي نلاحض انه عندما يجد الـProcess يقوم بالخروج من الحلقة دون اعادة th32ProcessID والدي يحتوي على Thread ID يتجه مباشرة الى كود الاسمبلي الاتي
نقوم في هدا الكود بقرائة الـThread Information Block وهذا الامر
يضع عنوان Thread Information Block في eax تم عملنا ازاحة للوصول الى عنوان الـThread ID وقمنا بتخزينه في المتغير TIDADDR , الان وبما اننا حصلنا على العنوان الدي يبدأ عنده Thread id فما علينا هو قرائته بالدالة ReadProcessMemory بهده الطريقة يمكننا معرفة معلومات كتيرة عن الـThread كما يمكن الوصول الى الـPEB وقرائة معلومات الـProcess ...... راجعو هدا الرابط :
انتهت الخطوة الاولى 2برمجة DLL التي تحتوي على الـHook Procedure كما دكرنا سابقا لنعمل Message Hook على رسائل نافدة غير نافدة برنامجنا نحتاج الى وضع الـHook Procedure في ملف DLL لنرى كود DLL
ملاحظة : حتى لا تتوهو هنا سيكون لدينا 2 DLL الاولى هي التي برمجنا في الدرس السابق والتي عند حقنها تضهر الرسالة Hello World والـDLL التانية التي تقوم بالـHook على الرسائل نرجع للكود اعلاه ، كما تلاحظون لا جديد نفس الـHook Proc التي اسعملناها في Local Hook الفرق اننا وضعناها في DLL لنتمكن من توزيعها على اي برنامج نريد فقط نلاحض زيادة بسيطة هي الجملة
هده الجملة تمتل نوع التصدير للدالة InjectDllProc لكي نتمكن من استدعائها من برنامجنا الكلمة _declspec تستخدم لاعلام الـLinker ببعض المعلومات التي من المفترض كتابتها يدويا ادا استعملنا طريقة Module-Definition File في التصدير ( للمزيد من المعلومات راجع MSDN ) dllexport تعني وضع الدالة في جدول التصدير Export Table للمكتبة ( ملف الـPE عامة ) نواجه مشكلا هنا هو ان الدالة رغم ان اسمها InjectDllProc الا انها لن تصدر بهدا الاسم يمكن التأكد من هدا بفتح المكتبة في برنامج LordPe تم Directories تم Export Table واضغط على التلات نقط ولاحض انها فعلا لم تصدر باسمها الحل هو كليك يمين تم Edit وسمها InjectDllProc تم Ok Save اضن الكود اصبح واضحا الان الى هنا انتهت الخطوة التانية تنصيب الـHook على البرنامج الهدف ما بقي لنا الان هو جلب عنوان الدالة InjectDllProc ( عبر الدالة GetProcAddress ) لكي نستعمل في الدالة SetWindowHookEx الكود :
|