pedump 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,6 +2,8 @@ source "http://rubygems.org"
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
4
  # gem "activesupport", ">= 2.3.5"
5
+ gem "rest-client", "~> 1.6.7"
6
+ gem "progressbar", "~> 0.9.2"
5
7
 
6
8
  # Add dependencies to develop your gem here.
7
9
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -7,8 +7,12 @@ GEM
7
7
  bundler (~> 1.0)
8
8
  git (>= 1.2.5)
9
9
  rake
10
+ mime-types (1.16)
11
+ progressbar (0.9.2)
10
12
  rake (0.9.2.2)
11
13
  rcov (0.9.11)
14
+ rest-client (1.6.7)
15
+ mime-types (>= 1.16)
12
16
  rspec (2.3.0)
13
17
  rspec-core (~> 2.3.0)
14
18
  rspec-expectations (~> 2.3.0)
@@ -24,5 +28,7 @@ PLATFORMS
24
28
  DEPENDENCIES
25
29
  bundler (~> 1.0.0)
26
30
  jeweler (~> 1.6.4)
31
+ progressbar (~> 0.9.2)
27
32
  rcov
33
+ rest-client (~> 1.6.7)
28
34
  rspec (~> 2.3.0)
data/Rakefile CHANGED
@@ -49,3 +49,29 @@ task :default => :spec
49
49
  # rdoc.rdoc_files.include('README*')
50
50
  # rdoc.rdoc_files.include('lib/**/*.rb')
51
51
  #end
52
+
53
+ namespace :test do
54
+ desc "test on all files in given path"
55
+ task :all_files do
56
+ require './lib/pedump'
57
+ require './lib/pedump/cli'
58
+ path = ENV['path'] || raise("run me with path=...")
59
+ `find #{path} -type f`.split("\n").each do |fname|
60
+ puts "\n### #{fname}\n"
61
+ PEdump::CLI.new(fname).run
62
+ end
63
+ end
64
+
65
+ namespace :all_files do
66
+ desc "output file name to stderr, use with stdout redirection"
67
+ task :stderr do
68
+ require './lib/pedump'
69
+ require './lib/pedump/cli'
70
+ path = ENV['path'] || raise("run me with path=...")
71
+ `find #{path} -type f`.split("\n").each do |fname|
72
+ STDERR.puts "\n### #{fname}\n"
73
+ PEdump::CLI.new(fname).run
74
+ end
75
+ end
76
+ end
77
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.3.0
data/lib/pedump.rb CHANGED
@@ -303,13 +303,17 @@ class PEdump
303
303
  end
304
304
 
305
305
  def dexor
306
- self[4..-9].sub(/\A(#{Regexp::escape(key)})+/,'').xor(key)
306
+ self[4..-9].sub(/\A(#{Regexp::escape(key)}){3}/,'').xor(key)
307
307
  end
308
308
 
309
309
  def decode
310
310
  x = dexor
311
- raise "dexored size must be a multiple of 8" unless x.size%8 == 0
312
- x.unpack('vvV'*(x.size/8)).each_slice(3).map{ |slice| Entry.new(*slice)}
311
+ if x.size%8 == 0
312
+ x.unpack('vvV'*(x.size/8)).each_slice(3).map{ |slice| Entry.new(*slice)}
313
+ else
314
+ PEdump.logger.error "[?] #{self.class}: dexored size(#{x.size}) must be a multiple of 8"
315
+ nil
316
+ end
313
317
  end
314
318
  end
315
319
 
@@ -441,6 +445,8 @@ class PEdump
441
445
  def _dump_handle h
442
446
  rich_hdr(h) # includes mz(h)
443
447
  resources(h) # includes pe(h)
448
+ imports h
449
+ exports h
444
450
  end
445
451
 
446
452
  def data_directory f=nil
@@ -472,16 +478,19 @@ class PEdump
472
478
  ImportedFunction = Struct.new(:hint, :name, :ordinal)
473
479
 
474
480
  def imports f=nil
481
+ return @imports if @imports
475
482
  return nil unless pe(f) && pe(f).ioh && f
476
483
  dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::IMPORT]
477
484
  return [] if !dir || (dir.va == 0 && dir.size == 0)
478
485
  va = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::IMPORT].va
479
- f.seek va2file(va)
486
+ file_offset = va2file(va)
487
+ return nil unless file_offset
488
+ f.seek file_offset
480
489
  r = []
481
490
  until (t=IMAGE_IMPORT_DESCRIPTOR.read(f)).empty?
482
491
  r << t
483
492
  end
484
- r.each do |x|
493
+ @imports = r.each do |x|
485
494
  if x.Name.to_i != 0 && (va = va2file(x.Name))
486
495
  f.seek va
487
496
  x.module_name = f.gets("\x00").chop
@@ -539,15 +548,21 @@ class PEdump
539
548
  :AddressOfNames,
540
549
  :AddressOfNameOrdinals,
541
550
  # manual:
542
- :name, :entry_points, :names, :ordinals
551
+ :name, :entry_points, :names, :name_ordinals
543
552
 
544
553
  def exports f=nil
554
+ return @exports if @exports
545
555
  return nil unless pe(f) && pe(f).ioh && f
546
556
  dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::EXPORT]
547
557
  return [] if !dir || (dir.va == 0 && dir.size == 0)
548
558
  va = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::EXPORT].va
