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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CLR-Unhook — 현대 보안 제품(CrowdStrike, Bitdefender, SentinelOne 등)은 clr.dll 내의 nLoadImage 함수를 후킹하여 메모리 내 .NET 어셈블리 로드를 가로채서 스캔합니다. 이 도구는 해당 함수의 후킹을 해제합니다. | Kitploit
도구/GitHubGitHub/hwbp/clr-unhook
Defensive ToolsExploitationPost-ExploitationPenetration TestingRed TeamingPayload Development
GitHubhwbp/clr-unhook

CLR-Unhook

현대 보안 제품(CrowdStrike, Bitdefender, SentinelOne 등)은 clr.dll 내의 nLoadImage 함수를 후킹하여 메모리 내 .NET 어셈블리 로드를 가로채서 스캔합니다. 이 도구는 해당 함수의 후킹을 해제합니다.

저장소 보기
217228개월 전Kitploit 검토 완료

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CLR 언후킹 도구

  • 참고: 깨끗한 CLR 효과를 보려면 디스크에서 DLL을 수동으로 메모리에 매핑해야 합니다. LoadLibraryA/W를 사용할 수 없습니다. 안티바이러스 솔루션이 DLL 로드 이벤트를 감지하고 즉시 후킹할 수 있기 때문입니다. 이 동작을 원한다면 GitHub에 있는 기존 수동 매퍼를 찾아 코드베이스에 통합할 수 있습니다. AV 업체들이 일반적으로 이를 좋아하지 않기 때문에 여기에는 포함하지 않았습니다.

.NET 공용 언어 런타임에서 원래 nLoadImage 함수 구현을 복원하여 EDR/AV 후크를 우회하는 네이티브 C++ 유틸리티입니다.

간단한 설명

이 도구는 CLR의 nLoadImage 함수에서 보안 제품 후크를 제거합니다. nLoadImage는 모든 인메모리 .NET 어셈블리 로딩을 처리하는 중요한 네이티브 진입점입니다. 디스크에서 깨끗한 clr.dll을 읽고, 메모리에서 후킹된 함수 바이트를 덮어씀으로써 원래 CLR 동작을 복원하여 Assembly.Load(byte[])가 EDR 검사나 스캔 없이 실행되도록 합니다.

이 도구의 기능

최신 보안 제품(BitDefender, CrowdStrike, SentinelOne 등)은 clr.dll 내부의 nLoadImage 함수를 후킹하여 인메모리 .NET 어셈블리 로드를 가로채고 스캔합니다. 이 도구는 다음 단계로 해당 함수를 언후킹합니다:

  1. 디스크에서 깨끗한 clr.dll 읽기
  2. 원래 nLoadImage 바이트 찾기
  3. 메모리에서 후킹된 버전 덮어쓰기

언후킹 후, Assembly.Load(byte[])는 EDR 검사 없이 실행됩니다.

nLoadImage 이해

nLoadImage는 .NET 런타임에서 모든 인메모리 어셈블리 로딩을 처리하는 중요한 네이티브 함수입니다. 관리 코드에서 InternalCall로 선언되어, C# 구현이 없으며 대신 네이티브 CLR 코드로의 직접 브리지 역할을 합니다.

호출 체인:

root@kitploit:~
Managed Code (C#)
    ↓
Assembly.Load(byte[])
    ↓
RuntimeAssembly.nLoadImage(...) [InternalCall - managed body 없음]
    ↓
clr.dll!AssemblyNative::LoadImage (Native C++ 구현)
    ↓
Assembly loaded into AppDomain

중요한 이유:

거의 모든 인메모리 어셈블리 로드는 nLoadImage를 거칩니다. Assembly.Load(byte[]) 메서드와 그 오버로드(심볼 바이트 로딩 포함)는 모두 내부적으로 nLoadImage를 호출합니다. Assembly.Load(byte[])를 호출하면 mscorlib.dll의 관리 코드가 RuntimeAssembly.nLoadImage()에 바이트 배열을 전달하는데, 이 메서드는 [MethodImpl(MethodImplOptions.InternalCall)]로 표시되어 있어 C#에서는 본문이 비어 있고 실행이 즉시 네이티브 CLR 코드로 점프합니다.

런타임에 어셈블리를 생성하는 직렬화 프레임워크, XML 직렬화 생성기, Cobalt Strike의 execute-assembly와 같은 동적 코드 생성 시나리오도 모두 이 단일 함수를 통과합니다.

네이티브 구현:

mscorlib.dll의 nLoadImage InternalCall 스텁은 clr.dll 내부의 네이티브 C++ 함수 AssemblyNative::LoadImage를 가리킵니다. 이 함수는:

  • 바이트 배열에서 PE 헤더를 파싱합니다
  • 메타데이터와 IL 코드를 검증합니다
  • 어셈블리용 메모리를 할당합니다
  • AppDomain에 어셈블리를 등록합니다
  • 로드 후 이벤트(ETW, .NET 4.8+에서 AMSI 스캐닝)를 트리거합니다
  • 혼합 모드 어셈블리(네이티브 + 관리)를 처리합니다
  • 강력한 이름 검증을 적용합니다

.NET Framework 4.8+에서는 모든 nLoadImage 호출이 실행 전에 자동으로 어셈블리 바이트를 Windows Defender의 AMSI(AmsiScanBuffer)에 전달하여 스캔하므로, 보안 제품에 중요한 병목 지점이 됩니다.

함수 시그니처 (.NET Framework 4.7+):

root@kitploit:~
[MethodImpl(MethodImplOptions.InternalCall)]
static internal extern Assembly nLoadImage(
    byte[] rawAssembly,              // PE bytes
    byte[] rawSymbolStore,           // Optional PDB bytes
    Evidence evidence,               // CAS evidence (obsolete)
    ref StackCrawlMark stackMark,    // Security stack marker
    bool fIntrospection,             // Reflection-only flag
    bool fSkipIntegrityCheck,        // Skip integrity validation
    SecurityContextSource securityContextSource  // Security context
);

Assembly.Load(byte[])를 호출하면 nLoadImage가 일반적으로 다음과 같은 매개변수로 호출됩니다:

root@kitploit:~
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return RuntimeAssembly.nLoadImage(
    rawAssembly,                            // Your byte array
    null,                                   // rawSymbolStore
    null,                                   // evidence
    ref stackMark,                          // LookForMyCaller
    false,                                  // fIntrospection
    SecurityContextSource.CurrentAssembly   // securityContextSource
);

fIntrospection 매개변수는 어셈블리가 실행용(false)으로 로드되는지 아니면 리플렉션 전용 검사(true)로 로드되는지를 제어합니다. Assembly.ReflectionOnlyLoad(byte[]) 메서드는 fIntrospection=true로 nLoadImage를 호출하여 코드 실행 없이 메타데이터 검사를 허용합니다.

EDR이 후킹하는 이유:

nLoadImage는 인메모리 어셈블리 로드의 단일 진입점이므로, EDR 제품은 clr.dll의 네이티브 수준에서 이를 후킹합니다. 이를 통해:

  • 로드되기 전에 모든 어셈블리 검사
  • 악성 패턴에 대한 바이트 배열 스캔
  • .NET이 어셈블리를 처리하기 전에 실행 차단
  • AMSI/ETW 우회 기술 우회 (후크가 해당 계층 아래에 있으므로)

기존 우회 방법(AMSI 패칭, ETW 비활성화)은 CLR 수준 후크에 영향을 주지 않습니다. 후크가 AMSI가 호출되기 전, CLR 내부에서 발생하기 때문입니다.

사용법

로컬 프로세스 (현재 프로세스)

root@kitploit:~
CLRUnhook.exe

현재 프로세스에서 CLR을 언후킹합니다. 참고: CLR이 이미 로드된 경우에만 작동합니다(.NET 애플리케이션에서 실행 중이거나 CLR을 수동으로 로드한 경우).

원격 프로세스 (다른 프로세스 대상)

root@kitploit:~
CLRUnhook.exe powershell.exe

CLRUnhook.exe 1234

원격 프로세스에서 CLR을 언후킹합니다.

출력 예시

성공적인 원격 언후킹

root@kitploit:~
=== CLR Unhooking Tool ===

[*] Mode -> Remote Process Unhooking
[*] Target -> PID 21436
[+] Found PID -> 21436
[*] Unhooking CLR->nLoadImage in remote process...
[DEBUG] Remote mode enabled
[DEBUG] Found clr.dll at 0x00007FFD38CB0000
[DEBUG] CLR path -> C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
[DEBUG] CLR module size -> 10108928 bytes
[DEBUG] Read 10108928 bytes from remote process
[DEBUG] Searching for 'nLoadImage' in module (size: 10108928)
[DEBUG] Remote base address: 0x00007FFD38CB0000
[DEBUG] Scanning for string 'nLoadImage' (11 bytes)...
[DEBUG] Found string at RVA 0x7c12b8
[DEBUG] Searching for remote pointer: 0x7ffd394712b8
[DEBUG] Found pointer at offset 0x7a4340
[DEBUG] Valid function pointer found at RVA 0x5e4f30
[DEBUG] Found nLoadImage at RVA 0x00000000005E4F30
[DEBUG] Hooked function address -> 0x00007FFD39294F30
[DEBUG] Clean function at offset 0x00000000005E4F30 in disk file
[DEBUG] Reading hooked bytes before patch...
[DEBUG] First 16 bytes BEFORE unhook:
       4C 8B DC 49 89 5B 08 49 89 73 10 4D 89 4B 20 57
[DEBUG] Clean bytes from disk:
       8B 4B 78 E8 88 A9 EA FF C6 44 24 28 00 80 3D A4
[DEBUG] Wrote 30 bytes successfully
[DEBUG] First 16 bytes AFTER unhook:
       8B 4B 78 E8 88 A9 EA FF C6 44 24 28 00 80 3D A4
[DEBUG] VERIFICATION SUCCESS: Patched bytes match clean bytes!
[+] SUCCESS -> CLR nLoadImage unhooked in remote process!
[+] EDR/AV hooks bypassed

[*] Press Enter to exit...

후크 체인

root@kitploit:~
Managed Code (C#)
    ↓
Assembly.Load(byte[])
    ↓
RuntimeAssembly.nLoadImage(...) [InternalCall]
    ↓
clr.dll!AssemblyNative::LoadImage
    ↓
[EDR HOOK] ← 우리가 우회하는 부분
    ↓
Original CLR Code

언후킹 과정

  1. 후킹된 함수 찾기 - 로드된 clr.dll에서 nLoadImage를 찾습니다 (현재 후킹된 상태)
  2. 깨끗한 복사본 로드 - C:\Windows\Microsoft.NET\Framework64\v4.0.30319\에서 원본 clr.dll을 읽습니다
  3. 깨끗한 바이트 추출 - 원래 함수의 처음 30바이트를 가져옵니다 (.NET은 JIT 방식이므로 문제를 방지하기 위함)
  4. 후크 덮어쓰기 - 후킹된 버전을 깨끗한 바이트로 패치합니다

함수 발견

패턴 스캐닝을 사용하여 nLoadImage를 찾습니다:

  1. 모듈 메모리에서 "nLoadImage" 문자열 검색
  2. 해당 문자열을 가리키는 포인터 찾기
  3. 문자열 포인터와 인접한 함수 포인터 찾기
  4. 주소가 모듈 범위 내에 있는지 검증

크레딧

기술 연구:

  • Matthew Graeber (@mattifestation) - InternalCall 메서드 및 CLR 내부 역공학

구현:

  • HWBP - 메모리 복원을 통한 CLR 언후킹
  • @Evilbytecode - 언후킹 도움 (JIT 방식의 .NET 관련 문제가 있었음)

면책 조항

교육 및 승인된 보안 연구용으로만 사용하세요.

이 도구를 무단으로 사용하여 보안 통제를 우회하는 경우 컴퓨터 사기 방지법(CFAA 및 동등 법률)을 위반할 수 있습니다. 귀하가 소유하거나 명시적인 서면 허가를 받은 시스템에서만 사용하십시오.

참고 자료

  • Reverse Engineering InternalCall Methods - Matthew Graeber
  • Microsoft .NET Reference Source
  • CLR Assembly Loading Pipeline Documentation

도구 다운로드