[2026 SWING magazine] 윈도우 악성코드 인젝션 기법 심층 분석 : Hollowing부터 Ghosting까지

1. 서론

가. 칼럼 작성 배경

최근 APT(Advanced Persistent Threat) 공격은 국가·기업을 가리지 않고 꾸준히 발생하고 있다. 안랩을 비롯한 여러 보안 업체의 최신 보고서에서 확인되었듯, 공격자들은 다양한 악성코드를 활용해 윈도우 환경을 중심으로 장기간 은밀하게 침투하고 있다. 이러한 APT 공격에는 합법적 프로세스에 악성 행위를 숨기는 “프로세스 인젝션” 기법이 탐지 우회 효과를 위해 주요 수단으로 사용되고 있으며, 날이 갈수록 그 기술이 고도화되고 있다.

나. 주제 선정 이유

프로세스 인젝션은 단순히 악성코드를 실행하는 데 그치지 않고, 정상 프로세스처럼 위장함으로써 보안 솔루션의 탐지를 어렵게 만든다는 점에서 연구 가치가 크다. 인젝션 기법이 프로세스 할로잉(Process Hollowing)에서 시작해 도플갱잉(Process Doppelgänging), 고스팅(Process Ghosting)으로 진화한 과정은 각각이 노린 보안 대응 체계의 허점을 역으로 보여주기도 한다. 각 기법은 윈도우 운영체제의 파일 처리, 메모리 매핑, 트랜잭션 기능 등을 교묘히 악용해 탐지를 회피하기 때문에 현업에서도 대응이 쉽지 않다. 이런 맥락에서, 이번 칼럼은 단순히 기술들을 나열하는데 그치지 않고 공격 기법의 진화 과정을 따라가며 보안 측면에서의 취약성을 짚어보는 데 초점을 두고 있다.

다. 칼럼 목표 및 구성

이번 칼럼은 프로세스 할로잉, 도플갱잉, 고스팅 기법을 직접 실습하며 그 동작 원리와 차이를 이해하는 데서 출발해, 각 기법이 실습 환경에서 탐지를 회피하는 매커니즘과 그 효과를 비교하고, 그 결과를 통해 보안 측면에서의 취약성과 한계를 짚어보려고 한다. 마지막으로 이러한 분석을 바탕으로 현업 보안 환경에서 적용 가능한 대응 방안을 모색하는 것을 목표로 한다.


2. 악성코드 은닉기법 개요

가. 프로세스 인젝션이란?

악성코드 은닉 기법은 공격자가 자신의 악성 행위를 정상 프로세스의 일부처럼 위장해 탐지 솔루션과 분석 절차를 회피하고, 장기적으로 시스템에 상주하거나 권한을 상승시킬 수 있도록 설계된 기술을 의미한다. 이 기법은 단순 실행형 악성코드와 달리, 정상적인 시스템 동작의 흐름을 악용한다는 점에서 탐지/차단을 어렵게 한다.
“프로세스 인젝션(Process Injection)”은 이러한 은닉 기법의 핵심으로, 정상 프로세스의 메모리 공간에 악성 페이로드를 삽입하고 이를 실행함으로써 악성 행위를 정상 프로세스의 맥락에서 수행하는 기법이다. 이를 통해 공격자는 탐지 과정에서 악성 코드가 독립된 프로세스가 아닌 정상적인 행위로 인식되도록 한다. 해당 공격의 수행을 위해 공격자는 윈도우 환경에서 API 호출을 통해 메모리 접근과 실행을 제어하거나 프로세스 간의 메모리를 조작할 수 있다.

A. 개념 및 정의

“프로세스 인젝션(Process Injection)”은 실행 중인 정상 프로세스의 메모리 공간에 악성 페이로드를 주입하고, 해당 정상 프로세스의 권한과 흐름을 이용해 악성 행위를 수행하는 기법이다. 공격자는 독립된 악성 프로세스를 실행하지 않고 explorer.exe, svchost.exe, notepad.exe와 같은 정상 프로세스의 내부에 코드를 숨겨 실행함으로써, 외부에서 보기에는 정상적인 동작처럼 보이도록 위장한다.
이 기법은 정상 프로세스의 메모리 공간을 조작하기 위해 프로세스 간 메모리 공유 기능을 악용한다. 악용에는 주로 OpenProcess, WriteProcessMemory, CreateRemoteThread, VirtualAllocEx, LoadLibrary와 같은 Windows API가 활용되며, 이러한 API들은 합법적인 기능이기 때문에 탐지를 더욱 어렵게 만든다. 해당 공격이 대부분 메모리 기반(fileless)으로 실행되는 점 역시 디스크에 악성 파일을 남기지 않거나 최소화된 흔적만 남김으로써 정적 분석이나 서명 기반 탐지를 통한 식별을 어렵게 만든다.

공격 절차는 보통 다음과 같은 흐름으로 진행된다.

  1. 대상 프로세스를 열거나 생성해 핸들을 확보
  2. 원격 메모리 공간을 할당하고 해당 영역에 악성코드를 기록
  3. 이후 원격 스레드를 생성하거나 실행 흐름을 변경하여 악성코드를 실행

이렇게 삽입된 악성코드는 해당 프로세스의 권한을 그대로 상속받는다. 악성코드가 관리자 권한 프로세스에 삽입되었을 경우 시스템 전체에 대한 제어권을 획득하는 것 역시 가능하다.

B. 공격자가 사용하는 이유

이러한 프로세스 인젝션은 공격자에게 여러 측면에서 이점을 가져다 준다.
첫째, 탐지 회피. 악성코드가 정상 프로세스의 일부로 동작하기 때문에 보안 솔루션이 정상 행위로 오인할 가능성이 높다. 또한 앞서 언급했듯 주로 파일리스 방식으로 실행되기 때문에, 디스크에 남는 흔적이 거의 없어 정적 분석과 포렌식 기반 탐지를 어렵게 한다.
둘째, 권한 상승. 추가적인 권한 상승 과정 없이도, 공격 대상 프로세스의 권한을 그대로 상속받고 이를 악용할 수 있다. 만일 관리자 권한을 상속받을 경우 이를 악용해 자격 증명 탈취, 보안 정책 변경, 네트워크 확산과 같은 추가적인 공격을 수행할 수 있다.
셋째, 지속성 확보. explorer.exesvchost.exe와 같은 시스템 종료 전까지 지속적으로 실행되는 프로세스에 코드를 삽입할 경우 지속적인 공격이 가능하다. 심지어 시스템이 재부팅되더라도 동일한 인젝션 루틴을 재실행해 은닉 상태를 유지할 수 있다.

C. 일반적인 탐지 우회 방식

프로세스 인젝션은 단순히 악성코드를 정상 프로세스에 삽입하는 것에 그치지 않고, 여러 탐지 우회 기법을 함께 사용한다.
첫째, API 호출 은닉. 보안 솔루션은 보통 OpenProcess, VirtualAllocEx, WriteProcessMemory, CreateRemoteThread, LoadLibrary와 같은 API 호출 패턴을 탐지 지표로 활용한다. 이러한 호출은 프로세스 핸들 확보, 메모리 공간 할당, 페이로드 기록, 원격 스레드 생성 같은 인젝션의 핵심 과정이기 때문이다. 공격자들은 이러한 탐지를 우회하기 위해 API 호출을 간접적으로 하거나, 동적으로 로드해 흔적을 줄이고, 심지어 API 후킹을 해제하거나 우회하는 방식으로 모니터링을 피한다.
둘째, 메모리 암호화와 난독화. 악성코드가 메모리에 평문 상태로 적재되면 탐지 솔루션이 이를 식별할 가능성이 높다. 이를 방지하기 위해 공격자는 페이로드를 XOR 연산이나 블록 암호화로 암호화한 뒤 필요할 때만 복호화해 실행한다. 또한 매 실행마다 키나 코드 구조를 바꾸는 ‘폴리모픽(polymorphic)’ 기법이나, 코드 자체를 재작성하는 ‘메타모픽(metamorphic)’ 기법을 통해 시그니처 기반 탐지를 어렵게 만든다. 이 과정에서 문자열 난독화, 스크립트 암호화, PowerShell 난독화 등 다양한 기법이 동원된다.
셋째, 인젝션 기법의 다양화.

  1. “DLL Injection”은 가장 일반적인 기법으로, 정상 프로세스의 메모리에 DLL 경로를 기록하고 로드하도록 하여 악성코드를 실행한다. 구현이 단순하고 안정적이지만, 디스크에 DLL 파일이 존재하기 때문에 비교적 탐지가 쉽다는 단점이 있다.
  2. “Reflective DLL Injection”은 DLL 파일을 디스크에 두지 않고, 메모리에서 직접 로드하는 기법이다. 해당 특성으로 인해 주로 파일리스(fileless) 공격에 활용된다. “DLL injection”과 달리 파일 기반 탐지로는 곧잘 탐지되지 않는다.
  3. “Code CaveInjection”은 실행 파일의 사용되지 않는 빈 공간에 악성코드를 심고 기존 코드 흐름을 변경하여 악성코드를 실행하는 기법이다. 새로운 파일을 드롭하지 않고도 실행할 수 있어 정적 탐지를 피하기 쉽다는 장점이 있다.
  4. “Process Hollowing”은 정상 프로세스를 일시 정지 상태로 생성한 뒤, 원래의 이미지를 제거하고 악성 페이로드를 같은 주소 공간에 매핑하여 실행하는 방식을 말한다. 외부에서는 정상 프로세스처럼 보이지만, 내부적으로 악성코드가 동작하는 것이 특징이다.
  5. “Process Doppelgänging”은 윈도우의 NTFS 트랜잭션 기능을 악용해, 디스크에 커밋되지 않은 임시 파일을 기반으로 프로세스를 시작하는 기법이다. 실행이 끝난 뒤에도 파일이 존재하지 않기 때문에 포렌식에서 흔적을 찾기 어렵다는 특징이 있다.
  6. “Process Ghosting”은 삭제된 파일 핸들을 기반으로 메모리 이미지를 생성하여, 프로세스를 실행하는 기법이다. 실행 후에도 디스크에 흔적이 거의 남지 않아 탐지하기 가장 어려운 기법이라고 평가 받는다.
    이처럼 프로세스 인젝션의 탐지 우회는 정적 분석이나 단순 시그니처 기반 탐지로는 식별이 거의 불가능할 정도로 정교해지고 있다.

