Tuesday, September 3, 2019

NTFS Timestamps vs Memory Mapped File

TL;DR: Memory Mapped File I/O overwrites file content without changing any timestamp in $STANDARD_INFORMATION, and $FILE_NAME attributes.

During my recent job interview, a question about NTFS timestamps took me by surprise. Should admit, I never took file timestamps (without regards to NTFS) as the credential source of information about actual file creation/modification date/time. Traditionally, users, without any specific permissions, were able to alter file timestamps. For example, allegedly the very first PC virus Vienna used timestamp with 62 seconds value as an indicator of the already infected file. Timestamps may "drift" due to the timezone or daylight saving changes. In other words, for me, they were falling into the intelligence category ("if it were a fact, it wouldn't be called intelligence"). Well, enough of my preconceptions, let's check NTFS.

There are plenty of good resources about NTFS timestamps, and their usage in forensic analysis. I linked some of them which I found interesting.

Long story short, four timestamps per MFT file attribute - file creation, modification, access (in most cases not updated by OS), and modification of attribute itself. One $STANDARD_INFORMATION (later $SI) attribute, and at least one $FILE_NAME (later $FN) attribute per file, so at least eight timestamps per file. User mode Windows API (like GetFileTime and SetFileTime) let you get or set only creation, modification, and access timestamps in the $SI attribute only.

As the most simple thing first, I am interested in the modification of an already existing file. Apparently, there is no legit way (without direct disk access, OS exploit, etc.) to change the file content without altering the NTFS timestamps or metadata. I guess it shouldn't be a surprise what my first bet for this task is the Memory Mapped File I/O. Just as a short intro, Memory Mapped File I/O is the part of user mode Windows API which let you map a file (or part of it) into the process memory, so all changes in the memory will be reflected in a file on disk (at some moment). It's the fascinating feature (especially for a lazy programmer) with many applications (and implications), and there are some suggestions what it may do the trick (at least sometimes).

I did the preliminary research test on Windows 7 x64 build 7601, with subsequent verification on Windows 10 x64 build 1907. The file content modification is "x = x + 127" for every byte of file or its part. There are two significant observations:

  1. Memory Mapped File I/O lets you overwrite file content without changing any timestamp in the $SI, and $FN attributes. During tests with the file size up to 200MB, I didn't come across any case of timestamp change.
  2. There is the odd situation with the Log Sequence Number (LSN) value. If you don't overwrite the very last memory page (the very last "FileSize % (remainder) PageSize (4096 by default)" bytes of the file), the LSN value stays unchanged. The test program is trying to skip the very last page unless file size is less than 4096.

I guess, the obvious todos are: check LSN, and USN journal records for the related file change operations; check the same scenarios with the Large-Page enabled (starting with Windows 10, build 1703).

The test program takes one command-line argument - file name, there is no support for a file name wildcards. In case of success, the output is: "file name": altered region size(file size).

// TouchFile.cpp

#include <Windows.h>

HANDLE hStdOutput;
CHAR cFileBuffer[65536];
DWORD nNumberOfBytesWritten;

int main() {
  if ((hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)) != INVALID_HANDLE_VALUE) {
    int argc = 0;
    if (LPWSTR * argv = CommandLineToArgvW(GetCommandLineW(), &argc)) {
      if (1 < argc) {
        HANDLE hFile;
        if ((hFile = CreateFileW(argv[1], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)) != INVALID_HANDLE_VALUE) {
          if (HANDLE hFileMappingObject = CreateFileMappingW(hFile, 0, PAGE_READWRITE, 0, 0, 0)) {
            if (LPVOID lpBaseAddress = MapViewOfFile(hFileMappingObject, FILE_MAP_WRITE, 0, 0, 0)) {
              DWORD dwFileSize = GetFileSize(hFile, 0), dwTouchSize = 4096 < dwFileSize ? dwFileSize & ~4095 : dwFileSize;
              for (DWORD i = 0; i < dwTouchSize; i++) reinterpret_cast<BYTE*>(lpBaseAddress)[i] += 127;
              UnmapViewOfFile(lpBaseAddress);
              WriteFile(hStdOutput, cFileBuffer, wsprintfA(cFileBuffer, "\"%S\": %u(%u)\n", argv[1], dwTouchSize, dwFileSize), &nNumberOfBytesWritten, 0);
            }
            CloseHandle(hFileMappingObject);
          }
          CloseHandle(hFile);
        }
      }
      GlobalFree(argv);
    }
  }
  ExitProcess(0);
}

