> Windows Syscalls
ntoskrnl.exeT1562.001T1106

NtAreMappedFilesTheSame

Prüft, ob zwei gemappte Views durch dieselbe Datei gestützt werden (Identitätstest des File-Objekts).

Prototyp

NTSTATUS NtAreMappedFilesTheSame(
  PVOID File1MappedAsAnImage,
  PVOID File2MappedAsFile
);

Argumente

NameTypeDirDescription
File1MappedAsAnImagePVOIDinZeiger innerhalb einer mit SEC_IMAGE gemappten View (typischerweise Basis einer geladenen DLL/EXE).
File2MappedAsFilePVOIDinZeiger innerhalb einer aus einem regulären Datei-Mapping gemappten View (beliebiger Section-Typ).

Syscall-IDs pro 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-Modul

ntoskrnl.exeNtAreMappedFilesTheSame

Verwandte 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

Undokumentierte Hinweise

Ein kleiner, aber überraschend tragender Helper: der Kernel läuft `MM_SECTION_OBJECT_POINTERS` für beide Adressen ab, vergleicht das zugrundeliegende `FILE_OBJECT` (genauer die `SectionObjectPointer`s) und liefert `STATUS_SUCCESS`, wenn beide auf dieselbe Backing-Datei verweisen — selbst wenn die zwei Views in Attributen (eine als Image, die andere als Data), in Schutz, Größe oder Offset abweichen. Die beiden Argumente sind aus historischen Gründen asymmetrisch *benannt* (Image vs File); in der Praxis darf jedes von jeder Sorte sein, und der Vergleich ist symmetrisch.

Häufige Malware-Nutzung

Spielt in beiden Lagern. **Defensive (und EDR-) Nutzung**: `\KnownDlls\ntdll.dll` öffnen, frische Kopie als Datei mappen, dann `NtAreMappedFilesTheSame(LoadedNtdllBase, FreshNtdllMap)` aufrufen. Lautet die Antwort *gleich*, hat die geladene ntdll dieselbe Backing-Datei — Verteidiger vergleichen dann die `.text`-Sektionen byteweise, um Inline-EDR/AV-Hooks zu finden und mit den unberührten Bytes zu überschreiben. Das ist das Fundament jeder modernen Unhooking-Primitive (Perun's Fart, FreshyCalls, SysWhispers3 +unhook, RefleXXion). **Offensive Nutzung**: ein **DLL-hollowed** Implant (sein Modul-Image im Speicher überschrieben, während die Datei unverändert ist) kann den Aufruf gegen sich selbst tätigen, um Manipulation zu erkennen — symmetrische Selbstverteidigung gegen Blue-Team-Unhooker. Einige Sandbox-Evasion-Checks bestätigen damit, dass eine geladene DLL tatsächlich aus `\System32\` stammt und nicht aus einer umgeleiteten Angreiferkopie.

Erkennungs­möglichkeiten

Praktisch kein eigenes Detection-Signal: der Syscall ist in gutartiger Software selten, in Security-Tooling aber zunehmend gängig (Defender, CrowdStrike, SentinelOne treffen ihn alle beim Unhook-Vergleich). Das starke Signal ist das *Pairing*: ein Prozess, der `\KnownDlls\ntdll.dll` öffnet (oder eine beliebige System-DLL aus `\System32` mappt) und dann sofort `NtAreMappedFilesTheSame` gegen seine eigene geladene ntdll aufruft, vollzieht einen Unhooking-Tanz. EDR-Anbieter schützen sich zunehmend selbst, indem sie Identifikation-per-Section-Identity-Tricks entfernen — liefert der Aufruf *gleich* für eine DLL, von der der EDR Unterschied erwartet, kann der EDR genau *das* erkennen und reagieren.

Direkte Syscall-Beispiele

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