pedump 0.0.1 → 0.1.0

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.
Files changed (5) hide show
  1. data/VERSION +1 -1
  2. data/lib/pedump.rb +215 -94
  3. data/lib/pedump/cli.rb +27 -22
  4. data/pedump.gemspec +2 -2
  5. metadata +11 -11
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.1.0
@@ -27,12 +27,37 @@ class String
27
27
  end
28
28
  end
29
29
 
30
+ class File
31
+ def checked_seek newpos
32
+ @file_range ||= (0..size)
33
+ @file_range.include?(newpos) && (seek(newpos) || true)
34
+ end
35
+ end
36
+
30
37
  class PEdump
31
- attr_accessor :fname, :logger
32
- attr_reader :mz, :dos_stub, :rich_hdr, :pe, :resources, :resource_directory
38
+ attr_accessor :fname, :logger, :force
33
39
 
34
- alias :rich_header :rich_hdr
35
- alias :rich :rich_hdr
40
+ def initialize fname, params = {}
41
+ @fname = fname
42
+ @force = params[:force]
43
+ @logger = @@logger = params[:logger] || PEdump::Logger.new(STDERR)
44
+ end
45
+
46
+ class Logger < ::Logger
47
+ def initialize *args
48
+ super
49
+ @formatter = proc do |severity,_,_,msg|
50
+ # quick and dirty way to remove duplicate messages
51
+ if @prevmsg == msg && severity != 'DEBUG' && severity != 'INFO'
52
+ ''
53
+ else
54
+ @prevmsg = msg
55
+ "#{msg}\n"
56
+ end
57
+ end
58
+ @level = Logger::WARN
59
+ end
60
+ end
36
61
 
37
62
  class << self
38
63
  def logger; @@logger; end
@@ -63,14 +88,19 @@ class PEdump
63
88
  end
64
89
  def x.read file, size = nil
65
90
  size ||= const_get 'SIZE'
66
- new(*file.read(size).to_s.unpack(const_get('FORMAT')))
91
+ data = file.read(size).to_s
92
+ if data.size < size && PEdump.logger
93
+ PEdump.logger.error "[!] #{self.to_s} want #{size} bytes, got #{data.size}"
94
+ end
95
+ new(*data.unpack(const_get('FORMAT')))
67
96
  end
68
97
  end
69
98
  end
70
99
  end
71
100
 
101
+
72
102
  # http://www.delorie.com/djgpp/doc/exe/