3. Process Hollowing

가. 동작 원리

그림 1. 프로세스 할로잉의 동작 원리

그림 1. [프로세스 할로잉의 동작 원리]

프로세스 할로잉은 프로세스 인젝션의 하위 범주에 속하는 공격 기법으로, 정상적인 프로세스의 메모리 주소 공간을 훼손하여 악성 코드를 실행한다. 일반적인 프로세스 할로잉의 공격 단계는 다음과 같다.
  1. 프로세스 생성
    : SUSPEND 상태의 호스트 프로세스를 생성한다.
    → 사용되는 API: CreateProcess() 등.

  2. 원본 이미지 언매핑
    : 호스트 프로세스의 정상적인 이미지를 메모리에서 할당 해제(unmap)한다.

  3. 악성 페이로드 매핑
    : 원본 이미지가 할당 해제된 빈 공간에 원하는 악성코드를 삽입한다.

  4. Entry Point 수정
    : 호스트 프로세스의 Entry Point(프로세스 시작 주소)가 악성 코드의 주소를 가리키도록 수정한다.

  5. 호스트 프로세스 실행 재개
    : 정지되어 있던 원본 프로세스를 재실행해 악성 코드를 실행한다.
    → 사용되는 API: resume() 등

즉 프로세스 할로잉(Process Hollowing)은 “Hollowing”이라는 이름에 걸맞게 원본 프로세스에게 할당된 메모리 공간에서 원본 프로세스 이미지를 “비워내고”, 그 빈 공간에 악성 코드를 삽입함으로써 이루어진다.
프로세스 할로잉에 의해 악성코드가 실행되는 과정을 정상 프로그램이 실행되는 과정을 아래 표로 비교했다.

정상 Windows 로더 Hollowing
1. 프로세스 생성 Suspended 상태로 껍데기 생성 Suspended 그대로 생성
2. 이미지 매핑 원본 PE를 메모리에 매핑 동일
3. 섹션 로드 원본 섹션 유지, EP 설정 준비 원본 언맵 → 악성코드 매핑
4. EP 설정 정상 EP를 실행 위치로 지정 악성코드의 EP로 덮어쓰기
5. 실행 정상 프로그램 실행 악성코드 실행
표1. [정상 프로그램과 프로세스 할로잉의 악성코드 실행 비교]

나. 실습 구현

https://github.com/idan1288/ProcessHollowing32-64

[ProcessHollowing.c POC 코드 주소]

실습 진행에 활용된 코드는 위의 깃허브 주소의 ProcessHollowing.c PoC 코드이다. 실습은 윈도우 11 64비트 환경에서 진행되었다.

(1) 선언부

그림 2. 선언부 코드

그림 2. [선언부 코드]
  • mtdll.lib
    • Windows의 핵심 라이브러리. 해당 라이브러리를 통해 프로그램들이 NT API를 호출한다.
  • Native API
    • NT API : Windows NT 커널에서 직접 사용되는 저수준(low-level) API. Windows 운영 체제의 핵심 기능에 접근하는 데 사용된다.
    • 해당 코드에서는 NtTerminateProcess(프로세스 말소), NtReadVirtualMemory(가상 메모리 읽기) 등을 사용한다.

(2) 인자/구조체 준비

그림 3. 인자, 구조체 코드

그림 3. [인자, 구조체 코드]
  • _CONTEXT 구조체의 ContextFlags를 초기화한다.
    → 모든 레지스터의 초기화를 허용
  • 레지스터에 TIB, entry point 등의 값이 저장된다.

(3) 껍데기(타겟) 프로세스 SUSPENDED 상태로 실행

그림 4 실행 파일을 “일시 중지된 상태”로 실행하려고 시도하는 코드

그림 4. [실행 파일을 “일시 중지된 상태”로 실행하려고 시도하는 코드]
  • CreateProcessw()로 target Executable로 전달한 프로세스를 SUSPENDED 상태로 실행한다.
    → 목적 : 초기 스레드 실행 이전의 메모리/레지스터를 바꾼다.
  • 인자 분석
    • arg[1]: 타겟 프로세스
    • arg[2]: 타겟 프로세스를 교체할 악성 프로세스
    • &pi: PROCESS_INFORMATION 구조체의 포인터
      → 해당 구조체는 만든 프로세스와 갖고 있는 메인 스레드의 정보를 저장한다.

(4) 대체할 프로그램 파일 형식으로 열어두기

그림 5. CreateFile을 이용한 대체 실행 파일 열기 과정

그림 5. [CreateFile을 이용한 대체 실행 파일 열기 과정]
  • CreateFileW()에 argv[2]를 전달해 대체할 프로그램(악성코드) 파일을 생성한 뒤 hFile에 저장한다.
  • 실패하면 앞서 만든 자식 프로세스를 종료하고 이후 GetFileSize()로 hFile의 사이즈를 알아둔다.
  • 매개변수 분석
    • dwCreationDisposition = OPEN_EXISTING
      → 이미 존재하는 파일만 열어야 한다. 열려는 파일의 경로가 잘못되었거나 파일이 없을 경우 INVALID_HANDLE_VALUE 에러로 처리된다.
      → 이때, 여는 건 디스크의 교체 EXE이며, 아직 대상 프로세스 메모리는 건드리지 않는다.

그림 6. 메모리 버퍼 확보 및 파일 로딩

그림 6. [메모리 버퍼 확보 및 파일 로딩]
  • VirtualAlloc을 통해, 현재 실행 중인 로컬 프로세스 메모리에 nSizeofFile(hfile의 크기)만큼 버퍼를 확보한다.
    → 파일 사이즈만큼의 가상공간을 만들어 두고, 파일을 읽어온다.
    → 나중에 타깃 프로세스에 그대로 써 넣기 위해 ReadFile()로 디스크의 EXE를 읽어 들여, PE 헤더/섹션 정보를 파싱한다.
  • image 포인터 : EXE 파일의 바이트가 그대로 들어있다.

(5) MZ 시그니처 체크/ NtHeader 포인터 Get

그림 7. PE 파일 유효성 검증 및 스레드 컨텍스트 확보

그림 7. [PE 파일 유효성 검증 및 스레드 컨텍스트 확보]
  • e_magic이 MZ인지 확인 → 정상 PE인지 판별한다.
  • e_lfanew 값으로 NT 헤더 위치(pNtH)를 찾는다.
  • NtGetContextThread: 일시중단된 타깃 스레드의 현재 레지스터 상태를 읽어 ctx구조체에 채운다.

(6) 타겟 프로세스의 Image Base 얻어오기/해당 주소영역 비우기

그림 8. PEB에서 Image Base를 읽어 충돌 여부 확인 → 동일하면 원본 이미지 언맵

그림 8. [PEB에서 Image Base를 읽어 충돌 여부 확인 → 동일하면 원본 이미지 언맵]
  • 껍데기 역할을 하는 타겟 프로세스의 PEB로부터 ImgaeBase 주소를 얻어온다.
    → PEB + offset(ImageBaseAddress)를 읽어 현재 로드된 원본 ImageBase를 얻을 수 있다.
  • ImageBaseAddress는 x86 PEB에서 0x08 / x64 PEB에서 0x10
  • 교체 EXE의 Preferred ImageBase 와 원본의 베이스가 같으면 충돌
    → 원본 이미지의 unmap이 가능하다.

(7) unmap된 주소영역에 새로 가상공간 할당하기

그림 9. 언맵된 ImageBase 주소에 SizeOfImage 크기만큼 메모리 커밋

그림 9. [언맵된 ImageBase 주소에 SizeOfImage 크기만큼 메모리 커밋]
  • VirtualAllocEx함수를 통해, SUSPENDED로 실행한 프로세스의 ImageBase 부분에 악성 파일의 SizeOfImage 만큼의 가상영역을 할당한다.
    → 해당 주소부분이 매핑 상태면 해당 영역 매핑에 실패.

(8) 할당된 가상영역에 데이터 채우기

그림 10. 새로 할당된 공간에 교체 EXE 전체 데이터로 덮어쓰기

그림 10. [새로 할당된 공간에 교체 EXE 전체 데이터로 덮어쓰기]
  • 헤더, 각 섹션을 가상주소 위치에 대응시켜 복사한다.
    → 껍데기 프로세스의 ImageBase부터 끝까지 악성 파일의 데이터로 덮어 씌워진다.

(9) CONTEXT 구조체 재정의/SUSPENDED 상태 해제

그림 11. CONTEXT 구조체 수정 및 EntryPoint 재설정 후 실행 재개

그림 11. [CONTEXT 구조체 수정 및 EntryPoint 재설정 후 실행 재개]
  • 처음에 get 해온 프로세스의 메인 스레드에 대한 레지스터 정보를 수정한다.
    → EntryPoint 오프셋 정보, ImageBase 정보 변경
  • Resume으로 실행을 재개하면, 교체 이미지의 EntryPoint부터 실행이 시작된다.
    → 즉 덮어씌운 악성 파일이 실행되며 본격적인 공격 행위가 개시된다.

<함수 흐름 정리 요약>

