كليك كنيد
كليك كنيد
  ضد ديباگ (Anti-Debugging)  

بخش اول
برنامه هاي مخرب از تكنيك هاي ضد ديباگ براي تشخيص نقاط انفصال (Breakpoints) و يا چك كردن وجود يك ديباگر استفاده مي كنند. اين تكنيك ها براي مقابله با نرم افزارهاي امنيتي (آنتي ويروس) مورد استفاده قرار مي گيرد.

نقاط انفصال (BreakPoints)
برنامه هاي مخرب براي تشخيص نقاط انفصال، شروع به جستجوي آپكدهاي 0xcc كرده و به اين ترتيب يك علامت SIGTRAP نمايش داده مي شود. كه اين، دستورالعمليست كه ديباگر براي كنترل برنامه در نقاط انفصال از آن استفاده مي كند. اگر برنامه، خود داراي اداره كننده علامت ها باشد مي تواند با تنظيم False براي نقطه انفصال آنرا حذف كند.
برنامه همچنين مي تواند نقاط انفصال را بازنويسي (Overwrite) كند. ويروس W95/Marburg از يك حلقه كشف رمز(decryption) براي بازنويسي نقاط انفصال استفاده مي كند. ويروس هاي خانواده Yankee Doodle از كدهايي با نام Hamming براي اصلاح خطاها و حذف نقاط انفصال (بخصوص در ويروسها) استفاده مي كنند.

محاسبه Checksum
برنامه مخرب همچنين ميتواند checksum كد خود را محاسبه كرده و در صورت تغيير آن، وجود ديباگر يا نقاط انفصال را تشخيص دهد. VAMPiRE يك برنامه ضد ضد ديباگ (anti-anti debugging) بوده كه وجود نقاط انفصال را تشخيص مي دهد.

تشخيص ديباگر
يكي از راه هاي ساده در تشخيص ديباگرها در سيستم هاي لينوكس فراخواني دستور Ptrace مي باشد. فراخواني اين دستور در يك پروسس بيش از يك بار امكان پذير نخواهد بود، بنابراين اگر برنامه در حال ديباگ باشد، تشخيص داده مي شود. در ويندوز در برنامه اي كه در حال ديباگ مي باشد فراخواني IsDebuggerPresent مقدار 1 را بازمي گرداند در غيراينصورت مقدار بازگشتي صفر است. اين تابع بسادگي فلگي را چك مي كند كه مقدار آن درصورتي كه برنامه در حال ديباگ شدن باشد، يك است. يا بايت دوم PEB چك مي شود. كد زير مثالي از اين تكنيك است:

[mov eax, fs:[30h
[move eax, byte [eax+2
test eax, eax
jne @DdebuggerDetected

در مثال بالا نشان داده مي شود كه eax با مقدار PEB پر شده سپس محتواي بايت دوم PEB به eax منتقل مي شود. در خط سوم چك مي شود كه آيا eax صفر است يا خير. اگر صفر باشد ديباگري موجود نيست در غيراينصورت ديباگر وجود دارد. هنگامی که یک پروسس توسط دیباگری که در حال اجراست، به وجود می آید، سیستم فلگ های FLG_HEAP_ENABLE_TAIL_CHECK، FLG_HEAP_ENABLE_FREE_CHECK  و FLG_HEAP_VALIDATE_PARAMETERS را برای دستکاری پشته (heap) در  ntdll.dll تنظیم می کند كه توسط كد زير قابل چك كردن مي باشد:

[mov eax, fs:[30h
[mov eax, [eax+68h
and eax, 0x70
test eax, eax
jne @DebuggerDetected


در مثال بالا ابتدا به PEB دسترسي پيدا كرديم، سپس شروع فلگ ها توسط اضافه كردن 68h به آدرس آفست PEB مورد دسترسي قرار گرفت و در آخر فلگ ها براي وجود ديباگرها چك مي شوند.
چك كردن فلگ هايي مثل ForceFlag درون پشته روش ديگري براي تشخيص وجود ديباگرهاست. مثالي را دراينجا ببينيد:

[mov eax, fs:[30h
mov eax, [eax+18h] ;process heap
mov eax, [eax+10h] ;heap flags
test eax, eax
jne @DebuggerDetected


مثال بالا نشان ميدهد كه چگونه پشته پروسس و فلگ هاي پشته مي توانند از طرف آفست PEB مورد دسترسي قرار گيرند. سپس براي وجود ديباگر چك مي شوند. روش ديگري براي تشخيص ديباگرها اجراي تابع NtQueryInformationProcess مي باشد، اين تابع مي تواند همراه با پارامتر ProcessInformationClass كه به عدد 7 تنظيم مي شود، اجرا گردد. در اين حالت، در صورتيكه پروسس در حال ديباگ شدن باشد، آن تابع مقدار 1 را بازمي گرداند. مثال زير را ببينيد:

push 0
push 4
push offset isdebugged
push 7 ;ProcessDebugPort
push -1
call NtQueryInformationProcess
test eax, eax
jne @ExitError
cmp isdebugged, 0
jne @DebuggerDetected

در اين مثال ابتدا پارامترها براي اجراي تابع NtQueryInformationProcess به استك منتقل مي شوند. اين پارامترها عبارتند از
1- هندل پروسس كه مساوي صفر است
2- طول اطلاعات پروسس (در اين مثال 4 بايت است)
3- كلاس اطلاعات پروسس (مقدار 7 ProcessDebugPort)
4- مقدار بازگشتي كه تعيين كننده وجود يا عدم وجود ديباگر است. اگر اين مقدار غير صفر باشد بنابراين پروسس توسط يك ديباگر در حال ديباگ شدن است. سپس NtQueryInformationProcess با اين پارامترها فراخواني شده و نتيجه در isdebugged قرار مي گيرد و بعد از آن چك مي شود كه صفر است يا خير.
روش هاي ديگري مثل چك كردن حافظه و جستجوي نام ديباگرها نيز براي تشخيص آنها وجود دارد.

چك كردن اجراي يك مرحله اي (Single Stepping)
- Single Stepping : به اجراي مرحله به مرحله يك برنامه توسط ديباگر گفته مي شود.
روش ديگر براي تشخيص ديباگر چك كردن اجراي يك مرحله اي است. اين كار توسط اضافه كردن مقداري به بالاي اشاره گر استك (Stack Pointer) و چك كردن وجود آن مقدار، انجام مي شود. اگر آن مقدار آنجا باشد به معناي اجراي برنامه در حالت تك مرحله ايست. زماني كه ديباگر، پروسس را درحالت تك مرحله اي اجرا مي كند، ابتدا دستورالعمل ها درون استك قرار داده شده و كنترل را بدست مي گيرد سپس دستورالعمل را از استك خارج كرده سراغ دستور بعدي مي رود. بنابراين اگر مقدار ياد شده هنوز وجود داشته باشد به اين معنيست كه چيز ديگري درحال اجراي پروسس بوده كه از استك به اين منظور استفاده مي كند. در مثال زير تشخيص اجراي تك مرحله اي توسط استك نشان داده شده است:

mov bp, sp ; pick stack pointer
push ax ; store any ax mark on the stack
pop ax ; pick the value from the stack
cmp word ptr [bp-2], ax ; compare against stack
jne debug ; if different, debugger detected.

در مثال بالا ابتدا مقداري در استك قرار داده مي شود سپس آن مقدار از استك برداشته مي شود و با استك مقايسه مي شود، اگر مساوي نبود وجود ديباگر تشخيص داده مي شود.

مترجم:
ابوالفضل محمودی

منبع :