class PEdump
pedump.rb by zed_0xff
http://zed.0xff.me http://github.com/zed-0xff
Constants
- CURDIRENTRY
- CURSOR_HOTSPOT
- CUR_ICO_HEADER
- EFI_IMAGE_DATA_DIRECTORY
www.intel.com/content/www/us/en/architecture-and-technology/unified-extensible-firmware-interface/efi-specifications-general-technology.html wiki.phoenix.com/wiki/index.php/EFI_TE_IMAGE_HEADER formats.kaitai.io/uefi_te/index.html ho.ax/tag/efi/ github.com/gdbinit/TELoader
- GOOD_FUNCTION_NAME_RE
- ICODIRENTRY
- IMAGE_DATA_DIRECTORY
- IMAGE_EXPORT_DIRECTORY
- IMAGE_IMPORT_DESCRIPTOR
sandsprite.com/CodeStuff/Understanding_imports.html stackoverflow.com/questions/5631317/import-table-it-vs-import-address-table-iat
- IMAGE_RESOURCE_DATA_ENTRY
- IMAGE_RESOURCE_DIRECTORY
- IMAGE_RESOURCE_DIRECTORY_ENTRY
- IMAGE_SECTION_HEADER
- IMAGE_SUBSYSTEMS
msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=VS.85).aspx
- IMAGE_TLS_DIRECTORY32
- IMAGE_TLS_DIRECTORY64
- MAX_ERRORS
- MAX_EXPORT_NUMBER_OF_NAMES
- MAX_IMAGE_IMPORT_DESCRIPTORS
- MINIDUMP_LOCATION_DESCRIPTOR
- MINIDUMP_MEMORY_DESCRIPTOR
- MINIDUMP_MEMORY_DESCRIPTOR64
- MINIDUMP_MEMORY_INFO
- MINIDUMP_STREAM_TYPE
msdn.microsoft.com/en-us/library/windows/desktop/ms680394(v=vs.85).aspx
- MZ
- RICH_IDS
data from raw.githubusercontent.com/dishather/richprint/master/comp_id.txt
- ROOT_RES_NAMES
- STRING
- SUPPORTED_SIGNATURES
- TE
- VERSION
Attributes
fname[RW]
force[RW]
io[RW]
logger[RW]
Public Class Methods
dump(fname, params = {})
click to toggle source
# File lib/pedump.rb, line 328 def self.dump fname, params = {} new(fname, params).dump end
logger()
click to toggle source
# File lib/pedump/core.rb, line 35 def logger; @@logger; end
logger=(l;)
click to toggle source
# File lib/pedump/core.rb, line 36 def logger= l; @@logger=l; end
new(io = nil, params = {})
click to toggle source
# File lib/pedump.rb, line 41 def initialize io = nil, params = {} if io.is_a?(Hash) @io, params = nil, io else @io = io end @force = params[:force] @logger = @@logger = Logger.create(params) end
ordlookup(dll, ord, make_name: false)
click to toggle source
# File lib/pedump/ordlookup.rb, line 5 def self.ordlookup(dll, ord, make_name: false) dll = dll.downcase @ordlookup ||= {} @ordlookup[dll] ||= begin yml_fname = File.expand_path(File.dirname(__FILE__) + "/../../data/ordlookup/" + dll + ".yml") if File.exist?(yml_fname) YAML.load_file(yml_fname) else {} end end @ordlookup[dll][ord] || (make_name ? "ord#{ord}" : nil) end
quiet() { || ... }
click to toggle source
# File lib/pedump.rb, line 332 def self.quiet oldlevel = @@logger.level @@logger.level = ::Logger::FATAL yield ensure @@logger.level = oldlevel end
Public Instance Methods
_detect_format()
click to toggle source
# File lib/pedump.rb, line 509 def _detect_format return :pe if @pe return :ne if @ne return :te if @te return :pe if pe() return :ne if ne() return :te if te() nil end
_dump_handle(h)
click to toggle source
# File lib/pedump.rb, line 459 def _dump_handle h if pe(h) # also calls mz(h) rich_hdr h resources h imports h # also calls tls(h) exports h packer h elsif te(h) end end
_read_resource_directory_tree(f)
click to toggle source
# File lib/pedump/resources.rb, line 12 def _read_resource_directory_tree f return nil unless pe(f) && pe(f).ioh && f res_dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::RESOURCE] return [] if !res_dir || (res_dir.va == 0 && res_dir.size == 0) res_va = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::RESOURCE].va res_section = @pe.section_table.find{ |t| t.VirtualAddress == res_va } unless res_section logger.warn "[?] can't find resource section for va=0x#{res_va.to_s(16)}" return [] end f.seek res_section.PointerToRawData IMAGE_RESOURCE_DIRECTORY.base = res_section.PointerToRawData #@resource_data_base = res_section.PointerToRawData - res_section.VirtualAddress IMAGE_RESOURCE_DIRECTORY.read(f) end
_scan_pe_resources(f=@io, dir=nil)
click to toggle source
# File lib/pedump/resources.rb, line 379 def _scan_pe_resources f=@io, dir=nil dir ||= resource_directory(f) return nil unless dir @pe_res_errors ||= 0 r = [] dir.entries.each_with_index do |entry,idx| case entry.data when IMAGE_RESOURCE_DIRECTORY if dir == @resource_directory # root resource directory entry_type = if entry.Name & 0x8000_0000 == 0 # root resource directory & entry name is a number ROOT_RES_NAMES[entry.Name] || entry.name else entry.name end r += _scan_pe_resources(f,entry.data).each do |res| res.type = entry_type res.parse f end else r += _scan_pe_resources(f,entry.data).each do |res| res.name = res.name == "##{res.lang}" ? entry.name : "#{entry.name} / #{res.name}" res.id ||= entry.Name if entry.Name.is_a?(Numeric) && entry.Name < 0x8000_0000 end end when IMAGE_RESOURCE_DATA_ENTRY file_offset = va2file(entry.data.OffsetToData, :quiet => (@pe_res_errors > MAX_ERRORS)) unless file_offset @pe_res_errors += 1 if @pe_res_errors > MAX_ERRORS PEdump.logger.warn "[?] too many errors getting resource data, stopped on #{idx} of #{dir.entries.size}" break end end r << Resource.new( nil, # type entry.name, nil, # id entry.Name, # lang #entry.data.OffsetToData + @resource_data_base, file_offset, entry.data.Size, entry.data.CodePage, entry.data.Reserved ) else if entry.data logger.error "[!] invalid resource entry: #{entry.data.inspect}" else # show NULL entries only in verbose mode logger.info "[!] invalid resource entry: #{entry.data.inspect}" end end end r.flatten.compact end
data_directory(f=@io)
click to toggle source
# File lib/pedump.rb, line 470 def data_directory f=@io if pe(f) pe.ioh && pe.ioh.DataDirectory elsif te(f) te.DataDirectory end end
dos_stub(f=@io)
click to toggle source
# File lib/pedump.rb, line 353 def dos_stub f=@io @dos_stub ||= begin return nil unless mz = mz(f) dos_stub_offset = mz.header_paragraphs.to_i * 0x10 dos_stub_size = mz.lfanew.to_i - dos_stub_offset if dos_stub_offset < 0 logger.warn "[?] invalid DOS stub offset #{dos_stub_offset}" nil elsif f && dos_stub_offset > f.size logger.warn "[?] DOS stub offset beyond EOF: #{dos_stub_offset}" nil elsif dos_stub_size < 0 logger.warn "[?] invalid DOS stub size #{dos_stub_size}" nil elsif dos_stub_size == 0 # no DOS stub, it's ok nil elsif !f # no open file, it's ok nil else return nil if dos_stub_size == MZ::SIZE && dos_stub_offset == 0 if dos_stub_size > 0x1000 logger.warn "[?] DOS stub size too big (#{dos_stub_size}), limiting to 0x1000" dos_stub_size = 0x1000 end f.seek dos_stub_offset DOSStub.new(f.read(dos_stub_size)).tap do |dos_stub| dos_stub.offset = dos_stub_offset if dos_stub['Rich'] if @rich_hdr = RichHdr.from_dos_stub(dos_stub) dos_stub[dos_stub.index(@rich_hdr)..-1] = '' end end end end end end
dump(f=@io)
click to toggle source
OPTIONAL: assigns @mz, @rich_hdr, @pe, etc
# File lib/pedump.rb, line 448 def dump f=@io if f.is_a?(String) File.open(f,'rb'){ |f| _dump_handle(f) } elsif f.is_a?(::IO) _dump_handle f elsif @io _dump_handle @io end self end
exports(f=@io)
click to toggle source
# File lib/pedump.rb, line 755 def exports f=@io if pe(f) pe_exports(f) elsif ne(f) ne(f).exports end end
imphash(f=@io)
click to toggle source
# File lib/pedump.rb, line 578 def imphash f=@io return @imphash if @imphash return nil unless pe(f) && pe(f).ioh && f imports = imports(f) return nil if imports.empty? a = [] imports.each do |iid| next unless iid.module_name names = [iid.original_first_thunk, iid.first_thunk].compact.flatten.map do |x| x.name || PEdump.ordlookup(iid.module_name, x.ordinal, make_name: true) end.compact.map(&:downcase).uniq libname = iid.module_name.downcase.sub(/\.(ocx|sys|dll)$/,'') # as in python's pefile names.each do |name| a << "#{libname}.#{name}" end end return nil if a.empty? @imphash = Digest::MD5.hexdigest(a.join(",")) end
imports(f=@io)
click to toggle source
# File lib/pedump.rb, line 568 def imports f=@io if pe(f) pe_imports(f) elsif ne(f) ne(f).imports else [] end end
logger=(l)
click to toggle source
# File lib/pedump.rb, line 324 def logger= l @logger = @@logger = l end
mz(f=@io)
click to toggle source
# File lib/pedump.rb, line 340 def mz f=@io @mz ||= f && MZ.read(f).tap do |mz| if mz.signature != 'MZ' && mz.signature != 'ZM' if @force #logger.warn "[?] no MZ signature. want: 'MZ' or 'ZM', got: #{mz.signature.inspect}" else #logger.error "[!] no MZ signature. want: 'MZ' or 'ZM', got: #{mz.signature.inspect}. (not forced)" return nil end end end end
ne(f=@io)
click to toggle source
# File lib/pedump/ne.rb, line 402 def ne f=@io return @ne if defined?(@ne) @ne ||= begin ne_offset = mz(f) && mz(f).lfanew if ne_offset.nil? logger.debug "[!] NULL NE offset (e_lfanew)." nil elsif ne_offset > f.size logger.fatal "[!] NE offset beyond EOF." nil else f.seek ne_offset if f.read(2) == 'NE' f.seek ne_offset NE.read f else nil end end end end
ne?()
click to toggle source
# File lib/pedump.rb, line 523 def ne? _detect_format() == :ne end
packer(f=@io)
click to toggle source
packer / compiler detection
# File lib/pedump.rb, line 910 def packer f=@io @packer ||= pe(f) && @pe.ioh && begin if PEdump::Packer.all.size == 0 logger.error "[?] no packer definitions found" nil else Packer.of f, :pedump => self end end end
Also aliased as: packers
pe(f=@io)
click to toggle source
# File lib/pedump/pe.rb, line 115 def pe f=@io @pe ||= begin pe_offset = mz(f) && mz(f).lfanew if pe_offset.nil? logger.debug "[!] NULL PE offset (e_lfanew). cannot continue." nil elsif pe_offset > f.size logger.fatal "[!] PE offset beyond EOF. cannot continue." nil else f.seek pe_offset PE.read f, :force => @force end end end
pe?()
click to toggle source
# File lib/pedump.rb, line 519 def pe? _detect_format() == :pe end
pe_exports(f=@io)
click to toggle source
# File lib/pedump.rb, line 763 def pe_exports f=@io return @exports if @exports return nil unless pe(f) && pe(f).ioh && f dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::EXPORT] return nil if !dir || (dir.va == 0 && dir.size == 0) va = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::EXPORT].va file_offset = va2file(va) return nil unless file_offset if !f.checked_seek(file_offset) || f.eof? logger.warn "[?] exports info beyond EOF" return nil end @exports = IMAGE_EXPORT_DIRECTORY.read(f).tap do |x| x.entry_points = [] x.name_ordinals = [] x.names = [] if x.Name.to_i != 0 && (ofs = va2file(x.Name)) f.seek ofs if f.eof? logger.warn "[?] export ofs 0x#{ofs.to_s(16)} beyond EOF" nil else x.name = f.gets("\x00").chomp("\x00") end end if x.NumberOfFunctions.to_i > 0 if x.AddressOfFunctions.to_i !=0 && (ofs = va2file(x.AddressOfFunctions)) f.seek ofs x.entry_points = [] x.NumberOfFunctions.times do if f.eof? logger.warn "[?] got EOF while reading exports entry_points" break end x.entry_points << f.read(4).unpack('V').first end end if x.AddressOfNameOrdinals.to_i !=0 && (ofs = va2file(x.AddressOfNameOrdinals)) f.seek ofs x.name_ordinals = [] x.NumberOfNames.times do if f.eof? logger.warn "[?] got EOF while reading exports name_ordinals" break end x.name_ordinals << f.read(2).unpack('v').first + x.Base end end end if x.NumberOfNames.to_i > 0 && x.AddressOfNames.to_i !=0 && (ofs = va2file(x.AddressOfNames)) f.seek ofs x.names = [] x.NumberOfNames.times do if f.eof? logger.warn "[?] got EOF while reading exports names" break end x.names << f.read(4).unpack('V').first end nErrors = 0 x.names.size.times do |i| begin f.seek va2file(x.names[i]) x.names[i] = f.gets("\x00").to_s.chomp("\x00") rescue nErrors += 1 if nErrors > MAX_ERRORS logger.warn "[?] too many errors getting export names, stopped on #{i} of #{x.names.size}" x.names = x.names[0,i] break end nil end end end ord2name = {} if x.names && x.names.any? n = x.NumberOfNames if n > MAX_EXPORT_NUMBER_OF_NAMES logger.warn "[?] NumberOfNames too big (#{x.NumberOfNames}), limiting to #{MAX_EXPORT_NUMBER_OF_NAMES}" n = MAX_EXPORT_NUMBER_OF_NAMES end n.times do |i| ord2name[x.name_ordinals[i]] ||= [] ord2name[x.name_ordinals[i]] << x.names[i] end end x.functions = [] x.entry_points.each_with_index do |ep,i| names = ord2name[i+x.Base] names = names.join(', ') if names next if ep.to_i == 0 && names.nil? x.functions << ExportedFunction.new(names, i+x.Base, ep) end end end
pe_imports(f=@io)
click to toggle source
# File lib/pedump.rb, line 602 def pe_imports f=@io return @imports if @imports return nil unless pe(f) && pe(f).ioh && f dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::IMPORT] return [] if !dir || (dir.va == 0 && dir.size == 0) file_offset = va2file(dir.va) return nil unless file_offset # scan TLS first, to catch many fake imports trick from # http://code.google.com/p/corkami/source/browse/trunk/asm/PE/manyimportsW7.asm tls_aoi = nil if (tls = tls(f)) && tls.any? tls_aoi = tls.first.AddressOfIndex.to_i - @pe.ioh.ImageBase.to_i tls_aoi = tls_aoi > 0 ? va2file(tls_aoi) : nil end r = []; t = nil if f.checked_seek(file_offset) while true if tls_aoi && tls_aoi == file_offset+16 # catched the neat trick! :) # f.tell + 12 = offset of 'FirstThunk' field from start of IMAGE_IMPORT_DESCRIPTOR structure logger.warn "[!] catched the 'imports terminator in TLS trick'" # http://code.google.com/p/corkami/source/browse/trunk/asm/PE/manyimportsW7.asm break end if r.size >= MAX_IMAGE_IMPORT_DESCRIPTORS logger.warn "[!] too many IMAGE_IMPORT_DESCRIPTORs, not reading more than #{r.size}" break end t = IMAGE_IMPORT_DESCRIPTOR.read(f) break if t.Name.to_i == 0 # also catches EOF r << t file_offset += IMAGE_IMPORT_DESCRIPTOR::SIZE end else logger.warn "[?] imports info beyond EOF" end n_bad_names = 0 logger.warn "[?] non-empty last IMAGE_IMPORT_DESCRIPTOR: #{t.inspect}" if t && !t.empty? @imports = r r = nil @imports.each_with_index do |x, iidx| if n_bad_names > MAX_ERRORS logger.warn "[!] too many bad imported function names. skipping further imports parsing" @imports = @imports[0,iidx] break end if x.Name.to_i != 0 && (ofs = va2file(x.Name)) begin f.seek ofs rescue logger.warn "[?] cannot seek to #{ofs} (VA=0x#{x.Name.to_i.to_s(16)} for reading imports, skipped" next end x.module_name = f.gets("\x00").to_s.chomp("\x00") end [:original_first_thunk, :first_thunk].each do |tbl| camel = tbl.capitalize.to_s.gsub(/_./){ |char| char[1..-1].upcase} if x[camel].to_i != 0 && (ofs = va2file(x[camel])) && f.checked_seek(ofs) x[tbl] ||= [] if pe.x64? x[tbl] << t while (t = f.read(8).to_s.unpack('Q').first).to_i != 0 else x[tbl] << t while (t = f.read(4).to_s.unpack('V').first).to_i != 0 end end cache = {} bits = pe.x64? ? 64 : 32 mask = 2**(bits-1) idx = -1 x[tbl] && x[tbl].map! do |t| idx += 1 va = x[camel].to_i + idx*4 cache[t] ||= if t & mask > 0 # 0x8000_0000(_0000_0000) ImportedFunction.new(nil,nil,t & (mask-1),va) # 0x7fff_ffff(_ffff_ffff) elsif ofs=va2file(t, :quiet => true) if !f.checked_seek(ofs) || f.eof? logger.warn "[?] import ofs 0x#{ofs.to_s(16)} VA=0x#{t.to_s(16)} beyond EOF" nil else hint = f.read(2).unpack('v').first name = f.gets("\x00").to_s.chomp("\x00") if !name.empty? && name !~ GOOD_FUNCTION_NAME_RE n_bad_names += 1 if n_bad_names > MAX_ERRORS nil else ImportedFunction.new(hint, name, nil, va) end else ImportedFunction.new(hint, name, nil, va) end end elsif tbl == :original_first_thunk # OriginalFirstThunk entries can not be invalid, show a warning msg logger.warn "[?] invalid VA 0x#{t.to_s(16)} in #{camel}[#{idx}] for #{x.module_name}" nil elsif tbl == :first_thunk # FirstThunk entries can be invalid, so `info` msg only logger.info "[?] invalid VA 0x#{t.to_s(16)} in #{camel}[#{idx}] for #{x.module_name}" nil else raise "You are not supposed to be here! O_o" end end x[tbl] && x[tbl].compact! end # [:original_first_thunk, :first_thunk].each if x.original_first_thunk && !x.first_thunk logger.warn "[?] import table: empty FirstThunk for #{x.module_name}" elsif !x.original_first_thunk && x.first_thunk logger.info "[?] import table: empty OriginalFirstThunk for #{x.module_name}" elsif logger.debug? # compare all but VAs if x.original_first_thunk != x.first_thunk logger.debug "[?] import table: OriginalFirstThunk != FirstThunk for #{x.module_name}" end end end # r.each @imports end
resource_directory(f=@io)
click to toggle source
# File lib/pedump/resources.rb, line 3 def resource_directory f=@io @resource_directory ||= if pe(f) _read_resource_directory_tree(f) elsif ne(f) ne(f).resource_directory(f) end end
resources(f=@io)
click to toggle source
resources
# File lib/pedump.rb, line 893 def resources f=@io @resources ||= if pe(f) _scan_pe_resources(f) elsif ne(f) ne(f).resources(f) end end
rich_hdr(f=@io)
click to toggle source
# File lib/pedump.rb, line 393 def rich_hdr f=@io dos_stub(f) && @rich_hdr end
Also aliased as: rich_header, rich
sections(f=@io)
click to toggle source
# File lib/pedump.rb, line 478 def sections f=@io if pe(f) pe.section_table elsif ne(f) ne.segments elsif te(f) te.sections end end
Also aliased as: section_table
security(f=@io)
click to toggle source
# File lib/pedump/security.rb, line 2 def security f=@io return nil unless pe(f) && pe(f).ioh && f dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::SECURITY] return nil if !dir || dir.va == 0 # IMAGE_DIRECTORY_ENTRY_SECURITY # Points to a list of WIN_CERTIFICATE structures, defined in WinTrust.H. # Not mapped into memory as part of the image. # Therefore, the VirtualAddress field is a file offset, rather than an RVA. # # http://msdn.microsoft.com/en-us/magazine/bb985997.aspx f.seek dir.va r = [] ofs = f.tell while !f.eof? && (f.tell-ofs < dir.size) r << WIN_CERTIFICATE.read(f) end r end
Also aliased as: signature
strings(f=@io)
click to toggle source
# File lib/pedump/resources.rb, line 227 def strings f=@io r = [] Array(resources(f)).find_all{ |x| x.type == 'STRING'}.each do |res| res.data.each_with_index do |string,idx| r << STRING.new( ((res.id.to_i-1)<<4) + idx, res.lang, string ) unless string.empty? end end r end
supported_file?(f=@io)
click to toggle source
# File lib/pedump.rb, line 489 def supported_file? f=@io pos = f.tell sig = f.read(2) f.seek(pos) if SUPPORTED_SIGNATURES.include?(sig) true else unless @not_supported_sig_warned msg = "no supported signature. want: #{SUPPORTED_SIGNATURES.join("/")}, got: #{sig.inspect}" if @force logger.warn "[?] #{msg}" else logger.error "[!] #{msg}. (not forced)" end @not_supported_sig_warned = true end false end end
te(f=@io)
click to toggle source
# File lib/pedump/te.rb, line 48 def te f=@io return @te if defined?(@te) @te ||= begin te_offset = 0 f.seek te_offset if f.read(2) == 'VZ' f.seek te_offset EFI_TE_IMAGE_HEADER.read f, :force => @force else nil end end end
te?()
click to toggle source
# File lib/pedump.rb, line 527 def te? _detect_format() == :te end
te_shift()
click to toggle source
# File lib/pedump/te.rb, line 40 def te_shift if @te @te.StrippedSize - EFI_TE_IMAGE_HEADER::REAL_SIZE else 0 end end
tls(f=@io)
click to toggle source
TLS
# File lib/pedump.rb, line 866 def tls f=@io @tls ||= pe(f) && pe(f).ioh && f && begin dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::TLS] return nil if !dir || dir.va == 0 return nil unless file_offset = va2file(dir.va) f.seek file_offset if f.eof? logger.info "[?] TLS info beyond EOF" return nil end klass = @pe.x64? ? IMAGE_TLS_DIRECTORY64 : IMAGE_TLS_DIRECTORY32 nEntries = [1,dir.size / klass.const_get('SIZE')].max r = [] nEntries.times do break if f.eof? || !(entry = klass.read(f)) r << entry end r end end
va2file(va, h={})
click to toggle source
# File lib/pedump.rb, line 399 def va2file va, h={} return nil if va.nil? va0 = va # save for log output of original addr if pe? # most common case, do nothing elsif te? va = va - te_shift() end sections.each do |s| if (s.VirtualAddress...(s.VirtualAddress+s.VirtualSize)).include?(va) offset = va - s.VirtualAddress return (s.PointerToRawData + offset) if offset < s.SizeOfRawData end end # not found with regular search. assume any of VirtualSize was 0, and try with RawSize sections.each do |s| if (s.VirtualAddress...(s.VirtualAddress+s.SizeOfRawData)).include?(va) offset = va - s.VirtualAddress return (s.PointerToRawData + offset) if offset < s.SizeOfRawData end end # still not found, bad/zero VirtualSizes & RawSizes ? # a special case - PE without sections return va if sections.empty? # check if only one section if sections.size == 1 || sections.all?{ |s| s.VirtualAddress.to_i == 0 } s = sections.first offset = va - s.VirtualAddress return (s.PointerToRawData + offset) if offset < s.SizeOfRawData #return va - s.VirtualAddress + s.PointerToRawData end # TODO: not all VirtualAdresses == 0 case if h[:quiet] logger.debug "[?] can't find file_offset of VA 0x#{va0.to_i.to_s(16)} (quiet=true)" else logger.error "[?] can't find file_offset of VA 0x#{va0.to_i.to_s(16)}" end nil end
version_info(f=@io)
click to toggle source
# File lib/pedump.rb, line 902 def version_info f=@io resources(f) && resources(f).find_all{ |res| res.type == 'VERSION' }.map(&:data).flatten end