(1) CreateProcess : 실행중지된 상태의 타겟 프로세스 생성
(2) NtUnmapViewOfSection : 타겟 프로세스의 이미지 메모리에서 할당 해제
(3) VirtualAlloc : 타겟 프로세스가 할당 해제된 섹션에 악성 파일 크기만큼의 공간을 할당
(4) WriteProcessMemory : 할당된 가상영역에 악성 페이로드 덮어씌움
(5) SetContextThread : CONTEXT 구조체를 수정해 타겟 프로세스 메인 스레드의 EntryPoint를 메모리에 할당한 악성 파일의 EntryPoint로 조작
(6) ResumeThread : 해당 스레드를 실행시켜 공격 행위 개시


**[실습 진행]**

간단한 메시지문을 출력하는 payload.c를 ProcessHollowing.exe를 이용하여 RegisterExplorer.exe에 inject하는 테스트 실행을 진행했다.

그림 12. 메시지 박스를 출력하는 테스트용 payload.c 코드

그림 12. [메시지 박스를 출력하는 테스트용 payload.c 코드]

payload.c : 메시지박스를 통해 간단한 문구를 출력하는 코드이다. Visual Studio를 통해 해당 코드를 exe로 컴파일해 payload.exe를 만들었다.

그림 13. 수정 후 빌드한 ProcessHollowing.exe 코드

그림 13. [수정 후 빌드한 ProcessHollowing.exe 코드]

위에서 분석했던 공격 코드를 조금 수정한 후, 마찬가지로 exe로 추출했다.
→ ProcessHollowing.exe

그림 14. payload_test.exe를 RegisterExplprer.exe에 주입한 cmd 출력 화면

그림 14. [payload_test.exe를 RegisterExplprer.exe에 주입한 cmd 출력 화면]

cmd 창에서 RegisterExplorer.exe에 payload_test를 inject해서 공격을 실행했다.

그림 15. 정상 프로세스 Registry Explorer 아이콘

그림 15. [정상 프로세스 Registry Explorer 아이콘]

그림 16. payload 실행 메시지 박스 출력

그림 16. [payload 실행 메시지 박스 출력]

그림 17. RegistryExplorer.exe만 확인되는 작업 관리자 화면(위장 성공)

그림 17. [RegistryExplorer.exe만 확인되는 작업 관리자 화면(위장 성공)]

메시지 박스로 공격이 성공했음을 확인했다. 이후 작업 관리자로 프로세스를 살펴보면 payload.exe가 작동 중임에도 작업 관리자의 세부 정보 탭에서는 RegistryExplorer.ex의 실행만 감지됨을 알 수 있다. payload.exe가 RegistryExplorer 프로세스 안에서 작동 중이기 때문에 작업 관리자 등에 별도로 감지되지 않는 현상으로, 이로써 프로세스 할로잉의 탐지 어려움까지 함께 체감할 수 있다.

다. 탐지 및 분석

해당 파트에서는 프로세스 할로잉의 동적/사후 탐지법을 정리한 뒤, 앞서 진행한 실습을 실시간/사후 탐지하여 그 내용과 결과를 분석하고자 한다.

우선 Process Hollowing은 파일리스 공격의 특성을 갖고 있기 때문에 PE 기반 탐지로는 쉽게 감지할 수 없다. 또한 CreateProcess 등 정상적인 맥락에서도 자주 호출되는 API를 이용하기 때문에 특정 API를 차단하는 식의 사전 방지 역시 효율이 떨어진다.
이러한 Process Hollowing 공격의 특성들을 고려하였을 때, 특정 행위들의 맥락 및 연속성에 대한 면밀한 관찰이 탐지에 중요한 역할을 할 것임을 예상할 수 있다.
즉 [생성 → 조작 → 재개]의 호출 시퀀스, 메모리 매핑 불일치, 부모-자식 관계 등의 이상이 동시에 보이는지를 묶어서 보아야 탐지 정밀도가 높아지는 것이다. 아래는 프로섹스 할로잉을 의심할 수 있는 정황의 리스트다.

  1. API/행위 시퀀스 모니터링:
    CreateProcessNtUnmapViewOfSectionVirtualAllocExWriteProcessMemorySetThreadContextResumeThread와 같은 API 호출이 연속으로 발생하는 경우
  • 주목할 지점
    • 단일 이벤트가 아니라 인접 시간대의 묶음
    • 프로세스 접근 권한과 Resume 시점이 가까이 붙는지 여부
      ⇒ API 호출 패턴 분석을 통해 이상 행동 감지가 가능하다.
  1. 실행 파일과 메모리 매핑 비교
    : 정상적인 실행 파일과 메모리에 로드된 실행 파일이 다른 경우
  • Private + EXECUTE(RX/RWX) 영역이 존재하고, 백킹 파일(원본 이미지)가 없는 경우
  • 주 모듈인 ImageBase, EP가 디스크의 PE와 다른 경우
  • 섹션 권한이 일괄 RWX 같이 느슨한 경우
    → 실행 파일의 서명 및 무결성을 검증하기
    → 백킹 없는 실행 영역, StartAddress가 모듈 범위 밖인 스레드, 모듈 로드 목록 확인 하기
    → Volatility 같은 도구를 활용해 메모리 내 실행 중인 프로세스 분석하기
  1. Parent-Child Process 관계 분석
    Process Hollowing은 주로 부모 프로세스는 공격 도구, 자식 프로세스는 정상적인 이름인 조합의 경우가 많다.

    → 각 프로세스의 PID, PPID 확인하기
    (ex) explorer.exe → cmd.exe (O) / winlogon.exe → powershell.exe (X)

  2. 코드 인젝션 / 무결성 점검
    프로세스 내 코드 영역을 주기적으로 스캔하여 실행 가능한 메모리 페이지 변경 여부 확인, 로드된 PE 구조가 디스크와 일치하는지의 여부 확인

4. Process Doppelgänging

가. 동작 원리

프로세스 도플갱잉은 2017년 BlackHat Europe에서 공개된 윈도우 악성코드 실행 기법으로, 윈도우의 TxF(Transactional NTFS)와 섹션 객체(SEC_IMEGE) 특성을 악용하여 디스크에는 정상 실행 파일을 유지하면서 메모리에는 공격자가 덮어쓴 악성 이미지 섹션을 실행하는 기법이다.
즉, 디스크의 정상 파일을 유지하면서 메모리에서 악성 코드를 실행하는 것이 도플갱잉의 본질이라고 할 수 있다. 이 공격의 매커니즘을 이해하는데 필수적인 트랜잭션의 개념을 짚고 넘어간 뒤, 공격의 흐름을 살펴보도록 하겠다.

A. 트랜잭션(Transaction)

트랜잭션은 데이터베이스나 파일 시스템에서 하나의 논리적 작업 단위를 의미한다. 한꺼번에 수행되어야 할 연산을 모아놓은 단위로도 이해될 수 있는데, 이 경우 하나의 트랜잭션으로 묶인 작업들이 전부 성공해야만 작업 결과가 최종적으로 반영 되며, 일부라도 오류가 발생할 경우 결과를 반영하지 않고 작업을 취소한다. 즉 트랜잭션의 목적은 한꺼번에 수행되어야 할 작업 중 일부만 수행ㅡ반영되어 발생하는 오류를 방지하여 작업의 완전성과 안정성을 보장하는 데 있다.

(1) 트랜잭션의 4가지 특징(ACID)

  • 원자성(Atomicity): 트랜잭션이 DB에 모두 반영되거나 아예 반영되지 않아야 한다.
  • 일관성(Consistenty): 작업 처리 결과가 일관적이어야 한다. 트랜잭션이 진행되는 동안 데이터베이스가 변경되더라도 업데이트된 데이터베이스로 트랜잭션이 진행되는 게 아니라, 처음 트랜잭션을 진행하기 위해 참조한 데이터베이스로 진행된다.
  • 독립성(Isolation): 둘 이상의 트랜지션이 동시에 실행되고 있을 경우, 어떤 트랜잭션이라도 다른 트랜잭션 연산에 끼어들 수 없다.
  • 영구성(Durability): 트랜잭션이 성공적으로 완료됐을 경우에 결과는 영구적으로 반영되어야 한다.

(2) 트랜잭션의 상태

그림 18. 트랜잭션의 상태

그림 18. [트랜잭션의 상태]
  • 트랜잭션 성공 : commit 연산이 성공해 트랜잭션 내에 발생한 변화가 데이터베이스에 반영된다.
  • 트랜잭션 실패 : 트랜잭션 실행 중 오류가 발생 → 트랜잭션을 종료하고, rollback 연산으로 트랜잭션 작업을 취소한다. 결과가 데이터베이스에 반영되지 않는다.

B. 윈도우 NTFS 트랜잭션(TxF, Transactional NTFS)

Windows 파일 시스템인 NTFS(New Technology File System)은 트랜잭션 개념을 파일 작업에 적용할 수 있다. 이를 TxF라고 하며, 해당 시스템은 파일 생성, 수정 같은 작업을 트랜잭션 단위로 묶어서 처리한다.

(1) NTFS의 장점

  • 대용량 파일 지원
  • 압축 및 암호화 지원
  • 트랜잭션 로깅을 통한 오류 복구 가능

앞서 살펴본 내용을 통해 윈도우가 데이터의 안정성을 위해 NTFS 트랜잭션 기능을 시스템에 차용했음을 알게 되었다. 그러나 Process Doppelgänging에서는 이러한 트랜직션 기능을 악용해 악성 실행 파일을 임시로 덮어쓰고, 데이터베이스 반영 여부를 결정하는 커밋 연산을 하지 않은 상태에서 실행 섹션을 생성함으로써 보안 솔루션을 회피한다. 이 공격의 흐름 및 단계는 다음과 같다.

