[Rev] 리버싱 · 작성: 2026-07-19 19:32:50 · 조회 5
분석당하기 싫은 프로그램(악성코드, 상용 소프트웨어의 라이선스 체크 로직, 게임 치트 방지 등)은 디버거가 붙어있는지 스스로 감지하거나, 분석을 어렵게 만드는 장치를 넣어둔다. 이 글은 자주 나오는 패턴과 우회 방법을 정리한다.
if (IsDebuggerPresent()) { exit(1); }
가장 단순한 방식. CheckRemoteDebuggerPresent, PEB(Process Environment Block)의 BeingDebugged 플래그를 직접 읽는 변종도 있다.
if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) { exit(1); }
리눅스는 한 프로세스에 디버거를 하나만 붙일 수 있다는 점을 이용한다. 자기 자신을 먼저 PTRACE_TRACEME로 추적 시도해서, 이미 gdb 같은 디버거가 붙어있으면 이 호출이 실패하는 걸로 감지한다.
start = rdtsc();
// 아무 동작
end = rdtsc();
if (end - start > THRESHOLD) { /* 디버거가 브레이크포인트로 멈췄다 판단 */ }
브레이크포인트에 걸려 실행이 잠깐 멈추면 명령어 사이 시간 간격이 비정상적으로 커진다는 걸 이용한다.
디버그 레지스터(DR0-DR7)에 값이 설정되어 있는지 직접 읽어서, 하드웨어 브레이크포인트가 걸려있는지 확인한다.
jne를 nop으로).IsDebuggerPresent 같은 함수의 리턴값을 Frida나 API 후킹 도구로 강제로 0(False)으로 바꿔치기한다. 바이너리 자체는 건드리지 않아서 재분석할 때마다 패치를 다시 할 필요가 없다.BeingDebugged 바이트를 디버거로 직접 0으로 바꿔버린다.안티 디버깅과 별개로, 분석 자체를 어렵게 만드는 기법들도 같이 쓰인다.
안티 디버깅 우회는 "감지 로직을 찾는 것" 자체가 리버싱 실력을 요구하는 역설적인 상황이다. 처음엔 strings로 관련 API 이름이나 ptrace 같은 특징적인 함수 호출을 먼저 검색해서 감지 코드의 위치부터 좁히는 걸 권한다.