549
- f.seek va2file(va)
550
- IMAGE_EXPORT_DIRECTORY.read(f).tap do |x|
559
+ file_offset = va2file(va)
560
+ return nil unless file_offset
561
+ f.seek file_offset
562
+ @exports = IMAGE_EXPORT_DIRECTORY.read(f).tap do |x|
563
+ x.entry_points = []
564
+ x.name_ordinals = []
565
+ x.names = []
551
566
  if x.Name.to_i != 0 && (va = va2file(x.Name))
552
567
  f.seek va
553
568
  x.name = f.gets("\x00").chop
@@ -559,7 +574,7 @@ class PEdump
559
574
  end
560
575
  if x.AddressOfNameOrdinals.to_i !=0 && (va = va2file(x.AddressOfNameOrdinals))
561
576
  f.seek va
562
- x.ordinals = f.read(x.NumberOfFunctions*2).unpack('v*').map{ |o| o+x.Base }
577
+ x.name_ordinals = f.read(x.NumberOfNames*2).unpack('v*').map{ |o| o+x.Base }
563
578
  end
564
579
  end
565
580
  if x.NumberOfNames.to_i != 0 && x.AddressOfNames.to_i !=0 && (va = va2file(x.AddressOfNames))
@@ -658,6 +673,13 @@ class PEdump
658
673
  return va - s.VirtualAddress + s.PointerToRawData
659
674
  end
660
675
  end
676
+ # not found with regular search. assume any of VirtualSize was 0, and try with RawSize
677
+ sections.each do |s|
678
+ if (s.VirtualAddress...(s.VirtualAddress+s.SizeOfRawData)).include?(va)
679
+ return va - s.VirtualAddress + s.PointerToRawData
680
+ end
681
+ end
682
+ logger.error "[?] can't find file_offset of VA 0x#{va.to_i.to_s(16)}"
661
683
  nil
662
684
  end
663
685
 
@@ -673,11 +695,11 @@ class PEdump
673
695
  end
674
696
  f.seek res_section.PointerToRawData
675
697
  IMAGE_RESOURCE_DIRECTORY.base = res_section.PointerToRawData
676
- @resource_data_base = res_section.PointerToRawData - res_section.VirtualAddress
698
+ #@resource_data_base = res_section.PointerToRawData - res_section.VirtualAddress
677
699
  IMAGE_RESOURCE_DIRECTORY.read(f)
678
700
  end
679
701
 
680
- class Resource < Struct.new(:type, :name, :id, :lang, :file_offset, :size, :cp, :reserved, :data)
702
+ class Resource < Struct.new(:type, :name, :id, :lang, :file_offset, :size, :cp, :reserved, :data, :valid)
681
703
  def bitmap_hdr
682
704
  bmp_info_hdr = data.find{ |x| x.is_a?(BITMAPINFOHEADER) }
683
705
  raise "no BITMAPINFOHEADER for #{self.type} #{self.name}" unless bmp_info_hdr
@@ -765,23 +787,70 @@ class PEdump
765
787
  when 'GROUP_CURSOR'
766
788
  f.seek file_offset
767
789
  data << CUR_ICO_HEADER.read(f)
790
+ nRead = CUR_ICO_HEADER::SIZE
768
791
  data.last.wNumImages.times do