C. 단계별 동작 흐름

(1) Transact – 트랜잭션 내부에서 정상 파일 변조

그림 19. 트랜잭션 단계에서 정상 파일을 페이로드로 덮어 씀

그림 19. [트랜잭션 단계에서 정상 파일을 페이로드로 덮어 씀]
  • CreateTransaction으로 트랜잭션 핸들을 얻는다.
    → 이 시점부터 해당 핸들로 열리는 파일 조작은 트랜잭션 컨텍스트 내부에서만 유효하다는 특징이 있다.
  • CreateFileTransacted API를 사용해서 svchost.exe 같은 정상 파일을 연 뒤, WriteFile 혹은 NtMapViewOfSection + RtlCopyMemory 등을 이용해서 정상 실행 파일 내용을 악성 페이로드 EXE 이미지로 교체한다.
  • 아직 commit 연산을 하지 않았으므로 이 내용은 디스크에 반영되지 않는다.

(2) Load - 섹션 객체 생성

그림 20. SEC_IMAGE 섹션을 만들어 메모리에 페이로드 매핑

그림 20. [SEC_IMAGE 섹션을 만들어 메모리에 페이로드 매핑]
  • NtCreateSection(&hSection, SEC_IMAGE, hTransactedFile)를 호출한다.
  • SEC_IMAGE 플래그는 PE 파일을 실행 가능한 이미지 섹션으로 매핑한다.
  • 생성된 섹션은 트랜잭션 내부에서 덮어쓴 악성 PE 내용을 기반으로 하며, 해당 색션 객체는 커널 오브젝트이기 때문에 핸들이 닫히지 않는 한 메모리에 그대로 남게 된다.
    → 따라서 이 시점에 이미 악성 코드가 메모리에 올라와 실행 가능한 형태가 된다.

(3) Rollback - 트랜잭션 취소

그림 21. 트랜잭션 취소로 디스크는 정상 복구, 메모리는 페이로드 유지

그림 21. [트랜잭션 취소로 디스크는 정상 복구, 메모리는 페이로드 유지]
  • RollbackTransaction(hTransaction)으로 트랜잭션을 취소해 트랜잭션 컨텍스트 내에서 발생한 모든 변경 사항을 취소한다. 디스크 파일은 원래 상태인 정상 실행 파일로 복원된다. 하지만 이미 생성된 섹션 객체는 커널 오브젝트 특성상 트랜잭션과 무관하게 살아있게 된다.
  • 즉 디스크에는 정상 파일, 메모리에는 악성 섹션이라는 모순적 상태가 존재하게 된다.
    → 여기서 Doppelgänging 도플갱잉의 “은닉성”이 완성된다. 디스크의 파일은 정상이므로 보안 솔루션의 검사에 잡히지 않지만, 해당 파일의 메모리 영역에 만들어진 섹션은 악성 코드로 채워져 있다.

(4) Animate - 악성 코드 실행

그림 22. NtCreateProcessEx + NtCreateThreadEx로 실제 악성 코드 실행 시작

그림 22. [NtCreateProcessEx + NtCreateThreadEx로 실제 악성 코드 실행 시작]
  • NtCreateProcessEx API를 호출해서 방금 만든 악성 섹션을 기반으로 새로운 프로세스를 생성한다. 이 프로세스는 겉보기에는 정상 EXE인 svchost.exe처럼 보이지만, 내부적으로는 악성 페이로드가 로드되어 있다.
  • NtQueryInformationProcess로 원격 프로세스의 PEB 주소를 얻고, ImageBaseAddress를 확인해서 로컬에서 페이로드 PE 헤더를 파싱한 뒤, AddressOfEntryPoint를 추출해 EntryPoint = ImageBaseAddress + RVA로 최종 진입점을 계산한다.
  • RtlCreateProcessParametersEx로 커맨드라인, 환경 블록 등을 만든 뒤
  • VirtualAllocEx + WriteProcessMemory로 원격 프로세스에 복사해서 원격 PEB의 ProcessParameters 포인터를 갱신한다.
    → 이로써 새 프로세스를 정상 프로세스로 위장한다.
  • NtCreateThreadEx를 호출하고, 시작 주소를 방금 계산한 EntryPoint로 설정한 뒤 스레드를 생성하면 새 스레드가 시작되고, 악성 페이로드 코드가 실행된다.

D. 주요 특징

  1. 디스크 흔적이 없다.
    앞서 설명했듯 롤백된 트랜잭션 컨텍스트 내 조작은 디스크 파일에 반영되지 않기 때문에, 디스크의 정상 파일은 조작되지 않은 상태를 유지한다. 따라서 디스크 파일을 검사하더라도 보안 솔루션에 감지되지 않는다.
  2. 탐지 우회
    Hollowing에서 의심되는 API인 NtUnmapViewOfSection, SetThreadContext를 쓰지 않고 섹션 기반 프로세스 생성과 PEB 수정 방법을 사용해서 자주 후킹되는 API 경로를 피할 수 있다.

나. 실습 구현

https://github.com/hasherezade/process_doppelganging
[Process Doppelgänging POC 코드 주소]

Hasherezade가 공개한 오픈소스 프로젝트 중 프로세스 도플갱잉 기법 동작을 구현한 예제를 분석하도록 하겠다. 코드를 통해 4단계 동작이 실제로 어떻게 API 수준에서 구현되는지 확인할 수 있다.

PoC는 단일 파일이 아닌 여러 모듈로 나눠져 있으며, 각 파일 역할은 다음과 같다.

  • main.cpp : 전체 Doppelgänging 흐름 제어
  • process_env : 원격 PEB와 프로세스 파라미터 설정
  • pe_hdrs_helper : 페이로드 PE 헤더 분석에서 특히 EntryPoint 추출 역할
  • ntdll_undoc : 문서화되지 않은 Native API를 동적으로 로드

▶ POC 코드 분석 ㅡ main.cpp

그림 23. 트랜잭션 시작

그림 23. [트랜잭션 시작]
  • make_transacted_section(BYTE* payloadBuf, DWORD payloadSize)
    : 디스크에 흔적을 남기지 않고 메모리에 실행 가능한 섹션을 만드는 단계로, Doppelgänging에서 Transact → Load → Rollback 과정을 담당한다.
  • CreateTransaction() : 트랜잭션 핸들 생성

그림 24. 임시 파일을 트랜잭션 컨텍스트에서 생성/쓰기

그림 24. [임시 파일을 트랜잭션 컨텍스트에서 생성/쓰기]
  • CreateFileTransactedW() : 임시 파일을 트랜잭션 컨텍스트로 열기
  • WriteFile() : payload.exe 내용을 트랜잭션 파일에 덮어쓰기
    → 트랜잭션 내부에서만 보이는 임시 파일에 악성 PE 바이트를 기록한다.

그림 25. 트랜잭션 파일로부터 이미지 섹션 생성

그림 25. [트랜잭션 파일로부터 이미지 섹션 생성]
  • SEC_IMAGE로 실행용 이미지 섹션을 생성한다.
    → 메모리 로더가 이해하는 PE 이미지를 준비할 수 있다.

그림 26. 롤백으로 디스크 흔적 제거

그림 26. [롤백으로 디스크 흔적 제거]
  • RollbackTransaction() : 트랜잭션 취소해서 디스크를 원상복구 시킨다.
  • 하지만 이미 생성된 섹션(hSection)은 메모리에 그대로 유지된다.
    → 여기서 만든 섹션은 “디스크에는 없는 악성 이미지”로, Doppelgänging의 은닉성을 담당한다.

그림 27. Doppelgänging의 Animate 단계 구현

그림 27. [Doppelgänging의 Animate 단계 구현]
  • 위에서 만든 섹션을 이용해서 새로운 프로세스를 만들고 실행시킨다.
  • make_transacted_section()을 호출해서 악성 섹션 객체를 확보한다.

그림 28. 섹션을 주 이미지로 새 프로세스 생성

그림 28. [섹션을 주 이미지로 새 프로세스 생성]
  • NtCreateProcessEx()로 섹션 기반 프로세스를 생성한다.
  • ParentProcess = NtCurrentProcess() (자기 자신 상속)
  • Flags = PS_INHERIT_HANDLES (핸들 상속)
  • SectionHandle = hSection (악성 섹션)
    → 파일 경로 없이 메모리 섹션만으로 프로세스 오브젝트를 생성한다.

그림 29. 원격 PEB 조회 → ImageBase 확보

그림 29. [원격 PEB 조회 → ImageBase 확보]
  • NtQueryInformationProcess()로 원격 프로세스의 PEB 주소를 획득할 수 있다.
  • buffer_remote_peb() : 원격 PEB를 읽어서 ImageBaseAddress를 확보한다.
    → 새 프로세스의 PEB, ImageBaseAddress를 읽어서 로더가 매핑한 베이스 주소를 얻는다.

그림 30. 실제 진입점 주소 계산

그림 30. [실제 진입점 주소 계산]
  • get_entry_point_rva(payloadBuf) : 로컬 payload의 OEP를 계산한다.
  • EntryPoint = ImageBase + RVA

그림 31. 프로세스 파라미터 세팅

그림 31. [프로세스 파라미터 세팅]
  • setup_process_parameters()
  • 실행 경로, 커맨드라인, 환경 블록 등을 원격 프로세스에 복사한다.
  • PEB의 ProcessParameters 필드를 새로 갱신하게 된다.

그림 32. 원격 스레드 생성 후 EP에서 실행 시작

그림 32. [원격 스레드 생성 후 EP에서 실행 시작]
  • NtCreateThreadEx() : 새 프로세스의 EntryPoint에서 실행을 개시한다.

그림 33. 프로그램 실행 시 진입점

그림 33. [프로그램 실행 시 진입점]