x64 build: TouchFile.7z, SHA1(TouchFile.exe)= c6f1f1c0adfb2bb7fdefc69165f765ebed55cbe8

Verification configuration: HP EliteBook 8730w, RAM 8GB, HDD OCZ-VERTEX4 512GB; Windows 10 x64 build 1907, clean install, default settings, all recommended updates (2019-08-30), offline user, no network connection; USB boot: Kali Linux Live 2019.2 (forensic mode), The Sleuth Kit 4.6.5. Verification scenario:

  1. Boot Windows: "xcopy /e /i ..." folder with test files (file size: 4095, 4096, 3MB), "certutil -hashfile ..." for file SHA1
  2. Boot Linux: "fls -i raw -f ntfs /dev/sda2 ...", "istat -i raw -f ntfs /dev/sda2 ..." for file metadata
  3. Boot Windows: "TouchFile ..." for file content overwrite
  4. Boot Linux: "istat -i raw -f ntfs /dev/sda2 ..." for file metadata
  5. Boot Windows: "certutil.exe -hashfile ..." for file SHA1
BeforeAfter
SHA1 C:\TestFolder\TestFile4095.tst 4c1732511805221435db376b8cbad7d0debf72cf

MFT Entry Header Values:
Entry: 124888        Sequence: 13
$LogFile Sequence Number: 537362867
Allocated File
Links: 2

$STANDARD_INFORMATION Attribute Values:
Flags: Archive
Owner ID: 0
Security ID: 2213  (S-1-5-21-2973299112-457765261-1731413466-1001)
Last User Journal Update Sequence Number: 101740432
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 06:57:40.000000000 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TESTFI~1.TST
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 0    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TestFile4095.tst
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 0    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

Attributes: 
Type: $STANDARD_INFORMATION (16-0)   Name: N/A   Resident   size: 72
Type: $FILE_NAME (48-3)   Name: N/A   Resident   size: 90
Type: $FILE_NAME (48-2)   Name: N/A   Resident   size: 98
Type: $DATA (128-4)   Name: N/A   Non-Resident   size: 4095  init_size: 4095
33536
SHA1 C:\TestFolder\TestFile4095.tst 0dd646c5f8e3f61fa7cad72a68de06cc50d063c8

MFT Entry Header Values:
Entry: 124888        Sequence: 13
$LogFile Sequence Number: 537882948
Allocated File
Links: 2

$STANDARD_INFORMATION Attribute Values:
Flags: Archive
Owner ID: 0
Security ID: 2213  (S-1-5-21-2973299112-457765261-1731413466-1001)
Last User Journal Update Sequence Number: 101740432
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 06:57:40.000000000 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TESTFI~1.TST
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 0    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TestFile4095.tst
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 0    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

Attributes: 
Type: $STANDARD_INFORMATION (16-0)   Name: N/A   Resident   size: 72
Type: $FILE_NAME (48-3)   Name: N/A   Resident   size: 90
Type: $FILE_NAME (48-2)   Name: N/A   Resident   size: 98
Type: $DATA (128-4)  Name: N/A  Non-Resident  size: 4095  init_size: 4095
33536
SHA1 C:\TestFolder\TestFile4096.tst 2b4104c0956ad137b3925920c7b8e4b3fd1df275

MFT Entry Header Values:
Entry: 124893        Sequence: 11
$LogFile Sequence Number: 537362895
Allocated File
Links: 2

$STANDARD_INFORMATION Attribute Values:
Flags: Archive
Owner ID: 0
Security ID: 2213  (S-1-5-21-2973299112-457765261-1731413466-1001)
Last User Journal Update Sequence Number: 101740928
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 06:57:34.000000000 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TESTFI~2.TST
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 4096    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TestFile4096.tst
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 4096    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

Attributes: 
Type: $STANDARD_INFORMATION (16-0)   Name: N/A   Resident   size: 72
Type: $FILE_NAME (48-3)   Name: N/A   Resident   size: 90
Type: $FILE_NAME (48-2)   Name: N/A   Resident   size: 98
Type: $DATA (128-1)   Name: N/A   Non-Resident   size: 4096  init_size: 4096
100611
SHA1 C:\TestFolder\TestFile4096.tst ba31ebd88c9abf4462da0ee43228720ba7775098

