
Windows 메모리 포렌식 및 위협 헌팅 도구로, 실행 중인 프로세스 메모리를 스캔하여 악성 패턴, 인젝션 기법, 반사적으로 로드된 .NET 어셈블리를 탐지하며, 다층 신뢰도 모델을 사용하여 오탐(false positive)을 줄입니다.

version : 0.9 (안정 버전)
Aether는 라이브 프로세스 메모리에서 악성 패턴을 스캔하고, 인젝션 기법, 임플란트 시그니처, 리플렉티브 로드된 .NET 어셈블리를 탐지하는 Windows 메모리 포렌식 및 위협 헌팅 도구입니다. 다중 계층 신뢰도 모델(multi-layer confidence model)을 사용하여 오탐(false positive)률을 크게 줄이고 악성 행위를 탐지합니다. Aether는 할로잉(Hollowing), APC, 스레드 하이재킹 기법 탐지에 뛰어난 역량을 갖추고 있습니다. 보안 분석가는 이 도구를 사용하여 의심스러운 영역을 스캔·헌팅하고, 오프라인 분석을 위해 스냅샷을 캡처할 수 있습니다.
문서: https://0xsp.com/docs/aether-getting-started/
연구 문서:
Aether 핵심 기능에 대한 간략한 설명입니다. 더 자세한 내용은 전체 기술 블로그 포스트를 참조하세요:
"msxsl:script"가 6D 00 73 00 78 00 ...로 저장되는 경우)rules/에 새 시그니처 추가MEM_PRIVATE 영역의 PE 헤더 탐지 — 리플렉티브 로드된 .NET 어셈블리 플래그 지정
(MZ + PE + BSJB 메타데이터)Aether는 원시 작업 집합(working-set) 신호 위에 다섯 개의 필터를 계층화하여, 하나의 탐지 결과가 보고되기 전에 여러 지표가 일치해야 하도록 FP 필터링을 적용합니다:
기타 구조적 검사:
MEM_IMAGE 할당
(DLL 할로잉 / 모듈 스톰핑)K32QueryWorkingSetEx를 통한 수정된 코드 페이지 탐지.
4KB 페이지마다가 아니라 영역마다 한 번의 syscall로 일괄 처리
(단순 루프보다 약 50~100배 빠름)MEM_PRIVATE + PAGE_EXECUTE_*
할당을 플래그 처리 (셸코드, JIT 스프레이, 동적 코드 스텁 할당)E9 ?? ?? ?? ?? — JMP rel32FF 25 ?? ?? ?? ?? — JMP [rip+disp32]68 ?? ?? ?? ?? C3 — PUSH imm32 ; RET48 B8 ?? ?? ?? ?? ?? ?? ?? ?? FF E0 — MOV RAX, imm64 ; JMP RAX49 BB ?? ?? ?? ?? ?? ?? ?? ?? 41 FF E3 — Detours 스타일
Aether는 더 엄격한 분류와 L1~L5 탐지 결과와의 교차 상관 관계로 스레드를 검사합니다.
대상 프로세스의 모든 생성된 스레드에 대해 Aether는 NtQueryInformationThread를 통해
Win32StartAddress를 읽고, 접근이 허용되면 GetThreadContext / Wow64GetThreadContext를
통해 라이브 Rip / Eip도 읽습니다.
그런 다음 각 주소는 아래 표와 같이 등급이 매겨집니다. 자세한 내용은 블로그 포스트를 참조하세요:
이 방식이 "start_address가 어떤 모듈에 있는지"만 확인하는 기본 검사보다 강력한 이유:
VirtualQueryEx 교차 검사 — 모든 주소는 모듈 목록에 대한 선형 스캔 대신
단일 O(1) 호출로 Type / Protect / AllocationBase를 조회TSAV_MODIFIED_HOST로 승격Win32StartAddress는 NtSetInformationThread를 통해
프로세스에서 쓸 수 있으며 스푸핑 가능한 필드입니다. 일시 중단된 스레드의 라이브 Rip은
로더가 쉽게 다시 쓸 수 없는 값입니다. 둘을 비교하여 의심스러운 영역으로 확인되는
불일치를 플래그합니다.Wow64GetThreadContext로 전환하여 Eip를 읽음QUERY_INFORMATION | GET_CONTEXT →
QUERY_INFORMATION → 순으로 폴백하므로
부분 접근 시나리오에서도 유용한 분류를 생성런타임 API 해석(resolution)은 악성코드가 자주 사용하는 기법입니다. Aether 탐지 메커니즘은 힙에서 유효한 모듈 주소와 포인터를 스캔하고, 그 결과를 아래 설명된 필터링 기준과 연관지어 이 동작을 식별합니다:
각 필터는 실제 텔레메트리에서 관찰된 특정 FP(오탐) 클래스를 제거합니다:
Aether는 현재 스텁 수준의 XOR 탐지 패턴을 지원하며, 메모리 영역 내 바이트 값의 무작위성을 확인하기 위해 Shannon 엔트로피 알고리즘을 채택하여 임계값을 초과하는 모든 항목을 플래그합니다. 높은 오탐(FP) 발생을 해결하기 위해 Aether는 여러 지표를 사용합니다.
GetExtendedTcpTable을 폴링MODIFIED_CODE_* 탐지 항목에
private_pages와 region_pages가 포함되어 트라이애지(triage)에 실제 수치 제공Aether.exe --scan --pid <PID> [OPTIONS]
Aether.exe --scan --lookup "ProcessName.exe"
Aether.exe --hunt <PID> SLEEP_MS PERIOD
Aether.exe --scan-all [OPTIONS]
git clone https://github.com/0xsp-SRD/aether
cd aether
# Debug build (safety checks enabled)
zig build
# Release build (smaller, faster binary)
zig build -Doptimize=ReleaseSafe
# or
zig build -Doptimize=ReleaseFast
빌드된 실행 파일은 zig-out/bin/Aether.exe에 생성됩니다.
추가 시그니처 스캔을 수행하려면 zig-out/bin/Aether.exe와 rules/ 디렉터리를 대상
Windows 머신에 복사하세요. 대상 프로세스에 관리자 권한이 필요한 경우 Aether.exe를
관리자 권한으로 실행해야 합니다.
Win32StartAddress 재작성은 프로브 시점에 스레드가 우연히 대기 상태에
머물러 있는 경우에만 탐지 가능 (Moneta와 동일한 제약)Aether Community는 GNU GPL v3.0에 따라 라이선스가 부여됩니다. 상업용 라이선스는 독점(proprietary) 또는 상업적 사용을 위해 작성자에게서만 획득할 수 있습니다.
| 레이어 | 필터 | 목적 |
|---|
| L1 | 구조적 | 실행 가능한 IMAGE 하위 영역만 고려 (.data / .rdata COW 노이즈 제거) |
| L2 | 정량적 | private_pages 수와 private_ratio로 등급 부여 (낮음 / 중간 / 높음) |
| L3 | 교차 검증 | 독립적인 신호가 동일한 할당 베이스에서 일치하는 경우에만 승격 — 시그니처 히트, missing_peb_entry, private_rwx, 훅 프롤로그 또는 온디스크 diff |
| L4 | CLR 인지 | CLR이 로드될 때 전체를 건너뛰는 대신 ngen / R2R / 계층형 JIT 대상(*.ni.dll, mscor*, clr*, coreclr, system.private.corelib*)에 대해 모듈별 억제 |
| L5 | 온디스크 diff | CreateFileMappingW(SEC_IMAGE_NO_EXECUTE)로 모듈 파일을 매핑하고, 각 프라이빗 실행 페이지의 처음 16바이트를 디스크의 동일한 RVA와 비교. 차이가 있으면 실제 수정 IOC |
MOV R11, imm64 ; JMP R11Cor_Private_IPCBlock_v4_<PID> 및 v2 Cor_Private_IPCBlock_<PID>
(레거시 .NET 2/3 / mscorwks)에 대한 섹션 객체 프로브.
이를 통해 이전 런타임을 실행하는 노이즈가 많은 앱 풀이 잘못 분류되지 않습니다.| 판정 | 심각도 | 조건 |
|---|
TSAV_SHELLCODE_PRIVATE | CRITICAL | 주소가 MEM_PRIVATE + PAGE_EXECUTE_* 영역에 있음 — 전형적인 CreateRemoteThread 셸코드 |
TSAV_SUSPENDED_RIP | CRITICAL | 일시 중단된 스레드의 Rip이 Win32StartAddress와 일치하지 않고 의심스러운 영역으로 확인됨 — Win32StartAddress 스푸핑(EarlyBird / APC 트릭) 및 SetThreadContext 하이재킹 탐지 |
TSAV_HOLLOWED_HOST | HIGH | PEB 모듈 목록에 없는 MEM_IMAGE 할당 내부의 주소 (DLL 할로잉 / 모듈 스톰핑) |
TSAV_MODIFIED_HOST | HIGH | L1~L5 파이프라인이 이미 MODIFIED_CODE_*, MISSING_PEB, PRIVATE_RWX, DISK_MEM_DIFF 또는 HOOK_PROLOGUE로 플래그한 MEM_IMAGE 할당 내부의 주소 |
TSAV_STAGED_PRIVATE_RW | HIGH | MEM_PRIVATE + PAGE_READWRITE — VirtualProtect 호출 전 셸코드 스테이징 |
TSAV_MAPPED_NONPE | MEDIUM | PE 헤더가 없는 MEM_MAPPED(페이지 파일 백업 섹션) — sRDI / 페이지 파일 리플렉티브 로더 |
TSAV_SPOOF_TRAMPOLINE | MEDIUM | 주소가 차단 목록의 트램펄린(LoadLibraryA/W/ExA/W, WinExec, CreateProcessA/W, VirtualAlloc[Ex], RtlExitUserThread, RtlExitUserProcess, NtTerminateProcess, ShellExecuteA/W)과 일치 |
QUERY_LIMITED_INFORMATION| 필터 | 규칙 | 제거되는 FP 클래스 |
|---|
| F1 | count >= 5 | 무작위 포인터 형태 데이터, NULL, HMODULE |
| F2 | 호스트 EXE만 가리키는 런(run) 거부 | 애플리케이션 클래스 C++ vtable |
| F3 | distinct_modules >= 2 | 단일 DLL 프레임워크 vtable (Qt, MFC, wxWidgets) |
| F4 | capability_modules >= 2 | 단일 OS DLL에 연결되는 브라우저 / CRT vtable (예: iertutil + ucrtbase + shlwapi) |
| F5 (L10) | 확인 가능한 포인터의 >= 80%가 export된 RVA에 위치 | Winsock LSP 디스패치 테이블, 플러그인 콜백 배열, 내부(비 export) 메서드를 가리키는 vtable |
| 플래그 | 설명 |
|---|
--pid, -p <PID> | 스캔할 대상 프로세스 ID |
--lookup, -l <name> | 프로세스 이름과 일치하는 모든 PID 찾기 |
--json, -j | 결과를 JSON으로 출력 (SIEM 통합용) |
--verbose, -v | 영역별 스캔 세부 정보 표시 |
--scan-all, -a | 모든 프로세스 스캔 |
--hunt, -b <PID> [ms] [hits] | 연결 모니터링 — ms 간격(기본값 2000)으로 폴링하고 hits 이상 발생한 엔드포인트 플래그 |
--networking | 네트워크 모니터링 모드 |
--rules, -r <dir> | 규칙 디렉터리 (기본값: rules/) |
--config, -c <file> | 단일 규칙 파일 (레거시 형식) |
--dump, `` | 사용자 지정 크기로 특정 메모리 영역 덤프 |
--read, `` | 터미널에서 메모리 영역 내용 실시간 읽기 |
--help, -h | 도움말 표시 |