그림 34. 사용자 입력 처리 후 전체 실행 제어

그림 34. [사용자 입력 처리 후 전체 실행 제어]
  • 기본 타깃은 calc.exe로 get_calc_path를 호출한다.
  • init_ntdll_func()으로 undocumented API (NtCreateProcessEx,NtCreateThreadEx 등)를 초기화한다.
  • buffer_payload()로 payload 파일을 메모리에 로드하고
  • process_doppel()로 Doppelgänging 공격을 실행한다.
    → make_transacted_section : 트랜잭션 기반으로 payload 섹션 만들고 디스크 흔적을 제거한다. (Transact + Load + Rollback)
    → process_doppel : 섹션을 기반으로 프로세스를 생성하고 주소 계산하고 PEB/파라미터 세팅 후 스레드를 실행한다. (Animate)
    → wmain : 사용자 입력을 처리하고 전체 실행을 제어한다.

이로써 main.cpp에 앞서 살펴본 4단계가 모두 구현돼 있음을 확인할 수 있다.

▶ POC 코드 분석 ㅡ ntdll_undoc.h

그림 35. ntdll_undoc.h 전체 코드

그림 35. [ntdll_undoc.h 전체 코드]
  • Windows Native API 중 공식 Win32 API에 노출되지 않은 함수들의 프로토타입 선언을 담고 있다.

▶ PoC 코드 분석 – ntdll_undoc.cpp

그림 36. 전역 함수 포인터 초기화

그림 36. [전역 함수 포인터 초기화]
  • 앞서 본 ntdll_undoc.h에서는 함수 원형만 선언되어 있었지만 .cpp에서는 실제로 함수 포인터들을 초기화하고 있다.

그림 37. init_ntdll_func() 함수 코드

그림 37. [init_ntdll_func() 함수 코드]
  • LoadLibraryA(“ntdll.dll”) : ntdll.dll을 현재 프로세스 주소 공간에 로드한다.
  • GetProcAddress로 NtCreateProcessEx, RtlCreateProcessParametersEx, NtCreateThreadEx 함수 주소를 얻는다.
    → 얻어온 주소를 적절한 함수 시그니처로 캐스팅해 전역 포인터에 저장하면 main.cpp에서 정식 API처럼 호출이 가능해진다.

▶ PoC 코드 분석 – process_env.h

그림 38. main.cpp의 process_doppel() 안에서 호출되는 보조 함수들의 원형이 정의되어 있는 헤더

그림 38. [main.cpp의 process_doppel() 안에서 호출되는 보조 함수들의 원형이 정의되어 있는 헤더]
  • Doppelgänging의 마지막 단계인 Animate에서 새로 생성된 프로세스가 정상 프로세스처럼 보이도록 환경 세팅하는 기능을 지원해주는 헤더이다.

▶ PoC 코드 분석 – process_env.cpp

그림 39. set_params_in_peb 함수

그림 39. [set_params_in_peb 함수]
  • 원격 프로세스의 PEB 구조체 안에 있는 ProcessParameters 필드를 업데이트해주는 함수다.

그림 40. buffer_remote_peb 함수

그림 40. [buffer_remote_peb 함수]
  • 원격 프로세스의 PEB 내용을 읽어서 로컬에 복사해주는 함수로, 이후 ImageBaseAddress를 얻어 EntryPoint 계산에 활용된다.

그림 41. write_params_into_process 함수 시작 부분

그림 41. [write_params_into_process 함수 시작 부분]
  • 로컬에서 만든 RTL_USER_PROCESS_PARAMETERS 블록과 환경 변수 블록을 원격 프로세스 주소 공간에 복사하는 함수이다. 이를 통해 원격 프로세스도 정상 프로그램처럼 환경 변수와 실행 파라미터를 가질 수 있게 된다.

그림 42. setup_process_parameters 함수 시작 부분

그림 42. [setup_process_parameters 함수 시작 부분]
  • Doppelgänging에서 새 프로세스에 정상적인 실행 파라미터를 부여하는 메인 함수 역할을 한다.

▶ PoC 코드 분석 – pe_hdrs_helper.h

그림 43. PE 헤더/섹션 헬퍼

그림 43. [PE 헤더/섹션 헬퍼]
  • Doppelgänging에서 쓰이는 payload.exe 파일은 결국 PE 포맷(윈도우 실행 파일 포맷)이다.
  • 이 모듈이 payload의 PE 헤더에서 아키텍처 및 EntryPoint를 파악하는 유틸리티 역할을 하게 된다.

▶ PoC 코드 분석 – pe_hdrs_helper.cpp

그림 44. get_nt_hrds 함수

그림 44. [get_nt_hrds 함수]
  • 주어진 버퍼가 유효한 PE 파일인지 확인하고 IMAGE_NT_HEADERS 구조체 위치를 반환하는 함수다.
  • 잘못된 파일을 분석하거나 오프셋이 조작된 공격용 파일을 걸러내기 위한 안정성 체크용으로 기본 전처리 단계에서 사용된다.

그림 45. get_pe_architecture 함수

그림 45. [get_pe_architecture 함수]
  • PE 파일의 아키텍처를 확인할 수 있다.
  • payload.exe와 현재 PoC 실행 환경이 호환되는지 확인하는데 사용된다.

그림 46. get_entry_point_rva 함수

그림 46. [get_entry_point_rva 함수]
  • PE 파일의 실행 시작 지점 RVA(AddressOfEntryPPoint)를 추출하기 위해 사용한다.
  • get_pe_architecture로 아키텍처를 확인한 후 NT 헤더 위치를 얻고 해당 값을 반환하게 된다.
  • RVA를 메모리 상의 ImageBase에 더해 실제 실행 주소 = OEP를 얻을 수 있다.

그림 47. TxF 실습 코드 예제

그림 47. [TxF 실습 코드 예제]

▶ TxF 실습 코드 분석 – 트랜잭션을 만들고 트랜잭션 내 파일을 쓰고 롤백/커밋하는 간단한 코드 예제이다.

  • CreateTansaction() : 트랜잭션 생성
  • CreateFileTransactedW(~) : 트랜잭션 컨텍스트로 파일 생성/쓰기
  • WriteFile() : 내용 기록
  • CommitTransaction() / RollbackTransaction() : 커밋/롤백

**[실습 진행]**

이제 위의 코드들을 활용해 실습을 진행하겠다. 이번 실습은 두 가지를 목표로 한다;
(1) 도플갱잉 기법이 디스크에 흔적을 남기지 않고도 PE 이미지를 실행 가능한 상태로 만드는 원리인 Transactional NTFS(TxF) 동작을 직접 확인
(2) 파일 액세스 시점의 행위인 로그를 모니터링해서 도플갱잉에 사용되는 패턴을 이해

그림 48. TxF 라이브러리 속성 설정

그림 48. [TxF 라이브러리 속성 설정]

TxF API가 ktmw32.lib에 정의되어 있는 관계로, 비쥬얼 스튜디오를 통해 프로젝트에 해당 라이브러리를 링크해 준다.

그림 49. TxF 실습 코드 예제 정상 실행 결과창

그림 49. [TxF 실습 코드 예제 정상 실행 결과창]

디버거를 실행해서 다음과 같은 결과가 나오면 정상적으로 실행이 된 것이다.

그림 50. exe 파일 실행 후 롤백되어 디스크에 파일이 존재하지 않는 모습

그림 50. [exe 파일 실행 후 롤백되어 디스크에 파일이 존재하지 않는 모습]

빌드된 exe 파일이 위치한 곳에서 cmd를 열어 xf.exe를 실행한 뒤 C\temp 폴더를 열어 디스크에는 파일이 존재하지 않는 것을 확인했다. 트랜잭션 콘텍스트 안에서 파일을 썼다가 RollbackTransaction으로 롤백을 했기 때문에, 디스크에 트랜잭션이 반영되지 않아 파일이 생성되지 않았다는 의미이다.

그림 51. exe commit 명령어를 사용 후 디스크에 파일이 존재하는 모습

그림 51. [exe commit 명령어를 사용 후 디스크에 파일이 존재하는 모습]

txf.exe commit 명령어를 입력한 후 다시 temp 폴더를 확인해보면 txf_demo.txt 파일이 생성되어 있다. 트랜잭션 이후 commit 연산을 통해 트랜잭션 내용이 디스크에 영구 반영된 것이다. 콘솔에 ???로 문자가 깨진 이유는 멀티바이트 문자열인 char를 사용해서인데, 이 맥락에서 크게 문제가 되진 않으니 무시해도 좋다.

TxF 동작이 실제로 잘 이뤄지는지 검증을 하기 위해 Procmon 모니터링 실습을 추가로 진행했다. 앞서 진행한 트랜잭션 롤백/커밋 각각의 경우에 윈도우의 로그 및 파일 폴더에 남겨진 아티팩트를 비교 분석할 것이다.

https://learn.microsoft.com/en-us/sysinternals/downloads/procmon
[procom 공식 다운로드 링크]

Procmon(Process Monitor) - Sysinternals 툴 공식 다운로드 링크를 통해 프로그램을 다운로드한다. TxF 관련 파일 로그를 잡기 위해 프로그램을 관리자 권한으로 실행할 필요가 있다.

그림 52. Process Monitor 시작 화면

그림 52. [Process Monitor 시작 화면]

먼저 트랜잭션 롤백의 경우다. Ctrl + E를 눌러서 캡처를 우선 중지한 후 Filter – Filter…(Ctrl + L)에 들어가준다.

그림 53. TxF 로그만 확인하기 위한 설정

그림 53. [TxF 로그만 확인하기 위한 설정]

왼쪽부터 Process Name – is – txf.exe – Include로 맞춰준 후 Add – OK를 눌러주면 txf.exe 관련 이벤트만 캡처할 수 있게 된다.

그림 54. txf.exe 로그 캡처 화면

그림 54. [txf.exe 로그 캡처 화면]

설정 후 다시 Ctrl + E를 눌러서 캡처를 시작한다. 이후 cmd에서 txf.exe를 실행하면 로그 캡처 목록들이 확인된다.

그림 55. Operation – CreateFile – WriteFile – CloseFile 트랜잭션 로그 순서 확인

그림 55. [Operation – CreateFile – WriteFile – CloseFile 트랜잭션 로그 순서 확인]

Operation 열에서 CreateFile, SUCCESS 옆에 C\temp\txt_demo.txt 경로를 확인해보면 순서대로 다음과 같다.

  • CreateFile : 트랜잭션 안에서 파일 생성
  • WriteFile : 트랜잭션 안에서 데이터 쓰기
  • CloseFile : 핸들 닫음 (트랜잭션 롤백 이후 디스크 반영 X)

그림 56. 로그 상에서는 트랜잭션이 실행됐지만 디스크에는 파일이 없는 모습

그림 56. [로그 상에서는 트랜잭션이 실행됐지만 디스크에는 파일이 없는 모습]

로그 상에서는 파일을 생성하고 쓰기까지 했지만 실제 탐색기를 보면 파일이 생기지 않았다는 걸 확인할 수 있다.

이번에는 트랜잭션 commit의 경우를 살펴보겠다. 먼저 ctrl+X로 로그를 전부 삭제한 뒤, ctrl+E로 다시 캡처를 시작한다. 이후 cmd에서 트랜잭션 commit을 실행하고, 로그와 파일 폴더를 동시에 확인하면, 이번에는 파일이 생성되었음을 확인할 수 있다. Procom Detail 부분을 보면 Desired Access: Generic Write 이후에 파일 속성이 확정 되었는데, 이는 트랜잭션이 실제 NTFS에 반영된 순간을 의미한다.

그림 57. commit 명령어 실행 로그 결과

그림 57. [commit 명령어 실행 로그 결과]

다. 탐지 및 분석

정리하자면 프로세스 도플갱잉은 트랜잭션 작동원리를 악용하여 디스크에 파일을 남기지 않고 악성 프로세스를 실행하는 기술이다.

(1) 도플갱잉이 실제로 이뤄지는 단계

  1. TxF를 이용해 임시 트랜잭션 파일 생성 → TxF
  2. 그 안에 악성 PE(실행 파일)를 씀 → WriteFIle
  3. NTCreateSection으로 이 트랜잭션 파일을 메모리 섹션으로 매핑 → Memory Section Object
  4. 트랜잭션 롤백해서 파일을 디스크에서 삭제 → RollbackTransaction()
  5. 이미 만들어둔 섹션으로 프로세스 생성(NTCreateProcessEx)
    → 실행은 남고 파일은 없음
    → 결과적으로 디스크에는 파일이 없지만 프로세스는 실행 중인 상태가 된다.
(2) 실습 분석
위에서 진행한 실습이 1~2단계에 해당한다.
  1. 트랜잭션 생성 → CreateTransaction()
  2. 트랜잭션 내 파일 생성 → CreateFileTransacted() + WriteFile()
  3. 롤백하면 파일 사라짐 → RollbackTransaction()
    → 즉 도플갱잉 공격자가 실제로 쓰는 TxF 동작을 악성 파일 없이 안전하게 재현 한 실습으로 볼 수 있다.

(3) 보안적 관점
프로세스 도플갱잉은 디스크에 흔적을 남기지 않음으로써 안티 바이러스/EDR의 디스크 PE 스캔을 우회한다. 때문에 방어 전략은 디스크 중심에서 행위 중심으로 전환되어야 한다.
프로세스, 이미지 로드, 파일 이벤트 등을 수집해 파일 생성 → 섹션(이미지) 생성 → 파일 삭제(트랜잭션 롤백) → 프로세스 생성/이미지 로드 순으로, 일련의 이벤트들을 상관관계로 탐지해서 행동 기반 가시성을 강화해야 할 필요가 있다.
또한 불필요한 관리자 권한 실행을 제한해서 악용의 기회를 줄여야 한다. 많은 섹션/매핑/트랜잭션 관련 API는 높은 권한에서 수행되기 때문에 권한 축소를 고려하고, 사용자 temp 폴더에서의 실행을 금지하거나 임시 폴더에서 실행 파일 생성 시에 자동으로 추가 검사를 하도록 유도하는 방법도 도움이 될 수 있다.

5. Process Ghosting

가. 동작 원리

프로세스 고스팅은 디스크에 이미 존재하지 않는/삭제된 실행 이미지를 메모리에 정상 실행 이미지처럼 맵핑해서 새 프로세스를 띄우는 기법이다. 차례로 프로세스 고스팅을 이해하는 데 필수적인 개념들을 설명한 뒤 공격 순서를 살펴보겠다.

A. 프로세스의 실행 단계

그림 58. 프로세스 실행 과정

그림 58. [프로세스 실행 과정]
  1. 실행하고 싶은 실행 파일(.exe)의 핸들 열기
  2. 실행 파일에 대한 이미지 섹션 열기
  3. 이미지 섹션을 활용해 프로세스 생성하기
  4. 프로세스에 대한 인수, 환경변수 할당
  5. 프로세스에서 실행할 첫 번째 스레드 생성

→ PE 파일의 이미지 섹션은 실행을 위해 메모리에 매핑되는 특별한 영역이다. 윈도우는 이미지 섹션을 메모리에 올리는 과정에서 내부적으로 캐시한다. 이러한 캐싱 작업 때문에, 최종적으로 메모리에 매핑된 이미지(프로세스)는 디스크에 있는 원본 실행 파일의 내용과 달라질 수 있다. 이 차이점은 추후 메모리 변조 기법에서 중요한 역할을 한다.

B. 윈도우의 실행 파일 수정 방지

윈도우는 이미 이미지 섹션으로 매핑된 실행 파일이 수정되는 것을 방지한다.

  • 메모리에 매핑된 이미지 섹션을 FILE_WRIE_DATA로 수정 시도할 경우 ERROR_SHARING_VIOLATION 발생.
  • 메모리에 매핑된 이미지 섹션 삭제 시도할 경우 STATUS_CANNOT_DELETE 또는 ACCESS_DENIED 오류 발생.

이러한 수정 방지 장치들은 파일의 이미지 섹션이 메모리에 매핑된 이후부터 적용된다. 만일 공격자가 삭제 대기(delete-pending) 상태의 파일을 생성한 뒤, 이 파일의 이미지 섹션을 메모리에 매핑하고, 파일 핸들을 닫아 삭제를 완료한다면 (‘삭제 대기’ 상태의 파일은 핸들이 닫힐 경우 자동으로 삭제된다),이 파일은 디스크 상에서는 삭제되지만, 메모리에는 해당 파일의 이미지 섹션이 남게 된다. 이때 메모리에 잔재하는 이미지 섹션을 이용해 악성 프로세스를 써넣는 식의 원래는 금지된 ‘매핑된 파일 수정’을 할 수 있다.

C. 안티 바이러스 콜백 우회

그림 59. 실제 프로세스가 생성되고 실행되는 예시

그림 59. [실제 프로세스가 생성되고 실행되는 예시]

여기서 잠깐 실제의 프로세스가 어떻게 생성되고 실행되는지 확인 해보자. 프로세스 모니터를 통해 Explorer.exe를 통해 notepad.exe가 실행되고 있음을 확인할 수 있다. 여기서 Explorer.exe는 윈도우 OS에게 특정 exe 파일을 통해 프로세스를 실행해 달라고 요청해주는 파일이다.
앞서 잠시 언급했듯, 실행 파일은 디스크에서 메모리로 매핑되는 과정에서 내용이 수정될 수 있다. 파일의 이미지 섹션이 메모리에 로드되는 시점에 캐시되는데, 이 캐싱 과정에서 내용이 미묘하게 수정될 수 있기 때문이다. 결과적으로 디스크에 있는 실행 파일의 내용과 메모리에 매핑된 파일 이미지의 내용은 다를 수 있다.
프로세스 실행 과정에서 언급되었듯, 프로세스의 실행에 이용되는 것은 디스크의 실행 파일이 아닌 메모리의 파일 이미지이다.
문제는 안티 바이러스 콜백이 호출되는 것이 주로 ‘프로세스의 실행 단계’ 중 5단계에 속하는 스레드의 생성 시점이라는 것이다. 앞서 제시한 공격 시나리오에 따르면, 만일 파일을 삭제 대기 상태로 생성한 뒤 메모리에 매핑하고, 핸들을 닫아 파일을 삭제시킨다면, 메모리에 남은 파일 이미지로 스레드를 생성했을 무렵, 안티 바이러스 콜백이 검사해야 할 디스크의 원본 파일은 이미 ‘삭제’된 상태이다. 안티 바이러스 콜백이 ‘삭제’된 상태의 파일을 살펴보려 할 경우 윈도우의 ‘실행 중인 파일 수정 방지’ 정책에 의해 STATUS_FILE_DELETE 에러가 발생한다.

D. 프로세스 도플갱잉과의 비교

두 공격 모두 디스크 상에는 존재하지 않는 실행 파일을 메모리에서 실행시킨다는 목표를 가지고 있다. 단, 도플갱잉의 경우 트랜직션 롤백 기능을 이용해 트랜잭션 컨텍스트에서 발생한 파일 수정을 모두 없던 일로 만든다면, 고스팅은 처음부터 삭제 대기 상태의 섹션을 생성하는 점에서 차이가 발생한다.

E. 공격 흐름

그림 60. 프로세스 고스팅 실행 단계

그림 60. [프로세스 고스팅 실행 단계]

그림 61. 프로세스 고스팅의 공격 흐름