73
- MZ = create_struct( "a2v13",
103
+ MZ = create_struct( "a2v13Qv2V6",
74
104
  :signature,
75
105
  :bytes_in_last_block,
76
106
  :blocks_in_file,
@@ -84,7 +114,16 @@ class PEdump
84
114
  :ip,
85
115
  :cs,
86
116
  :reloc_table_offset,
87
- :overlay_number
117
+ :overlay_number,
118
+ :reserved0, # 8 reserved bytes
119
+ :oem_id,
120
+ :oem_info,
121
+ :reserved2, # 20 reserved bytes
122
+ :reserved3,
123
+ :reserved4,
124
+ :reserved5,
125
+ :reserved6,
126
+ :lfanew
88
127
  )
89
128
 
90
129
  PE = Struct.new(
@@ -152,7 +191,7 @@ class PEdump
152
191
  def self.read file, size = SIZE
153
192
  usual_size = 224
154
193
  PEdump.logger.warn "[?] unusual size of IMAGE_OPTIONAL_HEADER = #{size} (must be #{usual_size})" if size != usual_size
155
- new(*file.read([size,SIZE].min).unpack(FORMAT)).tap do |ioh|
194
+ new(*file.read([size,SIZE].min).to_s.unpack(FORMAT)).tap do |ioh|
156
195
  ioh.DataDirectory = []
157
196
 
158
197
  # check if "...this address is outside the memory mapped file and is zeroed by the OS"
@@ -237,8 +276,7 @@ class PEdump
237
276
  class RichHdr < String
238
277
  attr_accessor :offset, :key # xor key
239
278
 
240
- Entry = Struct.new(:version,:id,:times)
241
- class Entry
279
+ class Entry < Struct.new(:version,:id,:times)
242
280
  def inspect
243
281
  "<id=#{id}, version=#{version}, times=#{times}>"
244
282
  end
@@ -249,7 +287,10 @@ class PEdump
249
287
  start_idx = stub.index(key.xor('DanS'))
250
288
  end_idx = stub.index('Rich')+8
251
289
  if stub[end_idx..-1].tr("\x00",'') != ''
252
- raise "[!] non-zero dos stub after rich_hdr: #{stub[end_idx..-1].inspect}"
290
+ t = stub[end_idx..-1]
291
+ t = "#{t[0,0x100]}..." if t.size > 0x100
292
+ PEdump.logger.error "[!] non-zero dos stub after rich_hdr: #{t.inspect}"
293
+ return nil
253
294
  end
254
295
  RichHdr.new(stub[start_idx, end_idx-start_idx]).tap do |x|
255
296
  x.key = key
@@ -272,18 +313,6 @@ class PEdump
272
313
  attr_accessor :offset
273
314
  end
274
315
 
275
- def initialize fname, params = {}
276
- @fname = fname
277
- @logger = params[:logger] ||
278
- begin
279
- Logger.new(STDERR).tap do |l|
280
- l.formatter = proc{ |_,_,_,msg| "#{msg}\n" }
281
- l.level = Logger::WARN
282
- end
283
- end
284
- @@logger = @logger
285
- end
286
-
287
316
  def logger= l
288
317
  @logger = @@logger = l
289
318
  end
@@ -292,57 +321,114 @@ class PEdump
292
321
  new(fname).dump
293
322
  end
294
323
 
295
- def dump
296
- File.open(@fname) do |f|
297
- mz_hdr = f.read 0x40
298
- @mz = MZ.new(*mz_hdr.unpack(MZ::FORMAT))
299
- if @mz.signature != 'MZ' && @mz.signature != 'ZM'
300
- logger.warn "[?] no MZ header (want: 'MZ' or 'ZM', got: #{@mz.signature.inspect}"
324
+ def mz f=nil
325
+ @mz ||= MZ.read(f).tap do |mz|
326
+ if mz.signature != 'MZ' && mz.signature != 'ZM'
327
+ logger.warn "[?] no MZ signature (want: 'MZ' or 'ZM', got: #{mz.signature.inspect}"
301
328
  end
302
- @pe_offset = mz_hdr.unpack("@60V").first
303
- logger.info "[.] PE offset = 0x%x" % @pe_offset
329
+ end
330
+ end
304
331
 
305
- if @pe_offset > 0x1000
306
- logger.error "[!] PE offset is too big!"
307
- else
308
- dos_stub_offset = @mz.header_paragraphs * 0x10
309
- dos_stub_size = @pe_offset - dos_stub_offset
310
- if dos_stub_size > 0
332
+ def dos_stub f=nil
333
+ @dos_stub ||=
334
+ begin
335
+ mz = mz(f)
336
+ dos_stub_offset = mz.header_paragraphs.to_i * 0x10
337
+ dos_stub_size = mz.lfanew.to_i - dos_stub_offset
338
+ if dos_stub_offset <= 0
339
+ logger.warn "[?] invalid DOS stub offset #{dos_stub_offset}"
340
+ nil
341
+ elsif dos_stub_offset > f.size
342
+ logger.warn "[?] DOS stub offset beyond EOF: #{dos_stub_offset}"
343
+ nil
344
+ elsif dos_stub_size < 0
345
+ logger.warn "[?] invalid DOS stub size #{dos_stub_size}"
346
+ nil
347
+ elsif dos_stub_size == 0
348
+ # no DOS stub, it's ok
349
+ nil
350
+ else
351
+ if dos_stub_size > 0x1000
352
+ logger.warn "[?] DOS stub size too big (#{dos_stub_size}), limiting to 0x1000"
353
+ dos_stub_size = 0x1000
354
+ end
311
355
  f.seek dos_stub_offset
312
- @dos_stub = DOSStub.new f.read(dos_stub_size)
313
- @dos_stub.offset = dos_stub_offset
314
- if @dos_stub['Rich']
315
- @rich_hdr = RichHdr.from_dos_stub(@dos_stub)
316
- @dos_stub[@dos_stub.index(@rich_hdr)..-1] = ''
356
+ DOSStub.new(f.read(dos_stub_size)).tap do |dos_stub|
357
+ dos_stub.offset = dos_stub_offset
358
+ if dos_stub['Rich']
359
+ if @rich_hdr = RichHdr.from_dos_stub(dos_stub)
360
+ dos_stub[dos_stub.index(@rich_hdr)..-1] = ''
361
+ end
362
+ end
317
363
  end
318
- else
319
- logger.info "[.] uncommon DOS stub size = #{dos_stub_size}"
320
364
  end
321
365
  end
366
+ end
367
+
368
+ def rich_hdr f=nil
369
+ dos_stub(f) && @rich_hdr
370
+ end
371
+ alias :rich_header :rich_hdr
372
+ alias :rich :rich_hdr
322
373
 
323
- f.seek @pe_offset
324
- @pe = PE.new(*f.read(4).unpack("a4"))
325
- logger.warn "[?] no PE header (want: 'PE\\x00\\x00', got: #{@pe.signature.inspect})" if @pe.signature != "PE\x00\x00"
326
- logger.error "[!] 'NE' format is not supported!" if @pe.signature == "NE\x00\x00"
327
- @pe.image_file_header = IMAGE_FILE_HEADER.read(f)
328
- if @pe.ifh.SizeOfOptionalHeader > 0
329
- if @pe.ifh.Machine == 0x8664
330
- @pe.image_optional_header = IMAGE_OPTIONAL_HEADER64.read(f, @pe.ifh.SizeOfOptionalHeader)
374
+ def pe f=nil
375
+ @pe ||=
376
+ begin
377
+ pe_offset = mz(f).try(:lfanew)
378
+ if pe_offset.nil?
379
+ logger.fatal "[!] NULL PE offset (e_lfanew). cannot continue."
380
+ nil
381
+ elsif pe_offset > f.size
382
+ logger.fatal "[!] PE offset beyond EOF. cannot continue."
383
+ nil
331
384
  else
332
- @pe.image_optional_header = IMAGE_OPTIONAL_HEADER.read(f, @pe.ifh.SizeOfOptionalHeader)
385
+ f.seek pe_offset
386
+ pe_sig = f.read 4
387
+ logger.error "[!] 'NE' format is not supported!" if pe_sig == "NE\x00\x00"
388
+ logger.warn "[?] no PE signature (want: 'PE\\x00\\x00', got: #{pe_sig.inspect})" if pe_sig != "PE\x00\x00"
389
+ PE.new(pe_sig).tap do |pe|
390
+ pe.image_file_header = IMAGE_FILE_HEADER.read(f)
391
+ if pe.ifh.SizeOfOptionalHeader > 0
392
+ if pe.ifh.Machine == 0x8664
393
+ pe.image_optional_header = IMAGE_OPTIONAL_HEADER64.read(f, pe.ifh.SizeOfOptionalHeader)
394
+ else
395
+ pe.image_optional_header = IMAGE_OPTIONAL_HEADER.read(f, pe.ifh.SizeOfOptionalHeader)
396
+ end
397
+ end
398
+
399
+ if (nToRead=pe.ifh.NumberOfSections) > 32
400
+ if @force
401
+ logger.warn "[!] too many sections (#{pe.ifh.NumberOfSections}). forced. reading all"
402
+ else
403
+ logger.warn "[!] too many sections (#{pe.ifh.NumberOfSections}). not forced, reading first 32"
404
+ nToRead = 32
405
+ end
406
+ end
407
+ pe.section_table = nToRead.times.map do
408
+ IMAGE_SECTION_HEADER.read(f)
409
+ end
410
+ end
333
411
  end
334
412
  end
335
- @pe.section_table = @pe.ifh.NumberOfSections.times.map do
336
- IMAGE_SECTION_HEADER.read(f)
337
- end
413
+ end
338
414
 
339
- @resource_directory = _read_resource_directory_tree(f)
340
- end
415
+ def resource_directory f=nil
416
+ @resource_directory ||= _read_resource_directory_tree(f)
417
+ end
418
+
419
+ # OPTIONAL: assigns @mz, @rich_hdr, @pe, etc
420
+ def dump f=nil
421
+ f ? pe(f) : File.open(@fname){ |f| pe(f) }
341
422
  self
342
423
  end
343
424
 
344
- def data_directory; @pe.ioh && @pe.ioh.DataDirectory; end
345
- def sections; @pe.section_table; end
425
+ def data_directory f=nil
426
+ pe(f) && pe.ioh && pe.ioh.DataDirectory
427
+ end
428
+
429
+ def sections f=nil
430
+ pe(f) && pe.section_table
431
+ end
346
432
  alias :section_table :sections
347
433
 
348
434
  IMAGE_RESOURCE_DIRECTORY = create_struct 'V2v4',
@@ -353,31 +439,62 @@ class PEdump
353
439
  class << self
354
440
  attr_accessor :base
355
441
  alias :read_without_children :read
356
- def read f
442
+ def read f, root=true
443
+ if root
444
+ @@loopchk1 = Hash.new(0)
445
+ @@loopchk2 = Hash.new(0)
446
+ @@loopchk3 = Hash.new(0)
447
+ elsif (@@loopchk1[f.tell] += 1) > 1
448
+ PEdump.logger.error "[!] #{self}: loop1 detected at file pos #{f.tell}" if @@loopchk1[f.tell] < 2
449
+ return nil
450
+ end
357
451
  read_without_children(f).tap do |r|
358
- r.entries = (r.NumberOfNamedEntries + r.NumberOfIdEntries).times.map do
359
- IMAGE_RESOURCE_DIRECTORY_ENTRY.read(f)
360
- end.each do |entry|
452
+ nToRead = r.NumberOfNamedEntries.to_i + r.NumberOfIdEntries.to_i
453
+ r.entries = []
454
+ nToRead.times do |i|
455
+ if f.eof?
456
+ PEdump.logger.error "[!] #{self}: #{nToRead} entries in directory, but got EOF on #{i}-th."
457
+ break
458
+ end
459
+ if (@@loopchk2[f.tell] += 1) > 1
460
+ PEdump.logger.error "[!] #{self}: loop2 detected at file pos #{f.tell}" if @@loopchk2[f.tell] < 2
461
+ next
462
+ end
463
+ r.entries << IMAGE_RESOURCE_DIRECTORY_ENTRY.read(f)
464
+ end
465
+ #r.entries.uniq!
466
+ r.entries.each do |entry|
361
467
  entry.name =
362
- if entry.Name & 0x8000_0000 > 0
468
+ if entry.Name.to_i & 0x8000_0000 > 0
363
469
  # Name is an address of unicode string
364
470
  f.seek base + entry.Name & 0x7fff_ffff
365
- nChars = f.read(2).unpack("v").first
366
- f.read(nChars*2).force_encoding('UTF-16LE').encode!('UTF-8')
471
+ nChars = f.read(2).to_s.unpack("v").first.to_i
472
+ begin
473
+ f.read(nChars*2).force_encoding('UTF-16LE').encode!('UTF-8')
474
+ rescue
475
+ PEdump.logger.error "[!] #{self} failed to read entry name: #{$!}"
476
+ "???"
477
+ end
367
478
  else
368
479
  # Name is a numeric id
369
480
  "##{entry.Name}"
370
481
  end
371
- f.seek base + entry.OffsetToData & 0x7fff_ffff
372
- entry.data =
373
- if entry.OffsetToData & 0x8000_0000 > 0
374
- # child is a directory
375
- IMAGE_RESOURCE_DIRECTORY.read(f)
376
- else
377
- # child is a resource
378
- IMAGE_RESOURCE_DATA_ENTRY.read(f)
482
+ if entry.OffsetToData && f.checked_seek(base + entry.OffsetToData & 0x7fff_ffff)
483
+ if (@@loopchk3[f.tell] += 1) > 1
484
+ PEdump.logger.error "[!] #{self}: loop3 detected at file pos #{f.tell}" if @@loopchk3[f.tell] < 2
485
+ next
379
486
  end
487
+ entry.data =
488
+ if entry.OffsetToData & 0x8000_0000 > 0
489
+ # child is a directory
490
+ IMAGE_RESOURCE_DIRECTORY.read(f,false)
491
+ else
492
+ # child is a resource
493
+ IMAGE_RESOURCE_DATA_ENTRY.read(f)
494
+ end
495
+ end
380
496
  end
497
+ @@loopchk1 = @@loopchk2 = @@loopchk3 = nil if root # save some memory
381
498
  end
382
499
  end
383
500
  end
@@ -400,7 +517,7 @@ class PEdump
400
517
  end
401
518
 
402
519
  def _read_resource_directory_tree f
403
- return nil unless @pe.ioh
520
+ return nil unless pe(f).try(:ioh)
404
521
  res_dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::RESOURCE]
405
522
  return [] if !res_dir || (res_dir.va == 0 && res_dir.size == 0)
406
523
  res_va = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::RESOURCE].va
