pedump 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
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)