Итак, первый прием самый банальный - использование стандартной виндовой функции IsDebuggerPresent, она возвращает 1 в случае если программа находиться под отладчиком или 0 если нет, использовать ее можно так:
invoke IsDebuggerPresent ; вызываем процедурку .IF eax == 0 ; сравниваем если eax вернулся 0 invoke isDPnext ; прыгаем на след точку .ENDIF
Эта процедурка очень простая и содержит в себе всего 3 команды:
mov eax, DWORD PTR FS:[18h] mov eax, DWORD PTR [eax+30h] movzx eax, byte ptr [eax+2]
А значит можно их вызвать и в ручную, например так, не используя прямого вызова функции IsDebuggerPresent:
assume fs:nothing mov eax, DWORD PTR FS:[18h] mov eax, DWORD PTR [eax+30h] movzx eax, byte ptr [eax+2] .IF eax == 0 invoke chkNTHeapFlag .ENDIF
Что еще можно сделать, ну поглядеть на флаг NtGlobalFlag, если он не ноль, то скорей всего программа работает в отладчике. Добыть этот флаг можно вот так:
assume fs:nothing mov eax, DWORD PTR FS:[18h] mov eax, DWORD PTR [eax+30h] mov bl, BYTE PTR[eax + 68h] mov ntFlag, bl
Все теже строчки, что и в предыдущем примере, только смотрим по смещению 68h, дальше опять сравниваем и выходим если там не 0. Ну и под конец этих вариантов, можно посмотреть как при помощи исключений делается перехват отладчика. Для начала необходимо объявить функцию - SetUnhandledExceptionFilter. Смысл в ней следующий, если этой функции передать некий адрес в программе, то после возникновения исключения, например деление на 0, программа будет продолжать работать начиная с того адреса который получила эта функция. Ну и пример конечно:
invoke SetUnhandledExceptionFilter, offset nfdebug
mov ebx, 0 div ebx
В случае возникновения исключения, а тут оно является делением на 0, программа начнет работу с адреса nfdebug.
А теперь большой пример нескольких комбинированных попыток защититься от отладчика:
.386 .model flat, stdcall option casemap: none include \masm32\include\windows.inc include \masm32\macros\macros.asm uselib kernel32, user32, masm32, comctl32 nfdebug PROTO ;прототип функции nfdebug isDPnext PROTO ;прототип функции isDPnext crtxcept PROTO ;прототип функции crtxcept chkNTHeapFlag PROTO ; прототип функции chkNTHeapFlag decodeString PROTO: DWORD, :BYTE ; прототип функции decodeString encodeString PROTO: DWORD, :BYTE ; прототип функции encodeString .data kern32 db 0Eh ; кодируем слово kernel32.dll db 17h db 1Ch db 0Bh db 09h db 5Fh db 01h db 1Ch db 4Ah db 08h db 00h db 6Ch db 00h excpName db "SetUnhandledExceptionFilter",0 ; название функции SetUnhandledExceptionFilter header db 0Dh ; кодируем тайтл сообщения db 00h db 6Ch db 6Fh db 04h db 4bh db 00h textMSG db 21h ; кодируем сообсно сообщение, чтобы было сложнее его поймать db 07h db 17h db 12h db 00h db 02h db 17h db 52h db 49h db 1Ah db 1Dh db 0Eh db 14h db 54h db 46h db 09h db 1Ah db 1Bh db 0Ah db 45h db 21h db 00h .data? kernel32p dd ? ; указатель на kernel32 ntFlag db ? ; NtGlobalFlag setExcp dd ? ; указатель на SetUnhandledExceptionFilter .code start: invoke decodeString, ADDR kern32, 0Ch ; декодируем строку invoke LoadLibrary, ADDR kern32 ;загружаем kernel32.dll invoke encodeString, ADDR kern32, 0Ch ; обратно закодируем строку mov kernel32p, eax ; сохраним указатель на kernel32.dll invoke GetProcAddress, kernel32p, ADDR excpName ; получаем указатель на функцию SetUnhandledExceptionFilter mov setExcp, eax ; сохраняем указатель push offset nfdebug ; передаем адрес, с которого продолжим выполение в случае исключения call setExcp ; вызываем функцию SetUnhandledExceptionFilter invoke IsDebuggerPresent ; вызываем IsDebuggerPresent .IF eax == 0 ; проверяем на 0 invoke isDPnext ; прыгаем на следующую проверку .ENDIF exit: invoke ExitProcess, 0 ; выход из программы isDPnext proc ; развернутая функция IsDebuggerPresent assume fs:nothing mov eax, DWORD PTR FS:[18h] ; бродим по структуре mov eax, DWORD PTR [eax+30h] ; бродим по структуре mov bl, BYTE PTR[eax + 68h] ; добываем флаг NtGlobalFlag mov ntFlag, bl ; запишем флаг NtGlobalFlag movzx eax, byte ptr [eax+2] .IF eax == 0 ; проверяем на 0 invoke chkNTHeapFlag прыгаем на следующую проверку .ENDIF Ret isDPnext EndP crtxcept proc ; функция вызывающая исключение mov ebx, 0 ; поместим в ebx 0 div ebx ; поделим на 0 и вызываем исключение Ret crtxcept EndP chkNTHeapFlag proc ; процедура проверки флага NtGlobalFlag .IF ntFlag == 0 invoke crtxcept .ENDIF Ret chkNTHeapFlag EndP nfdebug proc ; выводим что все ок, и нет дебагера invoke decodeString, ADDR textMSG, 15h ; декодируем сообщение invoke decodeString, ADDR header, 6 ; декодируем тайтл invoke MessageBox, NULL, ADDR textMSG, ADDR header,MB_OK ; выводим сообщение Ret nfdebug EndP decodeString proc uses eax ecx ebx address:DWORD, count:BYTE ; процедура которая кодирует строку mov eax, address ; копируем адрес строки xor ecx, ecx ; обнуляем ecx mov cl, count ; в eax загружаем количество строк add eax, ecx ; получаем конец строки encode: mov bl, BYTE PTR [eax] ; кидаем в bl текущий символ xor BYTE PTR [eax-1], bl ;xorим ее с предыдущим dec eax ; уменьшаем eax loop encode ; переходим к следующему символу Ret decodeString EndP encodeString proc uses eax ecx ebx address:DWORD, count:BYTE ; процедура которая декодирует строку mov eax, address ; копируем адрес строки xor ecx, ecx ; обнуляем ecx mov cl, count ; в eax загружаем количество строк nextcode: mov bl, BYTE PTR [eax+1] ; кидаем в bl следующий символ xor BYTE PTR [eax], bl ;xorим ее с текущим inc eax ; увеличиваем eax loop nextcode ; переходим к следующему символу Ret encodeString EndP end startМожно закодировать в принципе все строки и вызовы чтобы ничего найти нельзя было в строках, плюс еще использовать непрямое обнаружение kernel32.dll, да еще попробовать поискать дебаггер при помощи FindWindow, Proccess32First и Process32Next но мне уже стало лень этим заниматься. Может быть как нибудь в следующий раз. А на сегодня пока все...
Комментариев нет:
Отправить комментарий