Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
mora-hwbp — 하드웨어 브레이크포인트(DR0-DR7) 기반 패치리스 유저 모드 후킹 및 텔레메트리 계측 엔진(AMSI, WLDP 및 ETW PoC). | Kitploit
도구/GitHubGitHub/dovughs/mora-hwbp
Defensive ToolsIDS/IPS EvasionDebuggersLearning & EducationRed TeamingAdversarial Attack
GitHubdovughs/mora-hwbp

mora-hwbp

하드웨어 브레이크포인트(DR0-DR7) 기반 패치리스 유저 모드 후킹 및 텔레메트리 계측 엔진(AMSI, WLDP 및 ETW PoC).

저장소 보기
101일 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Mora-HWBP — 하드웨어 브레이크포인트를 통한 AMSI / WLDP / ETW 텔레메트리 후킹

하드웨어 브레이크포인트(CPU 디버그 레지스터) 기반 함수 후킹을 기존의 인메모리 코드 패칭의 대안으로 보여주는 보안 연구 개념 증명(POC).

목적 및 범위

이 저장소는 Windows 내부 구조에 대한 방어적 보안 연구, 레드팀/퍼플팀 교육, 탐지 엔지니어링, 학술 연구를 위해서만 게시되었습니다. 공격자가 프로세서 디버그 레지스터를 악용하여 사용자 모드 보안 텔레메트리를 무력화할 수 있는 방법과, 그에 못지않게 중요한, 그러한 기법을 탐지하기 위해 방어자가 무엇을 모니터링해야 하는지를 보여줍니다. 작성자는 이 코드의 오용에 대해 책임을 지지 않습니다. 명시적 허가 없이 시스템에 이 기법을 사용하는 것은 불법이며, 대부분의 관할권에서 관련 컴퓨터 사기 및 남용 법률을 위반합니다. 소유하거나 명시적 서면 허가를 받은 환경이 아닌 곳에는 배포하지 마십시오.


목차

  1. 개요
  2. 배경 — 왜 하드웨어 브레이크포인트인가?
  3. 대상 보안 구성 요소
  4. 아키텍처
  5. 기술 심층 분석
    • 5.1 x64에서의 하드웨어 브레이크포인트
    • 5.2 디버그 레지스터 레이아웃 (DR0–DR7)
    • 5.3 벡터 예외 처리기(VEH)
    • 5.4 구성 요소별 가로채기 로직
    • 5.5 스레드 관리 및 후크 지속성
  6. 내보낸 API
  7. 빌드 지침
  8. 인젝션 및 사용 예제
  9. 탐지 및 완화 (블루팀)
  10. 알려진 제한 사항
  11. 참고 자료

개요

mora_hwbp.c는 대상 프로세스(예: PowerShell 호스트)에 로드/인젝션되면, 프로세스 내 모든 스레드의 아키텍처 디버그 레지스터(DR0–DR7)에 저장된 CPU 하드웨어 브레이크포인트를 통해서만 네 개의 사용자 모드 함수를 후킹하는 DLL을 구현합니다:

프로세스별 **벡터 예외 처리기(VEH)**는 디버그 레지스터가 발생시키는 EXCEPTION_SINGLE_STEP(0x80000004) 오류를 수신하고, 예외 컨텍스트를 다시 작성하여 원래 함수의 성공적인 반환 경로를 시뮬레이션한 다음 실행을 재개합니다 — 모두 실행 가능한 메모리의 단일 바이트도 수정하지 않고 수행됩니다.

이 기법은 공격적 관점과 방어적 관점 모두에서 특히 흥미롭습니다:

  • 공격적으로, 수정된 .text 섹션(전통적인 인라인 후킹, EAT/IAT 패칭, Etwp* 스터빙)을 찾는 EDR/HIPS 무결성 검사를 우회합니다.
  • 방어적으로, 하드웨어 브레이크포인트는 탐지에 사용할 수 있는 매우 독특한 포렌식 아티팩트(디버그 레지스터 내용, 단일 스텝 예외 밀도, VEH 등록, GetThreadContext/SetThreadContext syscall 패턴)를 남깁니다.

