안티 디버깅은 프로그램을 디버깅하고 분석하는 것을 막는 것을 의미한다. 안티 디버깅 기법이 적용된 프로그램은 디버깅되고 있다고 의심된다면 오류를 띄우는 등 디버깅을 방해한다. 안티 디버깅을 공부하는 이유는 말 그대로 디버깅을 막기 위해서, 그리고 안티 디버깅 기법이 적용된 프로그램을 리버싱하여 분석하기 위해서일 것이다.
대표적인 안티 디버깅 기법으로는 PEB(프로세스 정보를 담은 구조체)의 BeingDebugged 바이트를 확인하여 프로세스가 디버그 모드인지 확인하는 방법과 디버깅으로 인한 시간 지연이 발생하는지 확인하는 방법 등이 있다. 이때 프로세스가 실행될 때 한 번만 확인하는 경우 정적(static) 안티 디버깅이라고 하고, 프로세스가 실행되는 동안 지속적으로 확인할 경우 동적(dynamic) 안티 디버깅이라고 한다. TLS 콜백 함수가 Entry Point 코드보다 먼저 실행되는 것을 이용해 안티 디버깅에 활용되기도 한다.
우선 다음과 같은 코드를 작성한다. MSVC x86 버전을 기준으로 작성하였다.
#include <stdio.h>
#include <windows.h>
int isdbg(void) {
__asm {
mov eax, fs:[0x30]
movzx eax, byte ptr [eax + 2]
}
}
int main(void) {
if(isdbg()) {
puts("debugger detected - 0");
} else if(IsDebuggerPresent()) {
puts("debugger detected - 1");
} else {
puts("execve completed");
}
return 0;
}
위의 코드는 두가지 방법으로 디버깅을 방지하고 있다. 우선, PEB에 직접 접근하는 방식으로 검사하며, 다음으로 윈도우에서 제공하는 IsDebuggerPresent() 함수를 이용하여 검사한다. 하지만 두 가지 방법 모두 PEB를 이용한다.
첫 번째 방법에서는 FS 레지스터는 TEB를 가리키며, 여기서 FS:[0x30]의 위치는 PEB를 가리킨다. 이를 이용하여 BeingDebugged 바이트를 참조하고 있다. 하지만 이렇게 직접 접근하는 것은 환경에 따라 문제가 발생하기 쉽다.
두 번째 방법에서는 windows.h 에서 정의된 윈도우에서 제공되는 IsDebuggerPresent() 함수를 이용한다. 사실 이 방법도 결국 해당 함수에서 PEB를 참조하여 파악하는 것이다.
사실 위의 코드에서 안티 디버깅을 우회하려면 결국 안티 디버깅 함수를 호출하고 if 문으로 검사하고 있기 때문에 조건 분기만 바꿔주면 된다.
x32dbg 프로그램을 활용해서 디버깅할 것이다. 출력 결과를 확인하기 위해 중단점을 설정하였다.
그냥 실행할 경우 안티 디버깅 기능에 의해 디버깅이 감지되었다고 뜬다. 이제 이것을 우회하기 위해서 어셈블 기능을 이용할 것이다.
분기를 jmp 로 바꿔서 디버깅 여부 확인이 끝난 후로 점프하면 안티 디버깅을 우회할 수 있다.
패치 기능을 활용해서 저장하였다.
저장한 파일로 디버깅해보면 안티 디버깅이 성공적으로 우회되는 것을 확인할 수 있다.
wa! 유익해요