MFT Entry Header Values:
Entry: 124893        Sequence: 11
$LogFile Sequence Number: 537362895
Allocated File
Links: 2

$STANDARD_INFORMATION Attribute Values:
Flags: Archive
Owner ID: 0
Security ID: 2213  (S-1-5-21-2973299112-457765261-1731413466-1001)
Last User Journal Update Sequence Number: 101740928
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 06:57:34.000000000 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TESTFI~2.TST
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 4096    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TestFile4096.tst
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 4096    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

Attributes: 
Type: $STANDARD_INFORMATION (16-0)   Name: N/A   Resident   size: 72
Type: $FILE_NAME (48-3)   Name: N/A   Resident   size: 90
Type: $FILE_NAME (48-2)   Name: N/A   Resident   size: 98
Type: $DATA (128-1)   Name: N/A   Non-Resident   size: 4096  init_size: 4096
100611
SHA1 C:\TestFolder\TestFile3516592.tst
f87e2398de1c05a8c7fe7cd97097cdc1b69da6ab

MFT Entry Header Values:
Entry: 124894        Sequence: 11
$LogFile Sequence Number: 537367229
Allocated File
Links: 2

$STANDARD_INFORMATION Attribute Values:
Flags: Archive
Owner ID: 0
Security ID: 2213  (S-1-5-21-2973299112-457765261-1731413466-1001)
Last User Journal Update Sequence Number: 101741440
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 06:59:46.000000000 (UTC)
MFT Modified:  2019-08-31 07:45:13.164794500 (UTC)
Accessed:      2019-08-31 07:45:13.164794500 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TESTFI~3.TST
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 3518464    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TestFile3516592.tst
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 3518464    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

Attributes: 
Type: $STANDARD_INFORMATION (16-0)   Name: N/A   Resident   size: 72
Type: $FILE_NAME (48-3)   Name: N/A   Resident   size: 90
Type: $FILE_NAME (48-2)   Name: N/A   Resident   size: 104
Type: $DATA (128-1) Name: N/A Non-Resident size: 3516592 init_size: 3516592
4363616 4363617 4363618 4363619 4363620 4363621 4363622 4363623 
...
4364464 4364465 4364466 4364467 4364468 4364469 4364470 4364471 
4364472 4364473 4364474
SHA1 C:\TestFolder\TestFile3516592.tst
8623d77cdd8b00e4966ba1056319a1db61aa8ce1

MFT Entry Header Values:
Entry: 124894        Sequence: 11
$LogFile Sequence Number: 537367229
Allocated File
Links: 2

$STANDARD_INFORMATION Attribute Values:
Flags: Archive
Owner ID: 0
Security ID: 2213  (S-1-5-21-2973299112-457765261-1731413466-1001)
Last User Journal Update Sequence Number: 101741440
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 06:59:46.000000000 (UTC)
MFT Modified:  2019-08-31 07:45:13.164794500 (UTC)
Accessed:      2019-08-31 07:45:13.164794500 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TESTFI~3.TST
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 3518464    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TestFile3516592.tst
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 3518464    Actual Size: 0
Created:       2019-08-31 07:45:12.772832300 (UTC)
File Modified: 2019-08-31 07:45:12.772832300 (UTC)
MFT Modified:  2019-08-31 07:45:12.772832300 (UTC)
Accessed:      2019-08-31 07:45:12.772832300 (UTC)

Attributes: 
Type: $STANDARD_INFORMATION (16-0)   Name: N/A   Resident   size: 72
Type: $FILE_NAME (48-3)   Name: N/A   Resident   size: 90
Type: $FILE_NAME (48-2)   Name: N/A   Resident   size: 104
Type: $DATA (128-1) Name: N/A Non-Resident size: 3516592 init_size: 3516592
4363616 4363617 4363618 4363619 4363620 4363621 4363622 4363623 
...
4364464 4364465 4364466 4364467 4364468 4364469 4364470 4364471 
4364472 4364473 4364474
SHA1 C:\TestFolder\TestFile235281024.tst
eb541e876895e8595e4fcb7322c183e7cabad382

MFT Entry Header Values:
Entry: 88106        Sequence: 10
$LogFile Sequence Number: 907469416
Allocated File
Links: 2