배경 — 왜 하드웨어 브레이크포인트인가?

기존의 사용자 모드 후킹 방식 — 인라인 디토어(5–14바이트 덮어쓰기), 임포트 주소 테이블(IAT) 후킹, 익스포트 주소 테이블(EAT) 후킹 — 은 공통된 약점을 공유합니다: 무결성 스캐너와 ETW가 관찰할 수 있는 메모리를 수정한다는 점입니다.

최신 AV/EDR 제품은 다음을 구현합니다:

  • PowerShell 및 .NET CLR 버퍼에 대한 메모리 스캐닝 / AMSI 스캔;
  • ETW 기반 텔레메트리 (Microsoft-Windows-PowerShell, .NET ETW, 위협 인텔리전스 공급자);
  • pageguard/guard-page 트릭, PAGE_EXECUTE_READWRITE로의 VirtualProtect 전환, 섹션 해시 불일치를 감지하는 커널 콜백 및 사용자 모드 무결성 검사.

하드웨어 브레이크포인트는 이 모든 것을 우회합니다:

  1. 하드웨어 브레이크포인트는 CPU 레지스터이지 메모리가 아닙니다 — .text에서 스캔할 것이 없습니다.
  2. Windows API SetThreadContext를 통해 스레드별로 설정되며, 무결성 스캐너가 사용하는 전형적인 "메모리 수정됨" 신호를 트리거하지 않습니다.
  3. 가로채기 지점은 전적으로 프로세서의 예외 디스패치가 처리하며, 사용자 모드 대상 함수가 실행되기 전에 프로세스 VEH 체인을 거칩니다.

이 POC는 현대 Windows 보안 스택에서 가장 널리 신뢰받는 세 가지 사용자 모드 보안 기본 요소인 AMSI(Antimalware Scan Interface), WLDP(Windows Lockdown Policy), ETW(Event Tracing for Windows) 를 대상으로 이 기법의 효율성과 탐지 가능성을 탐구합니다.


대상 보안 구성 요소

AMSI — Antimalware Scan Interface

AMSI는 애플리케이션(PowerShell, Office, VBScript, .NET 호스트 등)이 등록된 맬웨어 방지 공급자에게 콘텐츠 스캔을 요청할 수 있게 하는 Windows 플랫폼 통합 지점입니다. 두 가지 진입점이 특히 중요합니다:

  • AmsiScanBuffer(HANDLE hamsiContext, PVOID buffer, ULONG length, LPCWSTR contentName, HANDLE hamsiSession, AMSI_RESULT *pResult)
  • AmsiScanString(HANDLE hamsiContext, LPCWSTR string, LPCWSTR contentName, HANDLE hamsiSession, AMSI_RESULT *pResult)

반환되는 AMSI_RESULT를 AMSI_RESULT_CLEAN (0)으로 강제하면, 스크립트 엔진은 콘텐츠가 검사되었고 무해한 것으로 판명되었다고 믿으므로 실행이 중단 없이 계속됩니다.

WLDP — Windows Lockdown Policy

WLDP는 Windows Defender Application Control(WDAC / Device Guard)에 대한 정책 평가를 구현합니다. WldpIsClassInApprovedList는 주어진 COM 클래스(GUID로 식별)가 현재 정책에서 허용되는지 여부를 답합니다. AMSI는 내부적으로 WLDP를 조회하여 특정 스크립트/콘텐츠 클래스가 "신뢰됨"(승인 목록에 있음)인지 결정합니다. 함수가 클래스를 승인된 것으로 보고하면, AMSI는 해당 콘텐츠 유형에 대한 추가 검토를 건너뛸 수 있습니다.

DLL은 isApproved 출력 매개변수(RDX)를 TRUE로 설정하고 S_OK를 반환하여, 평가된 클래스가 신뢰된 것처럼 보이게 만듭니다.

