Windows API 후킹과 보안 대응 메커니즘
1. 들어가며
보고서의 주제는 Windows API를 활용한 후킹(Hooking) 기법과 이에 대한 보안 대응 메커니즘이다.
DLL 인젝션과 API 후킹은 리버싱, 악성코드 분석, 프로그램 동작 변조 등에 사용되는 대표적인 기술로, 실습을 통해 함수 후킹 방식의 구조와 동작 원리를 학습하였다.
특히 여러 다양한 후킹 기법을 비교하고, 이를 탐지하는 Windows의 보안 메커니즘(DEP, SRM, PatchGuard 등)에 대해서도 고찰하였다. 보고서는 이러한 후킹 기술이 실제로 어떻게 작동하며, Windows가 이를 어떻게 탐지하고 방어하는지를 실습과 이론을 통해 설명한다.
이를 통해 API 후킹 기술의 구조적 이해와 함께 보안 대응 체계의 필요성에 대해서도 생각해볼 수 있다.
2. Windows API 개요 및 DLL 인젝션
2.1 API 개념
API(Application Programming Interface)는 소프트웨어 개발자가 특정 기능을 효율적으로 구현할 수 있도록 미리 정의된 함수, 프로토콜, 도구의 집합이다. 애플리케이션 간의 상호작용을 정의하는 일종의 규칙 혹은 계약으로, 응용 프로그램은 API를 통해 운영체제나 외부 소프트웨어의 기능을 호출하거나 데이터를 주고받을 수 있다.
API의 작동 방식은 크게 세 단계로 나눌 수 있다. 먼저, 한 애플리케이션이 특정 데이터나 기능을 요청하는 요청(Request) 단계가 있다. 이 요청을 받은 대상 애플리케이션이나 시스템은 해당 요청을 처리하여 결과를 준비하는 처리(Processing) 단계를 거치고, 마지막으로 요청한 애플리케이션에게 결과 데이터를 반환하는 응답(Response) 단계가 이어진다. 이와 같은 API의 구조 덕분에 개발자는 복잡한 하드웨어 제어나 시스템 내부 구조에 대한 세부 내용을 몰라도 고수준에서 기능을 간편히 사용할 수 있다.
API는 여러 기준에 따라 분류될 수 있다. 접근 방식에 따라 공개 API(Public API), 비공개 API(Private API), 파트너 API 등으로 나뉘며, 사용 방식에 따라 REST API, SOAP API, RPC API, WebSocket API 등으로 세분화된다. 사용 범위에 따라서는 웹 API, 운영체제 API, 라이브러리 API 등이 있다. 이 중에서도 본 보고서에서 집중적으로 다루는 운영체제 API, 특히 Windows API는 운영체제의 핵심 기능과 밀접하게 연결되어 있어 시스템 자원 접근, 프로세스 제어, 사용자 인터페이스 구성 등 보안 분석 및 프로그램 조작에 필수적으로 활용된다.
2.2 운영체제 API와 Windows API의 역할
운영체제 API는 응용 프로그램이 운영 체제의 기능에 접근할 수 있도록 돕는 인터페이스다. 예를 들어, 프로그램이 파일을 읽거나, 메모리를 할당하거나, 다른 프로세스를 시작하는 등의 작업을 수행하려면 반드시 운영체제 API를 통해야 한다. 이 API는 운영체제의 커널 및 시스템 서비스와 상호작용하게 되며, 하드웨어와 소프트웨어 간의 통신을 간접적으로 가능하게 한다.
Windows API는 Microsoft Windows 운영체제에서 제공하는 대표적인 운영체제 API로, C 언어 기반으로 설계되어 있다.
Windows API는 크게 사용자 인터페이스(UI), 파일 시스템, 네트워크, 메모리, 프로세스 및 스레드 관리 등 다양한 영역을 포함하고 있으며,
이러한 기능들을 통해 응용 프로그램은 시스템 자원을 제어하거나 상태를 확인할 수 있다. 예를 들어, CreateFile, WriteProcessMemory, VirtualAllocEx, CreateRemoteThread 같은 API 함수는 모두 Windows에서 제공하는 것으로, 악성코드 분석, 리버싱, 인젝션 등의 상황에서 매우 빈번하게 사용된다.
이러한 Windows API는 보안에서 중요한 역할을 한다. 특히 메모리 조작, 프로세스 제어 등은 악성 행위뿐만 아니라 이를 방지하거나 탐지하는 보안 기법의 핵심이 된다.
3. 후킹 기법 이론 및 분류
3.1 함수 후킹 기본 개념
후킹(Hooking)은 실행 중인 프로그램의 특정 함수 호출이나 이벤트 발생을 가로채고 조작하는 기술이다. 일반적으로 원래 호출되었어야 할 함수 대신, 사용자가 지정한 후킹 함수가 먼저 실행되며, 이 함수 내에서 로직을 추가하거나 원래 함수의 동작을 수정할 수 있다. 후킹은 리버싱, 디버깅, 악성코드 작성 및 분석, 사용자 입력 감시, 게임 치트 제작 등 다양한 분야에서 사용된다.
함수 후킹은 다음과 같은 단계를 거쳐 이루어진다.
- 대상 함수 식별 단계에서는 가로채고자 하는 함수의 정확한 주소를 찾아야 한다.
- 후킹 함수 생성 단계에서 원래 함수의 시그니처(인자와 반환값 구조)에 맞는 새로운 함수를 작성한다.
- 후킹 코드 삽입 단계에서 실행 흐름을 후킹 함수로 전환하도록 코드 패치가 이뤄진다.
- 마지막으로 후킹 활성화를 통해 프로그램 실행 중 실제로 후킹 함수가 호출되도록 설정한다.
후킹은 크게 사용자 모드(User-mode) 후킹과 커널 모드(Kernel-mode) 후킹으로 나뉘며, 이 보고서에서는
주로 사용자 모드 후킹을 다룬다. 사용자 모드 후킹은 DLL 인젝션을 기반으로 실행되며, 후킹된 함수가 호출되었을 때
원하는 메시지를 출력하거나 행동을 조작하는 등을 통해 쉽게 확인할 수 있다.
3.2 Inline 후킹, IAT 후킹, VMT 후킹
함수 후킹은 구현 방식에 따라 다양한 방식으로 분류된다. 대표적인 방식으로는 Inline 후킹, IAT(Import Address Table) 후킹, 그리고 VMT(Virtual Method Table) 후킹이 있다.
Inline 후킹은 대상 함수의 시작 부분을 직접 수정하는 기법이다. 일반적으로 JMP 명령어(0xE9)를 삽입하여 함수 진입 시 사용자가 정의한 후킹 함수로 제어 흐름을 바꾼다. 이 방식은 구현이 직관적이고 빠르다는 장점이 있지만, 원본 함수가 매우 짧거나 메모리 보호 속성 때문에 수정이 어려운 경우 충돌이 발생할 수 있다. 또한 주소 계산 방식이나 복원 로직의 복잡도 때문에 오류 가능성도 존재한다. 이 단점을 보완하기 위해 Detours와 같은 후킹 라이브러리가 사용된다.
IAT 후킹은 프로그램의 PE 파일(Portable Executable) 구조 내에 존재하는 Import Address Table을 수정하는 방식이다. 특정 DLL 함수가 처음 로드될 때 이 테이블을 통해 함수 주소를 참조하므로, 해당 테이블을 후킹 함수의 주소로 바꾸면 원래 함수가 아닌 후킹 함수가 호출된다. IAT 후킹은 비교적 안전하게 구현할 수 있으나, 정적으로 로드된 함수에만 적용 가능하고, 동적으로 로딩되는 함수에는 적용이 어렵다는 단점이 있다.
VMT 후킹은 객체 지향 프로그래밍에서 사용하는 기법으로, 클래스의 가상 함수 테이블(Virtual Method Table)을 조작하는 방식이다. C++와 같은 언어에서 객체의 가상 함수 호출 시, 가상 함수 테이블의 포인터를 참조하게 되는데, 이 테이블을 수정하면 가상 함수 호출을 가로챌 수 있다. 이는 주로 COM 기반 구조나 DirectX/게임 엔진 후킹 등에서 활용된다.
4. 실습 사례 분석
4.1 기본 DLL 인젝션 실습
목표
이 실습의 목적은 Windows 운영체제에서 동작 중인 프로세스에 외부 DLL을 삽입하여 해당 프로세스의 동작을 변조하는 경험을 하는 것이다. 이를 통해 Windows API의 활용 방식, DLL의 동적 로딩 원리, 그리고 인젝션을 위한 기본적인 API들의 사용법을 익히고자 하였다.
원리
DLL 인젝션(DLL Injection)은 외부에서 작성한 DLL(Dynamic Link Library)을 실행 중인 다른 프로세스의
주소 공간에 강제로 삽입한 뒤, 그 DLL 내의 함수를 실행시키는 기법이다. Windows 운영체제에서는 VirtualAllocEx, WriteProcessMemory, CreateRemoteThread, LoadLibraryA 등의
API를 사용하여 타겟 프로세스의 메모리에 DLL 경로를 기록하고, 원격 스레드를 통해 로드시킨다.
실습 계획
- 간단한 DLL 제작: C++로 DLL 생성. (MessageBox를 띄우는 간단한 코드)
- DLL 인젝터 제작: OpenProcess()로 대상 프로세스 열기, VirtualAllocEx()로 메모리 할당 후 DLL 경로 복사, CreateRemoteThread()로 DLL 로드.
- 테스트 & 실행: Notepad.exe에 DLL을 주입하고 정상적으로 실행되는지 확인.
실습 과정
1) 간단한 DLL 제작
DLL injection을 사용하여 다른 프로세스에 DLL을 삽입하고 메시지 박스를 표시하는 코드를 작성한다. 이 DLL은 프로세스에 로드될 때 메시지 박스를 표시하여 성공적으로 삽입되었음을 알리며, 스레드 생성/소멸 또는 프로세스 언로드 시에는 아무런 동작도 수행하지 않는다.
이 코드 작성에 있어 중요한 부분은
- DllMain(): DLL이 로드될 때 실행되는 엔트리 포인트
- DLL_PROCESS_ATTACH: DLL이 프로세스에 로드될 때 실행됨
- MessageBoxA(): DLL이 인젝션되었을 때 메시지 박스 띄우기
이렇게 세 가지라 할 수 있다.
즉 이 코드에서는 MessageBoxA 함수를 사용하여 “DLL Injected Successfully!”라는 메시지 박스를 표시하도록 했다. 이는 DLL이 성공적으로 삽입(injection)되었음을 나타낸다.
이후 해당 DLL을 빌드하여 Release 폴더에 MyInjectedDLL.dll 파일이 생성되도록 했다.
빌드한 DLL이 정상적으로 실행되는지 테스트해보았다. DLL 수동 로드 테스트를 위해 작성한 코드는 다음과 같다.
이 코드에서 중요한 부분은 다음과 같다.
- LoadLibraryA 함수: 지정된 경로의 DLL을 메모리에 로드한다. HMODULE은 로드된 DLL의 핸들(메모리 주소)을 저장하는 데이터 형식이다. LoadLibraryA 함수가 성공하면 DLL의 핸들을 반환하고, 실패하면 NULL을 반환한다.
- if (hDll): LoadLibraryA 함수가 성공했는지 확인한다. 성공한 경우, “DLL Loaded Successfully!” 메시지를 출력하고, FreeLibrary 함수를 호출하여 DLL을 메모리에서 언로드한다. 실패한 경우, “Failed to Load DLL!” 메시지를 출력한다.
- FreeLibrary(hDll): FreeLibrary 함수는 LoadLibraryA 함수로 로드된 DLL을 메모리에서 언로드한다.
이후 이 코드를 실행하면
DLL에서 표시하는 메시지박스와 테스트 코드에서 표시하는 문장을 통해 DLL이 정상적으로 실행된다는 것을 확인할 수 있다.
2) DLL 인젝터 제작
이제 핵심 코드인 DLL 인젝션 기능을 구현해야 한다. 사용할 Windows API 함수는 다음과 같다.
API 함수 | 역할 |
---|---|
OpenProcess() | 대상 프로세스를 열고 핸들을 얻음 |
VirtualAllocEx() | 대상 프로세스의 메모리에 메모리를 할당 |
WriteProcessMemory() | 할당된 메모리에 DLL 경로를 씀 |
GetProcAddress() | LoadLibraryA의 주소를 얻음 |
CreateRemoteThread() | 원격 프로세스에서 LoadLibraryA 실행 |
InjectDLL 함수 정의: InjectDLL 함수는 DLL 주입을 수행한다.
processID: DLL을 주입할 대상 프로세스의 ID이다.
dllPath: 주입할 DLL 파일의 경로이다.
대상 프로세스 열기: OpenProcess 함수는 지정된 프로세스 ID의 프로세스 핸들을 얻는다.
PROCESS_ALL_ACCESS는 프로세스에 대한 모든 권한을 요청한다. 핸들을 얻지 못하면 오류 메시지를 출력하고 false를 반환한다.
대상 프로세스에 메모리 할당: VirtualAllocEx 함수는 대상 프로세스에 메모리를 할당한다. 할당된 메모리는 DLL 경로를 저장하는 데 사용된다. 메모리 할당에 실패하면 오류 메시지를 출력하고 false를 반환한다.
할당된 메모리에 DLL 경로 쓰기: WriteProcessMemory 함수는 할당된 메모리에 DLL 경로를 작성한다. 쓰기에 실패하면 오류 메시지를 출력하고 false를 반환한다.
LoadLibraryA 함수 주소 얻기: GetModuleHandleA 함수는 kernel32.dll의 핸들을 얻는다.
GetProcAddress 함수는 LoadLibraryA 함수의 주소를 얻는다.
LoadLibraryA 함수는 대상 프로세스에서 DLL을 로드하는 데 사용된다.
함수 주소를 얻지 못하면 오류 메시지를 출력하고 false를 반환한다.
원격 스레드 생성 (DLL 주입 실행): CreateRemoteThread 함수는 대상 프로세스에 원격 스레드를 생성한다. 원격 스레드는 LoadLibraryA 함수를 실행하여 DLL을 로드한다. 스레드 생성에 실패하면 오류 메시지를 출력하고 false를 반환한다.
성공적으로 주입 완료: 원격 스레드와 프로세스 핸들을 닫는다. true를 반환하여 DLL 주입이 성공했음을 나타낸다.
main 함수는 사용자로부터 프로세스 ID와 DLL 경로를 입력받는다. InjectDLL 함수를 호출하여 DLL을 주입하며, 주입 성공 여부에 따라 메시지를 출력한다.
이후 작성한 DLL 인젝터를 빌드하여 Release 폴더에 DLLInjector.exe 파일을 생성한다.
3) 테스트 & 실행
이제 실제 프로세스에 DLL을 주입해야 한다. 실행할 프로세스는 메모장이다. 메모장을 실행하고, 작업 관리자를 실행하여 메모장의 프로세스 ID(PID)를 확인한다.
PID가 10040임을 확인할 수 있다.
이제 터미널을 켜서 DLLInjector.exe를 실행한다. 대상 프로세스 ID에는 메모장의 PID를 입력하고, 주입할 DLL 경로에는 제작한 DLL의 경로를 입력한다. 이렇게 하면 DLL 주입 성공 메시지를 확인할 수 있다.
메모장을 확인해보면 출력되는 메시지가 조작한 대로 변조되었음을 확인할 수 있었다. DLL 인젝션이 성공적으로 이루어졌으며, 삽입된 DLL이 MessageBoxW 후킹을 수행하는 기능을 정상적으로 작동함을 확인하였다.
4.2 Detours 기반 후킹 실습
4.2.1 Microsoft Detours와 트램폴린 개념
Microsoft Detours 라이브러리는 Microsoft Windows에서 바이너리 함수를 모니터링 및 조작하기 위한 오픈 소스 라이브러리이다. Microsoft에서 개발했으며 Windows 애플리케이션 내에서 Windows API 호출을 가로채는 데 가장 일반적으로 사용된다.
본래 일반적인 후킹 방법은 원본 함수의 첫 몇 바이트를 강제로 수정하여 후킹한 함수로 점프하도록 변경한다. 이를 이미지로 나타내면 아래와 같다.
Detours 라이브러리가 일반적인 후킹과 차이를 두는 점은 트램폴린(Trampoline) 기법을 사용한다는 데에 있다. 이는 ‘원본 함수를 감싸는’ 방법으로, 후킹된 함수를 호출하면 원래 함수가 실행된 후, 추가 코드가 실행되도록 설계되어 있다.
트램폴린 함수는 다음과 같이 작동한다:
- DetourAttach()로 원본 함수와 후킹 함수 연결.
- Detours가 내부적으로 트램폴린 함수(Trampoline Function) 생성
- 원본 함수의 몇 바이트를 복사하여 새로운 메모리 영역에 저장.
- 이 트램폴린 함수는 원래 함수의 기능을 그대로 수행.
- 원본 함수가 호출될 때 후킹 함수가 실행된 후 트램폴린을 통해 원본 함수 실행.
일반적인 jmp 기반 후킹은 원본 함수의 첫 부분을 덮어쓰기 때문에 원래 코드 실행이 어렵다. 그러나 Detours는 트램폴린을 사용하여 원본 함수를 정상적으로 호출할 수 있도록 유지한다.
위의 이미지는 Detours를 이용한 후킹을 이미지화한 것이다. 이미지에서 나타난 후킹 과정을 정리해보면 다음과 같다:
- 로드된 DLL에서 원본 함수 특정 구문에 jmp 코드문 삽입
- 해당 jmp 코드문을 통해 로드된 DLL의 트램폴린 코드로 점프
- 트램폴린 코드에서는 원본 함수의 일부 구문을 실행하고, 임의 동작을 수행하는 후킹 코드를 별도로 실행함
- 지정 후킹 코드가 종료된 다음 다시 트램폴린 코드로 이동
- 트램폴린 코드가 종료될 때 원본 함수로 이동함
- 이후 원본 함수의 동작을 계속해서 진행
위와 같이 Detours를 사용하면 더 많은 단계를 거쳐 후킹을 목표한 함수에 다다르게 되며, 목표 함수는 그대로 두고 목표 함수의 실행 전후로 더 다양하고 효과적인 조작이 가능하다. 목표 함수가 원본 그대로 유지되는 것을 이용해 당연히 안정성 높은 조작 또한 가능하다고 말할 수 있다.
4.2.2 Microsoft Detours를 사용한 후킹 실습
목표
Detours 라이브러리를 이용하여 Windows API 함수 호출을 안전하게 후킹하는 방법을 학습한다. 후킹 시 원래 함수의 흐름을 유지하면서도 중간에 원하는 로직을 삽입할 수 있는 트램폴린 기법의 구조를 이해하고 구현한다.
실습 과정
- TargetApp.exe 실행 (MessageBox 반복 출력하는 앱)
- injector.exe 실행 → TargetApp.exe에 HookDll.dll을 주입
- 이후 TargetApp에서 MessageBoxW가 호출되면, 후킹된 함수가 실행되며 메시지가 변경됨
TargetApp.exe
“정상 메시지입니다”라는 문장을 출력하는 간단한 앱이다.
여기서 중요한 요소는 while(true) 무한 루프를 사용하여 프로그램을 종료하지 않도록 유지하고 있다는 것이다. 코드를 보면 사용자가 “취소(Cancel)” 버튼을 누를 때까지 MessageBoxW를 계속 호출하고 있는데, 이 구조를 이용해야 후킹 DLL 주입 이후 변조된 메시지를 제대로 확인 가능하다.
아무것도 하지 않고 MessageBox가 한 번 뜨고 종료되는 구조라면 계속 실행 상태가 아니므로 후킹이 불가능하기 때문에 이렇게 프로그램을 작성했다.
injector.exe
FindProcessId 함수는 주어진 이름의 프로세스를 찾아서 그 ID를 반환하거나 찾지 못하면 0을 반환한다.
InjectDLL 함수는 주어진 프로세스 ID를 가진 프로세스를 열고, 그 프로세스의 메모리 공간에 DLL 파일 경로를 쓴 다음 원격 스레드를 생성하여 LoadLibraryA 함수를 실행시켜 해당 DLL을 대상 프로세스에 로드한다.
main 함수는 위의 두 함수를 호출해 Targetapp.exe 프로세스를 찾아 HookDll.dll을 주입하는 역할을 한다.
HookDll.dll
DetourAttach(&(PVOID&)Real_MessageBoxW, MyMessageBoxW);: 여기서 핵심적인 후킹 작업이 수행된다. 이 함수 호출은 MessageBoxW가 호출될 때 실제로 MyMessageBoxW 함수가 대신 실행되도록 설정한다.
- (PVOID&)Real_MessageBoxW: 원래 MessageBoxW 함수의 주소를 가리키는 Real_MessageBoxW 포인터의 주소를 PVOID 타입의 포인터로 캐스팅하여 전달한다. Detours 라이브러리는 함수의 주소를 이렇게 받아서 후킹한다.
- MyMessageBoxW: MessageBoxW를 대신하여 실행될 후킹 함수의 주소를 전달한다.
- DetourTransactionCommit();: Detours 트랜잭션을 커밋한다. 이 시점에서 후킹이 실제로 적용된다.
- else if (ul_reason_for_call == DLL_PROCESS_DETACH): DLL이 프로세스에서 언로드될 때 실행되는 코드 블록이다. 후킹을 해제하는 역할을 한다.
- DetourTransactionBegin();: Detours 트랜잭션을 시작한다.
- DetourUpdateThread(GetCurrentThread());: 현재 스레드를 Detours 트랜잭션에 등록한다.
- DetourDetach(&(PVOID&)Real_MessageBoxW, MyMessageBoxW);: 후킹을 해제하는 작업이다. 원래 MessageBoxW 함수와 후킹 함수 간의 연결을 끊고, MessageBoxW가 정상적으로 작동하도록 복원한다.
- DetourTransactionCommit();: Detours 트랜잭션을 커밋한다. 이 시점에서 후킹이 해제된다.
실습 결과
TargetApp.exe는 처음 실행시키면 위와 같다. 이제 injector.exe를 실행시키고 TargetApp.exe의 ‘확인’ 버튼을 다시 누른다.
그러면 메시지가 변조된 것을 확인할 수 있다. 이와 같이 Detours를 이용한 트램폴린 기반 후킹이 의도대로 동작함을 실습을 통해 검증하였다.
5. 보안 메커니즘과 대응 기술
Windows 시스템은 다양한 후킹 및 인젝션 기법으로부터 자체를 보호하기 위해 사용자 모드와 커널 모드 모두에 걸쳐 여러 보안 메커니즘을 구축해 놓고 있다. 이 장에서는 다양한 DLL 인젝션 및 후킹 시도에 대응하기 위한 운영체제 차원의 보호 기술을 구체적으로 살펴본다.
5.1 DEP과 Windows Defender를 통한 인젝션 탐지 기법
5.1.1 DEP의 인젝션 탐지 방식
DEP은 Windows 자체 보안 기능으로, 메모리 영역을 “실행 가능” 또는 “실행 불가능”으로 표시하여, 데이터 영역에 있는 코드가 실행되는 것을 방지하는 보안 기능이다. 즉 OS 차원에서 “실행 가능한 코드”와 “데이터”를 구분하여, 데이터 영역(Heap, Stack 등)에서 코드가 실행되지 않도록 막는다. 보통 버퍼 오버플로우와 같은 취약점을 이용한 코드 실행 공격을 막기 위함이다.
대부분의 APC Injection은 쉘코드를 쓰기 위한 메모리를 VirtualAlloc()으로 할당하고, 여기에 코드를 복사하고 PAGE_EXECUTE_READWRITE 플래그를 준다. 이러한 우회 시도는 DEP가 활성화된 환경에서는 Heap이나 Stack에 있는 코드의 실행 시도를 비정상 실행 시도로 판단할 수 있다. 즉 DEP가 “실행 불가능”으로 표시한 영역의 코드를 실행하려는 시도이므로 DEP에 의해 실행 오류가 발생하거나, 보안 솔루션에 의해 DEP 우회 시도로 탐지될 수 있다.
비유하자면 DEP는 생산 라인(메모리)의 특정 구역(데이터 영역)에서는 원래 부품(코드)을 조립할 수 없도록 규칙을 정해 놓은 것과 같다. 불량 부품(악성 코드)을 그 구역에서 실행하려고 하면 DEP가 이를 막거나 경고하게 된다.
하지만 DEP는 단독으로는 후킹이나 인젝션 시도를 완전히 막지는 못한다. 예를 들어 VirtualAllocEx()를 이용하여 실행 권한(PAGE_EXECUTE_READWRITE)이 부여된 메모리 영역을 할당하고, WriteProcessMemory()와 CreateRemoteThread()로 DLL 경로를 삽입 및 실행하면 DEP를 우회할 수 있는 구조가 된다. 이러한 한계를 보완하고자 Windows는 Windows Defender를 포함한 여러 보안 체계를 병행 운영하고 있다.
5.1.2 Windows Defender의 인젝션 탐지 방식
이제는 Microsoft Defender라고 불리기도 하는 Windows Defender는 Microsoft Windows 운영체제에 기본적으로 내장된 악성 소프트웨어 방지 프로그램이다. 이러한 악성 소프트웨어 방지 프로그램은 APC injection과 같은 코드 인젝션 시도를 다양한 방식으로 탐지한다.
메모리 관련 보호 메커니즘
- DEP (Data Execution Prevention): 데이터 영역(Heap, Stack)에서의 코드 실행을 차단한다. 예를 들어, VirtualAllocEx()로 할당한 메모리에서 코드를 실행하려 하면 차단한다.
- CFG (Control Flow Guard): Microsoft 컴파일러에서 제공하는 기능이다. 미등록된 콜백 함수나 함수 포인터 호출을 차단한다. APC Injection 시 등록한 콜백이 CFG에 의해 거부될 수 있다.
- ACG (Arbitrary Code Guard): 브라우저, Office 등 주요 앱에서 작동하며, JIT, RWX 메모리 실행을 제한하여 메모리 권한 변경 및 실행이 일어나면 차단한다.
행위 기반 탐지
Defender는 실행 중인 프로세스의 API 호출 시퀀스와 인젝션 흐름을 감시한다.- OpenProcess → 타깃 프로세스 핸들 획득
- VirtualAllocEx → RWX 메모리 할당
- WriteProcessMemory → 쉘코드 또는 DLL 경로 쓰기
- CreateRemoteThread / QueueUserAPC → 외부 스레드 실행 트리거
위와 같은 API 호출이 주요 감시 대상이 될 수 있다. Defender는 이 일련의 흐름을 감지하고 시나리오 기반 탐지 로직을 통해 인젝션으로 분류한다.
주요 API 모니터링
Defender는 특정 Windows API 및 NT API를 행위 기반 탐지 및 로그 추적 대상으로 삼는다.API / 시스템 콜 역할 VirtualAllocEx 외부 프로세스에 메모리 할당 WriteProcessMemory 외부 프로세스에 코드 쓰기 CreateRemoteThread, QueueUserAPC, NtCreateThreadEx 외부 코드 실행 시도 NtQueueApcThread, NtQueueApcThreadEx 비동기 콜백을 스레드에 큐잉 SetThreadContext, GetThreadContext 스레드 레지스터 조작 시도 MapViewOfFile, CreateFileMapping DLL Hollowing/Reflective Injection에 사용됨 Exploit Protection / ASR (Attack Surface Reduction)
Windows Defender Exploit Guard는 미리 정의된 보안 정책으로 코드 인젝션 자체를 방지할 수 있다. 주요 ASR 규칙에는 다음과 같은 것들이 있다.규칙 이름 설명 Block code injection from Office child processes winword.exe 같은 앱이 WriteProcessMemory()를 호출하면 차단 Block process creation from Office macros CreateRemoteThread 차단 Use advanced protection against ransomware 의심되는 메모리 매핑을 차단
즉, Defender는 코드 인젝션 발생 전에 아예 인젝션 가능성을 차단할 수 있는 정책 기반 제어 기능도 갖추고 있다고 할 수 있다.
6. 마무리하며
이번 보고서를 작성하면서 Windows 환경에서 사용되는 API 후킹 및 DLL 인젝션 기술의 구조와 작동 원리를 실습을 통해 깊이 있게 이해할 수 있었다. 특히 CreateRemoteThread, Detours 등을 사용해 간단한 인젝션과 후킹을 실제로 적용해보며 함수 호출 흐름을 조작하는 기술이 얼마나 정교하게 구성되어 있는지 체감할 수 있었다. 또한 Windows Defender와 DEP 같은 보안 메커니즘이 이러한 후킹 및 인젝션 시도를 어떻게 탐지하고 차단하는지를 실습을 통해 경험하며, 운영체제 차원의 방어 체계 역시 함께 고려되어야 함을 깨달았다.
다만 본 보고서에서 다룬 기술들은 모두 사용자 모드(User Mode)에서의 인젝션과 후킹에 집중되어 있으며, 커널 모드에서의 후킹, 드라이버 개발, Ring0 레벨에서의 보안 우회 기법 등은 추가 학습이 필요한 영역으로 남아 있다. 향후에는 NT API Injection, Reflective DLL Injection, AMSI 우회, 커널 후킹 등 더 고급 주제를 다뤄 Windows 내부 구조와 보안 메커니즘을 보다 깊이 있게 이해하고자 한다. 이를 위해 SSDT, PatchGuard, SRM과 같은 커널 보안 메커니즘은 물론, Native API와 커널 디버깅 도구, Windows 드라이버 개발 환경(WDK) 등을 활용한 실습을 이어가는 것이 좋은 방향이 될 수 있을 것이다.
7. 참고 문헌
- James Shewmaker (2006). “Analyzing DLL Injection”. 《GSM Presentation》. Bluenotch.
- “Working with the AppInit_DLLs registry value”. 《Microsoft Help and Support》
- Jonathan Daniel (2013-11-27). “Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX”.
- Robert Kuster (2003-08-20). “Three Ways to Inject Your Code into Another Process”. CodeProject.
- Solomon, D. A., Russinovich, M. E., & Ionescu, A. (2017). Windows Internals, Part 1: System architecture, processes, threads, memory management, and more (7th ed.). Microsoft Press.
- Microsoft. (n.d.). Windows API 인덱스. Windows API 인덱스 - Win32 apps | Microsoft Learn
- Microsoft. (n.d.). DLL(동적 연결 라이브러리). DLL(동적 연결 라이브러리) - Windows Client | Microsoft Learn
- Microsoft Security. (2022-11-26). Microsoft Defender for Endpoint. https://www.microsoft.com/en-us/security/business/endpoint-security/microsoft-defender-endpoint.
- https://github.com/microsoft/detours
- https://learn.microsoft.com/ko-kr/windows/win32/apiindex/windows-api-list
- https://learn.microsoft.com/ko-kr/troubleshoot/windows-client/setup-upgrade-and-drivers/dynamic-link-library