@@ -451,14 +568,14 @@ class PEdump
451
568
  end
452
569
  end
453
570
 
454
- def bitmap_and_mask src_fname
571
+ def bitmap_mask src_fname
455
572
  File.open(src_fname, "rb") do |f|
456
573
  parse f
457
574
  bmp_info_hdr = bitmap_hdr
458
575
  bitmap_size = BITMAPINFOHEADER::SIZE + @palette_size + @imgdata_size
459
576
  return nil if bitmap_size >= self.size
460
577
 
461
- and_mask_size = self.size - bitmap_size
578
+ mask_size = self.size - bitmap_size
462
579
  f.seek file_offset + bitmap_size
463
580
 
464
581
  bmp_info_hdr = BITMAPINFOHEADER.new(*bmp_info_hdr[14..-1].unpack(BITMAPINFOHEADER::FORMAT))
@@ -470,10 +587,10 @@ class PEdump
470
587
  @palette_size = palette.size
471
588
 
472
589
  "BM" + [
473
- BITMAPINFOHEADER::SIZE + 14 + @palette_size + and_mask_size,
590
+ BITMAPINFOHEADER::SIZE + 14 + @palette_size + mask_size,
474
591
  0,
475
592
  BITMAPINFOHEADER::SIZE + 14 + @palette_size
476
- ].pack("V3") + bmp_info_hdr.pack + palette + f.read(and_mask_size)
593
+ ].pack("V3") + bmp_info_hdr.pack + palette + f.read(mask_size)
477
594
  end