ETW — Event Tracing for Windows

ntdll.dll의 EtwEventWrite는 시스템에서 사실상 모든 ETW 이벤트 생성의 핵심 사용자 모드 싱크입니다. 이를 억제하면 보안 모니터링과 관련된 광범위한 부작용이 발생합니다:

  • PowerShell 파이프라인 및 스크립트 블록 로깅 이벤트
  • .NET 어셈블리 로드 이벤트 (Microsoft-Windows-DotNETRuntime)
  • AMSI 검사 결과 텔레메트리
  • EDR 에이전트가 소비하는 위협 인텔리전스 공급자 이벤트

DLL은 실제 함수를 실행하지 않고 ERROR_SUCCESS (0)을 반환합니다.


아키텍처```

┌──────────────────────────────────────────────────────────────────────────┐ │ Target Process (e.g. powershell.exe) │ │ │ │ ┌──────────────────────────┐ ┌──────────────────────────────────┐│ │ │ mora_hwbp.dll │ │ CPU / Windows ││ │ │ │ │ ││ │ │ DllMain / InstallHook │ │ Thread A Thread B ││ │ │ │ │ │ ┌────────┐ ┌────────┐ ││ │ │ ▼ │ │ │ DR0..3 │ │ DR0..3 │ ││ │ │ Resolve exports │ │ └────────┘ └────────┘ ││ │ │ (amsi/wldp/ntdll) │ │ ││ │ │ │ │ │ #DB (single-step) ││ │ │ ▼ │ │ exception ──► Windows Dispatch ││ │ │ AddVectoredException │ │ │ ││ │ │ Handler(VEH) │ │ ▼ ││ │ │ │ │ │ ┌─────────────────────────────┐ ││ │ │ ▼ │ │ │ VectoredHandler (ours) │ ││ │ │ SetHwbpOnThread(ALL) │ │ │ • match #DB address │ ││ │ │ │ │ │ │ • rewrite context (RIP/RSP)│ ││ │ │ ▼ │ │ │ • spoof return value (RAX) │ ││ │ │ MonitorThread ◄──┐ │ │ │ • continue execution │ ││ │ │ (re-hook every │ │ │ └─────────────────────────────┘ ││ │ │ 500ms) └──────┘ │ ││ │ └──────────────────────────┘ └──────────────────────────────────┘│ └──────────────────────────────────────────────────────────────────────────┘

root@kitploit:~
**상위 수준 흐름:**

1. DLL이 대상 프로세스에 로드됩니다(모든 주입 기술을 통해 — [사용법](#injection--usage-example) 참조).
2. `DLL_PROCESS_ATTACH`에서 (또는 내보낸 `InstallHook`을 통해) 대상 내보내기 함수는 `GetProcAddress`로 확인됩니다(선택적으로 `LoadLibraryW`를 통해 모듈 로드를 강제).
3. **Vectored Exception Handler**가 프로세스의 **첫 번째** 핸들러로 등록됩니다(`AddVectoredExceptionHandler(1, ...)`).
4. **현재 스레드**는 즉시 후킹되고, 프로세스의 **모든 기존 스레드**는 `CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0)`으로 열거된 다음 후킹됩니다.
5. **모니터 스레드**가 500ms마다 깨어나 **새로 생성된 스레드**를 포함한 모든 스레드에 브레이크포인트를 다시 적용합니다. 따라서 후킹 이후에 스레드가 생성되거나 외부에서 브레이크포인트가 제거되어도 후크 지속성이 보장됩니다.
6. 어떤 스레드에서 후킹된 함수가 호출되면 CPU가 `#DB` 단일 스텝 예외를 발생시키고, Windows는 이를 VEH에 디스패치하며, VEH는 정상적인 반환을 시뮬레이션하고 실행을 계속합니다.

### 샘플 디버그 출력

![Sysinternals DebugView로 캡처한 HWBP 엔진 후크 상태 진단](https://assets.kitploit.com/production/public/readmes/50594/5cf99fadc07272ff598cbb9486ff7803a3234eb6aeaa8202684c27e97bd7e161.png)

*그림 1 — Sysinternals DebugView로 캡처한 샘플 진단 출력. 각 줄은 해당 디버그 레지스터에 대한 확인된 대상 주소와 실시간 적중 횟수를 보고합니다.*

---

## 기술 심층 분석

### 5.1 x64의 하드웨어 브레이크포인트

x86/x64에서 각 CPU는 **4개의 하드웨어 디버그 주소 레지스터**(`DR0`–`DR3`)와 제어 레지스터(`DR7`)를 제공합니다. `DR0`–`DR3`에 0이 아닌 브레이크포인트가 설정된 상태로 실행되는 스레드는 명령 포인터가 해당 주소에 도달하거나(데이터 접근이 구성된 조건과 일치하거나) 할 때마다 오류가 발생합니다. 상태 레지스터 `DR6`는 어떤 브레이크포인트가 발생했는지 기록합니다.

하드웨어 브레이크포인트는 **컨텍스트 민감형**입니다. 즉, 스레드의 `CONTEXT` 구조체에 저장되며 설정된 스레드에만 적용됩니다. 따라서 견고한 구현은 프로세스의 **모든 스레드**에 브레이크포인트를 설정하고(새 스레드에는 지속적으로 다시 적용해야) 합니다.

### 5.2 디버그 레지스터 레이아웃(DR0–DR7)

`DR7`은 브레이크포인트 활성화와 동작을 제어하는 비트 필드입니다:

| Bits   | Field  | Meaning                                             |
|--------|--------|-----------------------------------------------------|
| `0`    | `L0`   | 브레이크포인트 0(DR0)에 대한 로컬 활성화             |
| `2`    | `L1`   | 브레이크포인트 1(DR1)에 대한 로컬 활성화             |
| `4`    | `L2`   | 브레이크포인트 2(DR2)에 대한 로컬 활성화             |
| `6`    | `L3`   | 브레이크포인트 3(DR3)에 대한 로컬 활성화             |
| `8`    | `LE`   | 레거시 로컬 활성화(호환성을 위해 유지)                |
| `9`    | `GE`   | 레거시 전역 활성화(호환성을 위해 유지)                |
| `16–17`| `R/W0` | BP0의 접근 유형(`00` = 명령 실행)                    |
| `18–19`| `Len0` | BP0의 길이(`00` = 1바이트)                           |
| `20–21`| `R/W1` | BP1의 접근 유형(`00` = 명령 실행)                    |
| `22–23`| `Len1` | BP1의 길이(`00` = 1바이트)                           |
| `24–25`| `R/W2` | BP2의 접근 유형(`00` = 명령 실행)                    |
| `26–27`| `Len2` | BP2의 길이(`00` = 1바이트)                           |
| `28–29`| `R/W3` | BP3의 접근 유형(`00` = 명령 실행)                    |
| `30–31`| `Len3` | BP3의 길이(`00` = 1바이트)                           |

네 개의 브레이크포인트 모두 단일 바이트에 대한 **실행(명령 인출)** 조건으로 구성되며, 이는 함수 진입점 후크에 적합한 조건입니다.

### 5.3 Vectored Exception Handler(VEH)

브레이크포인트가 트리거되면 프로세서가 `#DB` 예외를 발생시킵니다. x64 Windows에서 `ntdll` 디스패치 루틴은 스레드의 구조적 예외 처리기(SEH) 체인보다 먼저 프로세스 전역 **VEH 체인**을 통해 이를 라우팅합니다. 이 프로젝트의 핸들러는:

1. **필터링** — `EXCEPTION_SINGLE_STEP`(`0x80000004`)만 처리하고, 나머지는 모두 `EXCEPTION_CONTINUE_SEARCH`로 전달됩니다.
2. **매칭** — `ExceptionAddress`를 네 개의 알려진 함수 주소와 비교합니다.
3. **컨텍스트 다시 작성**:
   - `RIP = *(RSP)` → 반환 주소를 스택에서 꺼내 원래 호출자로 "복귀".
   - `RSP += 8` → `ret` 시뮬레이션(x64 단일 명령 언와인드).
   - `RAX = 0` → `S_OK`/`ERROR_SUCCESS`(성공 반환 코드) 스푸핑.
   - `DR6 &= ~0xF` → 브레이크포인트 상태 비트를 지워 나중에 가짜 상태 없이 명령을 다시 실행할 수 있게 함.
4. **출력 매개변수 변경**([5.4](#54-per-component-interception-logic) 참조).
5. **`EXCEPTION_CONTINUE_EXECUTION` 반환** — Windows에 수정된 컨텍스트로 스레드를 다시 시작하도록 지시합니다. 즉, 실행은 *호출자*에서 재개되며 실제 대상 함수는 **절대 실행되지 않습니다**.

각 인터셉션 지점은 추가로 SEH `__try/__except` 가드로 감싸져 있어 잘못되었거나 예기치 않은 스택 레이아웃이 프로세스를 중단시키지 못합니다 — 적대적/강화된 대상에 대한 견고성 고려 사항입니다.

### 5.4 구성 요소별 인터셉션 로직

**DR0 — `AmsiScanBuffer`** (x64, 처음 6개 인자는 `RCX, RDX, R8, R9, [RSP+0x28], [RSP+0x30]`):```
HRESULT AmsiScanBuffer(HANDLE, PVOID, ULONG, LPCWSTR, HANDLE, AMSI_RESULT* pResult);
                                                        [RSP+0x28]  [RSP+0x30]
  • AMSI_RESULT_CLEAN (0)을 6번째 매개변수(pResult, [RSP+0x30])에 씁니다.
  • RAX에서 S_OK (0)를 반환합니다.

DR1 — AmsiScanString (x64, 처음 5개 인자는 RCX, RDX, R8, R9, [RSP+0x28]):``` HRESULT AmsiScanString(HANDLE, LPCWSTR, LPCWSTR, HANDLE, AMSI_RESULT* pResult); [RSP+0x28]

root@kitploit:~
- 5번째 매개변수(`pResult`, `[RSP+0x28]` 위치)에 `AMSI_RESULT_CLEAN (0)`을 씁니다.
- `RAX`에 `S_OK (0)`를 반환합니다.

**DR2 — `WldpIsClassInApprovedList`** (`RCX, RDX, R8`에 처음 3개 인자):```
HRESULT WldpIsClassInApprovedList(const GUID* classId, PBOOL isApproved, DWORD evalCriteria);
                                         RCX             RDX             R8
  • TRUE를 *isApproved에 기록합니다 (RDX 통해).
  • RAX에서 S_OK (0)를 반환합니다.
  • 결과: 평가된 콘텐츠 클래스가 잠금 정책에 의해 "승인"된 것으로 간주되며, AMSI는 해당 클래스에 대한 판단을 신뢰합니다.

DR3 — EtwEventWrite (처음 4개 인자는 RCX, RDX, R8, R9):``` ULONG EtwEventWrite(HANDLE RegHandle, PCEVENT_DESCRIPTOR EventDescriptor, ULONG UserDataCount, PEVENT_DATA_DESCRIPTOR UserData);

root@kitploit:~
- Returns `ERROR_SUCCESS (0)` in `RAX` without touching any output parameter.
- 결과: ETW 공급자는 후킹된 프로세스에서 **어떤** 이벤트도 수신하지 않으므로 스크립트 실행, 모듈 로드, 프로세스 생성 및 AMSI 원격 측정 로깅이 억제됩니다.

### 5.5 스레드 관리 및 후크 지속성

디버그 레지스터는 스레드별로 존재하므로 엔진은 후크를 지속적으로 유지해야 합니다:

1. **즉시 후킹** — `DllMain`(또는 `InstallHook`)은 `SetHwbpOnThread(GetCurrentThread())`로 호출 스레드를 후킹합니다.
2. **전체 스레드 스윕** — `HookAllThreads()`는 `TH32CS_SNAPTHREAD` 스냅샷을 통해 프로세스의 모든 스레드를 열거하고, 각 외부 스레드를 일시 중단(`SuspendThread`)한 후 중단점을 적용(`SetHwbpOnThread`)하고 다시 재개한 다음 핸들을 닫습니다. 일시 중단은 `GetThreadContext`와 `SetThreadContext` 사이의 컨텍스트 전환 중에 스레드가 오류를 일으키는 경합을 방지합니다.
3. **지속성 모니터** — `MonitorThreadProc`는 `Sleep(500)`으로 루프하며 500ms마다 `HookAllThreads()`를 호출합니다. 이는 **제거된 모든 중단점을 다시 설정**하고(예: 외부 `SetThreadContext` 호출, 디버깅 도구, 스레드 종료/생성) **초기 후크 이후 생성된 스레드를 포함**합니다.
4. **동기화** — `HookAllThreads`는 `CRITICAL_SECTION`(`g_HookLock`) 하에서 실행되므로 모니터 스레드와 초기 후킹 루틴이 컨텍스트 전환을 서로 간섭하지 않습니다.
5. **정리 해제** — `UninstallHook`는 모니터를 중지하고 모든 스레드에서 `DR0–DR7`을 지운 다음 VEH 등록을 해제합니다.

> **"후크 지속성" 질문에 대한 명시적 답변:** 그렇습니다. 중단점이 어떤 스레드에서 제거되면(다른 에이전트, 디버거 또는 EDR에 의해) 모니터 스레드가 **500ms 이내에 다시 적용합니다**. 또한 DLL 로드 후 생성된 모든 스레드는 한 번의 모니터 주기 내에 후킹됩니다. 이 특정 엔진을 무력화하는 유일한 확실한 방법은 모니터 스레드를 종료하고 *그리고* VEH를 정리하고 *그리고* 같은 시간 창 내에서 레지스터를 제거하는 것입니다. 또는 처음부터 `SetThreadContext`를 거부하는 안티디버깅을 사용하는 것입니다.

---

## 내보낸 API

| 내보내기       | 시그니처                          | 동작                                                                 |
|-------------------|------------------------------------|-----------------------------------------------------------------------|
| `InstallHook`     | `BOOL WINAPI InstallHook(void)`    | 대상을 확인하고, VEH를 등록하고, 모든 스레드를 후킹하고, 모니터를 시작합니다.   |
| `UninstallHook`   | `BOOL WINAPI UninstallHook(void)`  | 모니터를 중지하고, 모든 스레드의 중단점을 지우고, VEH를 제거합니다.        |
| `GetStats`        | `void WINAPI GetStats(void)`       | 현재 후크 상태를 (`OutputDebugStringA`를 통해) 출력합니다 — 주소, 적중 카운터. |

적중 카운터(`g_HaveAmsiBuf`, `g_HaveAmsiStr`, `g_HaveWldp`, `g_HaveEtw`)는 `InterlockedIncrement`로 관리되며 디버그 출력에 노출됩니다. 이는 실험실 환경에서 인터셉트가 실제로 발생하는지 검증하는 데 유용합니다.

`DllMain` 자체가 `DLL_PROCESS_ATTACH`에서 전체 후킹 시퀀스를 수행하므로, 내보낸 함수들은 런타임 로드/언로드 시나리오를 위한 선택적 편의 기능입니다.

---

## 빌드 지침

**요구 사항:** Windows 10/11 x64, Visual Studio Build Tools (`icx.exe`), SDK.

DLL을 컴파일합니다 (x64):```bat
icx.exe /nologo /O3 /MT /EHsc "mora_hwbp.c" /link /DLL /out:"mora_hwbp.dll" /LIBPATH:"C:\Program Files (x86)\Intel\oneAPI\compiler\latest\lib"

플래그 설명:

Flag용도
/O3최대 최적화 (함수 코드, 필수 아님)

결과물은 mora_hwbp.dll이며, 대상 프로세스에 로드할 수 있습니다.


인젝션 및 사용 예제

DLL은 AMSI/WLDP/ETW를 사용하는 프로세스에 로드되어야 합니다. PowerShell 호스트가 가장 표준적인 테스트 환경입니다. 로드는 일반적인 DLL 인젝션 기법으로 수행할 수 있습니다. Reflective/LoadLibrary 인젝션을 사용하는 최소한의 자체 포함 데모는 작은 C 로더로 수행할 수 있습니다:```bat rem Run from an x64 developer prompt (example with a generic loader) loader.exe mora_hwbp.dll powershell.exe

root@kitploit:~
또는 수동 랩 확인을 위해 선호하는 도구로 주입한 다음 PowerShell에서 검증하십시오:```powershell
# 1. Inject mora_hwbp.dll into the PowerShell process (via external tool).
# 2. Verify that classic AMSI test vectors now return clean.
"AmsiTestSample:7e72c3ce-861b-4339-8740-0ac1484c1386"

실험실 검증 전용. 디버거 또는 GetStats/OutputDebugString를 사용하여 네 개의 중단점 모두 스크립트 내용이 실행됨에 따라 히트를 보고하는지 확인하십시오.


탐지 및 완화 (블루 팀)

이 POC는 이중 목적을 가집니다: 공격적으로 효과적인 동일한 특성이 방어자가 정확히 찾아내야 할 대상이기도 합니다.

침해 지표 (IOC)

권장 완화 조치

  1. 감시/자체 모니터링 에이전트 — 중요 프로세스에서 GetThreadContext(CONTEXT_DEBUG_REGISTERS)를 폴링하고 승인된 디버거 프로필 외부의 0이 아닌 DR0–DR3가 있는 모든 스레드를 감사합니다.
  2. 커널 ETW 감사 — Microsoft-Windows-Kernel-Process + Thread 추적을 활성화하고 보안 관련 프로세스를 대상으로 하는 NtGetContextThread/NtSetContextThread에 대해 경고합니다.
  3. EDR 사용자 모드 후크 무결성 — 하드웨어 후크는 메모리 검사를 우회하므로 .text 무결성만이 아닌 행동 탐지(EtwEventWrite 아래의 ETW 소비자 후크, 커널 ETW, AMSI 소비자 재확인)에 의존합니다.
  4. 모니터 보호 — 진정한 적대적 환경에서는 다른 프로세스에 대한 스레드별 SetThreadContext를 명시적인 고심각도 신호로 취급합니다.
  5. 엔드포인트 강화 — WDAC(이 POC가 클래스 승인을 위해 명시적으로 우회하는 것 — WDAC를 인메모리 도구에 대한 단독 방어로 취급하지 마십시오), Credential Guard, LSASS 보호를 해당되는 경우 활성화합니다.

알려진 제한 사항

  • x64 전용 — 스택 오프셋 재작성은 x64 호출 규약(인자 RCX/RDX/R8/R9 이후 [RSP+0x20…])을 가정합니다. x86 변형은 [EBP+…] 스타일 파라미터 재구성이 필요할 것입니다.
  • 4개 슬롯만 — x64 아키텍처는 정확히 4개의 중단점 레지스터를 제공합니다. 이 방법만으로는 스레드당 4개 이상의 함수를 후킹할 수 없습니다.
  • 모니터 경합 창 — Sleep(500) 반복 사이에 (의도적으로 작은) 창이 있습니다. 매우 빠른 스레드 생성과 공격적인 스트리핑이 결합되면 이론적으로 수백 밀리초 동안 모니터를 앞지를 수 있습니다.
  • 안티디버그 간섭 — 디버그 레지스터를 적극적으로 모니터링하거나 지우는 구성 요소(실제 디버거, 일부 샌드박스, 특정 EDR)는 이 기법을 방해합니다.
  • OutputDebugStringA 기반 상태 — 진단은 디버그 출력 채널에 의존합니다. 완전히 스트리핑된/헤드리스 환경에서는 디버거를 연결하거나 출력을 리디렉션하여 실험실 관찰을 수행해야 합니다.
  • 메모리 지속성 프리미티브가 아님 — 이는 런타임 전용, 인프로세스 기법입니다. 자체적으로 디스크/레지스트리 지속성, 권한 상승, 프로세스 간 측면 이동을 제공하지 않습니다. 그 전체 목적은 하나의 인터셉션 프리미티브에 대한 통제된 연구입니다.

참고 자료

  • Microsoft Learn — 맬웨어 방지 검사 인터페이스 (AMSI)
  • Microsoft Learn — Windows 잠금 정책 (WLDP)
  • Microsoft Learn — Windows용 이벤트 추적 (ETW)
  • Microsoft Learn — CONTEXT 구조 및 디버그 레지스터
  • Intel® 64 및 IA-32 아키텍처 소프트웨어 개발자 매뉴얼, Vol. 3B — 디버그 레지스터 (Dr0–Dr7, #DB 예외)

라이선스 및 책임 있는 공개

이 프로젝트는 MIT 라이선스에 따라 라이선스가 부여됩니다 — 자세한 내용은 LICENSE 파일을 참조하십시오.

이 프로젝트는 교육 및 방어 연구 목적으로만 공개됩니다. 보안 벤더, 블루 팀 또는 탐지 엔지니어라면 이 저장소의 내용을 사용하여 하드웨어 중단점 기반 회피에 대한 탐지 범위를 개선하는 것이 좋습니다. 이 기술이 실제 환경에서 악용되는 것을 발견한 경우 조직의 책임 있는 공개 절차와 관련 벤더/당국 채널을 통해 신고하십시오.

사용에 따른 책임은 본인에게 있습니다. 이 기술의 무단 사용은 적용 가능한 법률을 위반할 수 있습니다.

도구 다운로드
레지스터후킹된 함수모듈목적
DR0AmsiScanBufferamsi.dllAMSI 콘텐츠 스캐닝 무력화
DR1AmsiScanStringamsi.dllAMSI 문자열 스캐닝 무력화
DR2WldpIsClassInApprovedListwldp.dllWLDP 클래스 승인 강제 (Device Guard / WDAC)
DR3EtwEventWritentdll.dllETW 이벤트 추적 억제
/MT
정적 CRT 연결 (런타임 DLL 종속성 없음)
/EHscC++/SEH 예외 처리 (__try에 필요)
/DLL내보내기 테이블이 있는 DLL 생성
아티팩트관찰 가능 징후
GetThreadContext / SetThreadContext 호출다른 프로세스/스레드에서의 고빈도 디버그 레지스터 컨텍스트 전환 (커널 ETW: Microsoft-Windows-Kernel-Process/Thread API).
0이 아닌 DR0–DR3CONTEXT_DEBUG_REGISTERS에 알려진 디버거 워크플로 외부의 사용자 모드 주소가 포함된 모든 스레드.
DR7 로컬 활성화 비트 (L0–L3) 및 R/W = 00디버거가 관리하지 않는 스레드의 실행 전용 중단점 — 강력한 이상 징후.
EXCEPTION_SINGLE_STEP 볼륨프로세스의 VEH에서 발생하는 높은 비율의 #DB 오류(0x80000004).
First-chance VEH 등록#DB 폭풍 직전에 새로 추가된 VEH(AddVectoredExceptionHandler).
TH32CS_SNAPTHREAD + SuspendThread/ResumeThread반복적인 스레드 열거 + 일시 중단 패턴 (500ms 모니터에서 사용).
이전에 로드되지 않은 경우 LoadLibraryW를 통한 wldp.dll/amsi.dll 로드대상 프로세스에서의 비정상적 모듈 로드.
EtwEventWrite 미도달예상 ETW 이벤트 부재 (스크립트 실행 중 PowerShell 운영 로그가 조용함).