$STANDARD_INFORMATION Attribute Values:
Flags: Archive
Owner ID: 0
Security ID: 2213  (S-1-5-21-2973299112-457765261-1731413466-1001)
Last User Journal Update Sequence Number: 113449752
Created:       2019-09-03 09:14:18.591216000 (UTC)
File Modified: 2019-09-01 19:36:28.000000000 (UTC)
MFT Modified:  2019-09-03 09:14:44.548521800 (UTC)
Accessed:      2019-09-03 09:14:44.548521800 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TESTFI~4.TST
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 235282432    Actual Size: 0
Created:       2019-09-03 09:14:18.591216000 (UTC)
File Modified: 2019-09-03 09:14:18.591216000 (UTC)
MFT Modified:  2019-09-03 09:14:18.591216000 (UTC)
Accessed:      2019-09-03 09:14:18.591216000 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TestFile235281024.tst
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 235282432    Actual Size: 0
Created:       2019-09-03 09:14:18.591216000 (UTC)
File Modified: 2019-09-03 09:14:18.591216000 (UTC)
MFT Modified:  2019-09-03 09:14:18.591216000 (UTC)
Accessed:      2019-09-03 09:14:18.591216000 (UTC)

Attributes: 
Type: $STANDARD_INFORMATION (16-0)   Name: N/A   Resident   size: 72
Type: $FILE_NAME (48-3)   Name: N/A   Resident   size: 90
Type: $FILE_NAME (48-2)   Name: N/A   Resident   size: 108
Type: $DATA (128-1) Name: N/A Non-Resident size: 235281024 init_size: 235281024
3959582 3959583 3959584 3959585 3959586 3959587 3959588 3959589 
...
4017014 4017015 4017016 4017017 4017018 4017019 4017020 4017021 
4017022 4017023 
SHA1 C:\TestFolder\TestFile235281024.tst
66817762fe8f32e065ea8c824367bdc8f47a3093

MFT Entry Header Values:
Entry: 88106        Sequence: 10
$LogFile Sequence Number: 907469416
Allocated File
Links: 2

$STANDARD_INFORMATION Attribute Values:
Flags: Archive
Owner ID: 0
Security ID: 2213  (S-1-5-21-2973299112-457765261-1731413466-1001)
Last User Journal Update Sequence Number: 113449752
Created:       2019-09-03 09:14:18.591216000 (UTC)
File Modified: 2019-09-01 19:36:28.000000000 (UTC)
MFT Modified:  2019-09-03 09:14:44.548521800 (UTC)
Accessed:      2019-09-03 09:14:44.548521800 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TESTFI~4.TST
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 235282432    Actual Size: 0
Created:       2019-09-03 09:14:18.591216000 (UTC)
File Modified: 2019-09-03 09:14:18.591216000 (UTC)
MFT Modified:  2019-09-03 09:14:18.591216000 (UTC)
Accessed:      2019-09-03 09:14:18.591216000 (UTC)

$FILE_NAME Attribute Values:
Flags: Archive
Name: TestFile235281024.tst
Parent MFT Entry: 78985  Sequence: 8
Allocated Size: 235282432    Actual Size: 0
Created:       2019-09-03 09:14:18.591216000 (UTC)
File Modified: 2019-09-03 09:14:18.591216000 (UTC)
MFT Modified:  2019-09-03 09:14:18.591216000 (UTC)
Accessed:      2019-09-03 09:14:18.591216000 (UTC)

Attributes: 
Type: $STANDARD_INFORMATION (16-0)   Name: N/A   Resident   size: 72
Type: $FILE_NAME (48-3)   Name: N/A   Resident   size: 90
Type: $FILE_NAME (48-2)   Name: N/A   Resident   size: 108
Type: $DATA (128-1) Name: N/A Non-Resident size: 235281024 init_size: 235281024
3959582 3959583 3959584 3959585 3959586 3959587 3959588 3959589 
...
4017014 4017015 4017016 4017017 4017018 4017019 4017020 4017021 
4017022 4017023 

No comments:

Post a Comment

NTFS Timestamps vs NtSetInformationFile & MoveFile

TL;DR: NtSetInformationFile, MoveFileW, NtSetInformationFile sequence overwrites all timestamps in $STANDARD_INFORMATION, and $FILE_NAME a...