478
595
  end
479
596
 
@@ -516,9 +633,9 @@ class PEdump
516
633
 
517
634
  STRING = Struct.new(:id, :lang, :value)
518
635
 
519
- def strings
636
+ def strings f=nil
520
637
  r = []
521
- Array(resources).find_all{ |x| x.type == 'STRING'}.each do |res|
638
+ Array(resources(f)).find_all{ |x| x.type == 'STRING'}.each do |res|
522
639
  res.data.each_with_index do |string,idx|
523
640
  r << STRING.new( ((res.id-1)<<4) + idx, res.lang, string ) unless string.empty?
524
641
  end
@@ -573,7 +690,12 @@ class PEdump
573
690
  %w'MESSAGETABLE GROUP_CURSOR' + [nil] + %w'GROUP_ICON' + [nil] +
574
691
  %w'VERSION DLGINCLUDE' + [nil] + %w'PLUGPLAY VXD ANICURSOR ANIICON HTML MANIFEST'
575
692
 
576
- def resources dir = @resource_directory
693
+ def resources f=nil
694
+ @resources ||= _scan_resources(f)
695
+ end
696
+
697
+ def _scan_resources f=nil, dir=nil
698
+ dir ||= resource_directory(f)
577
699
  return nil unless dir
578
700
  dir.entries.map do |entry|
