> Windows Syscalls
ntoskrnl.exeT1562.001T1106

NtAreMappedFilesTheSame

Determines whether two mapped views are backed by the same file (file object identity test).

Prototype

NTSTATUS NtAreMappedFilesTheSame(
  PVOID File1MappedAsAnImage,
  PVOID File2MappedAsFile
);

Arguments

NameTypeDirDescription
File1MappedAsAnImagePVOIDinPointer inside a view that was mapped with SEC_IMAGE (typically a loaded DLL/EXE base).
File2MappedAsFilePVOIDinPointer inside a view that was mapped from a regular file mapping (any section type).

Syscall IDs by Windows version

Windows versionSyscall IDBuild
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

Kernel module

ntoskrnl.exeNtAreMappedFilesTheSame

Related APIs

NtCreateSectionNtMapViewOfSectionNtMapViewOfSectionExGetModuleHandleWLoadLibraryExW

Syscall stub

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

Undocumented notes

A small but surprisingly load-bearing helper: the kernel walks `MM_SECTION_OBJECT_POINTERS` for both addresses, compares the underlying `FILE_OBJECT` (or, more precisely, the `SectionObjectPointer`s), and returns `STATUS_SUCCESS` when they refer to the same backing file — even if the two views differ in attributes (one as image, the other as data), in protection, in size, or in offset. The two arguments are *named* asymmetrically (Image vs File) for historical reasons; in practice either may be either, and the comparison is symmetric.

Common malware usage

Cuts both ways. **Defensive (and EDR) use**: open `\KnownDlls\ntdll.dll`, map a fresh copy as a file, then call `NtAreMappedFilesTheSame(LoadedNtdllBase, FreshlyMappedNtdll)`. If the answer is *same*, the loaded ntdll has the same backing file — defenders then byte-compare the `.text` sections to discover inline EDR/AV hooks and overwrite them with the pristine bytes. This is the foundation of every modern unhooking primitive (Perun's Fart, FreshyCalls, SysWhispers3 +unhook, RefleXXion). **Offensive use**: an implant that has been **DLL-hollowed** (its module image overwritten in memory while the underlying file is unchanged) can call this against itself to detect tampering — symmetric self-defense against blue-team unhookers. Some sandbox-evasion checks also use this call to confirm a loaded DLL really comes from `\System32\` rather than a redirected attacker copy.

Detection opportunities

Almost no detection signal of its own: the syscall is rare in benign software but increasingly common in security tooling (Defender, CrowdStrike, SentinelOne all hit it during unhook-comparison). The strong signal is *pairing*: a process that opens `\KnownDlls\ntdll.dll` (or maps any system DLL from `\System32`) and then immediately calls `NtAreMappedFilesTheSame` against its own loaded ntdll is performing an unhooking dance. EDR vendors increasingly self-protect by removing identification-by-section-identity tricks — if the call returns same on a DLL that the EDR expects to differ, the EDR can detect *that* and respond.

Direct syscall examples

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

MITRE ATT&CK mappings

Last verified: 2026-05-20