769
- data << CURDIRENTRY.read(f)
792
+ if nRead >= self.size
793
+ PEdump.logger.error "[!] refusing to read CURDIRENTRY beyond resource size"
794
+ break
795
+ end
796
+ data << CURDIRENTRY.read(f)
797
+ nRead += CURDIRENTRY::SIZE
770
798
  end
771
799
  when 'GROUP_ICON'
772
800
  f.seek file_offset
773
801
  data << CUR_ICO_HEADER.read(f)
802
+ nRead = CUR_ICO_HEADER::SIZE
774
803
  data.last.wNumImages.times do
775
- data << ICODIRENTRY.read(f)
804
+ if nRead >= self.size
805
+ PEdump.logger.error "[!] refusing to read ICODIRENTRY beyond resource size"
806
+ break
807
+ end
808
+ data << ICODIRENTRY.read(f)
809
+ nRead += ICODIRENTRY::SIZE
776
810
  end
777
811
  when 'STRING'
778
812
  f.seek file_offset
779
813
  16.times do
780
- nChars = f.read(2).unpack('v').first
781
- data << f.read(nChars*2).force_encoding('UTF-16LE').encode!('UTF-8')
814
+ break if f.tell >= file_offset+self.size
815
+ nChars = f.read(2).to_s.unpack('v').first.to_i
816
+ t =
817
+ if nChars*2 + 1 > self.size
818
+ # TODO: if it's not 1st string in table then truncated size must be less
819
+ PEdump.logger.error "[!] string size(#{nChars*2}) > stringtable size(#{self.size}). truncated to #{self.size-2}"
820
+ f.read(self.size-2)
821
+ else
822
+ f.read(nChars*2)
823
+ end
824
+ data <<
825
+ begin
826
+ t.force_encoding('UTF-16LE').encode!('UTF-8')
827
+ rescue
828
+ t.force_encoding('ASCII')
829
+ tt = t.size > 0x10 ? t[0,0x10].inspect+'...' : t.inspect
830
+ PEdump.logger.error "[!] cannot convert #{tt} to UTF-16"
831
+ [nChars,t].pack('va*')
832
+ end
782
833
  end
783
834
  # XXX: check if readed strings summary length is less than resource data length
784
835
  end
836
+
837
+ data.delete_if do |x|
838
+ valid = !x.respond_to?(:valid?) || x.valid?
839
+ PEdump.logger.warn "[?] ignoring invalid #{x.class}" unless valid
840
+ !valid
841
+ end
842
+ ensure
843
+ validate
844
+ end
845
+
846
+ def validate
847
+ self.valid =
848
+ case type
849
+ when 'BITMAP','ICON','CURSOR'
850
+ data.any?{ |x| x.is_a?(BITMAPINFOHEADER) && x.valid? }
851
+ else
852
+ true
853
+ end
785
854
  end
786
855
  end
787
856
 
@@ -799,7 +868,7 @@ class PEdump
799
868
 
800
869
  # see also http://www.informit.com/articles/article.aspx?p=1186882 about icons format
801
870
 
802
- BITMAPINFOHEADER = create_struct 'V3v2V6',
871
+ class BITMAPINFOHEADER < create_struct 'V3v2V6',
803
872
  :biSize, # BITMAPINFOHEADER::SIZE
804
873
  :biWidth,
805
874
  :biHeight,
@@ -812,6 +881,11 @@ class PEdump
812
881
  :biClrUsed,
813
882
  :biClrImportant
814
883
 
884
+ def valid?
885
+ self.biSize == 40
886
+ end
887
+ end
888
+
815
889
  # http://www.devsource.com/c/a/Architecture/Resources-From-PE-I/2/