579
701
  case entry.data
@@ -586,14 +708,12 @@ class PEdump
586
708
  else
587
709
  entry.name
588
710
  end
589
- File.open(@fname,"rb") do |f|
590
- resources(entry.data).each do |res|
591
- res.type = entry_type
592
- res.parse f
593
- end
711
+ _scan_resources(f,entry.data).each do |res|
712
+ res.type = entry_type
713
+ res.parse f
594
714
  end
595
715
  else
596
- resources(entry.data).each do |res|
716
+ _scan_resources(f,entry.data).each do |res|
597
717
  res.name = res.name == "##{res.lang}" ? entry.name : "#{entry.name} / #{res.name}"
598
718
  res.id ||= entry.Name if entry.Name.is_a?(Numeric) && entry.Name < 0x8000_0000
599
719
  end
@@ -610,9 +730,10 @@ class PEdump
610
730
  entry.data.Reserved
611
731
  )
612
732
  else
613
- raise "[!] invalid resource entry: #{entry.data.inspect}"
733
+ logger.error "[!] invalid resource entry: #{entry.data.inspect}"
734
+ nil
614
735
  end
615
- end.flatten
736
+ end.flatten.compact
616
737
  end
617
738
  end
618
739
 
@@ -633,10 +754,10 @@ if $0 == __FILE__
633
754
  fname = r.name.tr("/# ",'_')+".bmp"
