Jump to content

setMACE (timestomp) in au3

Recommended Posts

As part of another PoC tool, I've whipped together an au3 that uses NtSetInformationFile to update timestamps as available in the FILE_BASIC_INFORMATION structure. However, is it ok to post it?

The tool follows similar logic as Timestomp that was written in 2005 by James C. Foster and Vincent Liu, and presented at BlackHat the same year; http://www.forensicswiki.org/wiki/Timestomp


Last version added 16.08.11; http://www.mediafire.com/?77f3bw52oxc9v5g (including au3 and exe)

Edited by joakim
Link to post
Share on other sites

Here it is; http://www.mediafire.com/file/o9s82nzom2lj47k/setmace.zip exe and au3.

This tool follows similar logic as Timestomp that was written in 2005 by James C. Foster and Vincent Liu, and presented at BlackHat the same year (http://www.forensicswiki.org/wiki/Timestomp). It is a specialized tool for manipulating all 4 MAC(E) timestamps on files located on an NTFS volume (MAC values on FAT). It will update information in the $STANDARD_INFORMATION attribute of an MFT entry. Technically it is using the NtSetInformationFile function inside ntdll.dll with the FILE_BASIC_INFORMATION structure in FILE_INFORMATION_CLASS.

As is explained on the referenced site above, the $FILE_NAME attribute cannot be set by api, but a workaround is explained. That workaround is implemented in this tool by the -x parameter. Ie, it will update wanted timestamp for file and then move the target file into a randomly named subdirectory before redoing the update of timestamp on the target file now located in a new directory. This way all 8 timestamps may be modified.

Explanation of usage:

Commandline with parameter order fixed and must be followed.

- Parameter 1 is input/target file. Must be full path like "%CD%\file.ext" or "c:\folder\file.ext"

- Parameter 2 is determining which timestamp to update.

"-m" = LastWriteTime

"-a" = LastAccessTime

"-c" = CreationTime

"-e" = ChangeTime (in $MFT)

"-z" = all 4

- Parameter 3 is the wanted new timestamp. Format must be strictly followed like; "1954:20:49:22:39:44". That is YYYY:MM:DD:HH:MM:SS. Mseconds are always set to 0 to generate valid NTFS timestamps (1 second = 10.000). The smallest possible value is; "1601:01:01:00:00:00". However for that specific value mseconds is set to 1, so that the value is not ignored when writing it. It is written as UTC and thus will show up in explorer as interpreted by your timezone location.

- Parameter 4 determines if $FILE_NAME attribute should be updated as well.

"-n" will only update timestamps in $STANDARD_INFORMATION.

"-x" will also update timestamps in $FILE_NAME as well as in $STANDARD_INFORMATION. A subdir is created where the file is moved into.


setmace.exe "%CD%\file.txt" -z "2000:01:01:00:00:00" -x

Currently annoying message boxes is used to show error messages. That may change into logfile writing.

Thanks to wraithdu for good hints from the NtQueryInformationFile implementation in;

and Ascend4nt for the _WinTimeFunctions.au3


#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Res_Comment=Same logic as timestomp written by  James C. Foster and Vincent Liu in 2005.
#AutoIt3Wrapper_Res_Description=Changes MACE timestamps as you like
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
;by Joakim
#include "_WinTimeFunctions.au3";Ascend4nt
#include <WinAPI.au3>
#include <Date.au3>
#include <FileConstants.au3>
Opt("MustDeclareVars", 1)
Global $file = ""
Global $input2LocalFileTime = ""
Global Const $FileBasicInformation = 4
Global Const $OBJ_CASE_INSENSITIVE = 0x00000040
Global Const $FILE_DIRECTORY_FILE = 0x00000002
Global Const $FILE_NON_DIRECTORY_FILE = 0x00000040
Global Const $FILE_RANDOM_ACCESS = 0x00000800
Global Const $tagFILEBASICINFO = "int64 CreationTime;int64 LastAccessTime;int64 LastWriteTime;int64 ChangeTime;ulong FileAttributes;"
Global Const $tagIOSTATUSBLOCK = "dword Status;dword Information"
Global Const $tagOBJECTATTRIBUTES = "ulong Length;hwnd RootDirectory;ptr ObjectName;ulong Attributes;ptr SecurityDescriptor;ptr SecurityQualityOfService"
Global Const $tagUNICODESTRING = "ushort Length;ushort MaximumLength;ptr Buffer"

If $input2LocalFileTime = -1 Then
    MsgBox(0,"Error","Timestamp generation went wrong")
;divisible by 10,000,000 (one second)
If $cmdline[4] = "-x" Then

Func _set_mace($file)
    Local $hNTDLL = DllOpen("ntdll.dll")
    Local $szName = DllStructCreate("wchar[260]")
    Local $sUS = DllStructCreate($tagUNICODESTRING)
    Local $sOA = DllStructCreate($tagOBJECTATTRIBUTES)
    Local $sISB = DllStructCreate($tagIOSTATUSBLOCK)
    Local $buffer = DllStructCreate("byte[16384]")
    Local $ret
    $file = "\??\" & $file
    DllStructSetData($szName, 1, $file)
    $ret = DllCall($hNTDLL, "none", "RtlInitUnicodeString", "ptr", DllStructGetPtr($sUS), "ptr", DllStructGetPtr($szName))
    DllStructSetData($sOA, "Length", DllStructGetSize($sOA))
    DllStructSetData($sOA, "RootDirectory", Chr(0))
    DllStructSetData($sOA, "ObjectName", DllStructGetPtr($sUS))
    DllStructSetData($sOA, "Attributes", $OBJ_CASE_INSENSITIVE)
    DllStructSetData($sOA, "SecurityDescriptor", Chr(0))
    DllStructSetData($sOA, "SecurityQualityOfService", Chr(0))
    $ret = DllCall($hNTDLL, "int", "NtOpenFile", "hwnd*", "", "dword", $GENERIC_WRITE, "ptr", DllStructGetPtr($sOA), "ptr", DllStructGetPtr($sISB), _
                                "ulong", $FILE_SHARE_WRITE, "ulong", BitOR($FILE_NON_DIRECTORY_FILE, $FILE_RANDOM_ACCESS))
    Local $hFile = $ret[1]
    Local $pFSO = DllStructGetPtr($buffer)
    Local $sFSO = DllStructCreate($tagFILEBASICINFO, $pFSO)

        Case $cmdline[2] = "-m"
            DllStructSetData($sFSO, "LastWriteTime",$input2LocalFileTime)
        Case $cmdline[2] = "-a"
            DllStructSetData($sFSO, "LastAccessTime",$input2LocalFileTime)
        Case $cmdline[2] = "-c"
            DllStructSetData($sFSO, "CreationTime",$input2LocalFileTime)
        Case $cmdline[2] = "-e"
            DllStructSetData($sFSO, "ChangeTime",$input2LocalFileTime)
        Case $cmdline[2] = "-z"
            DllStructSetData($sFSO, "LastWriteTime",$input2LocalFileTime)
            DllStructSetData($sFSO, "LastAccessTime",$input2LocalFileTime)
            DllStructSetData($sFSO, "CreationTime",$input2LocalFileTime)
            DllStructSetData($sFSO, "ChangeTime",$input2LocalFileTime)

    $ret = DllCall($hNTDLL, "int", "NtSetInformationFile", "hwnd", $hFile, "ptr", DllStructGetPtr($sISB), "ptr", DllStructGetPtr($sFSO), _
                                "int", 16384, "int", $FileBasicInformation)
    $ret = DllCall($hNTDLL, "int", "NtClose", "hwnd", $hFile)

Func _config_timestamp()
Local $timestamp_array
Local $msec = 0
If StringLen($cmdline[3]) <> 19 Then
    MsgBox(0,"Error","Length of date/time is not correct: " & $cmdline[3])
$timestamp_array = StringSplit(StringReplace($cmdline[3],'"',''),":")
If $timestamp_array[0] <> 6 Then
    MsgBox(0,"Error","Not right date/time parameters supplied: " & $timestamp_array[0])
For $dateinputs = 1 To $timestamp_array[0]
    If StringIsDigit($timestamp_array[$dateinputs]) <> 1 Then
        MsgBox(0,"Error","Not right date/time format supplied: " & $timestamp_array[$dateinputs])
    If StringLen($timestamp_array[$dateinputs]) <> 2 And StringLen($timestamp_array[$dateinputs]) <> 4 Then
        MsgBox(0,"Error","Not right date/time format supplied: " & $timestamp_array[$dateinputs])
If $cmdline[3] = "1601:01:01:00:00:00" Then
    $msec = 1
$input2LocalFileTime = _WinTime_SystemTimeToLocalFileTime($timestamp_array[1],$timestamp_array[2],$timestamp_array[3],$timestamp_array[4],$timestamp_array[5],$timestamp_array[6],$msec,-1)
Return $input2LocalFileTime

Func _validate_parameters()
If $cmdline[0] <> 4 Then
    MsgBox(0,"Error","Wrong number of parameters supplied: " & $cmdline[0])
If $cmdline[2] <> "-m" And  $cmdline[2] <> "-a" And $cmdline[2] <> "-c" And $cmdline[2] <> "-e" And $cmdline[2] <> "-z" Then
    MsgBox(0,"Error","Input parameter number 2 is unknown: " & $cmdline[2])
If $cmdline[4] <> "-x" And $cmdline[4] <> "-n" Then
    MsgBox(0,"Error","Input parameter number 4 is unknown: " & $cmdline[4])
If FileExists($cmdline[1]) <> 1 Then
    MsgBox(0,"Error","Target file does not exist: " & $cmdline[1])
$file = $cmdline[1]

Func _fn_mace()
Local $l, $rnddir
Local $inptarget_lenght, $targetname, $output_folder, $newfile
$rnddir = Random(99, 99999, 1)
$l = 1
If StringInStr($cmdline[1],"\") Then
    $inptarget_lenght = StringLen($cmdline[1])
    For $l = 1 To $inptarget_lenght
        If StringMid($cmdline[1],$inptarget_lenght-$l,1) = "\" Then ExitLoop
    $targetname = StringMid($cmdline[1],$inptarget_lenght-$l+1,$l)
$output_folder = StringMid($cmdline[1],1,$inptarget_lenght-$l) & $rnddir & "\"
$newfile = $output_folder & $targetname

Func NT_SUCCESS($status)
    If 0 <= $status And $status <= 0x7FFFFFFF Then
        Return True
        Return False
Link to post
Share on other sites
  • 1 month later...
  • 4 months later...

Thanks a lot ;), I'll definitly will take a deeper look into this one. But on a second glance the site you're hosting on looks so interesting I think I'll sign-up anyhow :)...

Link to post
Share on other sites
  • 1 month later...

Made a new version with complete $FILE_NAME attribute timestamp support by writing the timestamps directly to physical disk. That means an extra 4 (and 8 for files with long file names because of the extra attribute) can now also be set to the most accurate precision possible (nanosec). That stupid "move" trick is now history and directories are supported too. Some restriction are present on nt6.x which means the systemdrive of a running system (and the volume with the pagefile) can not be written to without the help of a kernel mode driver. Also added support for dumping all $STANDARD_INFORMATION and $FILE_NAME for a file/directory (4+4 or 4+8).

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...