بازگشت | مشاهده نسخه اصلی

BreakPoint چيست ؟

چرا BreakPoint مهم است ؟


وقتي در حال ديباگ – به معناي بررسي مجدد و رفع خطاها و نواقص – يك برنامه هستيد ، شايد مايل باشيد در نقطه اي مشخص ، يعني مثلا" در ادرس خاصي رو حافظه ، يا قبل از اجراي دستور زبان ماشين خاصي ، مقدار برخي از متغيرها را – قبل از ادامه يافتن برنامه – چك كنيد ، يا قبل از فراخواني يك تابع ، از صحت اجرا و بازگشت تابع ديگري مطمئن شويد ، يا وقتي در حال مهندسي معكوس يك باينري هستيد شايد مايل باشيد درست هنگام فراخواني API به خصوصي ، يا هنگام ارجاع دسترسي به ماژول به خصوصي ، روند اجراي برنامه بصورت عادي متوقف ، و اعمالي توسط شما انجام شود‌ ، شايد مقاديري بررسي شوند يا وضعيت متغير يا تابعي در فضاي آدرسي برنامه – و در زمان اجرا – تغيير كند و ...مواردي مانند اين . در حقيقت هر وقت براي كاربر يك باينري مهم باشد كه در مسير و روند اجراي باينري ، در مقاطع خاص و مشخصي ، با توقف كليه روندهاي در حال اجراي برنامه ، وضعيت عناصر خاصي از برنامه بررسي ، يا محتواي برخي از آنها در همين حين تغيير كند ، يك BreakPoint مفيدترين گزينه است .

يك BreakPoint اصولا" چه چيزي است ؟



قبل از پاسخ بايد بدانيم BP ها را ميتوان به دو دسته كلي تقسيم كرد :

  • Hardware BP
  • Software BP

BP هاي اصطلاحا" سخت افزاري ، قابليتي هستند كه توسط خود پردازنده در اختيار سيستم عامل و نرم افزارهاي آن قرار ميگيرند . اغلب پردازنده هاي امروزي رجيسترهاي انحصاري براي فرآيندهاي مرتبط با ديباگ در نظر گرفته اند ، بدين معني كه آدرس و مشخصات BP مورد نظر كاربر در اين رجيسترها ثبت و در زمان مناسب توسط پردازنده استفاده خواهند شد ، و اين يعني توقف روند اجرا توسط خود پردازنده و با قابليتهاي داخلي اش انجام خواهد شد ، و شايد صحيح تر و فني تر باشد كه بگوئيم ، فرا رسيدن يك BP توسط پردازنده به ديباگر گزارش خواهد شد و اين ديباگر است كه با اعلان پردازنده ، روند اجرا را "كنترل" ( و نه لزوما" متوقف ) ميكند .

BP هاي اصطلاحا" نرم افزاري ، نقاط توقفي هستند كه توسط ديباگر ايجاد و مديريت ميشوند . ديباگر با دريافت موقعيتي كه كاربر باينري مايل است يك نقطه توقف باشد ، محل دقيق نقطه مذكور را با دستور ديگري كه اصطلاحا" تله يا Trap نام دارد پر ميكند ، كه اين Trap شايد يك Instruction مخصوص يا يك دستور نامناسب كه توليد خطا يا استثناء ميكند باشد ، كه بدين ترتيب ، با رسيدن به موقعيت مذكور و بروز "حادثهء" مورد نظر ، ديباگر از محقق شدن "فراخواني BP" مطمئن ميشود ، و برنامه را كنترل ميكند . Instruction يا دستوراتي كه به عنوان Trap در نظر گرفته ميشوند بايد تا حد امكان از لحاظ طول و اندازه كوتاه باشند ، بطوريكه نتوان به وسط يك Trap يا جائي بين آن ، Jump كرد اغلب پردازنده ها يك دستور غير صحيح يا illegal دارند كه ديباگرها ميتوانند از اين Instruction به عنوان Trap استفاده كنند .

مثال يك : پردازنده هاي خانواده x86 اينتل كه مبتني بر معماري IA32 هستند ، روي مدلهاي i386 به بعد ، حداقل هشت رجيستر به نامهاي DR0 تا DR7 به بعد به عنوان Debug Register در نظر گرفته است يا پردازنده هاي شركت فليپس كه مبتني بر مدل ARM4 و متعلق به خانوادهء LPC21xx هستند تا 12 رجيستر 32 بيتي براي ديباگ در نظر گرفته اند ؛ رجيسترهاي ديباگ بسته به معماري مورد نظر ، كاربرد و منظور مشخصي دارند و – اغلب – از هر كدام آنها وظيفه اي خاص انتظار ميرود كه حمايت از BP هاي سخت افزاري يكي از اين وظايف است .