634
755
  puts "[.] #{fname}"
635
756
  File.open(fname,"wb"){ |fo| fo << r.restore_bitmap(fi) }
636
- if and_mask = r.bitmap_and_mask(fi)
637
- fname.sub! '.bmp', '.and_mask.bmp'
757
+ if mask = r.bitmap_mask(fi)
758
+ fname.sub! '.bmp', '.mask.bmp'
638
759
  puts "[.] #{fname}"
639
- File.open(fname,"wb"){ |fo| fo << r.bitmap_and_mask(fi) }
760
+ File.open(fname,"wb"){ |fo| fo << r.bitmap_mask(fi) }
640
761
  end
641
762
  end
642
763
  end
@@ -29,6 +29,9 @@ class PEdump::CLI
29
29
  @options[:verbose] ||= 0
30
30
  @options[:verbose] += 1
31
31
  end
32
+ opts.on "-F", "--force", "Try to dump by all means (can cause exceptions & heavy wounds)" do |v|
33
+ @options[:force] = true
34
+ end
32
35
  opts.on "-f", "--format FORMAT", [:binary, :c, :dump, :hex, :inspect, :table],
33
36
  "Output format: bin,c,dump,hex,inspect,table (default)" do |v|
34
37
  @options[:format] = v
@@ -59,16 +62,18 @@ class PEdump::CLI
59
62
  puts "# -----------------------------------------------"
60
63
  puts "# #{fname}"
61
64
  puts "# -----------------------------------------------"
62
- puts
63
- end
64
- @pedump = PEdump.new fname
65
- if @options[:verbose]
66
- @pedump.logger.level = @options[:verbose] > 1 ? Logger::INFO : Logger::DEBUG
67
65
  end
68
- @pedump = @pedump.dump
69
66
 
70
- @actions.each do |action|
71
- dump_action action
67
+ File.open(fname,'rb') do |f|
68
+ @pedump = PEdump.new(fname, :force => @options[:force]).tap do |x|
69
+ if @options[:verbose]
70
+ x.logger.level = @options[:verbose] > 1 ? Logger::INFO : Logger::DEBUG
71
+ end
72
+ end
73
+
74
+ @actions.each do |action|
75
+ dump_action action,f
76
+ end
72
77
  end
73
78
  end
74
79
  rescue Errno::EPIPE
@@ -79,11 +84,11 @@ class PEdump::CLI
79
84
  def action_title action
80
85
  s = action.to_s.upcase.tr('_',' ')
81
86
  s += " Header" if [:mz, :pe, :rich].include?(action)
82
- "=== %s ===\n\n" % s
87
+ "\n=== %s ===\n\n" % s
83
88
  end
84
89
 
85
- def dump_action action
86
- data = @pedump.send(action)
90
+ def dump_action action, f
91
+ data = @pedump.send(action, f)
87
92
  return if !data || (data.respond_to?(:empty?) && data.empty?)
88
93
 
89
94
  puts action_title(action)
@@ -108,8 +113,6 @@ class PEdump::CLI
108
113
  end
109
114
  end
110
115
  dump data, dump_opts
111
- ensure
112
- puts
113
116
  end
114
117
 
115
118
  def dump data, opts = {}
@@ -165,7 +168,7 @@ class PEdump::CLI
165
168
  else
