TouchIT() : Sets Compilation time and Checksum for AutoHotkey executables

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

TouchIT() : Sets Compilation time and Checksum for AutoHotkey executables

10 Sep 2017, 10:07

Quick tip:
When you want to modify a file (with File object) without affecting the file's last modified timestamp,
the following couple of lines can be used to save/restore timestamps.

Code: Select all

; Save File timestamps  
DllCall( "GetFileTime", "Ptr",File.__Handle, "Int64P",T1, "Int64P",T2, "Int64P",T3 )
; Restore File timestamps
DllCall( "SetFileTime", "Ptr",File.__Handle, "Int64P",T1, "Int64P",T2, "Int64P",T3 )

TouchIT() - Touch Internal Timestamp.
The function was named after MS-DOS' touch.exe, a derivative of UNIX touch command
The compilation timestamp is stored as unix time, a UINT. The value represents the seconds elapsed since the year 1970.
The constant number 11644473600 is the seconds elapsed between the years 1601 and 1970.

Code: Select all

/*
    TouchIt() sets PE compilation timestamp to file's modified timestamp and fills in the PE checksum.  
    Written specifically for AutoHotkey 1.1 complied scripts, by SKAN, 06-Sep-2017.
    Note: PE Modification is NOT allowed in AutoHotkey 1.0 (Classic) executables.
*/

TouchIT( PEfile) {                                  
Local File, T1:=0, T2:=0, T3:=0, Chk1:=0, Chk2:=0
  File := FileOpen(PEfile,"rw")
  If ! IsObject(File)
      Return
  ; Save File timestamps  
  DllCall( "GetFileTime", "Ptr",File.__Handle, "Int64P",T1, "Int64P",T2, "Int64P",T3 )
  If ( File.ReadUSHORT()<>0x5A4D )                 ; Is IMAGE_DOS_HEADER.e_magic = 'MZ' ?
      Return File.Close() + ""
  File.Seek(60,0)                                  ; Seek IMAGE_DOS_HEADER.e_lfanew 
  File.Seek(File.ReadUINT(),0)                     ; Seek IMAGE_NT_HEADERS
  If ( File.ReadUINT()<>0x00004550 )               ; Is IMAGE_NT_HEADERS.Signature = 'PE' ?
      Return File.Close() + ""
  File.Seek(4,1)                                   ; Seek IMAGE_FILE_HEADER.TimeDateStamp
  File.WriteUINT(T3//10000000-11644473600)
  File.Seek(12+64,1)                               ; Seek IMAGE_OPTIONAL_HEADER.CheckSum
  DllCall( "ImageHlp.dll\MapFileAndCheckSumA", "AStr",PEfile, "PtrP",Chk1, "PtrP",Chk2 )
  File.WriteUINT(Chk2)                             ; Update checksum
  ; Restore File timestamps
  DllCall( "SetFileTime", "Ptr",File.__Handle, "Int64P",T1, "Int64P",T2, "Int64P",T3 )
  File.Close()
Return True
}

Couple of read-only helper functions:

PE_CompilationTime()
Returns Compilation time as local time in YYYYMMDDHHMMSS format

Code: Select all

PE_CompilationTime( PEfile ) {                       ; By SKAN | 10-Sep-2017
Local Bin, File := FileOpen(PEfile,"r"), nFILETIME := 0 
  If ! IsObject(File)
    Return
  File.RawRead(Bin,2048), File.Close()  
  If ( NumGet(Bin,0,"UShort")<>0x5A4D || NumGet(Bin,NumGet(Bin,60,"UInt"),"UInt")<>0x00004550 ) ;'MZ' and 'PE'
    Return
  nFILETIME := ( (NumGet(Bin,NumGet(Bin,60,"UInt")+8,"UInt")+11644473600 )*10000000 )  ; UNIXTIME to FILETIME  
  DllCall( "FileTimeToLocalFileTime", "Int64P",nFILETIME, "Int64P",nFILETIME )         ; FILETIME UTC to local
  DllCall( "FileTimeToSystemTime", "Int64P",nFILETIME, "Ptr",&Bin )                    ; Bin is SYSTEMTIME 
Return Format( "{1:04}{2:02}{3:02}{4:02}{5:02}{6:02}",   NumGet(Bin,00,"UShort"), NumGet(Bin,02,"UShort")
     , NumGet(Bin,06,"UShort"), NumGet(Bin,08,"UShort"), NumGet(Bin,10,"UShort"), NumGet(Bin,12,"UShort") )  
}
PE_CheckSum()

Code: Select all

PE_CheckSum( PEfile ) {                            ; By SKAN | 10-Sep-2017
Local Chk1:=0, Chk2:=0
If ( DllCall( "ImageHlp.dll\MapFileAndCheckSumA", "AStr",PEfile, "PtrP",Chk1, "PtrP",Chk2 ) = 0 )
  Return ( Chk1 = Chk2 ? "Checksum okay!" : "Checksum incorrect!" )
       . ( "`nCurrent Checksum: " Format( "0x{:08X}", Chk1 ) )
       . ( "`nCorrect Checksum: " Format( "0x{:08X}", Chk2 ) )
}

While writing these function, I used the following command line tool to crosscheck the results:
checksum.exe (32 KiB), download from http://www.the-sz.com/products/checksum/
The site has a good collection of tools.. Yet to try them. Homepage: http://www.the-sz.com/products/
My Scripts and Functions: V1  V2
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: TouchIT() : Sets Compilation time and Checksum for AutoHotkey executables

10 Sep 2017, 11:02

Cheers for the tip re. get/set time in milliseconds. I had two complicated functions involving FindFirstFile/CreateFile/SetFileTime for this. My knowledge has improved since I wrote those functions a long time ago. (I thought you'd already written every function ever back in the day! Still more. Cheers.)

There's this, if you hadn't seen it, thought you might like it. E.g. the StrGet/StrPut support hex recommendation I mentioned.
Wish List 2.0 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 13&t=36789

Btw I had been curious if you could edit an exe's description, as it appears in Task Manager, live, i.e. just after you run a script. So that each script could have a unique description. (Although you can check the command line instead.) I have done live edits that change the class name for GUIs or the InputBox size. Thereby avoiding binary edits to the exe. [EDIT: I tried this but couldn't get it to work, e.g. searching for 'AutoHotkey Unicode 32-bit' in the address space and using VirtualProtect/VirtualProtectEx and WriteProcessMemory.]
Last edited by jeeswg on 11 Sep 2017, 01:46, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
gwarble
Posts: 524
Joined: 30 Sep 2013, 15:01

Re: TouchIT() : Sets Compilation time and Checksum for AutoHotkey executables

10 Sep 2017, 13:14

thanks for sharing...
what kinds of systems use the unix time and/or pe checksum of an exe in some way? could this help with false positive virus detection to differentiate a compiled script from any other?
EitherMouse - Multiple mice, individual settings . . . . www.EitherMouse.com . . . . forum . . . .
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: TouchIT() : Sets Compilation time and Checksum for AutoHotkey executables

10 Sep 2017, 14:36

gwarble wrote:what kinds of systems use the unix time and/or pe checksum of an exe in some way?
First of all:
I don't compile my scripts. But recently, I have been creating slideshow exes (family photos) with AHK.
All photos have meta-tag of "date taken", but if I want to know when I created the slideshow, I have to rely on file's timestamp,
which can go awry when copied between FAT32 (My USB) and NTFS (HDD).
The compilation time (for compiled scripts) will be the datetime Lexikos compiled AutoHotkeySC.bin.
VirusTotal shows the Creation time.
BTW, 5 AV services have successfully flagged my MsgBox Hello World as suspicious :P

I wrote TouchIT() because,
1) I couldn't find a command line tool to do the job.
2) I feel AHK2EXE should incorporate this. ( attn: fincs )
gwarble wrote:could this help with false positive virus detection to differentiate a compiled script from any other?
I don't think so.

