Class: PEdump
- Defined in:
- lib/pedump.rb,
lib/pedump/ne.rb,
lib/pedump/pe.rb,
lib/pedump/tls.rb,
lib/pedump/core.rb,
lib/pedump/logger.rb,
lib/pedump/packer.rb,
lib/pedump/version.rb,
lib/pedump/security.rb,
lib/pedump/resources.rb,
lib/pedump/sig_parser.rb,
lib/pedump/composite_io.rb,
lib/pedump/version_info.rb,
lib/pedump/ne/version_info.rb
Overview
pedump.rb by zed_0xff
http://zed.0xff.me
http://github.com/zed-0xff
Defined Under Namespace
Modules: IMAGE_OPTIONAL_HEADER, Readable, SigParser, Unpacker, Version Classes: BITMAPINFOHEADER, CLI, ColoredLogger, Comparer, CompositeIO, DOSStub, ExportedFunction, IMAGE_FILE_HEADER, IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, IMAGE_RESOURCE_DIRECTORY, IMAGE_SECTION_HEADER, ImportedFunction, Loader, Logger, NE, PE, Packer, Resource, RichHdr, STRING, StringFileInfo, StringTable, VS_FIXEDFILEINFO, VS_VERSIONINFO, Var, VarFileInfo, VersionString, WIN_CERTIFICATE
Constant Summary collapse
- VERSION =
Version::STRING
- MZ =
create_struct( "a2v13Qv2V6", :signature, :bytes_in_last_block, :blocks_in_file, :num_relocs, :header_paragraphs, :min_extra_paragraphs, :max_extra_paragraphs, :ss, :sp, :checksum, :ip, :cs, :reloc_table_offset, :overlay_number, :reserved0, # 8 reserved bytes :oem_id, :oem_info, :reserved2, # 20 reserved bytes :reserved3, :reserved4, :reserved5, :reserved6, :lfanew )
- IMAGE_DATA_DIRECTORY =
create_struct( "VV", :va, :size, :type )
- IMAGE_SUBSYSTEMS =
%w'UNKNOWN NATIVE WINDOWS_GUI WINDOWS_CUI' + [nil,'OS2_CUI',nil,'POSIX_CUI',nil] + %w'WINDOWS_CE_GUI EFI_APPLICATION EFI_BOOT_SERVICE_DRIVER EFI_RUNTIME_DRIVER EFI_ROM XBOX' + [nil, 'WINDOWS_BOOT_APPLICATION']
- IMAGE_IMPORT_DESCRIPTOR =
create_struct 'V5', :OriginalFirstThunk, :TimeDateStamp, :ForwarderChain, :Name, :FirstThunk, # manual: :module_name, :original_first_thunk, :first_thunk
- IMAGE_EXPORT_DIRECTORY =
create_struct 'V2v2V2l2V3', :Characteristics, :TimeDateStamp, :MajorVersion, # These fields appear to be unused and are set to 0. :MinorVersion, # These fields appear to be unused and are set to 0. :Name, :Base, # The starting ordinal number for exported functions :NumberOfFunctions, :NumberOfNames, :AddressOfFunctions, :AddressOfNames, :AddressOfNameOrdinals, # manual: :name, :entry_points, :names, :name_ordinals, :functions, :description
- IMAGE_TLS_DIRECTORY32 =
create_struct 'V6', :StartAddressOfRawData, :EndAddressOfRawData, :AddressOfIndex, :AddressOfCallBacks, :SizeOfZeroFill, :Characteristics
- IMAGE_TLS_DIRECTORY64 =
create_struct 'Q4V2', :StartAddressOfRawData, :EndAddressOfRawData, :AddressOfIndex, :AddressOfCallBacks, :SizeOfZeroFill, :Characteristics
- CUR_ICO_HEADER =
create_struct('v3', :wReserved, # always 0 :wResID, # always 2 :wNumImages # Number of cursor images/directory entries )
- CURDIRENTRY =
create_struct 'v4Vv', :wWidth, :wHeight, # Divide by 2 to get the actual height. :wPlanes, :wBitCount, :dwBytesInImage, :wID
- CURSOR_HOTSPOT =
create_struct 'v2', :x, :y
- ICODIRENTRY =
create_struct 'C4v2Vv', :bWidth, :bHeight, :bColors, :bReserved, :wPlanes, :wBitCount, :dwBytesInImage, :wID
- ROOT_RES_NAMES =
numeration is started from 1
[nil] + # numeration is started from 1 %w'CURSOR BITMAP ICON MENU DIALOG STRING FONTDIR FONT ACCELERATORS RCDATA' + %w'MESSAGETABLE GROUP_CURSOR' + [nil] + %w'GROUP_ICON' + [nil] + %w'VERSION DLGINCLUDE' + [nil] + %w'PLUGPLAY VXD ANICURSOR ANIICON HTML MANIFEST'
- IMAGE_RESOURCE_DIRECTORY_ENTRY =
create_struct 'V2', :Name, :OffsetToData, :name, :data
- IMAGE_RESOURCE_DATA_ENTRY =
create_struct 'V4', :OffsetToData, :Size, :CodePage, :Reserved
- @@logger =
nil
Instance Attribute Summary collapse
-
#fname ⇒ Object
Returns the value of attribute fname.
-
#force ⇒ Object
Returns the value of attribute force.
-
#io ⇒ Object
Returns the value of attribute io.
-
#logger ⇒ Object
Returns the value of attribute logger.
Class Method Summary collapse
- .create_struct(fmt, *args) ⇒ Object
- .dump(fname, params = {}) ⇒ Object
- .logger ⇒ Object
- .logger=(l) ⇒ Object
- .quiet ⇒ Object
Instance Method Summary collapse
- #_dump_handle(h) ⇒ Object
- #_read_resource_directory_tree(f) ⇒ Object
- #_scan_pe_resources(f = @io, dir = nil) ⇒ Object
- #data_directory(f = @io) ⇒ Object
- #dos_stub(f = @io) ⇒ Object
-
#dump(f = @io) ⇒ Object
OPTIONAL: assigns @mz, @rich_hdr, @pe, etc.
- #exports(f = @io) ⇒ Object
- #imports(f = @io) ⇒ Object
-
#initialize(io = nil, params = {}) ⇒ PEdump
constructor
A new instance of PEdump.
- #mz(f = @io) ⇒ Object
- #ne(f = @io) ⇒ Object
- #ne? ⇒ Boolean
-
#packer(f = @io) ⇒ Object
(also: #packers)
packer / compiler detection.
- #pe(f = @io) ⇒ Object
- #pe? ⇒ Boolean
- #pe_exports(f = @io) ⇒ Object
- #pe_imports(f = @io) ⇒ Object
- #resource_directory(f = @io) ⇒ Object
-
#resources(f = @io) ⇒ Object
resources.
- #rich_hdr(f = @io) ⇒ Object (also: #rich_header, #rich)
- #sections(f = @io) ⇒ Object (also: #section_table)
- #security(f = @io) ⇒ Object (also: #signature)
- #strings(f = @io) ⇒ Object
-
#tls(f = @io) ⇒ Object
TLS.
- #va2file(va, h = {}) ⇒ Object
- #version_info(f = @io) ⇒ Object
Constructor Details
#initialize(io = nil, params = {}) ⇒ PEdump
Returns a new instance of PEdump.
25 26 27 28 29 30 31 32 33 |
# File 'lib/pedump.rb', line 25 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 |
Instance Attribute Details
#fname ⇒ Object
Returns the value of attribute fname.
19 20 21 |
# File 'lib/pedump.rb', line 19 def fname @fname end |
#force ⇒ Object
Returns the value of attribute force.
19 20 21 |
# File 'lib/pedump.rb', line 19 def force @force end |
#io ⇒ Object
Returns the value of attribute io.
19 20 21 |
# File 'lib/pedump.rb', line 19 def io @io end |
#logger ⇒ Object
Returns the value of attribute logger.
19 20 21 |
# File 'lib/pedump.rb', line 19 def logger @logger end |
Class Method Details
.create_struct(fmt, *args) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/pedump/core.rb', line 58 def create_struct fmt, *args size = fmt.scan(/([a-z])(\d*)/i).map do |f,len| [len.to_i, 1].max * case f when /[aAC]/ then 1 when 'v' then 2 when 'V','l' then 4 when 'Q' then 8 else raise "unknown fmt #{f.inspect}" end end.inject(&:+) Struct.new( *args ).tap do |x| x.const_set 'FORMAT', fmt x.const_set 'SIZE', size x.class_eval do def pack to_a.pack self.class.const_get('FORMAT') end def empty? to_a.all?{ |t| t == 0 || t.nil? || t.to_s.tr("\x00","").empty? } end end x.extend Readable end end |
.dump(fname, params = {}) ⇒ Object
297 298 299 |
# File 'lib/pedump.rb', line 297 def self.dump fname, params = {} new(fname, params).dump end |
.logger ⇒ Object
55 |
# File 'lib/pedump/core.rb', line 55 def logger; @@logger; end |
.logger=(l) ⇒ Object
56 |
# File 'lib/pedump/core.rb', line 56 def logger= l; @@logger=l; end |
.quiet ⇒ Object
301 302 303 304 305 306 307 |
# File 'lib/pedump.rb', line 301 def self.quiet oldlevel = @@logger.level @@logger.level = ::Logger::FATAL yield ensure @@logger.level = oldlevel end |
Instance Method Details
#_dump_handle(h) ⇒ Object
413 414 415 416 417 418 419 420 |
# File 'lib/pedump.rb', line 413 def _dump_handle h return unless pe(h) # also calls mz(h) rich_hdr h resources h imports h # also calls tls(h) exports h packer h end |
#_read_resource_directory_tree(f) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# 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) ⇒ Object
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/pedump/resources.rb', line 326 def _scan_pe_resources f=@io, dir=nil dir ||= resource_directory(f) return nil unless dir dir.entries.map do |entry| 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 _scan_pe_resources(f,entry.data).each do |res| res.type = entry_type res.parse f end else _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 Resource.new( nil, # type entry.name, nil, # id entry.Name, # lang #entry.data.OffsetToData + @resource_data_base, va2file(entry.data.OffsetToData), entry.data.Size, entry.data.CodePage, entry.data.Reserved ) else logger.error "[!] invalid resource entry: #{entry.data.inspect}" nil end end.flatten.compact end |
#data_directory(f = @io) ⇒ Object
422 423 424 |
# File 'lib/pedump.rb', line 422 def data_directory f=@io pe(f) && pe.ioh && pe.ioh.DataDirectory end |
#dos_stub(f = @io) ⇒ Object
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/pedump.rb', line 322 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) ⇒ Object
OPTIONAL: assigns @mz, @rich_hdr, @pe, etc
402 403 404 405 406 407 408 409 410 411 |
# File 'lib/pedump.rb', line 402 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) ⇒ Object
608 609 610 611 612 613 614 |
# File 'lib/pedump.rb', line 608 def exports f=@io if pe(f) pe_exports(f) elsif ne(f) ne(f).exports end end |
#imports(f = @io) ⇒ Object
479 480 481 482 483 484 485 |
# File 'lib/pedump.rb', line 479 def imports f=@io if pe(f) pe_imports(f) elsif ne(f) ne(f).imports end end |
#mz(f = @io) ⇒ Object
309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'lib/pedump.rb', line 309 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) ⇒ Object
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
# 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.fatal "[!] 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? ⇒ Boolean
435 436 437 |
# File 'lib/pedump.rb', line 435 def ne? @pe ? false : (@ne ? true : (pe ? false : (ne ? true : false))) end |
#packer(f = @io) ⇒ Object Also known as: packers
packer / compiler detection
763 764 765 766 767 768 769 770 771 772 773 |
# File 'lib/pedump.rb', line 763 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 |
#pe(f = @io) ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/pedump/pe.rb', line 95 def pe f=@io @pe ||= begin pe_offset = mz(f) && mz(f).lfanew if pe_offset.nil? logger.fatal "[!] 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? ⇒ Boolean
439 440 441 |
# File 'lib/pedump.rb', line 439 def pe? @pe ? true : (@ne ? false : (pe ? true : false )) end |
#pe_exports(f = @io) ⇒ Object
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 |
# File 'lib/pedump.rb', line 616 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 f.seek file_offset if f.eof? logger.info "[?] 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 > 100 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 > 2048 logger.warn "[?] NumberOfNames too big (#{x.NumberOfNames}), limiting to 2048" n = 2048 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].try(:join,', ') next if ep.to_i == 0 && names.nil? x.functions << ExportedFunction.new(names, i+x.Base, ep) end end end |
#pe_imports(f = @io) ⇒ Object
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 |
# File 'lib/pedump.rb', line 487 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 f.seek file_offset r = [] 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 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 logger.warn "[?] non-empty last IMAGE_IMPORT_DESCRIPTOR: #{t.inspect}" unless t.empty? @imports = r.each do |x| if x.Name.to_i != 0 && (ofs = va2file(x.Name)) f.seek ofs 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.seek ofs x[tbl] ||= [] if pe.x64? x[tbl] << t while (t = f.read(8).unpack('Q').first) != 0 else x[tbl] << t while (t = f.read(4).unpack('V').first) != 0 end end cache = {} bits = pe.x64? ? 64 : 32 idx = -1 x[tbl] && x[tbl].map! do |t| idx += 1 va = x[camel].to_i + idx*4 cache[t] ||= if t & (2**(bits-1)) > 0 # 0x8000_0000(_0000_0000) ImportedFunction.new(nil,nil,t & (2**(bits-1)-1),va) # 0x7fff_ffff(_ffff_ffff) elsif ofs=va2file(t, :quiet => true) f.seek ofs if f.eof? logger.warn "[?] import ofs 0x#{ofs.to_s(16)} beyond EOF" nil else ImportedFunction.new( f.read(2).unpack('v').first, f.gets("\x00").chomp("\x00"), nil, va ) 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 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 end |
#resource_directory(f = @io) ⇒ Object
3 4 5 6 7 8 9 10 |
# 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) ⇒ Object
resources
746 747 748 749 750 751 752 753 |
# File 'lib/pedump.rb', line 746 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) ⇒ Object Also known as: rich_header, rich
362 363 364 |
# File 'lib/pedump.rb', line 362 def rich_hdr f=@io dos_stub(f) && @rich_hdr end |
#sections(f = @io) ⇒ Object Also known as: section_table
426 427 428 429 430 431 432 |
# File 'lib/pedump.rb', line 426 def sections f=@io if pe(f) pe.section_table elsif ne(f) ne.segments end end |
#security(f = @io) ⇒ Object Also known as: signature
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 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 |
#strings(f = @io) ⇒ Object
188 189 190 191 192 193 194 195 196 |
# File 'lib/pedump/resources.rb', line 188 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-1)<<4) + idx, res.lang, string ) unless string.empty? end end r end |
#tls(f = @io) ⇒ Object
TLS
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 |
# File 'lib/pedump.rb', line 719 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 = {}) ⇒ Object
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/pedump.rb', line 368 def va2file va, h={} return nil if va.nil? sections.each do |s| if (s.VirtualAddress...(s.VirtualAddress+s.VirtualSize)).include?(va) return va - s.VirtualAddress + s.PointerToRawData 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) return va - s.VirtualAddress + s.PointerToRawData 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 return va - s.VirtualAddress + s.PointerToRawData end # TODO: not all VirtualAdresses == 0 case logger.error "[?] can't find file_offset of VA 0x#{va.to_i.to_s(16)}" unless h[:quiet] nil end |
#version_info(f = @io) ⇒ Object
755 756 757 |
# File 'lib/pedump.rb', line 755 def version_info f=@io resources(f) && resources(f).find_all{ |res| res.type == 'VERSION' }.map(&:data).flatten end |