Class: PEheader
- Inherits:
-
Object
- Object
- PEheader
- Defined in:
- lib/metadata/util/win32/peheader.rb
Overview
Notes:
The peheader object member 'icons' is an array of icons in the file. Sub 0 is the application
icon, 1 is usually the document icon. The format is the same as an .ico file. The simple test
writes found icons to the root dir as icon0.ico, icon1.ico, etc. Any icon editor will be able
to open them and display each resolution contained in the icon (if more than one).
Constant Summary collapse
- IMAGE_NT_SIGNATURE =
"PE\0\0"
- IMAGE_DOS_SIGNATURE =
"MZ"
- IMAGE_DIRECTORY_ENTRY_EXPORT =
PE Header structures defined
From WINNT.H
// Directory Entries
// Export Directory
0
- IMAGE_DIRECTORY_ENTRY_IMPORT =
// Import Directory
1
- IMAGE_DIRECTORY_ENTRY_RESOURCE =
// Resource Directory
2
- IMAGE_DIRECTORY_ENTRY_EXCEPTION =
// Exception Directory
3
- IMAGE_DIRECTORY_ENTRY_SECURITY =
// Security Directory
4
- IMAGE_DIRECTORY_ENTRY_BASERELOC =
// Base Relocation Table
5
- IMAGE_DIRECTORY_ENTRY_DEBUG =
// Debug Directory
6
- IMAGE_DIRECTORY_ENTRY_COPYRIGHT =
// Description String
7
- IMAGE_DIRECTORY_ENTRY_GLOBALPTR =
// Machine Value (MIPS GP)
8
- IMAGE_DIRECTORY_ENTRY_TLS =
// TLS Directory
9
- IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG =
// Load Configuration Directory
10
- IMAGE_NUMBEROF_DIRECTORY_ENTRIES =
16
- RT_CURSOR =
From WinUser.h /*
-
Predefined Resource Types
*/
-
1
- RT_BITMAP =
2
- RT_ICON =
3
- RT_MENU =
4
- RT_DIALOG =
5
- RT_STRING =
6
- RT_FONTDIR =
7
- RT_FONT =
8
- RT_ACCELERATOR =
9
- RT_RCDATA =
10
- RT_MESSAGETABLE =
11
- RT_GROUP_ICON =
14
- RT_VERSION =
16
- IMAGE_FILE_HEADER =
BinaryStruct.new([ 'v', 'Machine', 'v', 'NumberOfSections', 'V', 'TimeDateStamp', 'V', 'PointerToSymbolTable', 'V', 'NumberOfSymbols', 'v', 'SizeOfOptionalHeader', 'v', 'Characteristics', ])
- SIZEOF_IMAGE_FILE_HEADER =
IMAGE_FILE_HEADER.size
- IMAGE_DOS_HEADER =
// DOS .EXE header
BinaryStruct.new([ # // DOS .EXE header 'v', 'e_magic', # // Magic number 'v', 'e_cblp', # // Bytes on last page of file 'v', 'e_cp', # // Pages in file 'v', 'e_crlc', # // Relocations 'v', 'e_cparhdr', # // Size of header in paragraphs 'v', 'e_minalloc', # // Minimum extra paragraphs needed 'v', 'e_maxalloc', # // Maximum extra paragraphs needed 'v', 'e_ss', # // Initial (relative) SS value 'v', 'e_sp', # // Initial SP value 'v', 'e_csum', # // Checksum 'v', 'e_ip', # // Initial IP value 'v', 'e_cs', # // Initial (relative) CS value 'v', 'e_lfarlc', # // File address of relocation table 'v', 'e_ovno', # // Overlay number 'v', nil, # // Reserved words - e_res[4] 'v', nil, # // Reserved words - e_res[4] 'v', nil, # // Reserved words - e_res[4] 'v', nil, # // Reserved words - e_res[4] 'v', 'e_oemid', # // OEM identifier (for e_oeminfo) 'v', 'e_oeminfo', # // OEM information; e_oemid specific 'v', nil, # // Reserved words - e_res2[10] 'v', nil, # // Reserved words - e_res2[10] 'v', nil, # // Reserved words - e_res2[10] 'v', nil, # // Reserved words - e_res2[10] 'v', nil, # // Reserved words - e_res2[10] 'v', nil, # // Reserved words - e_res2[10] 'v', nil, # // Reserved words - e_res2[10] 'v', nil, # // Reserved words - e_res2[10] 'v', nil, # // Reserved words - e_res2[10] 'v', nil, # // Reserved words - e_res2[10] 'V', 'e_lfanew', # // File address of new exe header ])
- SIZEOF_IMAGE_DOS_HEADER =
IMAGE_DOS_HEADER.size
- IMAGE_OPTIONAL_HEADER32 =
BinaryStruct.new([ # // # // Standard fields. # // 'v', 'Magic', 'c', 'MajorLinkerVersion', 'c', 'MinorLinkerVersion', 'V', 'SizeOfCode', 'V', 'SizeOfInitializedData', 'V', 'SizeOfUninitializedData', 'V', 'AddressOfEntryPoint', 'V', 'BaseOfCode', 'V', 'BaseOfData', # # // # // NT additional fields. # // # 'V', 'ImageBase', 'V', 'SectionAlignment', 'V', 'FileAlignment', 'v', 'MajorOperatingSystemVersion', 'v', 'MinorOperatingSystemVersion', 'v', 'MajorImageVersion', 'v', 'MinorImageVersion', 'v', 'MajorSubsystemVersion', 'v', 'MinorSubsystemVersion', 'V', 'Win32VersionValue', 'V', 'SizeOfImage', 'V', 'SizeOfHeaders', 'V', 'CheckSum', 'v', 'Subsystem', 'v', 'DllCharacteristics', 'V', 'SizeOfStackReserve', 'V', 'SizeOfStackCommit', 'V', 'SizeOfHeapReserve', 'V', 'SizeOfHeapCommit', 'V', 'LoaderFlags', 'V', 'NumberOfRvaAndSizes', ])
- SIZEOF_IMAGE_OPTIONAL_HEADER32 =
IMAGE_OPTIONAL_HEADER32.size
- IMAGE_OPTIONAL_HEADER64 =
BinaryStruct.new([ 'v', 'Magic', 'c', 'MajorLinkerVersion', 'c', 'MinorLinkerVersion', 'V', 'SizeOfCode', 'V', 'SizeOfInitializedData', 'V', 'SizeOfUninitializedData', 'V', 'AddressOfEntryPoint', 'V', 'BaseOfCode', 'Q', 'ImageBase', 'V', 'SectionAlignment', 'V', 'FileAlignment', 'v', 'MajorOperatingSystemVersion', 'v', 'MinorOperatingSystemVersion', 'v', 'MajorImageVersion', 'v', 'MinorImageVersion', 'v', 'MajorSubsystemVersion', 'v', 'MinorSubsystemVersion', 'V', 'Win32VersionValue', 'V', 'SizeOfImage', 'V', 'SizeOfHeaders', 'V', 'CheckSum', 'v', 'Subsystem', 'v', 'DllCharacteristics', 'Q', 'SizeOfStackReserve', 'Q', 'SizeOfStackCommit', 'Q', 'SizeOfHeapReserve', 'Q', 'SizeOfHeapCommit', 'V', 'LoaderFlags', 'V', 'NumberOfRvaAndSizes', ])
- SIZEOF_IMAGE_OPTIONAL_HEADER64 =
IMAGE_OPTIONAL_HEADER64.size
- IMAGE_DATA_DIRECTORY =
BinaryStruct.new([ 'V', :virtualAddress, 'V', :size, ])
- SIZEOF_IMAGE_DATA_DIRECTORY =
IMAGE_DATA_DIRECTORY.size
- IMAGE_SECTION_HEADER =
BinaryStruct.new([ 'a8', 'Name', # union { # DWORD PhysicalAddress; # DWORD VirtualSize; # } Misc; 'V', :VirtualSize, 'V', :virtualAddress, 'V', 'SizeOfRawData', 'V', :PointerToRawData, 'V', 'PointerToRelocations', 'V', 'PointerToLinenumbers', 'v', 'NumberOfRelocations', 'v', 'NumberOfLinenumbers', 'V', 'Characteristics', ])
- SIZEOF_IMAGE_SECTION_HEADER =
IMAGE_SECTION_HEADER.size
- IMAGE_IMPORT_DESCRIPTOR =
BinaryStruct.new([ # union { # DWORD Characteristics; #// 0 for terminating null import descriptor # DWORD OriginalFirstThunk; #// RVA to original unbound IAT (PIMAGE_THUNK_DATA) # }; 'V', 'Characteristics', 'V', 'TimeDateStamp', # // 0 if not bound, # // -1 if bound, and real date\time stamp # // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) # // O.W. date/time stamp of DLL bound to (Old BIND) 'V', 'ForwarderChain', # // -1 if no forwarders 'V', 'Name', 'V', 'FirstThunk', # // RVA to IAT (if bound this IAT has actual addresses) ])
- SIZEOF_IMAGE_IMPORT_DESCRIPTOR =
IMAGE_IMPORT_DESCRIPTOR.size
- IMAGE_RESOURCE_DIRECTORY =
General resource definitions.
BinaryStruct.new([ 'L', :characteristics, 'L', :timeDateStamp, 'S', :majorVersion, 'S', :minorVersion, 'S', :numberOfNamedEntries, # Number of named entries that follow this struc (first). 'S', :numberOfIdEntries, # Number of ID entries that follow this struc (second). ])
- SIZEOF_IMAGE_RESOURCE_DIRECTORY =
IMAGE_RESOURCE_DIRECTORY.size
- IMAGE_RESOURCE_DIRECTORY_ENTRY =
BinaryStruct.new([ 'L', :name, # Name or ID. If bit 31 = 0 then ID. If bit 31 = 1, then # bits 0-30 are an offset (from start of rsrc) to IMAGE_RESOURCE_DIR_STRING_U. 'L', :offsetToData, # Ptr to dir or data. If bit 31 = 0, then ptr to # IMAGE_REDSOURCE_DATA_ENTRY. If bit 31 = 1, then bits 0-30 are ptr to IMAGE_RESOURCE_DIRECTORY. ])
- SIZEOF_IMAGE_RESOURCE_DIRECTORY_ENTRY =
IMAGE_REDSOURCE_DATA_ENTRY. If bit 31 = 1, then bits 0-30 are ptr to IMAGE_RESOURCE_DIRECTORY.
IMAGE_RESOURCE_DIRECTORY_ENTRY.size
- IMAGE_RESOURCE_DATA_ENTRY =
NOTE: Skipping string resource name because it is self-referencing: typedef struct _IMAGE_RESOURCE_DIR_STRING_U
WORD Length; WCHAR NameString[ 1 ];
IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U; The member NameString is Length characters long, so the final size of the structure is unknown. This is just handled without BinaryStruct.
BinaryStruct.new([ 'L', :offsetToData, # This offset is an RVA. 'L', :size, # Size in bytes. 'L', :codePage, # Code page (for strings). 'L', :reserved1, ])
- SIZEOF_IMAGE_RESOURCE_DATA_ENTRY =
IMAGE_RESOURCE_DATA_ENTRY.size
- GRPICONDIR =
Icon specific resource definitions.
BinaryStruct.new([ 'S', :idReserved1, 'S', :idType, # 1 for icons. 'S', :idCount, # Count of images. 'a*', :data, # Array of GRPICONDIRENTRY. ])
- SIZEOF_GRPICONDIR =
TODO: BinaryStruct.sizeof ignores the *
GRPICONDIR.size
- GRPICONDIRENTRY =
BinaryStruct.new([ 'C', :bWidth, # Pixel width of image. 'C', :bHeight, # Pixel height of image. 'C', :bColorCount, # Colors in image (0 if >= 8bpp). 'C', :bReserved1, 'S', :wPlanes, # Color planes. 'S', :wBitCount, # Bits per pixel. 'L', :dwBytesInRes, # Bytes in this resource. 'S', :nID, # Resource ID. # NOTE: In an .ico file, last member is 'L', 'dwImageOffset', an offset # from the beginning of the file to the BITMAPINFOHEADER of the icon data. ])
- SIZEOF_GRPICONDIRENTRY =
NOTE: In an .ico file, last member is ‘L’, ‘dwImageOffset’, an offset from the beginning of the file to the BITMAPINFOHEADER of the icon data.
GRPICONDIRENTRY.size
- MESSAGE_RESOURCE_DATA =
Messagetable specific resource definitions.
BinaryStruct.new([ 'L', :numberOfBlocks, # Length of data array. 'a*', :data, # Array of MESSAGE_RESOURCE_BLOCK. ])
- SIZEOF_MESSAGE_RESOURCE_DATA =
TODO: BinaryStruct.sizeof ignores the *
MESSAGE_RESOURCE_DATA.size
- MESSAGE_RESOURCE_BLOCK =
BinaryStruct.new([ 'L', :loId, 'L', :hiId, 'L', :offsetToEntries, # RVA? ])
- SIZEOF_MESSAGE_RESOURCE_BLOCK =
MESSAGE_RESOURCE_BLOCK.size
- SIZEOF_MRB =
12
- MESSAGE_RESOURCE_ENTRY =
BinaryStruct.new([ 'S', :length, # String length. 'S', :flags, # Encoding (see below). ])
- SIZEOF_MRE =
4
- SIZEOF_MESSAGE_RESOURCE_ENTRY =
MESSAGE_RESOURCE_ENTRY.size
- MESSAGE_RESOURCE_ANSI =
Text follows here.
0x0000
- MESSAGE_RESOURCE_UNICODE =
If set text is ANSI.
0x0001
- VS_VERSION_INFO_HEADER =
If set text is UNICODE.
BinaryStruct.new([ 'a32', 'sig', 's', nil, 's', nil, 's', nil, 's', nil, 's', nil, 'S', 'fminor', 'S', 'fmajor', 'S', 'fbuild', 'S', 'frev', 'S', 'pminor', 'S', 'pmajor', 'S', 'pbuild', 'S', 'prev', ])
- SIZEOF_VS_VERSION_INFO_HEADER =
VS_VERSION_INFO_HEADER.size
- STRING_INFO_HEADER =
BinaryStruct.new([ 'a30', 'sig', 'V', 'data_length', 's', 'type', 'a8', 'lang', 'a8', 'code_page', ])
- SIZEOF_STRING_INFO_HEADER =
STRING_INFO_HEADER.size
- VERSION_STRING_HEADER =
BinaryStruct.new([ 's', 'zero', 's', 'slen', 's', 'vlen', 's', 'type', ])
- SIZEOF_VERSION_STRING_HEADER =
VERSION_STRING_HEADER.size
- STRINGFILEINFO =
"S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0"
- VS_VERSION_INFO =
"V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0"
- IMAGE_SIZEOF_NT_OPTIONAL32_HEADER =
224
- IMAGE_SIZEOF_NT_OPTIONAL64_HEADER =
240
- IMAGE_NT_OPTIONAL_HDR32_MAGIC =
0x10b
- IMAGE_NT_OPTIONAL_HDR64_MAGIC =
0x20b
Instance Method Summary collapse
- #adjustAddress(rva) ⇒ Object
- #assembleIcons(iconEntries, grpIcons) ⇒ Object
- #dumpResourceDirectory(resDir, level, data_hash, rsc_id = nil) ⇒ Object
- #dumpResourceEntry(resDirEntry, level, data_hash, rsc_id) ⇒ Object
- #fileread(length) ⇒ Object
-
#fileseek(offset = 0, _message = nil) ⇒ Object
These file methods are here to assist in debugging.
- #find_all_resources(rsc, rsc_id = nil, &blk) ⇒ Object
- #get_resources_by_type(rt, locale_id = nil) ⇒ Object
- #getBaseResDir(_fBuf) {|@baseResDir| ... } ⇒ Object
-
#getDataDirs(fBuf, offset) ⇒ Object
////////////////////////////////////////////////////////////////////////// //.
-
#getDataEntries(fBuf, rsc_id = nil) ⇒ Object
Walk the resource directories and collect all the directories and resource pointers.
-
#getIconById(icons, id) ⇒ Object
Find a particular raw icon.
- #getIconDirEntries(_fBuf) ⇒ Object
- #getIcons(fBuf) ⇒ Object
- #getImportList ⇒ Object
- #getImports ⇒ Object
- #getMessagetables(requested_locale = 0x0409) ⇒ Object
- #getNextResourceDirectoryEntry(resDirEntry) ⇒ Object
- #getNextResourceResourceEntry(resEntry, rsc_type, size) ⇒ Object
- #getRawIcons(_fBuf) ⇒ Object
- #getResourceDirectory(resDirEntry) ⇒ Object
- #getResourceDirectoryEntry(resDir) ⇒ Object
- #getResourceDirectoryEntryName(resDirEntry) ⇒ Object
- #getSectionTable(fBuf, fhHash, offset) ⇒ Object
-
#getVersioninfo(requested_locale = 0x0409) ⇒ Object
Get versioninfo resource.
- #getVersionInfoHash(fBuf) ⇒ Object
- #icons ⇒ Object
- #imports ⇒ Object
-
#initialize(path) ⇒ PEheader
constructor
A new instance of PEheader.
- #messagetables ⇒ Object
- #readPE ⇒ Object
- #versioninfo ⇒ Object
Constructor Details
#initialize(path) ⇒ PEheader
Returns a new instance of PEheader.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/metadata/util/win32/peheader.rb', line 19 def initialize(path) @fname = path @dataDirs = [] @sectionTable = [] @baseResDir = nil if path.class != String @fHnd = path fileseek(0, 'init') fBuf = fileread(2) else # Do some basic file validation raise Errno::ENOENT, "File [#{@fname}] does not exist." if File.exist?(@fname) == false raise "File [#{@fname}] is empty." if File.zero?(@fname) # Open file and read contents into buffer @fHnd = File.open(@fname, "rb") fBuf = fileread(2) @fHnd.close end # Check for the MZ header raise "Version Information header not found in file [#{@fname}]" unless fBuf[0..1] == IMAGE_DOS_SIGNATURE readPE end |
Instance Method Details
#adjustAddress(rva) ⇒ Object
411 412 413 414 415 416 417 418 419 420 |
# File 'lib/metadata/util/win32/peheader.rb', line 411 def adjustAddress(rva) @sectionTable.each do |s| # Is the RVA within this section? if (rva >= s[:virtualAddress]) && (rva < (s[:virtualAddress] + s[:VirtualSize])) delta = s[:virtualAddress] - s[:PointerToRawData] return rva - delta end end nil end |
#assembleIcons(iconEntries, grpIcons) ⇒ Object
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/metadata/util/win32/peheader.rb', line 194 def assembleIcons(iconEntries, grpIcons) # For each major sub in grpIcons, construct an .ico blob. icons = [] 0.upto(grpIcons.size - 1) do |fileIdx| # Write icon directory. baseOffset = 16 * grpIcons[fileIdx].size + 6 thisOffset = 0 ico = StringIO.new ico.write([0].pack('S')) # idReserved ico.write([1].pack('S')) # idType ico.write([grpIcons[fileIdx].size].pack('S')) # idCount 0.upto(grpIcons[fileIdx].size - 1) do |iconIdx| icon = grpIcons[fileIdx][iconIdx] # Write icon dir entry. ico.write([icon[:bWidth]].pack('C')) ico.write([icon[:bHeight]].pack('C')) ico.write([icon[:bColorCount]].pack('C')) ico.write([0].pack('C')) ico.write([icon[:wPlanes]].pack('S')) ico.write([icon[:wBitCount]].pack('S')) ico.write([icon[:dwBytesInRes]].pack('L')) ico.write([baseOffset + thisOffset].pack('L')) thisOffset += icon[:dwBytesInRes] end # Write icon data. 0.upto(grpIcons[fileIdx].size - 1) { |iconIdx| ico.write(getIconById(iconEntries, grpIcons[fileIdx][iconIdx][:nID])) } # Save it as a string. ico.rewind icons << ico.read end icons end |
#dumpResourceDirectory(resDir, level, data_hash, rsc_id = nil) ⇒ Object
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/metadata/util/win32/peheader.rb', line 284 def dumpResourceDirectory(resDir, level, data_hash, rsc_id = nil) resDirEntry = getResourceDirectoryEntry(resDir) # Process each entry in the directory. # Note: Named entries are listed first. 1.upto(resDir[:numberOfNamedEntries]) do dumpResourceEntry(resDirEntry, level + 1, data_hash, rsc_id) resDirEntry = getNextResourceDirectoryEntry(resDirEntry) end 1.upto(resDir[:numberOfIdEntries]) do dumpResourceEntry(resDirEntry, level + 1, data_hash, rsc_id) resDirEntry = getNextResourceDirectoryEntry(resDirEntry) end end |
#dumpResourceEntry(resDirEntry, level, data_hash, rsc_id) ⇒ Object
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/metadata/util/win32/peheader.rb', line 300 def dumpResourceEntry(resDirEntry, level, data_hash, rsc_id) # 1.upto(level) {print " "} resDirEntry[:name] = getResourceDirectoryEntryName(resDirEntry) resDirEntry[:level] = level if resDirEntry[:isDir] # Filter by resource type so we do not process every available resource return if level == 1 && rsc_id && resDirEntry[:name] != rsc_id resDir = getResourceDirectory(resDirEntry) resDirEntry[:numberOfIdEntries] = resDir[:numberOfIdEntries] resDirEntry[:numberOfNamedEntries] = resDir[:numberOfNamedEntries] # puts "DIR: #{resDirEntry.inspect}" data_hash[resDirEntry[:name]] = resDirEntry resDirEntry[:children] = {} dumpResourceDirectory(resDir, level, resDirEntry[:children], rsc_id) else data_hash[resDirEntry[:name]] = resDirEntry resDirEntry[:data] = IMAGE_RESOURCE_DATA_ENTRY.decode(@dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE][:data][resDirEntry[:offsetToData]..-1]) # puts "RSC: #{resDirEntry.inspect}" end end |
#fileread(length) ⇒ Object
85 86 87 88 89 90 |
# File 'lib/metadata/util/win32/peheader.rb', line 85 def fileread(length) # st = Time.now data = @fHnd.read(length) # $log.warn "read time [#{Time.now-st}]" if $log data end |
#fileseek(offset = 0, _message = nil) ⇒ Object
These file methods are here to assist in debugging
79 80 81 82 83 |
# File 'lib/metadata/util/win32/peheader.rb', line 79 def fileseek(offset = 0, = nil) # st = Time.now @fHnd.seek(offset, IO::SEEK_SET) # $log.warn "seek time [#{Time.now-st}] from [#{message}]" if $log end |
#find_all_resources(rsc, rsc_id = nil, &blk) ⇒ Object
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/metadata/util/win32/peheader.rb', line 383 def find_all_resources(rsc, rsc_id = nil, &blk) # Resource Directory Levels: # 1 = Resource Type # 2 = Resource Identifier # 3 = Resource Langauge ID rsc.each do |lang_id, item| if item[:isDir] rsc_id = item[:name] if item[:level] == 2 find_all_resources(item[:children], rsc_id, &blk) else item[:rsc_id] = rsc_id item[:lang_id] = lang_id yield(item) end end end |
#get_resources_by_type(rt, locale_id = nil) ⇒ Object
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/metadata/util/win32/peheader.rb', line 365 def get_resources_by_type(rt, locale_id = nil) if (rsc = getDataEntries(@fBuf, rt)[rt]) resources = [] find_all_resources(rsc[:children]) { |r| resources << r } return if resources.empty? # Finding a resource is often by locale. If we do not find the requested # locale then return the first one. unless locale_id.nil? local_rsc = resources.detect { |r| r[:lang_id] == locale_id } resources = local_rsc.nil? ? [resources.first] : [local_rsc] end # Yield the resource data to the caller resources.each { |r| yield(r) } end end |
#getBaseResDir(_fBuf) {|@baseResDir| ... } ⇒ Object
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
# File 'lib/metadata/util/win32/peheader.rb', line 349 def getBaseResDir(_fBuf) if @baseResDir.nil? rsc = @dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE] rsc[:offset] = rsc[:virtualAddress] unless rsc[:offset].zero? rsc[:offset] = adjustAddress(rsc[:offset]) # Read in the resource part the file fileseek(rsc[:offset], 'getBaseResDir') rsc[:data] = fileread(rsc[:size]) @baseResDir = IMAGE_RESOURCE_DIRECTORY.decode(rsc[:data][0, SIZEOF_IMAGE_RESOURCE_DIRECTORY]) @baseResDir[:offset_into_data] = 0 end end yield(@baseResDir) unless @baseResDir.nil? end |
#getDataDirs(fBuf, offset) ⇒ Object
////////////////////////////////////////////////////////////////////////// //
111 112 113 114 115 116 117 118 119 |
# File 'lib/metadata/util/win32/peheader.rb', line 111 def getDataDirs(fBuf, offset) offset += @IMAGE_OPTIONAL_HEADER.size IMAGE_NUMBEROF_DIRECTORY_ENTRIES.times do ddHash = IMAGE_DATA_DIRECTORY.decode(fBuf[offset..-1]) offset += SIZEOF_IMAGE_DATA_DIRECTORY @dataDirs.push(ddHash) end offset end |
#getDataEntries(fBuf, rsc_id = nil) ⇒ Object
Walk the resource directories and collect all the directories and resource pointers
278 279 280 281 282 |
# File 'lib/metadata/util/win32/peheader.rb', line 278 def getDataEntries(fBuf, rsc_id = nil) result = {} getBaseResDir(fBuf) { |baseResDir| dumpResourceDirectory(baseResDir, 0, result, rsc_id) } result end |
#getIconById(icons, id) ⇒ Object
Find a particular raw icon.
228 229 230 231 |
# File 'lib/metadata/util/win32/peheader.rb', line 228 def getIconById(icons, id) icons.each { |icon| return icon[:icon] if icon[:rsc_id] == id } nil end |
#getIconDirEntries(_fBuf) ⇒ Object
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/metadata/util/win32/peheader.rb', line 177 def getIconDirEntries(_fBuf) # Read icon directory. grpIcons = [] # iconDirEntries = getDataEntries(RT_GROUP_ICON, fBuf) get_resources_by_type(RT_GROUP_ICON) do |icon_rsc| ent = icon_rsc[:data] ent[:offset] = adjustAddress(ent[:offsetToData]) fileseek(ent[:offset], 'getIconDirEntries') iconDir = fileread(ent[:size]) iconDir = GRPICONDIR.decode(iconDir) grpIconDirEntries = [] 0.upto(iconDir[:idCount] - 1) { |i| grpIconDirEntries << GRPICONDIRENTRY.decode(iconDir[:data][i * SIZEOF_GRPICONDIRENTRY, SIZEOF_GRPICONDIRENTRY]) } grpIcons << grpIconDirEntries end grpIcons end |
#getIcons(fBuf) ⇒ Object
158 159 160 161 162 |
# File 'lib/metadata/util/win32/peheader.rb', line 158 def getIcons(fBuf) iconEntries = getRawIcons(fBuf) grpIcons = getIconDirEntries(fBuf) assembleIcons(iconEntries, grpIcons) end |
#getImportList ⇒ Object
422 423 424 425 426 427 428 429 |
# File 'lib/metadata/util/win32/peheader.rb', line 422 def getImportList return nil if imports.nil? unless imports.empty? import_list = "" imports.each { |i| import_list += i + ", " } return import_list.rstrip.chomp(",") end end |
#getImports ⇒ Object
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/metadata/util/win32/peheader.rb', line 130 def getImports imports_libs = [] import = @dataDirs[IMAGE_DIRECTORY_ENTRY_IMPORT] import[:offset] = import[:virtualAddress] if import[:offset] != 0 import[:offset] = adjustAddress(import[:offset]) fileseek(import[:offset], 'getImports') data = fileread(import[:size]) offset = 0 loop do iiHash = IMAGE_IMPORT_DESCRIPTOR.decode(data[offset..-1]) break if iiHash['Name'] == 0 offset += SIZEOF_IMAGE_IMPORT_DESCRIPTOR iiHash['Name'] = adjustAddress(iiHash['Name']) - import[:offset] # Check if we have enough data. This happens if the import data only contains pointers if (data.length <= iiHash['Name']) size = iiHash['Name'] - data.length + 4096 data += fileread(size) end nameEnd = iiHash['Name'] + data[iiHash['Name']..-1].index("\0") - 1 imports_libs.push(data[iiHash['Name']..nameEnd].downcase) end end imports_libs end |
#getMessagetables(requested_locale = 0x0409) ⇒ Object
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/metadata/util/win32/peheader.rb', line 233 def getMessagetables(requested_locale = 0x0409) # Read message table resources. = {} get_resources_by_type(RT_MESSAGETABLE, requested_locale) do |msg_resource| # Get the block directory for this messagetable. msg_data = msg_resource[:data] offset = adjustAddress(msg_data[:offsetToData]) - @dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE][:offset] blkdir = MESSAGE_RESOURCE_DATA.decode(@dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE][:data][offset, msg_data[:size]]) 0.upto(blkdir[:numberOfBlocks] - 1) do |i| # Break out each block. blk = MESSAGE_RESOURCE_BLOCK.decode(blkdir[:data][i * SIZEOF_MRB, SIZEOF_MRB]) adrs = blk[:offsetToEntries] - 4 # Grab the block's strings. blk[:loId].upto(blk[:hiId]) do |idx| ent1 = MESSAGE_RESOURCE_ENTRY.decode(blkdir[:data][adrs, SIZEOF_MRE]) if ent1[:length] > 0 len = ent1[:length] - SIZEOF_MRE str = blkdir[:data][adrs + SIZEOF_MRE, len] (ent1[:flags] == MESSAGE_RESOURCE_UNICODE) ? str.UnicodeToUtf8! : str.AsciiToUtf8! str.gsub!(/\000/, "") [idx] = str adrs += len end adrs += SIZEOF_MRE end end end end |
#getNextResourceDirectoryEntry(resDirEntry) ⇒ Object
337 338 339 |
# File 'lib/metadata/util/win32/peheader.rb', line 337 def getNextResourceDirectoryEntry(resDirEntry) getNextResourceResourceEntry(resDirEntry, IMAGE_RESOURCE_DIRECTORY_ENTRY, SIZEOF_IMAGE_RESOURCE_DIRECTORY_ENTRY) end |
#getNextResourceResourceEntry(resEntry, rsc_type, size) ⇒ Object
341 342 343 344 345 346 347 |
# File 'lib/metadata/util/win32/peheader.rb', line 341 def getNextResourceResourceEntry(resEntry, rsc_type, size) offset = resEntry[:offset_into_data] + size entry = rsc_type.decode(@dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE][:data][offset..-1]) entry[:offset_into_data] = offset entry[:isDir] = bit?(entry[:offsetToData], 31) entry end |
#getRawIcons(_fBuf) ⇒ Object
164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/metadata/util/win32/peheader.rb', line 164 def getRawIcons(_fBuf) # Read raw icons. iconEntries = [] get_resources_by_type(RT_ICON) do |icon_rsc| ent = icon_rsc[:data] ent[:offset] = adjustAddress(ent[:offsetToData]) fileseek(ent[:offset], 'getRawIcons') icon_rsc[:icon] = fileread(ent[:size]) iconEntries << icon_rsc end iconEntries end |
#getResourceDirectory(resDirEntry) ⇒ Object
326 327 328 329 330 331 |
# File 'lib/metadata/util/win32/peheader.rb', line 326 def getResourceDirectory(resDirEntry) offset = resDirEntry[:offsetToData] & 0x7fffffff resDir = IMAGE_RESOURCE_DIRECTORY.decode(@dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE][:data][offset..-1]) resDir[:offset_into_data] = offset resDir end |
#getResourceDirectoryEntry(resDir) ⇒ Object
333 334 335 |
# File 'lib/metadata/util/win32/peheader.rb', line 333 def getResourceDirectoryEntry(resDir) getNextResourceResourceEntry(resDir, IMAGE_RESOURCE_DIRECTORY_ENTRY, SIZEOF_IMAGE_RESOURCE_DIRECTORY) end |
#getResourceDirectoryEntryName(resDirEntry) ⇒ Object
400 401 402 403 404 405 406 407 408 409 |
# File 'lib/metadata/util/win32/peheader.rb', line 400 def getResourceDirectoryEntryName(resDirEntry) return resDirEntry[:name] unless bit?(resDirEntry[:name], 31) # The low 30 bits of the 'Name' member is an offset to an IMAGE_RESOURCE_DIRECTORY_STRING_U struct. str = "" ptr = (resDirEntry[:name] & 0x7fffffff) len = @dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE][:data][ptr, 2].unpack('S')[0] str = @dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE][:data][ptr + 2, len * 2] str.UnicodeToUtf8! end |
#getSectionTable(fBuf, fhHash, offset) ⇒ Object
121 122 123 124 125 126 127 128 |
# File 'lib/metadata/util/win32/peheader.rb', line 121 def getSectionTable(fBuf, fhHash, offset) fhHash['NumberOfSections'].times do shHash = IMAGE_SECTION_HEADER.decode(fBuf[offset..-1]) offset += SIZEOF_IMAGE_SECTION_HEADER @sectionTable.push(shHash) end offset end |
#getVersioninfo(requested_locale = 0x0409) ⇒ Object
Get versioninfo resource.
265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/metadata/util/win32/peheader.rb', line 265 def getVersioninfo(requested_locale = 0x0409) aVersioninfoHash = {} get_resources_by_type(RT_VERSION, requested_locale) do |versionEntry| ent = versionEntry[:data] offset = adjustAddress(ent[:offsetToData]) - @dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE][:offset] versionInfo = @dataDirs[IMAGE_DIRECTORY_ENTRY_RESOURCE][:data][offset, ent[:size]] # versionInfo is a VS_FIXEDFILEINFO structure followed by StringFileInfo. aVersioninfoHash = getVersionInfoHash(versionInfo) end aVersioninfoHash end |
#getVersionInfoHash(fBuf) ⇒ Object
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 |
# File 'lib/metadata/util/win32/peheader.rb', line 431 def getVersionInfoHash(fBuf) viHash = {} # Find VS Version Info signature idx = fBuf.index(VS_VERSION_INFO) return viHash unless idx # raise "Version Information header not found in file" unless idx # $log.debug sprintf("Found at index: [0X%08X] (%d)", idx, idx) # Reduce buffer to just the signature to the end of the file fBuf = fBuf[idx..fBuf.length] offset = 0 vhHash = VS_VERSION_INFO_HEADER.decode(fBuf[offset..(offset + SIZEOF_VS_VERSION_INFO_HEADER)]) # Create VersionInfo hash viHash['FILEVERSION_HEADER'] = vhHash['fmajor'].to_s + "," + vhHash['fminor'].to_s + "," + vhHash['frev'].to_s + "," + vhHash['fbuild'].to_s viHash['PRODUCTVERSION_HEADER'] = vhHash['pmajor'].to_s + "," + vhHash['pminor'].to_s + "," + vhHash['prev'].to_s + "," + vhHash['pbuild'].to_s # Find the string file info signautre idx = fBuf.index(STRINGFILEINFO) return viHash unless idx # raise "String File information header not found in file [#{fname}]" unless idx offset = idx viEnd = offset + SIZEOF_STRING_INFO_HEADER viHash.merge!(STRING_INFO_HEADER.decode(fBuf[offset..viEnd])) viHash['sig'].UnicodeToUtf8!.tr!("\0", "") viHash['code_page'].UnicodeToUtf8!.tr!("\0", "") viHash['lang'].UnicodeToUtf8!.tr!("\0", "") # Read offsets for next string offset = viEnd vsHash = VERSION_STRING_HEADER.decode(fBuf[offset..offset + 6]) # Calculate the amount of version info data offset_end = offset + viHash['data_length'] - SIZEOF_STRING_INFO_HEADER while offset < offset_end break unless vsHash['zero'] == 0 break if vsHash['zero'].nil? || vsHash['vlen'].nil? || vsHash['slen'].nil? offset += SIZEOF_VERSION_STRING_HEADER name_len = vsHash['slen'] - 4 - (vsHash['vlen'] * 2) - 2 name = fBuf[offset...offset + name_len] offset += name_len value_len = (vsHash['vlen'] * 2) - 2 value = fBuf[offset...offset + value_len] break if name.nil? or value.nil? or name.empty? name.UnicodeToUtf8!.delete!("\0") # Do not allow spaces in the attribute names (will invalidate a XML file) name.tr!(" ", "_") value.UnicodeToUtf8!.delete!("\0") # $log.debug "[#{name}] => [#{value}]" viHash[name] = value offset += value_len + (vsHash['vlen'] % 2 * 2) # Read next offset header vsHash = VERSION_STRING_HEADER.decode(fBuf[offset..offset + 6]) # This is a work-around. In case the offset to the next record is slightly off unless vsHash['zero'] == 0 offset -= 2 # Read next offset header vsHash = VERSION_STRING_HEADER.decode(fBuf[offset..offset + 6]) end end viHash end |
#icons ⇒ Object
96 97 98 |
# File 'lib/metadata/util/win32/peheader.rb', line 96 def icons @icons ||= getIcons(@fBuf) end |
#imports ⇒ Object
92 93 94 |
# File 'lib/metadata/util/win32/peheader.rb', line 92 def imports @imports ||= getImports end |
#messagetables ⇒ Object
100 101 102 |
# File 'lib/metadata/util/win32/peheader.rb', line 100 def @messagetables ||= getMessagetables end |
#readPE ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/metadata/util/win32/peheader.rb', line 46 def readPE if @fname.class != String @fHnd = @fname fileseek(0, 'readPE') else # Open file @fHnd = File.open(@fname, "rb") end # Read contents into buffer # TODO: determine the proper amount of data to load here @fBuf = fileread(10240) # Read offsets for next string dhHash = IMAGE_DOS_HEADER.decode(@fBuf) offset = dhHash['e_lfanew'] # Offset to PE header raise "PE header not found in file [#{@fname}]" unless @fBuf[offset...offset + 4] == IMAGE_NT_SIGNATURE offset += 4 fhHash = IMAGE_FILE_HEADER.decode(@fBuf[offset..-1]) offset += SIZEOF_IMAGE_FILE_HEADER @is64Bit = fhHash['SizeOfOptionalHeader'] == IMAGE_SIZEOF_NT_OPTIONAL64_HEADER @IMAGE_OPTIONAL_HEADER = (@is64Bit == true) ? IMAGE_OPTIONAL_HEADER64 : IMAGE_OPTIONAL_HEADER32 # Commented out the following, since it is not currently being used. # ohHash = @IMAGE_OPTIONAL_HEADER.decode(@fBuf[offset, @IMAGE_OPTIONAL_HEADER.size]) # Read all the data directories & section table. offset = getDataDirs(@fBuf, offset) offset = getSectionTable(@fBuf, fhHash, offset) end |
#versioninfo ⇒ Object
104 105 106 |
# File 'lib/metadata/util/win32/peheader.rb', line 104 def versioninfo @versioninfo ||= getVersioninfo end |