Quote form MSDN:
Checksums are required for kernel-mode drivers and some system DLLs. The linker computes the original checksum at link time, if you use the appropriate linker switch. For more details, see your linker documentation.
It is recommended that all images have valid checksums. It is the caller's responsibility to place the newly computed checksum into the mapped image and update the on-disk image of the file.
None of AutoHotkey executables have a checksum. But since TouchIT() is modifying a part of PE Headers (Timestamp), it becomes a responsibility to update the checksum especially when dealing with third party EXEs that might have checksum.
It important to note that EXE's with a signed certificate with have everything in order, and should not be modified with any tool at all.

PS: I think AHK2EXE GUI should also support setting FileVersionInfo. Command line parameter could support description part.
My Scripts and Functions: V1  V2
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: TouchIT() : Sets Compilation time and Checksum for AutoHotkey executables

11 Sep 2017, 01:08

See here -> Upcoming Ahk2Exe changes (but I believe its still dead)
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: TouchIT() : Sets Compilation time and Checksum for AutoHotkey executables

11 Sep 2017, 07:59

jNizM wrote:See here -> Upcoming Ahk2Exe changes (but I believe its still dead)
Thanks for the link jNizM :)
My Scripts and Functions: V1  V2
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: TouchIT() : Sets Compilation time and Checksum for AutoHotkey executables

12 Sep 2017, 10:33

jeeswg wrote:Cheers for the tip re. get/set time in milliseconds.
MSDN wrote: FILETIME structure

It is not recommended that you add and subtract values from the FILETIME structure to obtain relative times. Instead, you should copy the low- and high-order parts of the file time to a ULARGE_INTEGER structure, perform 64-bit arithmetic on the QuadPart member, and copy the LowPart and HighPart members into the FILETIME structure.
Do not cast a pointer to a FILETIME structure to either a ULARGE_INTEGER* or __int64* value because it can cause alignment faults on 64-bit Windows.
This doesn't apply to AHK, right? It would be nice if somebody can throw light on this.



And an another line in PE_CompilationTime()

Code: Select all

DllCall( "FileTimeToLocalFileTime", "Int64P",nFILETIME, "Int64P",nFILETIME )
MSDN wrote:FileTimeToLocalFileTime function

Parameters

lpFileTime [in]
A pointer to a FILETIME structure containing the UTC-based file time to be converted into a local file time.
lpLocalFileTime [out]
A pointer to a FILETIME structure to receive the converted local file time. This parameter cannot be the same as the lpFileTime parameter.
I believe that, when ArgType is PtrP, a copy of variable is passed and the result is copied back into the variable.
So different pointers are being passed for the same nFILETIME?! Can somebody please clarify?
My Scripts and Functions: V1  V2

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: gwarble, JoeWinograd and 130 guests