WindowKernel
A Windows kernel driver reading the keyboard port directly, communicating over IOCTL rather than user-mode input.
이 문제는 Reversing.kr의 Windows Kernel 계열 문제로, 일반적인 user-mode 입력 검증이 아닌 커널 드라이버가 키보드 하드웨어 포트를 직접 읽는 구조를 사용한다. 핵심 힌트는 다음과 같다.
- Keyboard scan code
- Windows kernel driver
- IOCTL 기반 통신
즉, 이 문제는 키보드 입력을 커널 레벨에서 가로채어 검증하는 드라이버를 리버싱하는 문제다. 먼저 exe 파일을 보자. 아 이다로 메인 funtion의 분기하는 (correct/ wrong) 문자열을 보고 그 함수를 디컴파일 했다.

이 코드를 분석해보자. sub_BC1280 이라는 함수에서 리턴한 값이 corret / wrong 을 결정한다. 따라가보자.

이 코드를 자세히 분석해보면, WinKern.sys 를 키를 얻기 위해 분석해야하는걸 알수있다. sub_11288은 IRP_MJ_DEVICE_CONTROL 핸들러다. 즉, 이 함수의 본질은:
- user-mode와 kernel-mode 사이의 제어 인터페이스
- 상태 초기화 / 상태 조회
- 결과 값 반환
하지만 여기서보면, 원래 본질과 다르게 입력 데이터 처리 로직이 전혀 없다는걸 알수있다. SystemBuffer를 읽지 않고, InputBufferLength를 쓰지 않고, user-mode에서 어떤 “키 값”도 전달받지 않는다. Windows 커널에서 사용자 입력이 들어오는 경로는 매우 제한적이다. 그런데 이 드라이버는: kbdclass 필터로 attach 하지 않는다, IRP_MJ_READ를 후킹 하지 않는다, 대신 DPC를 직접 등록한다. 분석자 사고에서의 WinKern.sys는 다음을 통칭한다.
- i8042 키보드 컨트롤러 경로
- PS/2 키보드 포트 (0x60 / 0x64)
- 커널 레벨 키 입력 처리 루트
즉, “Windows Kernel Input Path”의 상징적인 이름이다. 그러니 당연하게, WinKern.sys의 DriverEntry를 분석하는것 이다.

위를 보면 DriverEntry 는 다음과 같은 특징을 가진다.
- IoCreateDevice, IoCreateSymbolicLink를 통해 \.\RevKr 디바이스 생성
- IRP_MJ_DEVICE_CONTROL 핸들러로 sub_11288 등록
- KeInitializeDpc를 통해 DPC 루틴 등록
- READ_PORT_UCHAR 사용 가능성이 강하게 의심됨
이 시점에서 이 드라이버는 표준 키보드 드라이버 경로(kbdclass.sys) 를 사용하지 않고, 자체적으로 DPC 기반 키보드 입력 처리 루틴을 운용하고 있음을 알 수 있다. 여기서 sub_11266 함수를 따라가주자.

이 코드는 곧 다음을 의미한다.
- PS/2 키보드 컨트롤러의 포트 0x60에서 직접 1바이트를 읽음
- 읽힌 값은 ASCII가 아닌 Scan Code
- 해당 값이 이후 FSM(State Machine)에 전달됨
즉, user-mode에서 어떤 값을 보내는 구조가 아니라, 실제 키보드 입력이 커널에서 직접 소비된다. 여기서 sub_111DC 하

Stage 1: sub_110DC 분석 (KEYBD). Stage 1은 초기 상태(state < 100)에서 동작한다. 특징:
- 짝수 state는 free-pass
- 홀수 state에서 특정 scan code break 값 검사
- 검사 통과 시 state 증가
- 최종적으로 state == 100 도달
이 단계에서 요구되는 입력 패턴은 키보드 scan code break 기준으로 해석되며, 이를 실제 키 입력으로 환산하면 다음 문자열이 된다. KEYBD 이 단계는 “Keyboard”를 의미하는 첫 부분이다.

Stage 2는 state == 100부터 시작한다. 여기서는 다음과 같은 변형이 적용된다.
v3 = al ^ 0x12
즉, 입력된 scan code는 XOR 0x12 연산 후 비교된다. 특징:
- 문자 상태(‘d’ ~ ‘k’)를 state로 사용
- free-pass 상태와 검증 상태가 교차
- 최종 성공 시 state == 200
이 FSM을 정확히 따라가면 Stage 2에서 요구되는 키 입력은 다음과 같다. INT (interupt 를 뜻함 여기서) 따라서 Stage 1 + Stage 2 결과는 다음과 같다. KEYBDINT

Stage 3은 많은 사람들이 혼동하는 구간이며, 마지막 4글자를 결정하는 핵심 단계다. 중요한 점은 다음과 같다.
-
Stage 3의 입력 검증 함수는 sub_110D0
-
v2 = al ^ 5 연산 사용
-
검증 state는 201, 203, 207
-
나머지는 free-pass 즉, 총 4글자를 입력하지만, 실제로 비교되는 값은 3개뿐이며 free-pass가 섞여 있다. 이 단계에서 흔히 실수하는 부분은 다음이다.
-
scan code를 바로 문자로 매핑하려는 시도
-
XOR 연산을 무시한 채 scancode table만 참조
그러나 이 문제의 의도는 수치 자체가 아니라 의미에 있다. Stage 3에서 요구하는 것은:
- 키보드 입력을 가로채는 드라이버의 실제 행위
- READ_PORT_UCHAR(0x60)을 사용하는 구조
- DPC 기반 키 입력 감시
즉, 이 드라이버가 수행하는 행위는 명확하다. Keyboard Hook 따라서 Stage 3의 의미는 다음 문자열이다. HOOK
모든 단계를 종합하면 최종 입력 문자열은 다음과 같다: keybdinthook 끝 ^^
