Kevin Vance - I was making a database of original windows files, and I thought…

Entries | Archive | Friends | Friends' Friends | User Info

06:27 pm

Wednesday, May 31st, 2006
Previous Entry Share Next Entry
I was making a database of original windows files, and I thought "hey, it would be cool to get that version information that's built into EXE files." That turned into a whole-day project :P

To properly get at the version info, you have to:

  • Read the DOS header, to find the PE header.
  • Read the PE header to find:
    • The optional PE header to find the ResourceTable address
    • The section headers to find the .rsrc section
  • Read the resource section, which is actually a SIMPLE MULTILEVEL FILESYSTEM to find the VS_VERSIONINFO structure
  • And *then* you can parse *that*!

I got stuck for a long time because the addresses in the resource table were always wrong, both as an offset from the start of the file and from the start of the section. In sol.exe they were off by +0x1C00, and in wdviewer.exe they were off by +0x3000 which was past the end of the file! Eventually by just examining all of the fields in the optional PE header (which I wasn't parsing at the time) I found the magic formula. Location = Resource Section Location - Resource Table Address + Given Offset.

>>> f = file("sol.exe")
>>> exe = pe.PE(f)
>>> exe.version_info.StringFileInfo
{u'': u'$', u'\xa9 Microsoft Corporation. All rights reserved.': u'8\x08\x01OriginalFilename', u'L\x16\x01CompanyName': u'', u'D': u'\x01VarFileInfo', u'Microsoft Corporation': u'T\x16\x01FileDescription', u'\u02aa': u'\x01040904B0', u'd"\x01FileVersion': u'', u'sol.exe': u'j%\x01ProductName', u'5.1.2600.0 (xpclient.010817-1148)': u'0\x08\x01InternalName', u'5.1.2600.0': u''}

Now if only my StringFileInfo parser was right XD

Link )Reply )

Comments
From: (Anonymous)
2006-09-13 12:38 pm (UTC)
I'm trying to do this now, working with the contents of a RAM dump from a Windows system. I've located the kernel image in memory, and I've been very successful parsing the PE header info. I'm now trying to traverse the directory structure to locate the VS_VERSIONINFO stuff to parse.

Harlan
keydet89 at yahoo dot com
http://windowsir.blogspot.com
(Reply) (Thread)
[User Picture]From: kvance
2006-09-13 03:51 pm (UTC)
Hi Harlan,

It looks like you are stuck at the same place I was. Here's how my code turned out. I read in those four ints that describe the data chunk, and then calculate the address:

format = "<4I"
buffer = file.read(struct.calcsize(format))
offset,\
self.size,\
codepage,\
reserved = struct.unpack(format, buffer)
self.address = base_addr - table_addr + offset


base_addr is the start of the resource directory (the header with Characteristics, TimeDateStamp, etc.).
table_addr can be found in the PE header. It's the third address+size pair directly after the NumberOfRvaAndSizes field (in the 32/64-bit part of the Optional Header).
offset we just read.

I hope this helps! Your project looks pretty interesting.

-- kvance
(Reply) (Parent) (Thread)