pedump 0.0.1 → 0.1.0

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