مثال دو : GDB يا GNU Debugger به عنوان معروفترين ديباگر منبع آزاد ، كه دامنه وسيعي از معماريهاي سخت افزاري و نرم افزاري را حمايت ميكند ، از گونه هاي مختلف و متنوع BP نرم افزاري پشتيباني ميكند ؛ Software BP ها ميتوانند مبتني بر يك Regular Expression باشند ، مثلا" در اين صورت كه EAX محتوي عددي خاص و EDX تهي بود ، آدرس مشخصي حاوي يك BP خواهد بود ، و الا خير ، كه به اين نوع BP اصطلاحا" WatchPoint گفته ميشود ؛ نوع ديگري از BP نرم افزاري بنام CatchPoint وقتي بوجود مي آيد كه "واقعهء" مشخصي اتفاق افتاده باشد ، مثلا" در صورت وقوع فلان استثناء در فلان روتين CPP يا فراخواني فلان ماژول توسط برنامه ، فلان آدرس حاوي BP خواهد بود . هنگام استفاده از GDB اگر بخواهيد روي تابع خاصي BP بگذاريد مينويسيد : Break function.name يا اگر مايليد روي آفست خاصي BP‌بگذاريد مينويسيد : Break offset.number و ...ديباگر هاي مختلف روشهاي متفاوتي براي تزريق BP به روند اجراي برنامه دارند ، و اغلب ديباگرهاي امروزي كه نما و رابطي بصري دارند به كمك چند كليك ، انواع متفاوتي از BP را روي كد ايجاد ميكنند ؛

چگونه از وجود BreakPoint مطلع شويم ؟


BP ها يا روي پردازنده هستند يا كدي هستند در متن برنامهء در حال اجرا ، پس بايد روش يا روشهاي مشخصي براي اطلاع از وجود يك BP هنگام اجرا كد وجود داشته باشد . فرض كنيد برنامه اي نوشته ايد كه به دلائلي مايليد مورد بررسي قرار نگيرد ، در واقع دوست نداريد كسي آن را ديباگ كند ، و ديباگ بدون BP امكان پذير نيست ؛ شايد ساده ترين روش بررسي رجيسترهاي CPU براي وجود يا عدم وجود BP باشد ، و بعد از آن بررسي محلهاي خاصي از برنامه كه امكان دارد نقاط خوبي براي يك توقف باشند ، وقتي به عنوان مثال روي معماري اينتل Trap يا همان illegal instruction ما int 3 هست ، قاعدتا" اگر يك BP نرم افزار معمولي در محل A وجود داشته باشد ، قبل از رسيدن به محل A بايد بررسي آن محل به خروجي 0xCC كه معادل int 3 است منتج شود . معمولا" سيستمهاي عامل دسترسي مستقيم به رجيسترهاي حساس و كنترلي را لغو ميكنند و اين خدمت از طريق API هاي سطح بالا ارائه ميشود ، و ميتوان از اين توابع براي كسب اطلاع از وجود Hardware BP استفاده كرد ، و اگر ديباگر با Hook و re-direct اين توابع ، خروجي آنها را تغيير دهد ، كسب اطلاع از وضعيت واقعي پردازنده دشوار است ، و مرحله بعدي نبرد ، مقابله با Hook است و ...و همينطور براي BP هاي نرم افزاري ...؛ در واقع روشهاي عمومي كسب اطلاع در مورد BP ساده و روشن اند اما وقتي اين چالش به يك مقابله مبدل شود ، صورت مسئله كسب اطلاع دربارهء BP نخواهد بود بلكه عبور از سد ها يا مقابله با روشهائي است كه واقعيت را تحريف ميكنند . يكي از مسائل جاري و عمومي مهندسي معكوس ، كشف نقاط ضعف نرم افزاري ، كرك نرم افزارهاي تجاري و قفلها و غيره ، مبارزه با ديباگ ، يا همان روتينهاي آنتي ديباگ هستند ، كه مسئلهء BreakPoint يكي از سر فصلهاي جدي آن است .

Memory BreakPoint چيست ؟

بر خلاف BP هاي سخت افزاري كه تعريف محدود و معيني دارند ، BP هاي نرم افزاري ميتوانند منعطف و خلاق باشند . در واقع براي اينكه نقطه اي ، نقطهء توقف باشد ، ميتوان شروط و قواعد و ملاحظات متعددي را در نظر گرفت ، كه هر كدام ، و يا با تركيب بعضي از آنها ، يك Software BreakPoint جديد داريم . Memory BreakPoint ها پيش از همه توسط ديباگر محبوب و معروف OllyDbg معرفي شدند .