그림 61. [프로세스 고스팅의 공격 흐름]

프로세스 고스팅의 공격 흐름을 요약하면 다음과 같다.

  1. 파일 생성
  2. NtSetInformationFile(FileDispositionInformation)을 이용해 파일을 삭제-대기(delete-pending) 상태로 생성
  3. 페이로드(실행 파일) 내용을 파일에 작성
    → 작성파일은 이미 delete-pending 상태이기 때문에 내용이 영구적으로 보존되지 않는다. delete-pending 상태로 인해 외부 파일 오픈 시도도 차단된다.
  4. 그 파일에 대한 이미지 섹션을 생성
  5. delete-pending 핸들을 닫아 파일을 삭제
  6. 이제 파일이 없이 존재하는 섹션으로 프로세스 실행
  7. 프로세스에 인자와 환경 변수 할당
  8. 해당 프로세스에서 실행할 스레드 생성

나. 실습 구현

파일이 삭제 대기(delete-pending) 상태가 되면 어떤 로그가 남는지, NTSTATUS 코드는 무엇이 발생하는지 확인하고자 한다.

▶ ghost_demo.c 실습 코드 분석 : 파일 삭제 대기 상태의 로그를 확인하기 위한 코드이다.

  • CreateFileW() : 파일을 쓰기 + 삭제 권한으로 열기
  • FILE_FLAG_DELETE_ON_CLOSE
    → 핸들을 닫는 순간 자동 삭제 = delete-on-close가 설정된다.
  • SetFileInformationByHandle()
    → FileDispositionInfo를 TRUE로 지정하면 삭제 대기 상태가 된다. 이 상태에서는 파일 핸들은 여전히 열려 있지만, 다른 프로세스나 동일 프로세스 내에서 파일을 열고자 시도하면 STATUS_DELETE_PENDING 에러로 실패하게 된다. 고스팅에서는 이 시점에서 NtCreateSection을 호출해 삭제 대기 상태의 파일로부터 섹션을 생성한다.
  • CreateFileW()
    → 두 번째 호출에서는 방금 삭제 예약된 파일을 다시 열어보려고 한다. 정상적이라면 실패하고 GetLastError() 에러가 표시된다.
  • CloseHandle(hFile)
    → FILE_FLAG_DELETE_ON_CLOSE 플래그를 설정해 놓았으므로, 파일 핸들을 닫을 시 윈도우는 이 시점에서 파일을 제거한다.

정리하자면 다음과 같다.

  1. CreateFile() → 파일 생성
  2. SetFileInformationByHandle() → 삭제 예약
  3. NtCreateSection() → 섹션 생성
  4. CloseHandle() → 파일 삭제
  5. NtCreateProcessEx() → 프로세스 실행

그림 62. 프로세스 고스팅 Procmon 모니터링 실습 예제 코드

그림 62. [프로세스 고스팅 Procmon 모니터링 실습 예제 코드]

그림 63. 비주얼 스튜디오에서 빌드 후 실행한 모습

그림 63. [비주얼 스튜디오에서 빌드 후 실행한 모습]

비주얼 스튜디오에서 데모 코드를 빌드한 후 실행하면 다음과 같은 로그가 나온다. 정상적으로 실행되는 것을 확인했으니 다음 단계로 넘어가겠다.

그림 64. ghost_demo.exe 로그 필터링

그림 64. [ghost_demo.exe 로그 필터링]

도플갱잉 실습과 마찬가지로 Process Name – is – ghost_demo.exe – Include로 맞춰준 후 Add – OK를 눌러주면프로세스 고스팅 관련 이벤트만 캡처할 수 있게 된다.

그림 65. exe 파일 실행 후 콘솔 화면

그림 65. [exe 파일 실행 후 콘솔 화면]

필터링 후 exe 파일을 실행했을 때의 콘솔 로그 화면이다.
CreatFile() + WriteFile()이 성공했으며, delete-pending로 마크된 파일을 다시 열려고 했으나 Error 5 = Access Denied 에러가 반환된 것을 통해, NTSTATUS를 STATUS_DELETE_PENDING으로 설정되었음을 추정한다. 이후 핸들을 닫자마자 파일이 완전 삭제됨을 출력해주고 있다.

그림 66. Procmon 로그

그림 66. [Procmon 로그]

Procmon 로그를 살펴보자.

  1. CreateFile → SUCCESS 파일이 정상 생성되었다.
  2. WriteFile → Hello Ghosting world가 기록되었다.
  3. SetDispositionInformationFile → 파일이 삭제 예약 상태로 전환되었다.
  4. CreateFile DELETE PENDING → 이미 delete-pending 상태라 재열기에 실패했다.
  5. CloseFile → 핸들을 닫으면서 파일이 실제로 삭제되었다.
  • 파란색 줄 내용: SetDispositionInformationFile = SetFileInformationByHandle() API 호출 성공, OS가 파일을 삭제 예정 상태인 delete = true로 표시했다.
  • 바로 아래 줄 내용 : CreateFile → DELETE PENDING. 다른 프로세스나 동일 프로세스에서 해당 파일을 다시 열려고 했지만 이미 삭제 예약된 상태라 실패했다.
  • CLoseFile 줄 내용 : 핸들이 닫혀혔으므로 파일이 완전 제거 되었다.

다. 탐지 및 분석

프로세스 고스팅은 디스크에서 파일이 사라지기 때문에 일반적인 파일 기반 탐지로는 잡을 수 없으며, 프로세스 생성 과정과 메모리 동작에 초점을 맞춰야 한다.

(1) 실습 결과 요약

해당 실습에서는 윈도우 파일 시스템의 내부 메커니즘을 이용한 Process Ghosting의 핵심 동작을 관찰했다. 데모 코드를 실행한 결과 다음과 같은 내용이 확인됐다.

  1. CreateFile()을 통해 ghost_demo.txt 파일 생성
  2. WriteFile()로 정상적으로 데이터 기록
  3. SetFileInformationByHandle(FileDispositionInfo) 호출로 파일이 delete-pending 상태로 전환
  4. 이후 동일 파일을 다시 열면 STATUS_DELETE_PENDING 오류 발생 = 재열기 불가
  5. 파일 핸들을 닫으면 디스크 상의 파일이 삭제되어 완전히 사라지게 된다.

Procmon 로그에서도 다음과 같은 시퀸스를 확인할 수 있었다.

그림 67. Procmon 로그 요약

그림 67. [Procmon 로그 요약]

이 결과는 파일이 실제로 디스크에서 삭제되었음에도 해당 파일의 메모리 섹션이 유지될 수 있음을 의미한다. 이 특성이 바로 공격자가 디스크에 흔적을 남기지 않고 실행 이미지를 유지하는 근거가 된다.

(2) 보안적 의미 분석

Process Ghosting은 Process Doppelganging과 유사하게, 디스크 상의 PE 파일 없이 프로세스를 실행시킬 수 있는 image tampering 계열의 기법이다. 도플갱잉과의 차이점은 TxF 대신 NTFS의 delete-pending 상태를 악용한다는 점이다.
파일이 이미 삭제된 상태에서 메모리에만 존재하기 때문에 디스크 포렌식으로는 악성 PE를 확보하기 어렵고, 프로세스 생성(섹션 매핑)과 스레드 생성 사이의 짧은 타이밍 동안 파일이 삭제되어 스캔 콜백이 실행되기 전에 파일이 사라질 수 있는 EDR 타이밍 문제도 발생할 수 있다.
이에 도플갱잉과 동일하게 행위 기반 탐지를 강화하는 방식으로 솔루션을 제안할 수 있다. 트랜잭션 API나 파일 삭제 예약 API를 커널 레벨에서 모니터링하고, 섹션 생성 및 프로세스 생성 이벤트와 시간을 상관 분석하며, 프로세스 생성 시점 뿐만 아니라 섹션 생성 시점에도 스캔을 트리거하도록 보안 제품 스캔 타이밍을 개선할 필요가 있다.

(3) 탐지 방법 정리

  1. NT API 사용 패턴 감지 → NtSetInformationFile(FileDispositionInformation) 호출로 파일을 삭제 보류 상태로 전환한 이후 바로 NtCreateSection → NtCreateProcessEx 호출이 이어지는 비정상적인 시퀀스를 모니터링해서 삭제 대기 상태의 파일을 이용해 프로세스를 생성하는 패턴이 존재하는지 확인한다.
  2. 프로세스 분석 → 실행 중인 프로세스 이미지 섹션이 가리키는 대상 파일이 이미 삭제된 상태인지를 확인하고 프로세스 이미지 경로가 일치하는지도 확인한다.
  3. 메모리 기반 분석 → 프로세스 메모리 덤프 및 검사를 통해 디스크에 존재하지 않는 이미지를 로드한 프로세스가 있는지 추적하고, 메모리 내 악성 페이로드 탐지, 매핑된 PE 헤더 검사, 보호 속성 등을 확인해 변조 및 악성코드 여부를 판단한다.

6. 기법 비교 및 종합 분석

가. 기술 및 실습 결과 비교

A. 기법별 상세 비교 분석

세 가지 기법(Process Hollowing, Doppelgänging, Ghosting)은 모두 정상적인 프로세스 생성 로직을 악용하여 디스크 기반 탐지를 회피한다는 공통점이 있으나, 메모리 로딩 방식과 디스크 상태 조작 방식에서 결정적인 차이를 보인다.

