> Windows Syscalls
ntoskrnl.exeT1562.001T1106

NtAreMappedFilesTheSame

Determina si dos vistas mapeadas están respaldadas por el mismo fichero (prueba de identidad de file object).

Prototipo

NTSTATUS NtAreMappedFilesTheSame(
  PVOID File1MappedAsAnImage,
  PVOID File2MappedAsFile
);

Argumentos

NameTypeDirDescription
File1MappedAsAnImagePVOIDinPuntero dentro de una vista mapeada con SEC_IMAGE (típicamente una base de DLL/EXE cargada).
File2MappedAsFilePVOIDinPuntero dentro de una vista mapeada desde un mapping de fichero regular (cualquier tipo de sección).

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070x8Awin10-1507
Win10 16070x8Awin10-1607
Win10 17030x8Bwin10-1703
Win10 17090x8Bwin10-1709
Win10 18030x8Cwin10-1803
Win10 18090x8Cwin10-1809
Win10 19030x8Cwin10-1903
Win10 19090x8Cwin10-1909
Win10 20040x8Ewin10-2004
Win10 20H20x8Ewin10-20h2
Win10 21H10x8Ewin10-21h1
Win10 21H20x8Ewin10-21h2
Win10 22H20x8Ewin10-22h2
Win11 21H20x8Ewin11-21h2
Win11 22H20x8Ewin11-22h2
Win11 23H20x8Ewin11-23h2
Win11 24H20x90win11-24h2
Server 20160x8Awinserver-2016
Server 20190x8Cwinserver-2019
Server 20220x8Ewinserver-2022
Server 20250x90winserver-2025

Módulo del kernel

ntoskrnl.exeNtAreMappedFilesTheSame

APIs relacionadas

NtCreateSectionNtMapViewOfSectionNtMapViewOfSectionExGetModuleHandleWLoadLibraryExW

Stub del syscall

4C 8B D1            mov r10, rcx
B8 90 00 00 00      mov eax, 0x90      ; Win11 24H2 SSN
F6 04 25 08 03 FE 7F 01   test byte ptr [0x7FFE0308], 1
75 03               jne short +3
0F 05               syscall
C3                  ret
CD 2E               int 2Eh
C3                  ret

Notas no documentadas

Una pequeña ayuda sorprendentemente importante: el kernel recorre los `MM_SECTION_OBJECT_POINTERS` de ambas direcciones, compara el `FILE_OBJECT` subyacente (más exactamente los `SectionObjectPointer`) y devuelve `STATUS_SUCCESS` cuando se refieren al mismo fichero de backing — incluso si las dos vistas difieren en atributos (una como imagen, otra como datos), en protección, en tamaño o en offset. Los dos argumentos están *nombrados* de forma asimétrica (Image vs File) por motivos históricos; en la práctica cualquiera puede ser de cualquier tipo y la comparación es simétrica.

Uso común por malware

Funciona en ambos bandos. **Uso defensivo (y de EDR)**: abrir `\KnownDlls\ntdll.dll`, mapear una copia fresca como fichero, luego llamar `NtAreMappedFilesTheSame(LoadedNtdllBase, FreshNtdllMap)`. Si la respuesta es *misma*, la ntdll cargada tiene el mismo fichero de backing — los defensores comparan entonces byte a byte las secciones `.text` para descubrir hooks inline de EDR/AV y sobrescribirlos con los bytes prístinos. Es la base de toda primitiva de unhooking moderna (Perun's Fart, FreshyCalls, SysWhispers3 +unhook, RefleXXion). **Uso ofensivo**: un implante **DLL-hollowed** (su imagen de módulo sobrescrita en memoria mientras el fichero permanece intacto) puede llamarse contra sí mismo para detectar manipulación — autodefensa simétrica contra los unhookers blue-team. Algunas verificaciones de evasión de sandbox también usan esta llamada para confirmar que una DLL cargada realmente proviene de `\System32\` y no de una copia redirigida del atacante.

Oportunidades de detección

Casi sin señal de detección propia: el syscall es raro en software benigno pero cada vez más común en herramientas de seguridad (Defender, CrowdStrike, SentinelOne lo invocan todos durante comparaciones de unhooking). La señal fuerte es el *pairing*: un proceso que abre `\KnownDlls\ntdll.dll` (o mapea cualquier DLL del sistema desde `\System32`) e inmediatamente llama a `NtAreMappedFilesTheSame` contra su propia ntdll cargada está realizando una danza de unhooking. Los proveedores EDR se autoprotegen cada vez más eliminando trucos de identificación por identidad de sección — si la llamada devuelve same sobre una DLL que el EDR espera distinta, el EDR puede detectar *eso* y responder.

Ejemplos de syscalls directos

cVerify a fresh ntdll maps the same file as the loaded one

// Defender / red-team unhooking helper.
HANDLE hSection = OpenSectionByName(L"\\KnownDlls\\ntdll.dll");
PVOID  freshBase = NULL; SIZE_T viewSize = 0;
NtMapViewOfSection(hSection, NtCurrentProcess(),
                   &freshBase, 0, 0, NULL, &viewSize,
                   ViewShare, 0, PAGE_READONLY);

PVOID loadedNtdll = GetModuleHandleW(L"ntdll.dll");

if (NtAreMappedFilesTheSame(loadedNtdll, freshBase) == STATUS_SUCCESS) {
    // Same backing file: safe to byte-compare and unhook .text.
    PatchTextSectionFromFresh(loadedNtdll, freshBase);
}

asmx64 direct stub (Win11 24H2)

; NtAreMappedFilesTheSame direct stub — SSN 0x90 on Win11 24H2
NtAreMappedFilesTheSame PROC
    mov  r10, rcx
    mov  eax, 90h
    syscall
    ret
NtAreMappedFilesTheSame ENDP

rustSelf-check for DLL hollowing

// An implant uses this call to detect that its own module image was
// overwritten in memory (DLL hollowing) — the section identity persists
// even if the bytes changed.
use ntapi::ntmmapi::NtAreMappedFilesTheSame;
use winapi::shared::ntdef::PVOID;

unsafe fn module_was_hollowed(loaded: PVOID, fresh: PVOID) -> bool {
    let s = NtAreMappedFilesTheSame(loaded, fresh);
    if s != 0 {
        // Section identity differs — module image has been replaced.
        return true;
    }
    // Same section: byte-compare to decide if .text was rewritten.
    text_section_differs(loaded, fresh)
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20