jira0004 has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I am writing some tools in Perl that extract and report information about Microsoft Windows binary files (.exe and .dll). The Microsoft Windows compiler embeds the date and time that the given .exe or .dll was compiled. This can be a super useful piece of information to have -- given two instances of an .exe binary or a .dll binary you can check to see if the two instances of the same file have the same compile date and time. If the two instances have the same date and time they are probably the same file, if the times/dates differ, then the given source has been re-compiled and the two instances differ in that the source has been recompiled.

So my goal here is to extract the compile date/time from the Microsoft Windows binary (.exe)/(.dll) that the Microsoft Windows compiler embeds in the binary data and I want to do that in Perl. I have tried Win32::File::VersionInfo and I have tried Win32::Exe . Win32::Exe does not work for a .dll because it attempts to load too much system information and thus takes just entirely too long. Win32::File::VersionInfo gets a lot of version information but it does not get the date/time the .dll or .exe was compiled. Here is a hash of information retrieved from Win32::File::VersionInfo .

x $version_info 0 HASH(0x1bc307c) 'Date' => 0000000000000000 'FileVersion' => '6.0.2900.2578' 'Flags' => HASH(0x1be5560) 'Debug' => 0 'InfoInferred' => 0 'Patched' => 0 'Prerelease' => 0 'PrivateBuild' => 0 'SpecialBuild' => 0 'Lang' => HASH(0x1bc3070) 'English (United States)' => HASH(0x1be5578) 'CompanyName' => 'Microsoft Corporation' 'FileDescription' => 'Windows Shell Common Dll' 'FileVersion' => '6.00.2900.2578 (xpsp.041130-1728)' 'InternalName' => 'SHELL32' 'LegalCopyright' => '⌐ Microsoft Corporation. All right +s reserved.' 'OriginalFilename' => 'SHELL32.DLL' 'ProductName' => 'Microsoft« Windows« Operating System' 'ProductVersion' => '6.00.2900.2578' 'OS' => 'NT/Win32' 'ProductVersion' => '6.0.2900.2578' 'Raw' => HASH(0x1bcac54) 'Date' => 0000000000000000 'FileVersion' => '000600000B540A12' 'FlagMask' => '0000003F' 'Flags' => 00000000 'OS' => 00040004 'ProductVersion' => '000600000B540A12' 'SubType' => 00000000 'Type' => 00000002 'Type' => 'DLL'

I have also tried Win32API::File::Time . This method has a function named GetFileTime . However, the GetFileTime just gets the date/time the file was created within my file system, it does not extract this embeded date/time that the file was compiled.

Does any one know how I can get the embedded date/time that a file was compiled out of a Microsoft Windows .exe or .dll file in Perl? If anyone even knows how this value is encoded/embedded in the .exe or .dll and could describe the algorithm for traversing the binary data and extracting this value, then I would be able to implement this algorithm in Perl myself.

The problem I have been having is that I haven't found any Perl modules where some one has done this already (written a method for getting the embedded compile date/time out of a Microsoft Windows .exe or a Microsoft Windows .dll and I haven't found a description of how this value is embedded so I haven't been able to just write my own algorithm for extracting this information.

Any information would be usful.

Thanks, Sincerely,

Peter Jirak

jira0004@yahoo.com

Replies are listed 'Best First'.
Re: Getting compile time out of Windows binary (exe and dll) files
by GrandFather (Sage) on Aug 16, 2005 at 22:05 UTC

    It is possible, but tricky. The information that you want is buried in a somewhat complicated fashion in the file. You need to locate the IMAGE_FILE_HEADER structure in the file's PE header (prefixed by "PE\0\0"). That contains a DWORD TimeDateStamp field which has "The time that the linker (or compiler for an OBJ file) produced this file. This field holds the number of seconds since December 31st, 1969, at 4:00 P.M.". The C struct is:

    typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; }

    Perl is Huffman encoded by design.
Re: Getting compile time out of Windows binary (exe and dll) files
by BrowserUk (Pope) on Aug 16, 2005 at 23:10 UTC

    Update: A somewhat more robust version. It correctly handles all but a dozen or so of the 6000+ exes and dlls on my system, though a couple of dozen more have timestamps well in the future (which is noted).

    #! perl -slw use strict; open EXE, '<:raw', $ARGV[0] or die "$ARGV[0] : $!"; my $dos = do{ local $/ = \65536; <EXE> }; die "$ARGV[0] is not a .exe or .dll (sig='${ \substr $dos, 0, 2 }')" unless substr( $dos, 0, 2 ) eq 'MZ'; my $coffoff = 8+ unpack 'x60 V', $dos; read( EXE, $dos, $coffoff - 65536 + 4, 65536 ) or die $! if $coffoff > 65536; my $ts = unpack "x$coffoff V", $dos; print "$ARGV[0] : ", scalar( localtime $ts) || "has unfathomable times +tamp value $ts" );

    Try this


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.

      Thanks alot this is really very helpful. This extracts that embedded time stamp just like I wanted!

      Thanks, again,

      Sincerely

      Peter Jirak

      jira0004@yahoo.com
Re: Getting compile time out of Windows binary (exe and dll) files
by thor (Priest) on Aug 16, 2005 at 21:59 UTC
    If your goal is to see whether two files are the same, couldn't you just use hashing? Take a look at Digest for more info.

    thor

    Feel the white light, the light within
    Be your own disciple, fan the sparks of will
    For all of us waiting, your kingdom will come

      Or alternatively calling 'diff' or even the win32 equivalent 'comp' to see if the files are different (both work with binary files).

      Or even more technically downloading MinGW and using the 'objdump.exe' tool?