166
169
  if COMMENTS[k]
167
170
  printf "%30s: %10d %12s %s\n", k, v, v<10 ? v : ("0x"+v.to_s(16)),
168
- COMMENTS[k][v] || COMMENTS[k]['default'] || ''
171
+ COMMENTS[k][v] || (COMMENTS[k].is_a?(Hash) ? COMMENTS[k]['default'] : '') || ''
169
172
  else
170
173
  printf "%30s: %10d %12s\n", k, v, v<10 ? v : ("0x"+v.to_s(16))
171
174
  end
@@ -257,8 +260,10 @@ class PEdump::CLI
257
260
  dir.entries.each do |child|
258
261
  dump_res_dir child, level+1
259
262
  end
260
- else
263
+ elsif dir
261
264
  printf "DATA: %8x %8x %5s %8x\n", dir.OffsetToData, dir.Size, dir.CodePage, dir.Reserved
265
+ else
266
+ puts # null dir
262
267
  end
263
268
  end
264
269
 
@@ -309,18 +314,18 @@ class PEdump::CLI
309
314
  data.each do |s|
310
315
  name = s.Name[/[^a-z0-9_.]/i] ? s.Name.inspect : s.Name
311
316
  name = "#{name}\n " if name.size > 8
312
- printf " %-8s %8x %8x %8x %8x %5x %8x %5x %8x %8x %s\n", name,
313
- s.VirtualAddress, s.VirtualSize,
314
- s.SizeOfRawData, s.PointerToRawData,
315
- s.NumberOfRelocations, s.PointerToRelocations,
316
- s.NumberOfLinenumbers, s.PointerToLinenumbers,
317
- s.flags, s.flags_desc
317
+ printf " %-8s %8x %8x %8x %8x %5x %8x %5x %8x %8x %s\n", name.to_s,
318
+ s.VirtualAddress.to_i, s.VirtualSize.to_i,
319
+ s.SizeOfRawData.to_i, s.PointerToRawData.to_i,
320
+ s.NumberOfRelocations.to_i, s.PointerToRelocations.to_i,
321
+ s.NumberOfLinenumbers.to_i, s.PointerToLinenumbers.to_i,
322
+ s.flags.to_i, s.flags_desc
318
323
  end
319
324
  end
320
325
 
321
326
  def dump_data_dir data
322
327
  data.each do |row|
323
- printf " %-12s rva:0x%8x size:0x %8x\n", row.type, row.va, row.size
328
+ printf " %-12s rva:0x%8x size:0x %8x\n", row.type, row.va.to_i, row.size.to_i
324
329
  end
325
330
  end
326
331
 
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "pedump"
8
- s.version = "0.0.1"
8
+ s.version = "0.1.0"
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-07"
12
+ s.date = "2011-12-09"
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"]
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.0.1
4
+ version: 0.1.0
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-07 00:00:00.000000000Z
12
+ date: 2011-12-09 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70189996908160 !ruby/object:Gem::Requirement
16
+ requirement: &70102209592580 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 2.3.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70189996908160
24
+ version_requirements: *70102209592580
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: bundler
27
- requirement: &70189996906020 !ruby/object:Gem::Requirement
27
+ requirement: &70102209591820 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.0.0
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70189996906020
35
+ version_requirements: *70102209591820
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: jeweler
38
- requirement: &70189996904540 !ruby/object:Gem::Requirement
38
+ requirement: &70102209590740 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.6.4
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70189996904540
46
+ version_requirements: *70102209590740
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rcov
49
- requirement: &70189996901000 !ruby/object:Gem::Requirement
49
+ requirement: &70102209585380 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70189996901000
57
+ version_requirements: *70102209585380
58
58
  description: dump headers, sections, extract resources of win32 PE exe,dll,etc
59
59
  email: zed.0xff@gmail.com
60
60
  executables:
@@ -93,7 +93,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
93
  version: '0'
94
94
  segments:
95
95
  - 0
96
- hash: -797634097994231623
96
+ hash: 3334158789950577908
97
97
  required_rubygems_version: !ruby/object:Gem::Requirement
98
98
  none: false
99
99
  requirements: