
.NET 프로세스 모니터로, 네이티브 계층에서 CLR을 후킹하고, 메모리에서 리플렉티브 어셈블리를 덤프하며, AMSI/ETW 무결성을 온디스크 바이너리와 비교하여 검사합니다.
악성코드 샘플에서 jlaive 포크만 쳐다보고 있느라 지친 나머지, 런타임에 그것들을 실제로 뜯어낼 공개 도구가 없어서 내가 만든 윈도우 도구다.
간단히 말하면, 네이티브 계층에서 CLR을 후킹하고, 리플렉티브 어셈블리 로드를 추적하며, 메모리에서 직접 PE를 자동으로 덤프하는 .NET 프로세스 모니터다. 또한 디스크 상의 원본 바이너리와 AMSI 및 ETW 무결성을 비교하고, clr.dll 문자열 패칭이나 직접적인 LoadFromBuffer 사용 같은 우회 기법도 탐지한다.
샘플은 어디서 찾나? https://tria.ge 를 확인해 보는 걸 추천한다 (광고 아님). 원하는 샘플을 다운로드하고 패밀리 기준으로 필터링할 수 있다.
이름을 왜 nemesis로 지었는지 궁금할 것이다.
그건 이 도구의 정확한 목적을 나타내기 때문이다. nemesis는 상대에게 끊임없는 도전이나 파멸로 존재하는 것을 뜻하며, 그것이 이 프로젝트의 이념이다.
그리스 신화에서 nemesis는 신성한 응징의 정령으로, 너무 오만해지거나 자신이 건드릴 수 없다고 생각하는 자들에게 응분의 대가를 안겨주는 존재였다. "FUD"라고 자랑하는 악성코드에게는 좀 노골적인 비유지만 말이다.
나는 악성코드 분석가다. 이 일을 (내겐 취미지만) 오래 하다 보면 같은 로더 체인을 계속 보게 된다. 특히 jlaive(일명 crybat)가 대박을 치고 모든 스크립트 키디들이 포크하면서 더 심해졌다.
패턴은 어이없을 정도로 단순하지만 대처하기는 지랄같이 짜증난다:
something.bat → obfuscated powershell → csharp stub → your actual payload
워드 샐러드처럼 보이는 .bat을 더블클릭한다. cmd가 쓰레기 같은 코드로 powershell을 실행한다. powershell이 .NET 스텁을 복호화/압축 해제한다 (aes, gzip, base64). 그 스텁이 amsi + etw를 패치하고, 실제 exe/dll을 메모리에 리플렉티브 로드하면 끝이다. 쓸만한 형태로 디스크에 아무것도 남지 않는다.
그게 나를 짜증나게 했다. 이 특정 체인, 즉 .NET 페이로드가 실제로 구체화되는 지점을 후킹하고, 프로세스가 자멸하기 전에 덤프하며, 이런 스텁들이 항상 하는 amsi/etw 패치를 잡아내는 데 초점을 맞춘 좋은 공개 도구가 없다. 그래서 nemesis를 만들었다.
만능 해결책은 아니다. 네 샌드박스를 대체하지도 않는다. 하지만 테스트 박스에서 의심스러운 .bat에 대해 실제로 돌려보고 아티팩트를 뽑아낼 수 있는 뭔가를 제공한다.
런처 (Launcher.exe)
Nemesis.dll을 주입한다nemesis dll (Nemesis.dll)
nLoadImagenLoadFileAssemblyNative::LoadFromBuffer (nLoadImage에서 패턴 해석)%TEMP%\Nemesis_dumps로 덤프를 큐에 넣는다amsi.dll / ntdll.dll 익스포트를 디스크 사본과 비교한다 (AmsiScanBuffer / EtwEventWrite의 전형적인 ret 패치를 잡아낸다).rdata 문자열도 확인한다 (일부 우회는 그것을 패치한다. 이에 관한 훌륭한 vxug 논문이 있다; 2024-11-21 - New AMSI Bypss Technique Modifying CLRDLL in Memory.pdf)%TEMP%\Nemesis.log에 로깅한다. 콘솔이 뭐랄까 이상해지는 문제를 피하기 위해 ENABLE_VIRTUAL_TERMINAL_PROCESSING도 사용한다 :D기본적으로: bat 체인을 실행시키고, 크립터가 실제로 페이로드를 로드하는 지점에서 잡아내며, 가는 길에 회피 기법들을 로깅한다.
c++ 데스크톱 + masm (x64)이 포함된 visual studio 2022+가 필요하다.
Nemesis.slnx를 열고 Release | x64를 선택한 뒤 솔루션을 빌드한다.
이게 실제 사용 사례다. 의심스러운 bat을 지정하고 뭐가 나오는지 보면 된다:
cd x64\Release
.\Launcher.exe "C:\path\to\suspicious.bat"
-- 뒤의 추가 인자는 대상에 전달된다:
.\Launcher.exe myapp.exe -- --some-flag
사용자 지정 dll 경로:
.\Launcher.exe --dll C:\path\Nemesis.dll myapp.exe
아티팩트:
%TEMP%\Nemesis.log%TEMP%\Nemesis_dumps하는 것:
하지 않는 것:
LNK1104로 실패하면? 아직 nemesis.dll을 로드한 게 있다. 대상을 죽이고 리빌드해라pwsh.exe vcpkg 노이즈는 무해하다, 무시해라무엇과 싸우는지 이해하고 싶다면:
nemesis를 사용함으로써 이를 수락하는 것이다. 이는 있는 그대로 제공되며 보증이 없다 — 모든 위험은 사용자가 부담한다.
합법적이고 승인된 사용(랩 vm, 소유한 시스템, 명시적 허가)에 대한 책임은 전적으로 사용자에게 있다. 법이 허용하는 최대 범위 내에서, 저자와 zypherion.tech는 사용 또는 오용으로 인해 발생하는 모든 손해, 손실, 법적 청구에 대해 모든 책임을 부인한다. 전체 조건은 LICENSE를 참조.
비상업적 / 개인 / 연구 / 취미 사용 → PolyForm Noncommercial 1.0.0
상업적 사용 (판매, 유료 제품, saas, 클라이언트 작업 등) → 별도 라이선스가 필요하다. polyform noncommercial은 그것을 커버하지 않는다.
상업적 라이선스를 원하면 연락해라:
[[email protected] / @wd6g(discord) / telegram: @ZypherionTechnologies]
짧은 메모: compilemethod를 살펴보고 고쳐야 한다. 현재로선 크립터들이 보통 그것을 전혀 사용하지 않기 때문에 그다지 필요하지 않다... 어차피
asm.load(...)를 써야 하니까. 그리고 rdata str도 제대로 테스트하지 못했으니 확인해야 한다는 걸 상기시켜 준다... 멍청한 코드로 PR하지 마라. n(Native) 백엔드 예를 들어 nLoadImage는 정상적으로 후킹할 수 없다. 레지스터를 보존해야 하고 그냥 별로다. 그래서 우리가 asm을 쓰는 것이다.