Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CLR-Unhook — Los productos de seguridad modernos (CrowdStrike, Bitdefender, SentinelOne, etc.) enganchan la función nLoadImage dentro de clr.dll para interceptar y escanear cargas de ensamblados .NET en memoria. Esta herramienta desengancha esa función. | Kitploit
Herramientas/GitHubGitHub/hwbp/clr-unhook
Herramientas DefensivasExplotaciónPost-ExplotaciónPruebas de PenetraciónRed TeamingDesarrollo de Payloads
GitHubhwbp/clr-unhook

CLR-Unhook

Los productos de seguridad modernos (CrowdStrike, Bitdefender, SentinelOne, etc.) enganchan la función nLoadImage dentro de clr.dll para interceptar y escanear cargas de ensamblados .NET en memoria. Esta herramienta desengancha esa función.

Ver Repositorio
217221hace 9 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

Herramienta de Desenganche de CLR

  • Nota: Para que esto tenga el efecto de un CLR limpio, necesitarías mapear manualmente la DLL desde el disco a la memoria. No puedes usar LoadLibraryA/W, porque las soluciones antivirus detectarán el evento de carga de DLL y pueden engancharlo inmediatamente. Si deseas este comportamiento, puedes buscar mapeadores manuales existentes en GitHub e integrar uno en tu base de código. No incluyo uno aquí, ya que los proveedores de antivirus generalmente no aprecian eso.

Una utilidad nativa en C++ que evita los ganchos (hooks) de EDR/AV en el Common Language Runtime de .NET restaurando la implementación original de la función nLoadImage.

Descripción Rápida

Esta herramienta elimina los ganchos de productos de seguridad de la función nLoadImage del CLR, el punto de entrada nativo crítico que maneja toda la carga de ensamblados .NET en memoria. Al leer la clr.dll limpia desde el disco y sobrescribir los bytes de la función enganchada en memoria, restaura el comportamiento original del CLR, permitiendo que Assembly.Load(byte[]) se ejecute sin inspección ni escaneo del EDR.

¿Qué Hace Esto?

Los productos de seguridad modernos (BitDefender, CrowdStrike, SentinelOne, etc.) enganchan la función nLoadImage dentro de clr.dll para interceptar y escanear las cargas de ensamblados .NET en memoria. Esta herramienta desengancha esa función:

  1. Leyendo la clr.dll limpia del disco
  2. Encontrando los bytes originales de nLoadImage
  3. Sobrescribiendo la versión enganchada en memoria

Después del desenganche, Assembly.Load(byte[]) se ejecuta sin inspección del EDR.

Entendiendo nLoadImage

nLoadImage es la función nativa crítica que maneja todas las cargas de ensamblados en memoria en el runtime de .NET. Está declarada como un InternalCall en código administrado, lo que significa que no tiene implementación en C#; en cambio, es un puente directo al código nativo del CLR.

La Cadena de Llamadas:

root@kitploit:~
Código Administrado (C#)
    ↓
Assembly.Load(byte[])
    ↓
RuntimeAssembly.nLoadImage(...) [InternalCall - sin cuerpo administrado]
    ↓
clr.dll!AssemblyNative::LoadImage (Implementación nativa en C++)
    ↓
Ensamblado cargado en AppDomain

Por Qué es Crítico:

Casi todas las cargas de ensamblados en memoria pasan por nLoadImage. El método Assembly.Load(byte[]) y sus sobrecargas (incluyendo la carga con bytes de símbolos) invocan a nLoadImage internamente. Cuando llamas a Assembly.Load(byte[]), el código administrado en mscorlib.dll pasa tu arreglo de bytes a través de RuntimeAssembly.nLoadImage(), que está marcado con [MethodImpl(MethodImplOptions.InternalCall)] - lo que significa que su cuerpo está vacío en C# y la ejecución salta inmediatamente al código nativo del CLR.

Incluso los escenarios de generación dinámica de código - frameworks de serialización que emiten ensamblados en tiempo de ejecución, generación de serializadores XML, y herramientas de red team como execute-assembly de Cobalt Strike - todos pasan por esta única función.

Implementación Nativa:

El stub InternalCall de nLoadImage en mscorlib.dll apunta a la función nativa C++ AssemblyNative::LoadImage dentro de clr.dll. Esta función:

  • Analiza los encabezados PE del arreglo de bytes
  • Valida los metadatos y el código IL
  • Asigna memoria para el ensamblado
  • Registra el ensamblado en el AppDomain
  • Desencadena eventos posteriores a la carga (ETW, escaneo AMSI en .NET 4.8+)
  • Maneja ensamblados en modo mixto (nativo + administrado)
  • Aplica la verificación de nombre seguro

En .NET Framework 4.8+, cada llamada a nLoadImage pasa automáticamente los bytes del ensamblado a AMSI de Windows Defender (AmsiScanBuffer) para escaneo antes de la ejecución, convirtiéndolo en un punto de estrangulamiento crítico para los productos de seguridad.

Firma de la Función (.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
);

Cuando llamas a Assembly.Load(byte[]), invoca nLoadImage con estos parámetros típicos:

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
);

