pedump 0.4.5 → 0.4.6

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/Gemfile CHANGED
@@ -4,6 +4,7 @@ source "http://rubygems.org"
4
4
  # gem "activesupport", ">= 2.3.5"
5
5
  gem "multipart-post", "~> 1.1.4"
6
6
  gem "progressbar", "~> 0.9.2"
7
+ gem "awesome_print"
7
8
 
8
9
  # Add dependencies to develop your gem here.
9
10
  # Include everything needed to run rake, tests, features, etc.
@@ -12,5 +13,6 @@ group :development do
12
13
  gem "bundler", "~> 1.0.0"
13
14
  gem "jeweler", "~> 1.6.4"
14
15
  gem "rcov", ">= 0"
15
- gem "awesome_print"
16
+ gem "what_methods"
17
+ gem "looksee"
16
18
  end
@@ -1,13 +1,14 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- awesome_print (0.4.0)
4
+ awesome_print (1.0.2)
5
5
  diff-lcs (1.1.3)
6
6
  git (1.2.5)
7
7
  jeweler (1.6.4)
8
8
  bundler (~> 1.0)
9
9
  git (>= 1.2.5)
10
10
  rake
11
+ looksee (1.0.3)
11
12
  multipart-post (1.1.4)
12
13
  progressbar (0.9.2)
13
14
  rake (0.9.2.2)
@@ -20,6 +21,7 @@ GEM
20
21
  rspec-expectations (2.3.0)
21
22
  diff-lcs (~> 1.1.2)
22
23
  rspec-mocks (2.3.0)
24
+ what_methods (1.0.1)
23
25
 
24
26
  PLATFORMS
25
27
  ruby
@@ -28,7 +30,9 @@ DEPENDENCIES
28
30
  awesome_print
29
31
  bundler (~> 1.0.0)
30
32
  jeweler (~> 1.6.4)
33
+ looksee
31
34
  multipart-post (~> 1.1.4)
32
35
  progressbar (~> 0.9.2)
33
36
  rcov
34
37
  rspec (~> 2.3.0)
38
+ what_methods
data/README.md CHANGED
@@ -43,6 +43,7 @@ Usage
43
43
  --pe
44
44
  --data-directory
45
45
  -S, --sections
46
+ --tls
46
47
  -s, --strings
47
48
  -R, --resources
48
49
  --resource-directory
@@ -53,6 +54,7 @@ Usage
53
54
  --deep packer deep scan, significantly slower
54
55
  -P, --packer-only packer/compiler detect only,
55
56
  mimics 'file' command output
57
+ -r, --recursive recurse dirs in packer detect
56
58
  --all Dump all but resource-directory (default)
57
59
  --va2file VA Convert RVA to file offset
58
60
  -W, --web Uploads files to a http://pedump.me
@@ -126,7 +128,7 @@ Usage
126
128
  # IMAGE_FILE_HEADER:
127
129
  Machine: 332 0x14c x86
128
130
  NumberOfSections: 4 4
129
- TimeDateStamp: "2008-09-14 11:28:52"
131
+ TimeDateStamp: "2008-09-14 07:28:52"
130
132
  PointerToSymbolTable: 0 0
131
133
  NumberOfSymbols: 0 0
132
134
  SizeOfOptionalHeader: 224 0xe0
@@ -315,7 +317,7 @@ Usage
315
317
  === EXPORTS ===
316
318
 
317
319
  # module "zlib.dll"
318
- # flags=0x0 ts="1996-05-07 12:46:46" version=0.0 ord_base=1
320
+ # flags=0x0 ts="1996-05-07 08:46:46" version=0.0 ord_base=1
319
321
  # nFuncs=27 nNames=27
320
322
 
321
323
  ORD ENTRY_VA NAME
@@ -328,24 +330,24 @@ Usage
328
330
  7 37f0 deflateInit2_
329
331
  8 37c0 deflateInit_
330
332
  9 3bc0 deflateParams
