앞서 소개해 드린 각 기법들 중에서 Debug 기법에 대한 설명입니다.
실습으로 메모장의 kernel32!WriteFile() API 를 후킹하여 기존과는 다른 동작을 하도록 만들어 보겠습니다.
실습으로 메모장의 kernel32!WriteFile() API 를 후킹하여 기존과는 다른 동작을 하도록 만들어 보겠습니다.
<실습 예제 – WriteFile() API hooking>
API Hooking 의 기본 설명은 아래 글을 참고하세요.
API Hooking - 리버싱의 '꽃'
API Hooking - Tech Map
Debug Technique
<Fig. 1>
Debug 방식의 API 후킹을 설명 드리겠습니다. (위의 Tech Map 에서 빨간색 표시 부분을 참고하세요)
이 방식의 장점은 후킹을 위해서 '디버깅'을 사용하므로 좀 더 interactive 한 후킹을 수행할 수 있습니다. 즉, 간단한 GUI 를 제공하여 후킹 대상 프로그램의 실행을 제어하고, 메모리를 자유롭게 사용할 수 있습니다.
하지만 먼저 Debugger 구조에 대한 이해가 필요합니다.
Debugger 설명
# 용어
간단한 용어 정리부터 하겠습니다.
Debugger – debugging tool
Debuggee – application to debug
Debuggee – application to debug
# 디버거 기능
Debugger 의 기능은 Debuggee 가 올바르게 실행되는지 확인하고 (예상치 못한) 프로그램의 오류를 발견하는 것입니다.
Debugger 는 Debuggee 의 명령어 instruction 을 하나씩 실행 가능하며, 레지스터와 메모리에 대한 모든 접근 권한을 가집니다.
# 디버거 동작 원리
일단 Debugger 프로세스로 등록되면 OS 는 Debuggee 에게 debug event가 발생할 때 Debuggee 의 실행을 멈추고 해당 event 를 Debugger 에게 통보합니다. Debugger 는 해당 event 에 대해 적절한 처리를 한 후 Debuggee 의 실행을 재개합니다.
* 일반적인 예외(Exception)도 Debug event 에 해당합니다.
* 만약 해당 프로세스가 디버깅 중이 아니었다면 debug event 는 자체 예외처리 아니면 OS 의 예외처리 루틴에서 처리됩니다.
* Debugger 는 debug event 중에서 처리할 수 없거나 관심 없는 event 들은 OS 가 처리하도록 만들어 줍니다.
* 만약 해당 프로세스가 디버깅 중이 아니었다면 debug event 는 자체 예외처리 아니면 OS 의 예외처리 루틴에서 처리됩니다.
* Debugger 는 debug event 중에서 처리할 수 없거나 관심 없는 event 들은 OS 가 처리하도록 만들어 줍니다.
아래 그림은 위 설명을 도식화 한 것입니다.
<Fig. 2>
# Debug event
Debug event 입니다.
EXCEPTION_DEBUG_EVENT
CREATE_THREAD_DEBUG_EVENT
CREATE_PROCESS_DEBUG_EVENT
EXIT_THREAD_DEBUG_EVENT
EXIT_PROCESS_DEBUG_EVENT
LOAD_DLL_DEBUG_EVENT
UNLOAD_DLL_DEBUG_EVENT
OUTPUT_DEBUG_STRING_EVENT
RIP_EVENT
* 출처 : http://msdn.microsoft.com/en-us/library/ms679302(VS.85).aspx
CREATE_THREAD_DEBUG_EVENT
CREATE_PROCESS_DEBUG_EVENT
EXIT_THREAD_DEBUG_EVENT
EXIT_PROCESS_DEBUG_EVENT
LOAD_DLL_DEBUG_EVENT
UNLOAD_DLL_DEBUG_EVENT
OUTPUT_DEBUG_STRING_EVENT
RIP_EVENT
* 출처 : http://msdn.microsoft.com/en-us/library/ms679302(VS.85).aspx
<List 1>
위 Debug event 중에서 Debugging 관련된 event 는 아래에 표시된 EXCEPTION_DEBUG_EVENT 입니다.
EXCEPTION_ACCESS_VIOLATION
EXCEPTION_ARRAY_BOUNDS_EXCEEDED
EXCEPTION_BREAKPOINT
EXCEPTION_DATATYPE_MISALIGNMENT
EXCEPTION_FLT_DENORMAL_OPERAND
EXCEPTION_FLT_DIVIDE_BY_ZERO
EXCEPTION_FLT_INEXACT_RESULT
EXCEPTION_FLT_INVALID_OPERATION
EXCEPTION_FLT_OVERFLOW
EXCEPTION_FLT_STACK_CHECK
EXCEPTION_FLT_UNDERFLOW
EXCEPTION_ILLEGAL_INSTRUCTION
EXCEPTION_IN_PAGE_ERROR
EXCEPTION_INT_DIVIDE_BY_ZERO
EXCEPTION_INT_OVERFLOW
EXCEPTION_INVALID_DISPOSITION
EXCEPTION_NONCONTINUABLE_EXCEPTION
EXCEPTION_PRIV_INSTRUCTION
EXCEPTION_SINGLE_STEP
EXCEPTION_STACK_OVERFLOW
* 출처 : http://msdn.microsoft.com/en-us/library/aa363082(VS.85).aspx
EXCEPTION_ARRAY_BOUNDS_EXCEEDED
EXCEPTION_BREAKPOINT
EXCEPTION_DATATYPE_MISALIGNMENT
EXCEPTION_FLT_DENORMAL_OPERAND
EXCEPTION_FLT_DIVIDE_BY_ZERO
EXCEPTION_FLT_INEXACT_RESULT
EXCEPTION_FLT_INVALID_OPERATION
EXCEPTION_FLT_OVERFLOW
EXCEPTION_FLT_STACK_CHECK
EXCEPTION_FLT_UNDERFLOW
EXCEPTION_ILLEGAL_INSTRUCTION
EXCEPTION_IN_PAGE_ERROR
EXCEPTION_INT_DIVIDE_BY_ZERO
EXCEPTION_INT_OVERFLOW
EXCEPTION_INVALID_DISPOSITION
EXCEPTION_NONCONTINUABLE_EXCEPTION
EXCEPTION_PRIV_INSTRUCTION
EXCEPTION_SINGLE_STEP
EXCEPTION_STACK_OVERFLOW
* 출처 : http://msdn.microsoft.com/en-us/library/aa363082(VS.85).aspx
<List 2>
각종 예외(Exception) 중에서 Debugger 가 반드시 처리해야 하는 예외는 바로 EXCEPTION_BREAKPOINT 예외입니다.
BreakPoint 는 어셈블리 명령어 "INT3" 이며, IA-32 Op code 는 0xCC 입니다. 코드 디버깅 중에 INT3 명령어를 만나면 Debugger 에게 EXCEPTION_BREAKPOINT 예외 이벤트가 날아갑니다.
Debugger 에서 BreakPoint 를 구현하는 방법은 간단합니다.
BreakPoint 를 설치하기 원하는 코드의 메모리 시작 주소에서 1 byte 를 0xCC 로 바꿔 치는 것입니다. 디버깅을 계속 진행하고 싶을 때는 다시 원래 값으로 복원시키고 실행해줍니다.
Debug 방식의 API Hooking 은 이와 같은 BreakPoint 의 특성을 이용하는 것입니다.
API Hooking - Debug Method
Debug 기법을 통한 API Hooking 에 대해 좀 더 자세히 설명 드리겠습니다.
기본적인 아이디어는 Debugger-Debuggee 관계를 가진 상태에서 Debuggee 의 API 시작 부분을 0xCC 로 바꿔 제어를 Debugger 로 가져온 상태에서 원하는 작업을 수행한 후 Debuggee 를 다시 실행상태로 바꾸는 것입니다.
작업 흐름은 아래와 같습니다.
- 후킹을 원하는 프로세스에 ‘attach’ 하여 Debuggee 로 만듦
- Hook : API 시작 주소의 첫 바이트를 0xCC 로 변경
- 해당 API 가 호출되면 제어는 Debugger 에게 넘어옴
- 원하는 작업을 수행(파라미터, 리턴 값 조작 등)
- Unhook : Debuggee 의 0xCC 를 원래대로 복원시킴 (<– API 의 정상 실행을 위해)
- 해당 API 실행 (0xCC 가 빠진 정상적인 상태)
- Hook : 다시 0xCC 로 바꿈 (<– 지속적인 후킹을 위해)
- Debuggee 에게 제어를 되돌려줌
- Hook : API 시작 주소의 첫 바이트를 0xCC 로 변경
- 해당 API 가 호출되면 제어는 Debugger 에게 넘어옴
- 원하는 작업을 수행(파라미터, 리턴 값 조작 등)
- Unhook : Debuggee 의 0xCC 를 원래대로 복원시킴 (<– API 의 정상 실행을 위해)
- 해당 API 실행 (0xCC 가 빠진 정상적인 상태)
- Hook : 다시 0xCC 로 바꿈 (<– 지속적인 후킹을 위해)
- Debuggee 에게 제어를 되돌려줌
위 방식은 가장 간단한 경우를 소개한 것입니다.
이걸 기준으로 다양하게 변형할 수 있습니다. 가령 original API 를 호출 하지 않을 수 도 있고, 사용자가 제공한 custom API 를 호출 할 수 도 있고, 한번만 후킹 할 수도 있고, 여러 번 후킹 할 수도 있습니다.
작업 목적에 따라서 알맞게 변형해서 사용하시면 됩니다.
Notepad.exe 의 WriteFile() API Hooking
지금 까지 공부한 내용을 바탕으로 실제 코드를 보면서 실습을 해보도록 하겠습니다.
작업할 내용은 Notepad.exe 의 WriteFile() API 후킹입니다.
입력된 파라미터를 조작하여 소문자로 입력된 내용을 전부 대문자로 바꿔 보겠습니다.
입력된 파라미터를 조작하여 소문자로 입력된 내용을 전부 대문자로 바꿔 보겠습니다.
즉, Notepad 에서 입력된 모든 소문자는 파일로 저장되는 순간에 대문자로 변경되어 저장됩니다.
Notepad.exe 를 실행시킨 후 PID 를 알아냅니다.
<Fig. 3>
첨부된 후킹 프로그램(hookdbg.exe)을 실행합니다.
hookdbg.exe 는 콘솔 기반 프로그램이며 실행 파라미터로 후킹 할 프로세스의 PID 를 넘겨 받습니다.
<Fig. 4>
위 그림과 같이 hookdbg.exe 를 실행하면 PID 1688 에 해당하는 notepad 프로세스의 WriteFile() API 후킹이 시작됩니다.
그리고 notepad 에 아무 글자나 입력해 보세요.
<Fig. 5>
입력을 마치셨으면 저장을 해주세요.
<Fig. 6>
저장을 마치면 notepad 화면에는 아무런 변화가 일어나지 않습니다. (WriteFile() API 만 후킹 했다는 사실을 기억해 주세요.)
notepad 를 종료해 주시고, hookdbg 프로그램을 봐주세요.
<Fig. 7>
위 그림을 보시면 “original string” 에는 제가 입력한 문자열이 나타나고, “converted string” 에는 변경된(소문자 -> 대문자) 문자열이 나타납니다.
이것은 hookdbg.exe 프로그램 내부에서 후킹의 진행과정을 표시하기 위해서 출력하는 문자열입니다.
실제로 대문자로 저장되었는지 파일을 열어서 확인합니다.
<Fig. 8>
정확히 모든 소문자가 대문자로 변경되어서 저장되었습니다.
이 예제는 아주 간단한 기능을 가지고 있지만 Debug Method 에 대한 기본적인 개념을 잘 설명해줄 수 있습니다.
다음 포스트에서 hookdbg.exe 의 실제 코드를 상세히 살펴보도록 하겠습니다.
API Hooking - 메모장 WriteFile() 후킹 (2)
+---+
ReverseCore
'study' 카테고리의 다른 글
| API Hooking – 계산기, 한글을 배우다. (3) (26) | 2009/11/20 |
|---|---|
| API Hooking - 계산기, 한글을 배우다. (2) (14) | 2009/11/13 |
| API Hooking - 계산기, 한글을 배우다. (1) (27) | 2009/11/10 |
| API Hooking - 메모장 WriteFile() 후킹 (3) (18) | 2009/11/04 |
| API Hooking - 메모장 WriteFile() 후킹 (2) (1) | 2009/11/03 |
| API Hooking - 메모장 WriteFile() 후킹 (1) (22) | 2009/10/08 |
| API Hooking - Tech Map (10) | 2009/09/29 |
| API Hooking - 리버싱의 '꽃' (12) | 2009/09/22 |
| DLL Ejection - 침투시킨 DLL 빼내기 (14) | 2009/08/14 |
| DLL Injection - 다른 프로세스에 침투하기 (4) (10) | 2009/07/30 |
| DLL Injection - 다른 프로세스에 침투하기 (3) (4) | 2009/07/17 |
0xCC,
API,
API Hooking,
Breakpoint,
Debug,
Debug Method,
Debuggee,
debugger,
DEBUG_EVENT,
EXCEPION_DEBUG_EVENT,
EXCEPTION_BREAKPOINT,
Hook,
hookdbg.exe,
INT3,
it,
NotePad,
WriteFile,
디버거,
디버기,
메모장,
후킹
hookdbg.exe