(1) Process Hollowing (프로세스 할로잉)

  • 핵심 메커니즘: Unmapping & Overwriting (메모리 비우기 및 덮어쓰기)
  • 악용 기능: 정상 프로세스의 Suspend(일시 정지) 상태
  • 메모리 로딩: 정상 파일을 로드한 뒤, 메모리 섹션을 해제(Unmap)하고 악성 코드 주입
  • 디스크 조작: 디스크 상태 직접 조작 없음 (메모리만 변조됨)
  • 탐지 회피: 정상 프로세스 이름과 권한을 유지하나, 메모리 스캔 시 탐지 가능성 높음
  • 주요 API: NtUnmapViewOfSection, NtWriteVirtualMemory, NtResumeThread

(2) Process Doppelgänging (프로세스 도플갱잉)

  • 핵심 메커니즘: TxF (Transactional NTFS, 트랜잭션 롤백 악용)
  • 악용 기능: NTFS 파일 시스템의 트랜잭션(TxF) 기능
  • 메모리 로딩: 트랜잭션 내에서 악성 코드를 작성 후 매핑하고 즉시 롤백
  • 디스크 조작: 트랜잭션 ‘롤백(Rollback)’을 이용해 디스크 기록을 원천 차단
  • 탐지 회피: 디스크와 메모리의 불일치 유발 (디스크엔 정상 파일만 남음)
  • 주요 API: CreateTransaction, RollbackTransaction, NtCreateProcessEx

(3) Process Ghosting (프로세스 고스팅)

  • 핵심 메커니즘: Delete Pending (삭제 대기 상태 악용)
  • 악용 기능: 파일의 삭제 대기(Delete Pending) 상태 플래그
  • 메모리 로딩: 삭제 대기 파일을 생성하여 핸들 확보 후 작성, 이미지 섹션 매핑
  • 디스크 조작: ‘삭제(Delete)’ 상태를 이용하여 파일 내용이 디스크에 남지 않게 처리
  • 탐지 회피: 디스크에 악성 파일 흔적 자체가 남지 않아 초기 생성 탐지 우회 용이
  • 주요 API: NtSetInformationFile (Delete-Pending 설정), NtCreateProcessEx

B. 실행 흐름 (Execution Flow) 요약

(1) Process Hollowing (프로세스 할로잉)
Create(Suspend) → Unmap → Write(Malicious) → Resume

(2) Process Doppelgänging (프로세스 도플갱잉)
Transact → Write → Map → Rollback → Execute

(3) Process Ghosting (프로세스 고스팅)
Create(Delete Pending) → Write → Map → Close(Delete) → Execute

세 기법 모두 ‘Process Injection’ 계통의 공격이며, 합법적인 프로세스로 위장하여 권한을 획득하고 보안 탐지를 교란하는 것이 주목적이다. Hollowing은 메모리 조작에 집중하는 반면, Doppelgänging과 Ghosting은 파일 시스템(NTFS)의 특성을 더 깊이 악용하여 디스크 흔적 자체를 지우는 진화된 형태를 보인다.

나. 보안 대응 관점에서의 평가

A. 탐지 전략

행위 기반 탐지 (Behavior-Based Detection)
행위 기반 탐지란 사전에 정의된 악성 코드가 아니라, 실행 중 발생하는 동적 행위(Dynamic Behavior)에 주목하여 위협을 판단하는 방식이다. 전통적인 시그니처(Signature) 기반 탐지는 파일의 해시나 특정 바이트 패턴을 검사하므로, 디스크에 흔적을 남기지 않거나 실행 중에만 존재하는 새로운 공격 방법 ㅡ 제로데이(Zero-day) 공격이나 파일리스(Fileless) 악성코드 등의 탐지에 효과적이다.

기술적 구성으로는 다음과 같은 요소가 있다.

  • 데이터 수집: OS 수준의 이벤트 후킹 (시스템 콜, 파일 I/O, 레지스트리 등)
  • 행위 모델링: 화이트리스트(정상 행위만 허용) 또는 머신러닝(비정상 패턴 학습) 기반 분석
  • 이상 탐지: 정책 위반 또는 통계적 이상 징후(Anomaly) 포착

B. 기법별 핵심 모니터링 포인트 (API 및 시퀀스)

: 단일 API 호출이 아닌, API 호출의 연속적인 시퀀스(Sequence)와 문맥(Context)을 분석 대상으로 삼는다.

(1) 공통 모니터링 대상

  • 권한이 낮은 프로세스가 시스템 프로세스의 핸들을 획득하는 행위
  • 원격 프로세스 메모리에 VirtualAllocEx, WriteProcessMemory 등을 수행하고 CreateRemoteThread를 호출하는 흐름

(2) Process Hollowing 탐지

  • Key Indicator: CreateProcess 시 CREATE_SUSPENDED 플래그 사용 빈도 분석
  • 자식 프로세스의 메모리 내용(EP, ImageBase)이 디스크의 원본 파일과 불일치하는지 검증

(3) Process Doppelgänging 탐지

  • Key Indicator: TxF 관련 API (CreateTransaction, RollbackTransaction) 모니터링.
  • 트랜잭션 내에서 실행 파일이 생성되자마자 실행 없이 롤백되거나 삭제되는 패턴 감시

(4) Process Ghosting 탐지

  • Key Indicator: NtSetInformationFile을 통해 삭제 대기(Delete-Pending) 플래그가 설정된 파일이 이미지 섹션으로 매핑되는지 감시
  • 프로세스는 실행 중이나, 해당 경로에 디스크 파일이 존재하지 않는 ‘Phantom’ 상태 탐지

C. 예방 및 대응 (Mitigation & Response)

(1) 예방(Prevention)

  • OS 패치 및 업데이트: 최신 보안 패치 적용 (OS 레벨에서 특정 우회 기법이 막히는 경우가 많다)
  • 공격 표면 축소: 불필요한 관리자 권한 축소 및 신뢰할 수 없는 매크로/스크립트 실행 차단

(2) 대응 및 복구 (Response)

  • EDR 솔루션 활용: 시스템 전체의 행위 로그를 분석하여 연관 관계 파악
  • 메모리 포렌식: 디스크에 파일이 없으므로, 메모리 덤프(Memory Dump)를 획득하여 인젝션된 악성 페이로드(PE) 추출 및 분석

결론

이번 칼럼에서는 프로세스 인젝션 계열의 대표적인 기법들을 비교 분석하며, 윈도우 운영체제 내부 구조(Internals)가 갖는 미세한 틈(Gap)들이 실제 공격에서 어떻게 치명적인 무기로 변모하는지 확인할 수 있었다.

프로세스 할로잉에서 시작해 도플갱잉, 고스팅으로 이어지는 공격 기술의 진화는 단순한 변형이 아니다. 이들은 각기 다른 API와 메커니즘을 사용하지만, 결국 “보안 솔루션이 ‘정상’이라고 신뢰하는 구간을 얼마나 자연스럽게 속일 수 있는가”라는 하나의 공통된 목적을 향해 고도화되고 있음을 알 수 있다. 특히 TxF나 삭제 대기 상태와 같은 합법적인 파일 시스템 기능을 악용하여 디스크 흔적을 지우는 방식은 기존의 시그니처 기반 탐지 체계를 무력화시키는 강력한 위협이다.

따라서 이러한 공격을 효과적으로 방어하기 위해서는 단순한 파일 해시 스캔이나 경로 기반의 정적 검증만으로는 더 이상 충분하지 않으며, 아래와 같은 다각도의 ‘행위 기반 탐지(Behavior-Based Detection)’ 체계가 필수적으로 수반되어야 한다.

  1. 프로세스 생성 과정 전반의 이벤트 시퀀스(Sequence) 분석
  2. 메모리에 로드된 이미지 섹션과 디스크 원본 파일 간의 무결성 교차 검증(Cross-Validation)
  3. 파일의 생성-삭제-대체와 같은 비정상적인 트랜잭션 행위에 대한 실시간 모니터링

결국 방어의 핵심은 ‘정상처럼 보이지만 결코 정상적이지 않은 생성 흐름’을 포착하는 데 있다. 공격자는 끊임없이 OS의 정상 기능을 가장하여 숨어들 것이며, 이에 맞서는 향후의 보안 솔루션 역시 운영체제 커널 레벨의 깊은 가시성을 확보하고, 프로세스의 맥락(Context)을 정교하게 이해하는 방향으로 나아가야 할 것이다.


참고자료

  • 이정섭, 박은석, & 박용수. (2020). 윈도우 환경에서 프로세스 할로잉 공격과 탐지방법 [학술대회 발표자료]. 한국통신학회(KICS). https://journal-home.s3.ap-northeast-2.amazonaws.com/site/2020kics/presentation/0681.pdf
  • Malwarebytes Labs. (2018, August 20). Process Doppelgänging meets Process Hollowing: Osiris. Malwarebytes. https://www.malwarebytes.com/blog/news/2018/08/process-doppelganging-meets-process-hollowing_osiris
  • Liberman, T. (2017, December). Lost in transaction: Process doppelgänging [Conference presentation]. Black Hat Europe 2017. https://www.blackhat.com/docs/eu-17/materials/eu-17-Liberman-Lost-In-Transaction-Process-Doppelganging.pdf
  • hasherezade. (2022). process_ghosting (Version 0.1) [Computer software]. GitHub. https://github.com/hasherezade/process_ghosting
  • Rodriguez, R. (2021, December 13). Process ghosting: A new executable image tampering attack [Blog post]. Elastic. https://www.elastic.co/blog/process-ghosting-a-new-executable-image-tampering-attack
  • MITRE. (n.d.). Process Doppelgänging. In MITRE ATT&CK® techniques. https://attack.mitre.org/techniques/T1055/013/
  • Unprotect.it. (n.d.). Process Doppelgänging. https://unprotect.it/technique/process-doppelganging/
  • Microsoft. (2024, June 28). FAT, HPFS, and NTFS file systems. Microsoft Learn. https://learn.microsoft.com/ko-kr/troubleshoot/windows-client/backup-and-storage/fat-hpfs-and-ntfs-file-systems