pedump 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -98,6 +98,17 @@ namespace :test do
98
98
  end
99
99
  end
100
100
  end
101
+
102
+ desc "test on corkami binaries"
103
+ task :corkami do
104
+ require './lib/pedump'
105
+ require './lib/pedump/cli'
106
+ path = "samples/corkami"
107
+ `find #{path} -type f`.split("\n").each do |fname|
108
+ STDERR.puts "\n### #{fname}\n"
109
+ PEdump::CLI.new(fname).run
110
+ end
111
+ end
101
112
  end
102
113
 
103
114
  def check_file url
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.2
1
+ 0.4.3
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'logger'
3
+ require 'stringio'
4
+ require 'pedump/composite_io'
5
+ require 'pedump/pe'
3
6
  require 'pedump/version'
4
7
 
5
8
  # pedump.rb by zed_0xff
@@ -135,22 +138,6 @@ class PEdump
135
138
  :lfanew
136
139
  )
137
140
 
138
- class PE < Struct.new(
139
- :signature, # "PE\x00\x00"
140
- :image_file_header,
141
- :image_optional_header,
142
- :section_table
143
- )
144
- alias :ifh :image_file_header
145
- alias :ioh :image_optional_header
146
- def x64?
147
- ifh && ifh.Machine == 0x8664
148
- end
149
- def dll?
150
- ifh && ifh.flags.include?('DLL')
151
- end
152
- end
153
-
154
141
  # http://msdn.microsoft.com/en-us/library/ms809762.aspx
155
142
  class IMAGE_FILE_HEADER < create_struct( 'v2V3v2',
156
143
  :Machine, # w
@@ -307,6 +294,7 @@ class PEdump
307
294
  )
308
295
  class IMAGE_SECTION_HEADER
309
296
  alias :flags :Characteristics
297
+ alias :va :VirtualAddress
310
298
  def flags_desc
311
299
  r = ''
312
300
  f = self.flags.to_i
@@ -455,54 +443,7 @@ class PEdump
455
443
  nil
456
444
  else
457
445
  f.seek pe_offset
458
- pe_sig = f.read 4
459
- logger.error "[!] 'NE' format is not supported!" if pe_sig == "NE\x00\x00"
460
- if pe_sig != "PE\x00\x00"
461
- if @force
462
- logger.warn "[?] no PE signature (want: 'PE\\x00\\x00', got: #{pe_sig.inspect})"
463
- else
464
- logger.error "[?] no PE signature (want: 'PE\\x00\\x00', got: #{pe_sig.inspect}). (not forced)"
465
- return nil
466
- end
467
- end
468
- PE.new(pe_sig).tap do |pe|
469
- pe.image_file_header = IMAGE_FILE_HEADER.read(f)
470
- if pe.ifh.SizeOfOptionalHeader > 0
471
- if pe.x64?
472
- pe.image_optional_header = IMAGE_OPTIONAL_HEADER64.read(f, pe.ifh.SizeOfOptionalHeader)
473
- else
474
- pe.image_optional_header = IMAGE_OPTIONAL_HEADER32.read(f, pe.ifh.SizeOfOptionalHeader)
475
- end
476
- end
477
-
478
- if (nToRead=pe.ifh.NumberOfSections) > 0xffff
479
- if @force.is_a?(Numeric) && @force > 1
480
- logger.warn "[!] too many sections (#{pe.ifh.NumberOfSections}). forced. reading all"
481
- else
482
- logger.warn "[!] too many sections (#{pe.ifh.NumberOfSections}). not forced, reading first 65535"
483
- nToRead = 65535
484
- end
485
- end
486
- pe.section_table = []
487
- nToRead.times do
488
- break if f.eof?
489
- pe.section_table << IMAGE_SECTION_HEADER.read(f)
490
- end
491
-
492
- # if pe.section_table.empty?
493
- # pe.section_table << IMAGE_SECTION_HEADER.new("")
494
- # logger.warn "[?] no sections, appending empty one"
495
- # end
496
-
497
- if pe.section_table.any?
498
- # zero all missing values of last section
499
- pe.section_table.last.tap do |last_section|
500
- last_section.each_pair do |k,v|
501
- last_section[k] = 0 if v.nil?
502
- end
503
- end
504
- end
505
- end
446
+ PE.read f, :force => @force
506
447
  end
507
448
  end
508
449
  end
@@ -591,7 +532,12 @@ class PEdump
591
532
  ImportedFunction.new(nil,nil,t & (2**(bits-1)-1)) # 0x7fff_ffff(_ffff_ffff)
592
533
  elsif va=va2file(t)
593
534
  f.seek va
594
- ImportedFunction.new(f.read(2).unpack('v').first, f.gets("\x00").chop)
535
+ if f.eof?
536
+ logger.warn "[?] import va 0x#{va.to_s(16)} beyond EOF"
537
+ nil
538
+ else
539
+ ImportedFunction.new(f.read(2).unpack('v').first, f.gets("\x00").chop)
540
+ end
595
541
  else
596
542
  nil
597
543
  end
@@ -632,34 +578,65 @@ class PEdump
632
578
  return @exports if @exports
633
579
  return nil unless pe(f) && pe(f).ioh && f
634
580
  dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::EXPORT]
635
- return [] if !dir || (dir.va == 0 && dir.size == 0)
581
+ return nil if !dir || (dir.va == 0 && dir.size == 0)
636
582
  va = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::EXPORT].va
637
583
  file_offset = va2file(va)
638
584
  return nil unless file_offset
639
585
  f.seek file_offset
586
+ if f.eof?
587
+ logger.info "[?] exports info beyond EOF"
588
+ return nil
589
+ end
640
590
  @exports = IMAGE_EXPORT_DIRECTORY.read(f).tap do |x|
641
591
  x.entry_points = []
642
592
  x.name_ordinals = []
643
593
  x.names = []
644
594
  if x.Name.to_i != 0 && (va = va2file(x.Name))
645
595
  f.seek va
646
- x.name = f.gets("\x00").chop
596
+ if f.eof?
597
+ logger.warn "[?] export va 0x#{va.to_s(16)} beyond EOF"
598
+ nil
599
+ else
600
+ x.name = f.gets("\x00").chomp("\x00")
601
+ end
647
602
  end
648
603
  if x.NumberOfFunctions.to_i != 0
649
604
  if x.AddressOfFunctions.to_i !=0 && (va = va2file(x.AddressOfFunctions))
650
605
  f.seek va
651
- x.entry_points = f.read(x.NumberOfFunctions*4).unpack('V*')
606
+ x.entry_points = []
607
+ x.NumberOfFunctions.times do
608
+ if f.eof?
609
+ logger.warn "[?] got EOF while reading exports entry_points"
610
+ break
611
+ end
612
+ x.entry_points << f.read(4).unpack('V').first
613
+ end
652
614
  end
653
615
  if x.AddressOfNameOrdinals.to_i !=0 && (va = va2file(x.AddressOfNameOrdinals))
654
616
  f.seek va
655
- x.name_ordinals = f.read(x.NumberOfNames*2).unpack('v*').map{ |o| o+x.Base }
617
+ x.name_ordinals = []
618
+ x.NumberOfNames.times do
619
+ if f.eof?
620
+ logger.warn "[?] got EOF while reading exports name_ordinals"
621
+ break
622
+ end
623
+ x.name_ordinals << f.read(2).unpack('v').first + x.Base
624
+ end
656
625
  end
657
626
  end
658
627
  if x.NumberOfNames.to_i != 0 && x.AddressOfNames.to_i !=0 && (va = va2file(x.AddressOfNames))
659
628
  f.seek va
660
- x.names = f.read(x.NumberOfNames*4).unpack('V*').map do |va|
629
+ x.names = []
630
+ x.NumberOfNames.times do
631
+ if f.eof?
632
+ logger.warn "[?] got EOF while reading exports names"
633
+ break
634
+ end
635
+ x.names << f.read(4).unpack('V').first
636
+ end
637
+ x.names.map! do |va|
661
638
  f.seek va2file(va)
662
- f.gets("\x00").chop
639
+ f.gets("\x00").to_s.chomp("\x00")
663
640
  end
664
641
  end
665
642
  end
@@ -746,6 +723,8 @@ class PEdump
746
723
  :OffsetToData, :Size, :CodePage, :Reserved
747
724
 
748
725
  def va2file va
726
+ return nil if va.nil?
727
+
749
728
  sections.each do |s|
750
729
  if (s.VirtualAddress...(s.VirtualAddress+s.VirtualSize)).include?(va)
751
730
  return va - s.VirtualAddress + s.PointerToRawData
@@ -486,8 +486,8 @@ class PEdump::CLI
486
486
  data.name.inspect,
487
487
  data.Characteristics.to_i,
488
488
  Time.at(data.TimeDateStamp.to_i).utc.strftime('"%Y-%m-%d %H:%M:%S"'),
489
- data.MajorVersion, data.MinorVersion,
490
- data.Base
489
+ data.MajorVersion.to_i, data.MinorVersion.to_i,
490
+ data.Base.to_i
491
491
 
492
492
  if @options[:verbose] > 0
493
493
  [%w'Names', %w'EntryPoints Functions', %w'Ordinals NameOrdinals'].each do |x|
@@ -498,25 +498,26 @@ class PEdump::CLI
498
498
  end
499
499
 
500
500
  printf "# nFuncs=%d nNames=%d\n",
501
- data.NumberOfFunctions,
502
- data.NumberOfNames
501
+ data.NumberOfFunctions.to_i,
502
+ data.NumberOfNames.to_i
503
503
 
504
504
  return unless data.name_ordinals.any? || data.entry_points.any? || data.names.any?
505
505
 
506
506
  puts
507
507
 
508
508
  ord2name = {}
509
- data.NumberOfNames.times do |i|
510
- ord2name[data.name_ordinals[i]] ||= []
511
- ord2name[data.name_ordinals[i]] << data.names[i]
509
+ if data.names && data.names.any?
510
+ data.NumberOfNames.times do |i|
511
+ ord2name[data.name_ordinals[i]] ||= []
512
+ ord2name[data.name_ordinals[i]] << data.names[i]
513
+ end
512
514
  end
513
515
 
514
516
  printf "%5s %8s %s\n", "ORD", "ENTRY_VA", "NAME"
515
- data.NumberOfFunctions.times do |i|
516
- ep = data.entry_points[i]
517
+ data.entry_points.each_with_index do |ep,i|
517
518
  names = ord2name[i+data.Base].try(:join,', ')
518
519
  next if ep.to_i == 0 && names.nil?
519
- printf "%5d %8x %s\n", i + data.Base, ep, names
520
+ printf "%5x %8x %s\n", i + data.Base, ep, names
520
521
  end
521
522
  end
522
523
 
@@ -0,0 +1,33 @@
1
+ class PEdump
2
+ class CompositeIO
3
+ def initialize(*ios)
4
+ @ios = ios.flatten
5
+ @pos = 0
6
+ end
7
+
8
+ def read(amount = nil, buf = nil)
9
+ buf ||= ''; buf1 = ''
10
+
11
+ # truncates buffer to zero length if nothing read
12
+ @ios.first.read(amount,buf)
13
+
14
+ @ios[1..-1].each do |io|
15
+ break if amount && buf.size >= amount
16
+ io.read(amount ? (amount-buf.size) : nil, buf1)
17
+ buf << buf1
18
+ end
19
+
20
+ @pos += buf.size
21
+
22
+ buf.size > 0 ? buf : (amount ? nil : buf )
23
+ end
24
+
25
+ def tell
26
+ @pos
27
+ end
28
+
29
+ def eof?
30
+ @ios.all?(&:eof?)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,89 @@
1
+ class PEdump
2
+ class PE < Struct.new(
3
+ :signature, # "PE\x00\x00"
4
+ :image_file_header,
5
+ :image_optional_header, # includes data directory
6
+ :section_table
7
+ )
8
+ alias :ifh :image_file_header
9
+ alias :ioh :image_optional_header
10
+ alias :sections :section_table
11
+ alias :sections= :section_table=
12
+ def x64?
13
+ ifh && ifh.Machine == 0x8664
14
+ end
15
+ def dll?
16
+ ifh && ifh.flags.include?('DLL')
17
+ end
18
+
19
+
20
+ def self.read f, args = nil
21
+ force = args.is_a?(Hash) && args[:force]
22
+
23
+ pe_offset = f.tell
24
+ pe_sig = f.read 4
25
+ logger.error "[!] 'NE' format is not supported!" if pe_sig == "NE\x00\x00"
26
+ if pe_sig != "PE\x00\x00"
27
+ if force
28
+ logger.warn "[?] no PE signature (want: 'PE\\x00\\x00', got: #{pe_sig.inspect})"
29
+ else
30
+ logger.error "[?] no PE signature (want: 'PE\\x00\\x00', got: #{pe_sig.inspect}). (not forced)"
31
+ return nil
32
+ end
33
+ end
34
+ PE.new(pe_sig).tap do |pe|
35
+ pe.image_file_header = IMAGE_FILE_HEADER.read(f)
36
+ if pe.ifh.SizeOfOptionalHeader > 0
37
+ if pe.x64?
38
+ pe.image_optional_header = IMAGE_OPTIONAL_HEADER64.read(f, pe.ifh.SizeOfOptionalHeader)
39
+ else
40
+ pe.image_optional_header = IMAGE_OPTIONAL_HEADER32.read(f, pe.ifh.SizeOfOptionalHeader)
41
+ end
42
+ end
43
+
44
+ if (nToRead=pe.ifh.NumberOfSections) > 0xffff
45
+ if force.is_a?(Numeric) && force > 1
46
+ logger.warn "[!] too many sections (#{pe.ifh.NumberOfSections}). forced. reading all"
47
+ else
48
+ logger.warn "[!] too many sections (#{pe.ifh.NumberOfSections}). not forced, reading first 65535"
49
+ nToRead = 65535
50
+ end
51
+ end
52
+ pe.sections = []
53
+ nToRead.times do
54
+ break if f.eof?
55
+ pe.sections << IMAGE_SECTION_HEADER.read(f)
56
+ end
57
+
58
+ if pe.sections.any?
59
+ # zero all missing values of last section
60
+ pe.sections.last.tap do |last_section|
61
+ last_section.each_pair do |k,v|
62
+ last_section[k] = 0 if v.nil?
63
+ end
64
+ end
65
+ end
66
+
67
+ pe_end = f.tell
68
+ if s=pe.sections.find{ |s| (pe_offset...pe_end).include?(s.va) }
69
+ if !f.respond_to?(:seek)
70
+ # already called with CompositeIO ?
71
+ logger.error "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! 2nd time?!"
72
+
73
+ elsif pe_end-pe_offset < 0x100_000
74
+ logger.warn "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! trying to rebuild..."
75
+ f.seek pe_offset
76
+ data = f.read(s.va-pe_offset)
77
+ f.seek s.PointerToRawData
78
+ io = CompositeIO.new(StringIO.new(data), f)
79
+ return PE.read(io, args)
80
+ else
81
+ logger.error "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! too big to rebuild!"
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ def self.logger; PEdump.logger; end
88
+ end
89
+ end
@@ -2,7 +2,7 @@ class PEdump
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 4
5
- PATCH = 2
5
+ PATCH = 3
6
6
  BUILD = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "pedump"
8
- s.version = "0.4.2"
8
+ s.version = "0.4.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Andrey \"Zed\" Zaikin"]
12
- s.date = "2011-12-19"
12
+ s.date = "2011-12-20"
13
13
  s.description = "dump headers, sections, extract resources of win32 PE exe,dll,etc"
14
14
  s.email = "zed.0xff@gmail.com"
15
15
  s.executables = ["pedump"]
@@ -35,17 +35,20 @@ Gem::Specification.new do |s|
35
35
  "data/userdb.txt",
36
36
  "lib/pedump.rb",
37
37
  "lib/pedump/cli.rb",
38
+ "lib/pedump/composite_io.rb",
38
39
  "lib/pedump/packer.rb",
40
+ "lib/pedump/pe.rb",
39
41
  "lib/pedump/sig_parser.rb",
40
42
  "lib/pedump/version.rb",
41
43
  "lib/pedump/version_info.rb",
42
44
  "pedump.gemspec",
43
- "samples/65535sects.7z",
44
45
  "samples/calc.7z",
45
- "samples/imports_badterm.exe",
46
- "samples/imports_vterm.exe",
46
+ "samples/corkami.7z",
47
47
  "samples/zlib.dll",
48
48
  "spec/65535sects_spec.rb",
49
+ "spec/composite_io_spec.rb",
50
+ "spec/dllord_spec.rb",
51
+ "spec/foldedhdr_spec.rb",
49
52
  "spec/imports_badterm_spec.rb",
50
53
  "spec/imports_vterm_spec.rb",
51
54
  "spec/pe_spec.rb",
@@ -53,7 +56,8 @@ Gem::Specification.new do |s|
53
56
  "spec/resource_spec.rb",
54
57
  "spec/sig_all_packers_spec.rb",
55
58
  "spec/sig_spec.rb",
56
- "spec/spec_helper.rb"
59
+ "spec/spec_helper.rb",
60
+ "spec/virtsectblXP_spec.rb"
57
61
  ]
58
62
  s.homepage = "http://github.com/zed-0xff/pedump"
59
63
  s.licenses = ["MIT"]
Binary file
@@ -1,16 +1,8 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require File.expand_path(File.dirname(__FILE__) + '/../lib/pedump')
3
3
 
4
- describe 'a PE file with 65535 sections' do
5
- before :all do
6
- fname = File.expand_path(File.dirname(__FILE__) + '/../samples/65535sects.exe')
7
- File.open(fname,"rb") do |f|
8
- @pedump = PEdump.new(fname)
9
- @sections = @pedump.sections(f)
10
- end
11
- end
12
-
4
+ describe 'corkami/65535sects.exe' do
13
5
  it "should have 65535 sections" do
14
- @sections.size.should == 65535
6
+ sample.sections.size.should == 65535
15
7
  end
16
8
  end
@@ -0,0 +1,72 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/pedump/composite_io')
3
+
4
+ describe PEdump::CompositeIO do
5
+ it "concatenates" do
6
+ io = PEdump::CompositeIO.new(
7
+ StringIO.new('foo'),
8
+ StringIO.new('bar'),
9
+ StringIO.new('baz')
10
+ )
11
+ io.read.should == 'foobarbaz'
12
+ end
13
+
14
+ it "reads sequentally" do
15
+ io = PEdump::CompositeIO.new(
16
+ StringIO.new('foo1'),
17
+ StringIO.new('bar2'),
18
+ StringIO.new('baz')
19
+ )
20
+ io.read(3).should == 'foo'
21
+ io.read(3).should == '1ba'
22
+ io.read(3).should == 'r2b'
23
+ io.read(3).should == 'az'
24
+ end
25
+
26
+ it "behaves like StringIO" do
27
+ io1 = StringIO.new('foo')
28
+ io2 = PEdump::CompositeIO.new(StringIO.new('foo'))
29
+
30
+ io1.read.should == io2.read # 'foo'
31
+ io1.read.should == io2.read # ''
32
+ io1.read(3).should == io2.read(3) # nil
33
+ end
34
+
35
+ it "tracks number of bytes read" do
36
+ io = PEdump::CompositeIO.new(
37
+ StringIO.new('foo1'),
38
+ StringIO.new('bar2'),
39
+ StringIO.new('baz')
40
+ )
41
+ io.tell.should == 0
42
+ io.read(3)
43
+ io.tell.should == 3
44
+ io.read(4)
45
+ io.tell.should == 7
46
+ io.read
47
+ io.tell.should == 11
48
+ io.read
49
+ io.tell.should == 11
50
+ io.read 10
51
+ io.tell.should == 11
52
+ end
53
+
54
+ it "chains eof? call" do
55
+ io = PEdump::CompositeIO.new(
56
+ StringIO.new('foo1'),
57
+ StringIO.new('bar2'),
58
+ StringIO.new('baz')
59
+ )
60
+ io.eof?.should be_false
61
+ io.read(3)
62
+ io.eof?.should be_false
63
+ io.read(4)
64
+ io.eof?.should be_false
65
+ io.read
66
+ io.eof?.should be_true
67
+ io.read
68
+ io.eof?.should be_true
69
+ io.read 10
70
+ io.eof?.should be_true
71
+ end
72
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/pedump')
3
+
4
+ describe 'corkami/dllord.dll' do
5
+ it "should have 1 import" do
6
+ sample.imports.size.should == 1
7
+ sample.imports.map(&:module_name).should == %w'msvcrt.dll'
8
+ sample.imports.map do |iid|
9
+ (iid.original_first_thunk + iid.first_thunk).uniq.map(&:name)
10
+ end.flatten.should == ["printf"]
11
+ end
12
+
13
+ it "exports at least 2 entries" do
14
+ sample.exports.Base.should == 0x313
15
+ sample.exports.name.should be_nil
16
+ sample.exports.names.should be_empty
17
+ sample.exports.name_ordinals.should be_empty
18
+ sample.exports.entry_points[0].should == 0xffff_ffff
19
+ sample.exports.entry_points[1].should == 0x1008
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/pedump')
3
+
4
+ [ 'corkami/foldedhdr.exe', 'corkami/foldedhdrW7.exe' ].each do |fname|
5
+ describe fname do
6
+ before :all do
7
+ @sample = sample
8
+ end
9
+
10
+ it "should have 2 imports" do
11
+ @sample.imports.size.should == 2
12
+ @sample.imports.map(&:module_name).should == %w'kernel32.dll msvcrt.dll'
13
+ @sample.imports.map do |iid|
14
+ (iid.original_first_thunk + iid.first_thunk).uniq.map(&:name)
15
+ end.flatten.should == ["ExitProcess", "printf"]
16
+ end
17
+
18
+ it "should have 1 section" do
19
+ @sample.sections.size.should == 1
20
+ s = @sample.sections.first
21
+ s.VirtualSize.should == 0x1000
22
+ s.VirtualAddress.should == 0x1000
23
+ s.SizeOfRawData.should == 0x200
24
+ s.PointerToRawData.should == 0x200
25
+ s.flags.should == 0xa0000000
26
+ end
27
+ end
28
+ end
@@ -1,58 +1,52 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require File.expand_path(File.dirname(__FILE__) + '/../lib/pedump')
3
3
 
4
- describe 'Imports' do
4
+ describe 'corkami/imports_badterm.exe' do
5
5
  # PE with a 'bad' imports terminator, just the dll name is empty
6
6
  # http://code.google.com/p/corkami/source/browse/trunk/asm/PE/imports_badterm.asm
7
- describe "imports_badterm.exe" do
8
- before :all do
9
- fname = File.expand_path(File.dirname(__FILE__) + '/../samples/imports_badterm.exe')
10
- File.open(fname,"rb") do |f|
11
- @pedump = PEdump.new(fname)
12
- @imports = @pedump.imports(f)
13
- end
14
- end
7
+ before :all do
8
+ @imports = sample.imports
9
+ end
15
10
 
16
- it "should have 2 IMAGE_IMPORT_DESCRIPTORs" do
17
- @imports.size.should == 2
18
- end
11
+ it "should have 2 IMAGE_IMPORT_DESCRIPTORs" do
12
+ @imports.size.should == 2
13
+ end
19
14
 
20
- it "should have only IMAGE_IMPORT_DESCRIPTORs" do
21
- @imports.map(&:class).uniq.should == [PEdump::IMAGE_IMPORT_DESCRIPTOR]
22
- end
15
+ it "should have only IMAGE_IMPORT_DESCRIPTORs" do
16
+ @imports.map(&:class).uniq.should == [PEdump::IMAGE_IMPORT_DESCRIPTOR]
17
+ end
23
18
 
24
- it "should have all entries thunks equal" do
25
- @imports.each do |iid|
26
- iid.first_thunk.should == iid.original_first_thunk
27
- end
19
+ it "should have all entries thunks equal" do
20
+ @imports.each do |iid|
21
+ iid.first_thunk.should == iid.original_first_thunk
28
22
  end
23
+ end
29
24
 
30
- describe "1st image_import_descriptor" do
31
- it "should be from kernel32.dll" do
32
- @imports[0].module_name.should == "kernel32.dll"
33
- end
34
- it "should have 1 function" do
35
- @imports[0].first_thunk.size.should == 1
36
- end
37
- it "should have ExitProcess" do
38
- @imports[0].first_thunk.first.name.should == "ExitProcess"
39
- @imports[0].first_thunk.first.hint.should == 0
40
- @imports[0].first_thunk.first.ordinal.should be_nil
41
- end
25
+ describe "1st image_import_descriptor" do
26
+ it "should be from kernel32.dll" do
27
+ @imports[0].module_name.should == "kernel32.dll"
28
+ end
29
+ it "should have 1 function" do
30
+ @imports[0].first_thunk.size.should == 1
31
+ end
32
+ it "should have ExitProcess" do
33
+ @imports[0].first_thunk.first.name.should == "ExitProcess"
34
+ @imports[0].first_thunk.first.hint.should == 0
35
+ @imports[0].first_thunk.first.ordinal.should be_nil
42
36
  end
37
+ end
43
38
 
44
- describe "2nd image_import_descriptor" do
45
- it "should be from msvcrt.dll" do
46
- @imports[1].module_name.should == "msvcrt.dll"
47
- end
48
- it "should have 1 function" do
49
- @imports[1].first_thunk.size.should == 1
50
- end
51
- it "should have printf" do
52
- @imports[1].first_thunk.first.name.should == "printf"
53
- @imports[1].first_thunk.first.hint.should == 0
54
- @imports[1].first_thunk.first.ordinal.should be_nil
55
- end
39
+ describe "2nd image_import_descriptor" do
40
+ it "should be from msvcrt.dll" do
41
+ @imports[1].module_name.should == "msvcrt.dll"
42
+ end
43
+ it "should have 1 function" do
44
+ @imports[1].first_thunk.size.should == 1
45
+ end
46
+ it "should have printf" do
47
+ @imports[1].first_thunk.first.name.should == "printf"
48
+ @imports[1].first_thunk.first.hint.should == 0
49
+ @imports[1].first_thunk.first.ordinal.should be_nil
56
50
  end
57
51
  end
58
52
  end
@@ -1,58 +1,52 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require File.expand_path(File.dirname(__FILE__) + '/../lib/pedump')
3
3
 
4
- describe 'Imports' do
4
+ describe 'corkami/imports_vterm.exe' do
5
5
  # http://code.google.com/p/corkami/source/browse/trunk/asm/PE/imports_vterm.asm
6
6
  #describe "import terminator in virtual space" do
7
- describe "imports_vterm.exe" do
8
- before :all do
9
- fname = File.expand_path(File.dirname(__FILE__) + '/../samples/imports_vterm.exe')
10
- File.open(fname,"rb") do |f|
11
- @pedump = PEdump.new(fname)
12
- @imports = @pedump.imports(f)
13
- end
14
- end
7
+ before :all do
8
+ @imports = sample.imports
9
+ end
15
10
 
16
- it "should have 2 IMAGE_IMPORT_DESCRIPTORs" do
17
- @imports.size.should == 2
18
- end
11
+ it "should have 2 IMAGE_IMPORT_DESCRIPTORs" do
12
+ @imports.size.should == 2
13
+ end
19
14
 
20
- it "should have only IMAGE_IMPORT_DESCRIPTORs" do
21
- @imports.map(&:class).uniq.should == [PEdump::IMAGE_IMPORT_DESCRIPTOR]
22
- end
15
+ it "should have only IMAGE_IMPORT_DESCRIPTORs" do
16
+ @imports.map(&:class).uniq.should == [PEdump::IMAGE_IMPORT_DESCRIPTOR]
17
+ end
23
18
 
24
- it "should have all entries thunks equal" do
25
- @imports.each do |iid|
26
- iid.first_thunk.should == iid.original_first_thunk
27
- end
19
+ it "should have all entries thunks equal" do
20
+ @imports.each do |iid|
21
+ iid.first_thunk.should == iid.original_first_thunk
28
22
  end
23
+ end
29
24
 
30
- describe "1st image_import_descriptor" do
31
- it "should be from kernel32.dll" do
32
- @imports[0].module_name.should == "kernel32.dll"
33
- end
34
- it "should have 1 function" do
35
- @imports[0].first_thunk.size.should == 1
36
- end
37
- it "should have ExitProcess" do
38
- @imports[0].first_thunk.first.name.should == "ExitProcess"
39
- @imports[0].first_thunk.first.hint.should == 0
40
- @imports[0].first_thunk.first.ordinal.should be_nil
41
- end
25
+ describe "1st image_import_descriptor" do
26
+ it "should be from kernel32.dll" do
27
+ @imports[0].module_name.should == "kernel32.dll"
28
+ end
29
+ it "should have 1 function" do
30
+ @imports[0].first_thunk.size.should == 1
31
+ end
32
+ it "should have ExitProcess" do
33
+ @imports[0].first_thunk.first.name.should == "ExitProcess"
34
+ @imports[0].first_thunk.first.hint.should == 0
35
+ @imports[0].first_thunk.first.ordinal.should be_nil
42
36
  end
37
+ end
43
38
 
44
- describe "2nd image_import_descriptor" do
45
- it "should be from msvcrt.dll" do
46
- @imports[1].module_name.should == "msvcrt.dll"
47
- end
48
- it "should have 1 function" do
49
- @imports[1].first_thunk.size.should == 1
50
- end
51
- it "should have printf" do
52
- @imports[1].first_thunk.first.name.should == "printf"
53
- @imports[1].first_thunk.first.hint.should == 0
54
- @imports[1].first_thunk.first.ordinal.should be_nil
55
- end
39
+ describe "2nd image_import_descriptor" do
40
+ it "should be from msvcrt.dll" do
41
+ @imports[1].module_name.should == "msvcrt.dll"
42
+ end
43
+ it "should have 1 function" do
44
+ @imports[1].first_thunk.size.should == 1
45
+ end
46
+ it "should have printf" do
47
+ @imports[1].first_thunk.first.name.should == "printf"
48
+ @imports[1].first_thunk.first.hint.should == 0
49
+ @imports[1].first_thunk.first.ordinal.should be_nil
56
50
  end
57
51
  end
58
52
  end
@@ -3,12 +3,22 @@ require File.expand_path(File.dirname(__FILE__) + '/../lib/pedump/packer')
3
3
 
4
4
  describe "PEdump::Packer" do
5
5
  describe "matchers" do
6
- PEdump::SigParser.parse(:raw => true).each do |sig|
7
- data = sig.re.join
8
- next if data == "This program cannot be run in DOS mo"
9
- it "should find #{sig.name}" do
10
- PEdump::Packer.of(data).map(&:name).should include(sig.name)
6
+ if ENV['SLOW']
7
+ PEdump::SigParser.parse(:raw => true).each do |sig|
8
+ data = sig.re.join
9
+ next if data == "This program cannot be run in DOS mo"
10
+ it "should find #{sig.name}" do
11
+ a = PEdump::Packer.of(data).map(&:name)
12
+ a.size.should > 0
13
+
14
+ a = sig.name.split - a.join(' ').split - ['Exe','PE']
15
+ a.delete_if{ |x| x[/[vV\.\/()\[\]]/] }
16
+ p a if a.size > 1
17
+ a.size.should < 2
18
+ end
11
19
  end
20
+ else
21
+ pending "SLOW"
12
22
  end
13
23
  end
14
24
  end
@@ -8,5 +8,22 @@ require 'pedump'
8
8
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
9
 
10
10
  RSpec.configure do |config|
11
-
11
+ end
12
+
13
+ def sample
14
+ @pedump ||=
15
+ begin
16
+ fname =
17
+ if self.example
18
+ # called from it(...)
19
+ self.example.full_description.split.first
20
+ else
21
+ # called from before(:all)
22
+ self.class.metadata[:example_group][:description_args].first
23
+ end
24
+ fname = File.expand_path(File.dirname(__FILE__) + '/../samples/' + fname)
25
+ File.open(fname,"rb") do |f|
26
+ PEdump.new(fname).dump
27
+ end
28
+ end
12
29
  end
@@ -0,0 +1,12 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/pedump')
3
+
4
+ describe 'corkami/virtsectblXP.exe' do
5
+ it "should have 2 imports" do
6
+ sample.imports.size.should == 2
7
+ sample.imports.map(&:module_name).should == %w'kernel32.dll msvcrt.dll'
8
+ sample.imports.map do |iid|
9
+ (iid.original_first_thunk + iid.first_thunk).uniq.map(&:name)
10
+ end.flatten.should == ["ExitProcess", "printf"]
11
+ end
12
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pedump
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-19 00:00:00.000000000 Z
12
+ date: 2011-12-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multipart-post
16
- requirement: &70341710237060 !ruby/object:Gem::Requirement
16
+ requirement: &70155235875660 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.1.4
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70341710237060
24
+ version_requirements: *70155235875660
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: progressbar
27
- requirement: &70341710236340 !ruby/object:Gem::Requirement
27
+ requirement: &70155235891480 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.9.2
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70341710236340
35
+ version_requirements: *70155235891480
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &70341710257880 !ruby/object:Gem::Requirement
38
+ requirement: &70155235890940 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 2.3.0
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70341710257880
46
+ version_requirements: *70155235890940
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: bundler
49
- requirement: &70341710257240 !ruby/object:Gem::Requirement
49
+ requirement: &70155235890060 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.0.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70341710257240
57
+ version_requirements: *70155235890060
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: jeweler
60
- requirement: &70341710256380 !ruby/object:Gem::Requirement
60
+ requirement: &70155235889180 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.6.4
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70341710256380
68
+ version_requirements: *70155235889180
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rcov
71
- requirement: &70341710255420 !ruby/object:Gem::Requirement
71
+ requirement: &70155235888640 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70341710255420
79
+ version_requirements: *70155235888640
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: awesome_print
82
- requirement: &70341710253940 !ruby/object:Gem::Requirement
82
+ requirement: &70155235888120 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,7 +87,7 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70341710253940
90
+ version_requirements: *70155235888120
91
91
  description: dump headers, sections, extract resources of win32 PE exe,dll,etc
92
92
  email: zed.0xff@gmail.com
93
93
  executables:
@@ -114,17 +114,20 @@ files:
114
114
  - data/userdb.txt
115
115
  - lib/pedump.rb
116
116
  - lib/pedump/cli.rb
117
+ - lib/pedump/composite_io.rb
117
118
  - lib/pedump/packer.rb
119
+ - lib/pedump/pe.rb
118
120
  - lib/pedump/sig_parser.rb
119
121
  - lib/pedump/version.rb
120
122
  - lib/pedump/version_info.rb
121
123
  - pedump.gemspec
122
- - samples/65535sects.7z
123
124
  - samples/calc.7z
124
- - samples/imports_badterm.exe
125
- - samples/imports_vterm.exe
125
+ - samples/corkami.7z
126
126
  - samples/zlib.dll
127
127
  - spec/65535sects_spec.rb
128
+ - spec/composite_io_spec.rb
129
+ - spec/dllord_spec.rb
130
+ - spec/foldedhdr_spec.rb
128
131
  - spec/imports_badterm_spec.rb
129
132
  - spec/imports_vterm_spec.rb
130
133
  - spec/pe_spec.rb
@@ -133,6 +136,7 @@ files:
133
136
  - spec/sig_all_packers_spec.rb
134
137
  - spec/sig_spec.rb
135
138
  - spec/spec_helper.rb
139
+ - spec/virtsectblXP_spec.rb
136
140
  homepage: http://github.com/zed-0xff/pedump
137
141
  licenses:
138
142
  - MIT
@@ -148,7 +152,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
152
  version: '0'
149
153
  segments:
150
154
  - 0
151
- hash: 1913101081356959317
155
+ hash: 2848967461238967885
152
156
  required_rubygems_version: !ruby/object:Gem::Requirement
153
157
  none: false
154
158
  requirements:
Binary file
Binary file
Binary file