331
- 10 3b40 deflateReset
332
- 11 3a40 deflateSetDictionary
333
- 12 7510 gzclose
334
- 13 6f00 gzdopen
335
- 14 75a0 gzerror
336
- 15 73f0 gzflush
337
- 16 6c50 gzopen
338
- 17 7190 gzread
339
- 18 7350 gzwrite
340
- 19 4e50 inflate
341
- 20 4cc0 inflateEnd
342
- 21 4d20 inflateInit2_
343
- 22 4e30 inflateInit_
344
- 23 4c70 inflateReset
345
- 24 5260 inflateSetDictionary
346
- 25 52f0 inflateSync
347
- 26 4bd0 uncompress
348
- 27 e340 zlib_version
333
+ a 3b40 deflateReset
334
+ b 3a40 deflateSetDictionary
335
+ c 7510 gzclose
336
+ d 6f00 gzdopen
337
+ e 75a0 gzerror
338
+ f 73f0 gzflush
339
+ 10 6c50 gzopen
340
+ 11 7190 gzread
341
+ 12 7350 gzwrite
342
+ 13 4e50 inflate
343
+ 14 4cc0 inflateEnd
344
+ 15 4d20 inflateInit2_
345
+ 16 4e30 inflateInit_
346
+ 17 4c70 inflateReset
347
+ 18 5260 inflateSetDictionary
348
+ 19 52f0 inflateSync
349
+ 1a 4bd0 uncompress
350
+ 1b e340 zlib_version
349
351
 
350
352
  ### VS_VERSIONINFO parsing
351
353
 
data/Rakefile CHANGED
@@ -190,3 +190,28 @@ task :readme do
190
190
  Dir.chdir '..'
191
191
  File.open('README.md','w'){ |f| f << result }
192
192
  end
193
+
194
+ namespace :console do
195
+ desc "start console with PEdump::Loader with loaded file"
196
+ task :load do
197
+ raise "gimme a fname" unless fname = ENV['fname']
198
+ require './lib/pedump'
199
+ require './lib/pedump/loader'
200
+ require 'pp'
201
+ File.open(fname,"rb") do |f|
202
+ @ldr = PEdump::Loader.new f
203
+ puts "[.] loader is at @ldr"
204
+ pp @ldr.sections
205
+ Rake::Task["console"].execute
206
+ end
207
+ end
208
+ end
209
+
210
+ desc "compare two PE files"
211
+ task :cmp do
212
+ raise "gimme a f1" unless f1 = ENV['f1']
213
+ raise "gimme a f2" unless f2 = ENV['f2']
214
+ require './lib/pedump'
215
+ require './lib/pedump/comparer'
216
+ PEdump::Comparer.cmp(f1,f2)
217
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.5
1
+ 0.4.6
@@ -12,16 +12,20 @@ require 'pedump/tls'
12
12
  # http://github.com/zed-0xff
13
13
 
14
14
  class PEdump
15
- attr_accessor :fname, :logger, :force
15
+ attr_accessor :fname, :logger, :force, :io
16
16
 
17
17
  VERSION = Version::STRING
18
18
 
19
19
  @@logger = nil
20
20
 
21
- def initialize fname, params = {}
22
- @fname = fname
21
+ def initialize io = nil, params = {}
22
+ if io.is_a?(Hash)
23
+ @io, params = nil, io
24
+ else
25
+ @io = io
26
+ end
23
27
  @force = params[:force]
24
- @logger = @@logger = params[:logger] || PEdump::Logger.new(params[:logdev] || STDERR)
28
+ @logger = @@logger = Logger.create(params)
25
29
  end
26
30
 
27
31
  # http://www.delorie.com/djgpp/doc/exe/
@@ -83,10 +87,10 @@ class PEdump
83
87
  0x8000 => 'BYTES_REVERSED_HI' # The bytes of the word are reversed. This flag is obsolete.
84
88
  }
85
89
 
86
- def initialize *args
87
- super
88
- self.TimeDateStamp = Time.at(self.TimeDateStamp).utc
89
- end
90
+ # def initialize *args
91
+ # super
92
+ # self.TimeDateStamp = Time.at(self.TimeDateStamp).utc
93
+ # end
90
94
  def flags
91
95
  FLAGS.find_all{ |k,v| (self.Characteristics & k) != 0 }.map(&:last)
92
96
  end
@@ -226,6 +230,10 @@ class PEdump
226
230
  r << ' SHARED' if f & 0x10000000 > 0
227
231
  r
228
232
  end
233
+
234
+ def pack
235
+ to_a.pack FORMAT.tr('A','a') # pad names with NULL bytes on pack()
236
+ end
229
237
  end
230
238
 
231
239
  # http://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=VS.85).aspx
@@ -286,7 +294,15 @@ class PEdump
286
294
  new(fname, params).dump
287
295
  end
288
296
 
289
- def mz f=nil
297
+ def self.quiet
298
+ oldlevel = @@logger.level
299
+ @@logger.level = ::Logger::FATAL
300
+ yield
301
+ ensure
302
+ @@logger.level = oldlevel
303
+ end
304
+
305
+ def mz f=@io
290
306
  @mz ||= f && MZ.read(f).tap do |mz|
291
307
  if mz.signature != 'MZ' && mz.signature != 'ZM'
292
308
  if @force
@@ -299,7 +315,7 @@ class PEdump
299
315
  end
300
316
  end
301
317
 
302
- def dos_stub f=nil
318
+ def dos_stub f=@io
303
319
  @dos_stub ||=
304
320
  begin
305
321
  return nil unless mz = mz(f)
@@ -339,13 +355,13 @@ class PEdump
339
355
  end
340
356
  end
341
357
 
342
- def rich_hdr f=nil
358
+ def rich_hdr f=@io
343
359
  dos_stub(f) && @rich_hdr
344
360
  end
345
361
  alias :rich_header :rich_hdr
346
362
  alias :rich :rich_hdr
347
363
 
348
- def pe f=nil
364
+ def pe f=@io
349
365
  @pe ||=
350
366
  begin
351
367
  pe_offset = mz(f) && mz(f).lfanew
@@ -396,8 +412,14 @@ class PEdump
396
412
  end
397
413
 
398
414
  # OPTIONAL: assigns @mz, @rich_hdr, @pe, etc
399
- def dump f=nil
400
- f ? _dump_handle(f) : File.open(@fname,'rb'){ |f| _dump_handle(f) }
415
+ def dump f=@io
416
+ if f.is_a?(String)
417
+ File.open(f,'rb'){ |f| _dump_handle(f) }
418
+ elsif f.is_a?(::IO)
419
+ _dump_handle f
420
+ elsif @io
421
+ _dump_handle @io
422
+ end
401
423
  self
402
424
  end
403
425
 
@@ -410,11 +432,11 @@ class PEdump
410
432
  packer h
411
433
  end
412
434
 
413
- def data_directory f=nil
435
+ def data_directory f=@io
414
436
  pe(f) && pe.ioh && pe.ioh.DataDirectory
415
437
  end
416
438
 
417
- def sections f=nil
439
+ def sections f=@io
418
440
  pe(f) && pe.section_table
419
441
  end
420
442
  alias :section_table :sections
@@ -436,9 +458,25 @@ class PEdump
436
458
  :original_first_thunk,
437
459
  :first_thunk
438
460
 
439
- ImportedFunction = Struct.new(:hint, :name, :ordinal)
461
+ class ImportedFunction < Struct.new(:hint, :name, :ordinal, :va)
462
+ # def == x
463
+ # self.hint == x.hint && self.name == x.name && self.ordinal == x.ordinal
464
+ # end
465
+ # def <=> x
466
+ # self.to_a[0..-2] <=> x.to_a[0..-2]
467
+ # end
468
+
469
+ # magic to be able to easy merge :first_thunk & :original_first_thunk arrays
470
+ # (keeping va different)
471
+ def hash
472
+ self.to_a[0..-2].hash
473
+ end
474
+ def eql? x
475
+ self.hint == x.hint && self.name == x.name && self.ordinal == x.ordinal
476
+ end
477
+ end
440
478
 
441
- def imports f=nil
479
+ def imports f=@io
442
480
  return @imports if @imports
443
481
  return nil unless pe(f) && pe(f).ioh && f
444
482
  dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::IMPORT]
@@ -472,14 +510,14 @@ class PEdump
472
510
 
473
511
  logger.warn "[?] non-empty last IMAGE_IMPORT_DESCRIPTOR: #{t.inspect}" unless t.empty?
474
512
  @imports = r.each do |x|
475
- if x.Name.to_i != 0 && (va = va2file(x.Name))
476
- f.seek va
477
- x.module_name = f.gets("\x00").chomp("\x00")
513
+ if x.Name.to_i != 0 && (ofs = va2file(x.Name))
514
+ f.seek ofs
515
+ x.module_name = f.gets("\x00").to_s.chomp("\x00")
478
516
  end
479
517
  [:original_first_thunk, :first_thunk].each do |tbl|
480
518
  camel = tbl.capitalize.to_s.gsub(/_./){ |char| char[1..-1].upcase}
481
- if x[camel].to_i != 0 && (va = va2file(x[camel]))
482
- f.seek va
519
+ if x[camel].to_i != 0 && (ofs = va2file(x[camel]))
520
+ f.seek ofs
483
521
  x[tbl] ||= []
484
522
  if pe.x64?
485
523
  x[tbl] << t while (t = f.read(8).unpack('Q').first) != 0
@@ -492,16 +530,22 @@ class PEdump
492
530
  idx = -1
493
531
  x[tbl] && x[tbl].map! do |t|
494
532
  idx += 1
533
+ va = x[camel].to_i + idx*4
495
534
  cache[t] ||=
496
- if t & (2**(bits-1)) > 0 # 0x8000_0000(_0000_0000)
497
- ImportedFunction.new(nil,nil,t & (2**(bits-1)-1)) # 0x7fff_ffff(_ffff_ffff)
498
- elsif va=va2file(t, :quiet => true)
499
- f.seek va
535
+ if t & (2**(bits-1)) > 0 # 0x8000_0000(_0000_0000)
536
+ ImportedFunction.new(nil,nil,t & (2**(bits-1)-1),va) # 0x7fff_ffff(_ffff_ffff)
537
+ elsif ofs=va2file(t, :quiet => true)
538
+ f.seek ofs
500
539
  if f.eof?
501
- logger.warn "[?] import va 0x#{va.to_s(16)} beyond EOF"
540
+ logger.warn "[?] import ofs 0x#{ofs.to_s(16)} beyond EOF"
502
541
  nil
503
542
  else
504
- ImportedFunction.new(f.read(2).unpack('v').first, f.gets("\x00").chop)
543
+ ImportedFunction.new(
544
+ f.read(2).unpack('v').first,
545
+ f.gets("\x00").chomp("\x00"),
546
+ nil,
547
+ va
548
+ )
505
549
  end
506
550
  elsif tbl == :original_first_thunk
507
551
  # OriginalFirstThunk entries can not be invalid, show a warning msg
@@ -521,8 +565,11 @@ class PEdump
521
565
  logger.warn "[?] import table: empty FirstThunk for #{x.module_name}"
522
566
  elsif !x.original_first_thunk && x.first_thunk
523
567
  logger.info "[?] import table: empty OriginalFirstThunk for #{x.module_name}"
524
- elsif x.original_first_thunk != x.first_thunk
525
- logger.debug "[?] import table: OriginalFirstThunk != FirstThunk for #{x.module_name}"
568
+ elsif logger.debug?
569
+ # compare all but VAs
570
+ if x.original_first_thunk != x.first_thunk
571
+ logger.debug "[?] import table: OriginalFirstThunk != FirstThunk for #{x.module_name}"
572
+ end
526
573
  end