816
890
  CUR_ICO_HEADER = create_struct('v3',
817
891
  :wReserved, # always 0
@@ -878,7 +952,8 @@ class PEdump
878
952
  entry.name,
879
953
  nil, # id
880
954
  entry.Name, # lang
881
- entry.data.OffsetToData + @resource_data_base,
955
+ #entry.data.OffsetToData + @resource_data_base,
956
+ va2file(entry.data.OffsetToData),
882
957
  entry.data.Size,
883
958
  entry.data.CodePage,
884
959
  entry.data.Reserved
data/lib/pedump/cli.rb CHANGED
@@ -14,10 +14,12 @@ class PEdump::CLI
14
14
 
15
15
  KNOWN_ACTIONS = (
16
16
  %w'mz dos_stub rich pe data_directory sections' +
17
- %w'strings resources resource_directory imports exports'
17
+ %w'strings resources resource_directory imports exports web'
18
18
  ).map(&:to_sym)
19
19
 
20
- DEFAULT_ALL_ACTIONS = KNOWN_ACTIONS - %w'resource_directory'.map(&:to_sym)
20
+ DEFAULT_ALL_ACTIONS = KNOWN_ACTIONS - %w'resource_directory web'.map(&:to_sym)
21
+
22
+ URL_BASE = "http://pedump.me"
21
23
 
22
24
  def initialize argv = ARGV
23
25
  @argv = argv
@@ -41,7 +43,6 @@ class PEdump::CLI
41
43
  "Output format: bin,c,dump,hex,inspect,table (default)" do |v|
42
44
  @options[:format] = v
43
45
  end
44
- # TODO: imports, exports
45
46
  KNOWN_ACTIONS.each do |t|
46
47
  opts.on "--#{t.to_s.tr('_','-')}", eval("lambda{ |_| @actions << :#{t.to_s.tr('-','_')} }")
47
48
  end
@@ -51,6 +52,9 @@ class PEdump::CLI
51
52
  opts.on "--va2file VA", "Convert RVA to file offset" do |va|
52
53
  @actions << [:va2file,va]
53
54
  end
55
+ opts.on "-W", "--web", "Upload file to a #{URL_BASE} for a nice HTML tables with image previews, candies & stuff" do
56
+ @actions << :web
57
+ end
54
58
  end
55
59
 
56
60
  if (@argv = optparser.parse(@argv)).empty?
@@ -79,10 +83,14 @@ class PEdump::CLI
79
83
  end
80
84
  end
81
85
 
82
- return if !@options[:force] && !@pedump.mz(f)
86
+ next if !@options[:force] && !@pedump.mz(f)
83
87
 
84
88
  @actions.each do |action|
85
- dump_action action,f
89
+ if action == :web
90
+ upload f
91
+ else
92
+ dump_action action,f
93
+ end
86
94
  end
87
95
  end
88
96
  end
@@ -91,6 +99,71 @@ class PEdump::CLI
91
99
  # prevents a 'Broken pipe - <STDOUT> (Errno::EPIPE)' message
92
100
  end
93
101
 
102
+ class ProgressProxy
103
+ def initialize file
104
+ @file = file
105
+ @pbar = ProgressBar.new("[.] uploading", file.size, STDOUT)
106
+ @pbar.try(:file_transfer_mode)
107
+ @pbar.bar_mark = '='
108
+ end
109
+ def read *args
110
+ @pbar.inc args.first
111
+ @file.read *args
112
+ end
113
+ def method_missing *args
114
+ @file.send *args
115
+ end
116
+ def respond_to? *args
117
+ @file.respond_to?(*args) || super(*args)
118
+ end
119
+ end
120
+
121
+ def upload f
122
+ if @pedump.mz(f).signature != 'MZ'
123
+ @pedump.logger.error "[!] refusing to upload a non-MZ file"
124
+ return
125
+ end
126
+
127
+ require 'digest/md5'
128
+ require 'open-uri'
129
+ require 'rest-client'
130
+ require 'progressbar'
131
+
132
+ stdout_sync = STDOUT.sync
133
+ STDOUT.sync = true
134
+
135
+ md5 = Digest::MD5.file(f.path).hexdigest
136
+ @pedump.logger.info "[.] md5: #{md5}"
137
+ url = "#{URL_BASE}/#{md5}/"
138
+
139
+ @pedump.logger.info "[.] checking if file already uploaded.."
140
+ begin
141
+ if (r=open(url).read) == "OK"
142
+ @pedump.logger.warn "[.] file already uploaded: #{url}"
143
+ return
144
+ else
145
+ raise "invalid server response: #{r}"
146
+ end
147
+ rescue OpenURI::HTTPError
148
+ raise unless $!.to_s == "404 Not Found"
149
+ end
150
+
151
+ f.rewind
152
+ if (r=RestClient.post(URL_BASE, :file => ProgressProxy.new(f))) != "OK"
153
+ raise "invalid server response: #{r}"
154
+ end
155
+ puts
156
+ puts "[.] analyzing..."
157
+
158
+ if (r=open(File.join(URL_BASE,md5,'analyze')).read) != "OK"
159
+ raise "invalid server response: #{r}"
160
+ end
161
+
162
+ puts "[.] uploaded: #{url}"
163
+ ensure
164
+ STDOUT.sync = stdout_sync
165
+ end
166
+
94
167
  def action_title action
95
168
  s = action.to_s.upcase.tr('_',' ')
96
169
  s += " Header" if [:mz, :pe, :rich].include?(action)
@@ -242,33 +315,52 @@ class PEdump::CLI
242
315
  end
243
316
 
244
317
  def dump_exports data
245
- printf "# module_name=%s flags=0x%x ts=%s version=%d.%d\n",
318
+ printf "# module %s\n# flags=0x%x ts=%s version=%d.%d ord_base=%d\n",
246
319
  data.name.inspect,
247
320
  data.Characteristics,
248
321
  Time.at(data.TimeDateStamp.to_i).strftime('"%Y-%m-%d %H:%M:%S"'),
249
- data.MajorVersion, data.MinorVersion
322
+ data.MajorVersion, data.MinorVersion,
323
+ data.Base
324
+
325
+ if @options[:verbose]
326
+ printf "# Names rva=0x%08x file_offset=%8d\n",
327
+ data.AddressOfNames, @pedump.va2file(data.AddressOfNames)
328
+ printf "# EntryPoints rva=0x%08x file_offset=%8d\n",
329
+ data.AddressOfFunctions, @pedump.va2file(data.AddressOfFunctions)
330
+ printf "# Ordinals rva=0x%08x file_offset=%8d\n",
331
+ data.AddressOfNameOrdinals, @pedump.va2file(data.AddressOfNameOrdinals)
332
+ end
250
333
 
251
- printf "# n_funcs=%d n_names=%d\n",
334
+ printf "# nFuncs=%d nNames=%d\n",
252
335
  data.NumberOfFunctions,
253
336
  data.NumberOfNames
254
337
 
338
+ return unless data.name_ordinals.any? || data.entry_points.any? || data.names.any?
339
+
255
340
  puts
256
341
 
342
+ ord2name = {}
343
+ data.NumberOfNames.times do |i|
344
+ ord2name[data.name_ordinals[i]] ||= []
345
+ ord2name[data.name_ordinals[i]] << data.names[i]
346
+ end
347
+
257
348
  printf "%5s %8s %s\n", "ORD", "ENTRY_VA", "NAME"
258
349
  data.NumberOfFunctions.times do |i|
259
- printf "%5s %8x %s\n",
260
- data.ordinals[i].try(:to_s,16),
261
- data.entry_points[i],
262
- data.names[i]
350
+ ep = data.entry_points[i]
351
+ names = ord2name[i+data.Base].try(:join,', ')
352
+ next if ep.to_i == 0 && names.nil?
353
+ printf "%5d %8x %s\n", i + data.Base, ep, names
263
354
  end
264
355
  end
265
356
 
266
357
  def dump_imports data
267
- fmt = "%-15s %5s %5s %s\n"
358
+ fmt = "%-15s %5s %5s %s\n"
268
359
  printf fmt, "MODULE_NAME", "HINT", "ORD", "FUNCTION_NAME"
269
360
  data.each do |iid|
270
361
  # image import descriptor
271
362
  (Array(iid.original_first_thunk) + Array(iid.first_thunk)).uniq.each do |f|
363
+ next unless f
272
364
  # imported function
273
365
  printf fmt,
274
366
  iid.module_name,
@@ -373,7 +465,7 @@ class PEdump::CLI
373
465
  fmt.each_with_index do |f,i|
374
466
  v = res.send(keys[i])
375
467
  if f['x']
376
- printf f.tr('x','s'), v < 10 ? v.to_s : "0x#{v.to_s(16)}"
468
+ printf f.tr('x','s'), v.to_i < 10 ? v.to_s : "0x#{v.to_s(16)}"
377
469
  else
378
470
  printf f, v
379
471
  end
@@ -403,10 +495,18 @@ class PEdump::CLI
403
495
  end
404
496
 
405
497
  def dump_rich_hdr data
406
- puts " LIB_ID VERSION TIMES_USED "
407
- data.decode.each do |row|
408
- printf " %5d %2x %7d %4x %7d %3x\n",
409
- row.id, row.id, row.version, row.version, row.times, row.times
498
+ if decoded = data.decode
499
+ puts " LIB_ID VERSION TIMES_USED "
500
+ decoded.each do |row|
501
+ printf " %5d %2x %7d %4x %7d %3x\n",
502
+ row.id, row.id, row.version, row.version, row.times, row.times
503
+ end
504
+ else
505
+ puts "# raw:"
506
+ puts hexdump(data)
507
+ puts
508
+ puts "# dexored:"
509
+ puts hexdump(data.dexor)
410
510
  end
411
511
  end
412
512
 
data/pedump.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "pedump"
8
- s.version = "0.2.1"
8
+ s.version = "0.3.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-10"
12
+ s.date = "2011-12-11"
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"]
@@ -43,17 +43,23 @@ Gem::Specification.new do |s|
43
43
  s.specification_version = 3
44
44
 
45
45
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
+ s.add_runtime_dependency(%q<rest-client>, ["~> 1.6.7"])
47
+ s.add_runtime_dependency(%q<progressbar>, ["~> 0.9.2"])
46
48
  s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
47
49
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
48
50
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
49
51
  s.add_development_dependency(%q<rcov>, [">= 0"])
50
52
  else
53
+ s.add_dependency(%q<rest-client>, ["~> 1.6.7"])
54
+ s.add_dependency(%q<progressbar>, ["~> 0.9.2"])
51
55
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
52
56
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
53
57
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
54
58
  s.add_dependency(%q<rcov>, [">= 0"])
55
59
  end
56
60
  else
61
+ s.add_dependency(%q<rest-client>, ["~> 1.6.7"])
62
+ s.add_dependency(%q<progressbar>, ["~> 0.9.2"])
57
63
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
58
64
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
59
65
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
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.2.1
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,33 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-10 00:00:00.000000000Z
12
+ date: 2011-12-11 00:00:00.000000000Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: &70185231241440 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.6.7
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70185231241440
25
+ - !ruby/object:Gem::Dependency
26
+ name: progressbar
27
+ requirement: &70185231240020 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.9.2
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70185231240020
14
36
  - !ruby/object:Gem::Dependency
15
37
  name: rspec
16
- requirement: &70303206510780 !ruby/object:Gem::Requirement
38
+ requirement: &70185231238140 !ruby/object:Gem::Requirement
17
39
  none: false
18
40
  requirements:
19
41
  - - ~>
@@ -21,10 +43,10 @@ dependencies:
21
43
  version: 2.3.0
22
44
  type: :development
23
45
  prerelease: false
24
- version_requirements: *70303206510780
46
+ version_requirements: *70185231238140
25
47
  - !ruby/object:Gem::Dependency
26
48
  name: bundler
27
- requirement: &70303206635540 !ruby/object:Gem::Requirement
49
+ requirement: &70185231228680 !ruby/object:Gem::Requirement
28
50
  none: false
29
51
  requirements:
30
52
  - - ~>
@@ -32,10 +54,10 @@ dependencies:
32
54
  version: 1.0.0
33
55
  type: :development
34
56
  prerelease: false
35
- version_requirements: *70303206635540
57
+ version_requirements: *70185231228680
36
58
  - !ruby/object:Gem::Dependency
37
59
  name: jeweler
38
- requirement: &70303206642320 !ruby/object:Gem::Requirement
60
+ requirement: &70185231227000 !ruby/object:Gem::Requirement
39
61
  none: false
40
62
  requirements:
41
63
  - - ~>
@@ -43,10 +65,10 @@ dependencies:
43
65
  version: 1.6.4
44
66
  type: :development
45
67
  prerelease: false
46
- version_requirements: *70303206642320
68
+ version_requirements: *70185231227000
47
69
  - !ruby/object:Gem::Dependency
48
70
  name: rcov
49
- requirement: &70303206648540 !ruby/object:Gem::Requirement
71
+ requirement: &70185231225760 !ruby/object:Gem::Requirement
50
72
  none: false
51
73
  requirements:
52
74
  - - ! '>='
@@ -54,7 +76,7 @@ dependencies:
54
76
  version: '0'
55
77
  type: :development
56
78
  prerelease: false
57
- version_requirements: *70303206648540
79
+ version_requirements: *70185231225760
58
80
  description: dump headers, sections, extract resources of win32 PE exe,dll,etc
59
81
  email: zed.0xff@gmail.com
60
82
  executables:
@@ -93,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
115
  version: '0'
94
116
  segments:
95
117
  - 0
96
- hash: -1918854361818125320
118
+ hash: 2723794485104812379
97
119
  required_rubygems_version: !ruby/object:Gem::Requirement
98
120
  none: false
99
121
  requirements: