PDA

View Full Version : BreakPoint چیست ؟



Inprise
شنبه 02 اردیبهشت 1385, 22:21 عصر
BreakPoint چیست ؟

به عنوان یک تعریف ساده ، BP نقطه ای از برنامه است که کاربر مایل است با رسیدن روند اجرای برنامه به آن نقطه ، کنترل فرآیند پردازش برنامه توسط پردازنده را مجددا" در اختیار بگیرد ؛

چرا BreakPoint مهم است ؟

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

یک BreakPoint اصولا" چه چیزی است ؟


قبل از پاسخ باید بدانیم BP ها را میتوان به دو دسته کلی تقسیم کرد :
Hardware BP
Software BPBP های اصطلاحا" سخت افزاری ، قابلیتی هستند که توسط خود پردازنده در اختیار سیستم عامل و نرم افزارهای آن قرار میگیرند . اغلب پردازنده های امروزی رجیسترهای انحصاری برای فرآیندهای مرتبط با دیباگ در نظر گرفته اند ، بدین معنی که آدرس و مشخصات 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 را روی کد ایجاد میکنند ؛


http://img10.picsplace.to/4/bp1.JPG



چگونه از وجود 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,d wnewprotect,&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 ارائه میکنند ، و این داستان ادامه دارد ...




موفق باشید
Inpy

mr_esmaily
شنبه 02 اردیبهشت 1385, 22:33 عصر
سلام
مفید و جالب بود.