527
574
  end
528
575
  end
@@ -547,7 +594,7 @@ class PEdump
547
594
  # manual:
548
595
  :name, :entry_points, :names, :name_ordinals
549
596
 
550
- def exports f=nil
597
+ def exports f=@io
551
598
  return @exports if @exports
552
599
  return nil unless pe(f) && pe(f).ioh && f
553
600
  dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::EXPORT]
@@ -564,18 +611,18 @@ class PEdump
564
611
  x.entry_points = []
565
612
  x.name_ordinals = []
566
613
  x.names = []
567
- if x.Name.to_i != 0 && (va = va2file(x.Name))
568
- f.seek va
614
+ if x.Name.to_i != 0 && (ofs = va2file(x.Name))
615
+ f.seek ofs
569
616
  if f.eof?
570
- logger.warn "[?] export va 0x#{va.to_s(16)} beyond EOF"
617
+ logger.warn "[?] export ofs 0x#{ofs.to_s(16)} beyond EOF"
571
618
  nil
572
619
  else
573
620
  x.name = f.gets("\x00").chomp("\x00")
574
621
  end
575
622
  end
576
623
  if x.NumberOfFunctions.to_i != 0
577
- if x.AddressOfFunctions.to_i !=0 && (va = va2file(x.AddressOfFunctions))
578
- f.seek va
624
+ if x.AddressOfFunctions.to_i !=0 && (ofs = va2file(x.AddressOfFunctions))
625
+ f.seek ofs
579
626
  x.entry_points = []
580
627
  x.NumberOfFunctions.times do
581
628
  if f.eof?
@@ -585,8 +632,8 @@ class PEdump
585
632
  x.entry_points << f.read(4).unpack('V').first
586
633
  end
587
634
  end
588
- if x.AddressOfNameOrdinals.to_i !=0 && (va = va2file(x.AddressOfNameOrdinals))
589
- f.seek va
635
+ if x.AddressOfNameOrdinals.to_i !=0 && (ofs = va2file(x.AddressOfNameOrdinals))
636
+ f.seek ofs
590
637
  x.name_ordinals = []
591
638
  x.NumberOfNames.times do
592
639
  if f.eof?
@@ -597,8 +644,8 @@ class PEdump
597
644
  end
598
645
  end
599
646
  end
600
- if x.NumberOfNames.to_i != 0 && x.AddressOfNames.to_i !=0 && (va = va2file(x.AddressOfNames))
601
- f.seek va
647
+ if x.NumberOfNames.to_i != 0 && x.AddressOfNames.to_i !=0 && (ofs = va2file(x.AddressOfNames))
648
+ f.seek ofs
602
649
  x.names = []
603
650
  x.NumberOfNames.times do
604
651
  if f.eof?
@@ -619,7 +666,7 @@ class PEdump
619
666
  # TLS
620
667
  ##############################################################################
621
668
 
622
- def tls f=nil
669
+ def tls f=@io
623
670
  @tls ||= pe(f) && pe(f).ioh && f &&
624
671
  begin
625
672
  dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::TLS]
@@ -646,11 +693,11 @@ class PEdump
646
693
  # resources
647
694
  ##############################################################################
648
695
 
649
- def resources f=nil
696
+ def resources f=@io
650
697
  @resources ||= _scan_resources(f)
651
698
  end
652
699
 
653
- def version_info f=nil
700
+ def version_info f=@io
654
701
  resources(f) && resources(f).find_all{ |res| res.type == 'VERSION' }.map(&:data).flatten
655
702
  end
656
703
 
@@ -658,7 +705,7 @@ class PEdump
658
705
  # packer / compiler detection
659
706
  ##############################################################################
660
707
 
661
- def packer f = nil
708
+ def packer f=@io
662
709
  @packer ||= pe(f) && @pe.ioh &&
663
710
  begin
664
711
  if !(va=@pe.ioh.AddressOfEntryPoint)