El parámetro fIntrospection controla si el ensamblado se carga para ejecución (false) o solo para inspección por reflexión (true). El método Assembly.ReflectionOnlyLoad(byte[]) llama a nLoadImage con fIntrospection=true, permitiendo el examen de metadatos sin ejecución de código.

Por Qué lo Enganchan los EDR:

Dado que nLoadImage es el único punto de entrada para todas las cargas de ensamblados en memoria, los productos EDR lo enganchan a nivel nativo en clr.dll. Esto les permite:

  • Inspeccionar cada ensamblado antes de que se cargue
  • Escanear arreglos de bytes en busca de patrones maliciosos
  • Bloquear la ejecución antes de que .NET siquiera procese el ensamblado
  • Omitir técnicas de evasión de AMSI/ETW (ya que el gancho está por debajo de esas capas)

Las soluciones tradicionales (parcheo de AMSI, desactivación de ETW) no afectan los ganchos a nivel de CLR porque operan en un nivel superior en la pila. El gancho ocurre dentro del propio CLR, antes de que AMSI siquiera sea invocado.

Uso

Proceso Local (Proceso Actual)

root@kitploit:~
CLRUnhook.exe

Desengancha el CLR en el proceso actual. Nota: Esto solo funciona si el CLR ya está cargado (es decir, ejecutándose desde una aplicación .NET o después de cargar el CLR manualmente).

Proceso Remoto (Apuntar a Otro Proceso)

root@kitploit:~
CLRUnhook.exe powershell.exe

CLRUnhook.exe 1234

Desengancha el CLR en un proceso remoto.

Ejemplo de Salida

Desenganche Remoto Exitoso

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...

La Cadena de Ganchos

root@kitploit:~
Managed Code (C#)
    ↓
Assembly.Load(byte[])
    ↓
RuntimeAssembly.nLoadImage(...) [InternalCall]
    ↓
clr.dll!AssemblyNative::LoadImage
    ↓
[EDR HOOK] ← We bypass this
    ↓
Original CLR Code

El Proceso de Desenganche

  1. Localizar función enganchada - Encuentra nLoadImage en la clr.dll cargada (actualmente enganchada)
  2. Cargar copia limpia - Lee la clr.dll original desde C:\Windows\Microsoft.NET\Framework64\v4.0.30319\
  3. Extraer bytes limpios - Obtiene los primeros 30 bytes de la función original, .NET es JIT, no queremos tener problemas.
  4. Sobrescribir gancho - Parchea la versión enganchada con bytes limpios

Descubrimiento de la Función

Utiliza escaneo de patrones para localizar nLoadImage:

  1. Buscar la cadena "nLoadImage" en la memoria del módulo
  2. Encontrar el puntero a esa cadena
  3. Localizar el puntero de función adyacente al puntero de cadena
  4. Validar que la dirección esté dentro de los límites del módulo

Créditos

Investigación de la Técnica:

  • Matthew Graeber (@mattifestation) - Ingeniería inversa de métodos InternalCall e internos del CLR

Implementación:

  • HWBP - Desenganche del CLR mediante restauración de memoria
  • @Evilbytecode - Me ayudó con el desenganche, tuve algunos problemas con .NET siendo JIT.

Aviso Legal

SOLO PARA FINES EDUCATIVOS E INVESTIGACIÓN DE SEGURIDAD AUTORIZADA.

El uso no autorizado de esta herramienta para eludir controles de seguridad puede violar las leyes de fraude informático (CFAA, estatutos equivalentes). Úselo solo en sistemas que posea o para los que tenga permiso explícito por escrito para realizar pruebas.

Referencias

  • Reverse Engineering InternalCall Methods - Matthew Graeber
  • Microsoft .NET Reference Source
  • Documentación de la canalización de carga de ensamblados de CLR

Descargar herramienta