Version 1 of Reading Portable Executable headers

Updated 2003-07-13 19:54:36

--AF 13-07-03

 array set cputype {
    0 Unknown
    332 80386
    333 80486
    334 Pentium
    354 "MIPS Mark 1"
    355 "MIPS Mark 2"
    358 "MIPS Mark 3"
 }

 array set flags {
    1     "Relocation info stripped"
    2     "File is executable"
    4     "Line nunbers stripped"
    8     "Local symbols stripped"
    16    "Agressively trim working set"
    32    "Can handle >2GB addresses"
    128   "Bytes of machine word are reversed"
    256   "32 bit word machine"
    512   "Debugging info stripped"
    1024  "Dont run from removable media"
    2048  "Dont run from network"
    4096  "System file"
    8092  "DLL"
    16384 "Run only on UP machine"
    32768 "Bytes of machine word are reversed"
 }

 array set subsystem {
    0 Unknown
    1 Native
    2 "Windows GUI"
    3 "Windows Character"
    5 "OS/2 Character"
    7 "POSIX Character"
 }

 array set dllflags {
    1 "Per process library initialization"
    2 "Per process library termination"
    4 "Per thread library initialization"
    8 "Per thread library termination"
 }

 proc readPEInfo {file} {
    set fh [open $file r]
    fconfigure $fh -encoding binary

    seek $fh 24 start
    set tmp [scan [read $fh 1] %c]
    if {$tmp < 64} { puts "no windows header"; return }

    seek $fh 60 start
    set tmp [scan [read $fh 1] %c]
    seek $fh $tmp start
    if {[read $fh 4] != "PE\000\000"} { puts "windows header not found"; return }

    binary scan [read $fh 2] s* tmp
    if {[info exists ::cputype($tmp)]} {
        puts "CPU: $::cputype($tmp)"
    } else {
        puts "CPU: Unidentified"
    }

    binary scan [read $fh 2] s* tmp
    puts "Object table entries: $tmp"

    binary scan [read $fh 4] i* tmp
    puts "Linked: [clock format $tmp -gmt 1]"

    seek $fh 8 current
    set tmp [scan [read $fh 2] %c]
    puts "Header size: [expr $tmp + 192] bytes"

    binary scan [read $fh 2] s* tmp
    set flags {}
    foreach x [lsort -integer -decreasing [array names ::flags]] {
        if {$tmp > $x} {
            incr tmp -$x
            lappend flags $::flags($x)
        }
    }
    puts "Flags: [join $flags ", "]"

    seek $fh 2 current
    puts "Linker version: [scan [read $fh 1] %c].[scan [read $fh 1] %c]"

    binary scan [read $fh 4] i* tmp
    puts "Size of code: $tmp"

    binary scan [read $fh 4] i* tmp
    puts "Size of initialized data: $tmp"

    binary scan [read $fh 4] i* tmp
    puts "Size of uninitialized data: $tmp"

    seek $fh 24 current
    puts "OS version: [scan [read $fh 2] %c].[scan [read $fh 2] %c]"

    puts "Image version: [scan [read $fh 2] %c].[scan [read $fh 2] %c]"

    puts "Subsystem version: [scan [read $fh 2] %c].[scan [read $fh 2] %c]"

    seek $fh 4 current
    binary scan [read $fh 4] i* tmp
    puts "Size of image: $tmp"

    binary scan [read $fh 4] i* tmp
    puts "Size of headers: $tmp"

    seek $fh 4 current
    set tmp [scan [read $fh 2] %c]
    if {[info exists ::subsystem($tmp)]} {
        puts "Subsystem: $::subsystem($tmp)"
    } else {
        puts "Subsystem: Unidentified"
    }

    set tmp [scan [read $fh 2] %c]
    if {$tmp == "0"} {
        set flags "None"
    } else {
        set flags {}
        foreach x [lsort -integer -decreasing [array names ::dllflags]] {
            if {$tmp > $x} {
                incr tmp -$x
                lappend flags $::dllflags($x)
            }
        }
    }
    puts "DLL flags: [join $flags ", "]"

    binary scan [read $fh 4] i* tmp
    puts "Stack reserve size: $tmp"

    binary scan [read $fh 4] i* tmp
    puts "Stack commit size: $tmp"

    binary scan [read $fh 4] i* tmp
    puts "Heap reserve size: $tmp"

    binary scan [read $fh 4] i* tmp
    puts "Heap commit size: $tmp"

    close $fh
 }

Output looks like this

 readPEInfo tclkit.exe 

 CPU: 80386
 Object table entries: 3
 Linked: Mon Mar 03 20:55:05 GMT 2003
 Header size: 416 bytes
 Flags: 32 bit word machine, Local symbols stripped, Line nunbers stripped, File is executable
 Linker version: 6.0
 Size of code: 671744
 Size of initialized data: 16384
 Size of uninitialized data: 1085440
 OS version: 4.0
 Image version: 0.0
 Subsystem version: 4.0
 Size of image: 1777664
 Size of headers: 4096
 Subsystem: Windows GUI
 DLL flags: None
 Stack reserve size: 1048576
 Stack commit size: 4096
 Heap reserve size: 1048576
 Heap commit size: 4096