fluer.dev/blog
2025-03-10

Halo's Gate — Unhooking ntdll via Syscall 번호 동적 복구

EDR이 ntdll을 후킹한 환경에서 인접한 stub을 읽어 올바른 SSN을 복구하는 기법을 분석합니다.

syscallevasionwindows-internals

개요

Hell's Gate는 ntdll.dll의 syscall stub에서 SSN(System Service Number)을 런타임에 읽어 직접 syscall을 호출하는 기법이다. 그런데 EDR이 해당 stub 앞에 jmp <hook> 패치를 심으면 mov eax, <SSN> 명령이 덮어씌워져 SSN 추출이 실패한다.

Halo's Gate는 이를 우회하기 위해, 후킹된 stub의 인접 함수에서 SSN을 읽어 ±1씩 가감하여 원하는 함수의 SSN을 복구한다.

Syscall Stub 구조

정상 상태의 NtAllocateVirtualMemory stub:

4C 8B D1          mov r10, rcx
B8 18 00 00 00    mov eax, 0x18    ; SSN = 0x18
0F 05             syscall
C3                ret

EDR 후킹 후:

E9 XX XX XX XX    jmp <EDR hook>   ; 첫 바이트가 0xE9로 패치됨
B8 18 00 00 00    mov eax, 0x18    ; (도달 불가)
0F 05             syscall
C3                ret

복구 로직

// stub이 후킹됐는지 확인
BOOL is_hooked(PBYTE stub) {
    return stub[0] == 0xE9;  // jmp 명령
}

// 인접 함수에서 SSN 복구
DWORD halos_gate(PBYTE ntdll_base, DWORD target_hash) {
    // export table에서 함수 목록 순회
    // target 함수 발견 시 ±1 함수 stub 확인
    // 후킹 없는 인접 stub에서 SSN 읽기
    // SSN ± offset 반환
}

SysWhispers3와의 차이

기법 SSN 획득 방법 특징
Hell's Gate 직접 stub 파싱 후킹 시 실패
Halo's Gate 인접 stub fallback 후킹 환경 대응
SysWhispers3 컴파일 타임 하드코딩 간단하나 정적 시그니처
FreshyCalls PEB sort by address 후킹 무관

결론

Halo's Gate는 단일 함수 후킹 환경에서 유효하지만, EDR이 연속된 여러 함수를 후킹하면 복구 실패 가능성이 있다. 실제 오퍼레이션에서는 FreshyCalls 또는 간접 syscall(RecycledGate)과 조합하는 것이 안정적이다.

← 목록으로