يك Memory BreakPoint ، دسترسي به مكان يا "محدوده" خاصي از فضاي آدرسي برنامه را به ديباگر اطلاع ميدهد . تفاوت چشمگير Memory BP ها در ماهيت انهاست . Hardware BP ها از رجيسترهاي CPU كمك ميگيرند پس كشف انها چندان دشوار نيست و Software BP ها هميشه چيزي شبيه به 0xCC به كد برنامه روي حافظه اضافه ميكنند و كشف آنها روز از ذهن نيست ، اما Memory BP ها – خصوصا" روي ويندوز – از تكنيك متفاوتي استفاده ميكنند كه پيدا كردن آنها به هيچ عنوان ساده نيست .

فضاي آدرسي يك پروسه وقتي پردازنده و سيستم عامل در وضعيت Protected-Mode عمل ميكنند به بخشهاي كوچكي بنام Page تقسيم شده است . اين Page ها كه كوچكترين عناصر Virtual Memory هستند ، براي خوانده شدن و نوشته شدن و اجرا ، ميتوانند مانند فايلها ، داراي حقوق دسترسي باشند . يعني سيستم عامل ميتواند با ارائه توابعي ، حقوق دسترسي براي هر كدام از Page هاي Virtual Memory فراهم كند . ويندوز با توابعي نظير VirtualProtectEX براي Page ها حافظه ، حق دسترسي تعريف ميكند ، و اين حقوق دسترسي هنگام دسترسي به Pageهاي مورد نظر با توابعي نظير ReadProcessMemory يا WriteProcessMemory و ساير توابع خودشان را نشان خواهند داد . مثلا" براي اعطاي مجوز Read و Write به Page اي حاوي حاوي آدرس 0X401000 است ( يعني Page اي كه اين ادرس در آن قرار دارد ) ميتوان از چنين متدي استفاده كرد :

VirtualProtectEx(pi.hprocess,(LPVOID)dwaddress,1,dwnewprotect,&oldprotect )


كه در آن pi.hprocess هندلي به پروسه مورد نظر و dwaddress آدرس مورد نظر و dwnewprotect معادل حق دسترسي Read و Write يعني PAGE_READWRITE هست ؛ و پس از اين ، Page‌ كه حاوي اين آدرس است ، براي خواندن ، و نوشتن ، در دسترس خواهد بود ، يعني هر درخواستي براي خواندن از آن ، يا براي نوشتن روي آن ، با موفقيت مواجه خواهد شد ، مگر خطائي در سيستم عامل يا فرآيند مورد نظر ايجاد شود . براي مطالعه مجوزهاي موجود براي Page ها MSDN را ببينيد . اگر مجوز يك Page را معادل PAGE_GUARD تعريف كنيد ، به مفهوم Memory BP نزديك شده ايد ؛ يعني هر گاه Page اي با اين مجوز فراخواني شود ، براي هر عملي ، مانند خواندن يا نوشتن ، خطائي محتوي STATUS_GUARD_PAGE_VIOLATION رخ خواهد داد . مديريت اين حقوق دسترسي و فراخواني اين استثناء به عهدهء مدير حافظه مجازي ويندوز – VMM – هست . به كمك اين ويژگي و امكاني بنام Trap flag در پردازنده كه رجيستر 8 بيتي است و براي اجراي برنامه بصورت single-step در نظر گرفته شده ( يعني اجراي مرحله به مرحله هر دستور اسمبلي و توقف قبل از اجراي دستور بعدي و صدور يك استثناء محتوي EXCEPTION_SINGLE_STEP ) ميتوان Memory BP ها را مديريت كرد . مفيدترين كاربرد Memory BP ها در Unpacking است ، يعني برگرداندن برنامه هاي Pack شده به حالت اوليه ، يا وضعيتي كه بتوان روند اجراي "كدهاي واقعي" را ديباگ كرد .

آشنائي با مفهوم BreakPoint براي كسب تسلط بر Debugging ضروري است . BP هاي مختلف براي نيل به مقاصد متفاوتي مناسب هستند كه كسب تجربه و تبحر بيش از هر چيز در ايجاد اين شناخت موثر است . اغلب راه حلهاي نرم افزاري حفاظت از نرم افزار ، روتينهائي براي كشف BP هاي مختلف دارند ، و متقابلا" ديباگرها و كاربران علاقه مند هر كدام ، امكاناتي براي عبور و فريب دادن روتينهاي BP-detection ارائه ميكنند

  جزئـیات تاپيک
 
نویسنده: Inprise
ارسال شده توسط: Salar Khalilzadeh
منبع: barnamenevis.org
تاریخ ارسال: 1387/03/23 3:08 PM
تعداد مشاهده: 351
تعداد آرا: 0
امتیاز آرا:   از بدون رای

Copyright © 2009 SoftProjects.org | About | Valid XHTML | CSS