Q. 이 프로그램은 디버거 프로그램을 탐지하는 기능을 갖고 있다.
디버거를 탐지하는 함수의 이름은 무엇인가?
해당 문제를 풀기 위해서는, 먼저 4.exe 파일을 다운로드한 후에 DIE 파일에서 열어준다.

DIE로 확인한 결과, 해당 프로그램은 패킹되어 있지 않기 때문에 바로 디버깅이 가능하다.
따라서 곧바로 Immunity Debugger에서 파일을 열어 분석을 진행한다.
Immunity Debugger에서 파일을 실행했을 때는 다음과 같은 화면이 나타난다.

반면, 파일을 더블 클릭하여 일반적으로 실행했을 때는 다른 화면이 출력된다.

이러한 화면이 나타난다. 왜 디버거로 실행했을 때와 일반 실행 시 출력되는 문구가 다른 것일까?

코드를 더 자세히 살펴보면,
“디버깅 당함” 문구를 출력하는 함수가 호출되는 위치를 확인할 수 있다.
이후 우클릭 → Search For → All intermodular calls 메뉴를 이용해 외부 함수 호출 목록을 살펴보면,
디버거 탐지와 관련된 IsDebuggerPresent 함수가 호출되고 있음을 발견할 수 있었다.

따라서 이 프로그램은 IsDebuggerPresent 함수를 이용해,
디버거의 존재를 확인하는 구조로 되어 있다는 것을 예측해볼 수 있었다.

메인 함수의 흐름은 다음과 같다.
(1) IsDebuggerPresent 함수 호출
→ 현재 프로세스가 디버거에 의해 디버깅되고 있는지 검사한다.
만약 디버거로 실행 중이라면 1(TRUE)을, 아니라면 0(FALSE)을 반환하며, 이 반환값은 EAX 레지스터에 저장된다.
즉, 디버거가 붙어 있으면 EAX = 1, 일반 실행 상태라면 EAX = 0이 된다.
(2) TEST EAX, EAX 실행
→ IsDebuggerPresent의 반환값이 저장된 EAX를 자기 자신과 비트 단위로 AND 연산한다. 이 명령의 목적은 실제 연산 결과를 사용하는 것이 아니라, 연산 결과가 0인지 아닌지를 판단하여 CPU의 플래그(특히 ZF, Zero Flag)를 설정하는 것이다.
따라서
- EAX가 0이라면 결과가 0 → ZF = 1
- EAX가 1이라면 결과가 1 → ZF = 0 으로 바뀐다. 즉, 이 단계에서 디버거가 없으면 ZF=1, 있으면 ZF=0이 설정된다.
(3) JE SHORT 0x0040107E 실행
→ JE(Jump if Equal)는 “ZF가 1일 때 점프하라”는 의미의 조건 분기 명령이다. 따라서 위의 TEST 명령 결과에 따라 다음과 같은 흐름으로 작동한다.
- ZF = 1 (EAX=0, 디버거 없음) → 점프 발생 → "정상" 메세지 출력
- ZF = 0 (EAX=1, 디버거 있음) → 점프하지 않음 → “디버깅 당함” 메시지 출력
결국 이 프로그램은 IsDebuggerPresent가 반환한 값(디버거 존재 여부)에 따라 TEST → JE 흐름을 통해 “현재 디버거가 존재하는가?”를 판단하고, 그 결과에 따라 분기하여 서로 다른 메시지를 출력하는 구조로 되어 있다.

문제에서 찾는, 디버거를 탐지하는 함수의 이름은 IsDebuggerPresent 함수임을 확인할 수 있다.
** 디버거에서 "정상" 메시지를 출력하기 위한 방법


원래 프로그램의 0040106D 주소에는 JE SHORT 0040107E 명령이 존재한다.
JE(Jump if Equal)는 ZF(Zero Flag)가 1일 때만 점프하는 조건부 분기 명령으로, 디버거가 없을 때(EAX=0, ZF=1)만 “정상” 메시지를 출력하도록 설계되어 있었다. 반대로 디버거가 있을 경우(EAX=1, ZF=0), 점프가 발생하지 않아
“디버깅 당함” 문자열을 출력하는 코드가 실행된다.
이제 프로그램이 디버거 환경에서도 ‘정상’ 메시지를 출력하도록 만들기 위해, 이 분기 명령을 JE → JNZ 로 수정하였다.
- 변경 전: JE SHORT 0040107E (ZF=1일 때 점프)
- 변경 후: JNZ SHORT 0040107E (ZF=0일 때 점프)
JNZ (Jump if Not Zero) 명령은 ZF가 0일 때 점프하도록 동작한다.
즉, TEST EAX, EAX의 결과가 0이 아닐 때(=디버거가 있을 때) 점프가 발생한다.
** 따라서 디버거가 감지된 경우(ZF=0), JNZ 명령이 작동하여 “디버깅 당함” 문자열을 PUSH 하는 코드 부분(0x0040106F 이후)을 건너뛰고, 곧바로 0x0040107E의 “정상” 메시지 출력 코드로 이동한다.
-> 그 결과, 프로그램은 디버깅 중에도 “정상” 메시지를 출력하는 동작으로 변경되는 것이다.
(위의 사진처럼, 분기 명령어를 JNZ로 변경한 뒤 실행하면 디버거에서도 “정상” 메시지가 출력되는 것을 확인할 수 있다.)
'INTERTLUDE > 리버싱 스터디' 카테고리의 다른 글
| Codeengn Basic RCE 12 (0) | 2025.11.07 |
|---|---|
| Codeengn Basic RCE 19 (0) | 2025.10.08 |
| Codeengn Basic RCE 7 (0) | 2025.09.30 |
| Codeengn Basic RCE 10 (0) | 2025.09.30 |
| Codeengn Basic RCE 8 (0) | 2025.09.30 |