pedump 0.4.0 → 0.5.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 (70) hide show
  1. data/.travis.yml +4 -0
  2. data/Gemfile +10 -6
  3. data/Gemfile.lock +27 -19
  4. data/README.md +37 -25
  5. data/Rakefile +45 -6
  6. data/VERSION +1 -1
  7. data/data/fs.txt +37 -1408
  8. data/data/jc-userdb.txt +14371 -0
  9. data/data/sig.bin +0 -0
  10. data/lib/pedump.rb +355 -618
  11. data/lib/pedump/cli.rb +214 -113
  12. data/lib/pedump/comparer.rb +147 -0
  13. data/lib/pedump/composite_io.rb +56 -0
  14. data/lib/pedump/core.rb +38 -0
  15. data/lib/pedump/core_ext/try.rb +57 -0
  16. data/lib/pedump/loader.rb +393 -0
  17. data/lib/pedump/loader/minidump.rb +187 -0
  18. data/lib/pedump/loader/section.rb +57 -0
  19. data/lib/pedump/logger.rb +67 -0
  20. data/lib/pedump/ne.rb +425 -0
  21. data/lib/pedump/ne/version_info.rb +171 -0
  22. data/lib/pedump/packer.rb +50 -2
  23. data/lib/pedump/pe.rb +121 -0
  24. data/lib/pedump/resources.rb +436 -0
  25. data/lib/pedump/security.rb +58 -0
  26. data/lib/pedump/sig_parser.rb +145 -24
  27. data/lib/pedump/tls.rb +17 -0
  28. data/lib/pedump/unpacker.rb +26 -0
  29. data/lib/pedump/unpacker/aspack.rb +858 -0
  30. data/lib/pedump/unpacker/upx.rb +13 -0
  31. data/lib/pedump/version.rb +1 -1
  32. data/lib/pedump/version_info.rb +15 -10
  33. data/misc/aspack/Makefile +3 -0
  34. data/misc/aspack/aspack_unlzx.c +92 -0
  35. data/misc/aspack/lzxdec.c +479 -0
  36. data/misc/aspack/lzxdec.h +56 -0
  37. data/misc/nedump.c +751 -0
  38. data/pedump.gemspec +75 -25
  39. data/samples/bad/68.exe +0 -0
  40. data/samples/bad/data_dir_15_entries.exe +0 -0
  41. data/spec/65535sects_spec.rb +8 -0
  42. data/spec/bad_imports_spec.rb +20 -0
  43. data/spec/bad_samples_spec.rb +13 -0
  44. data/spec/composite_io_spec.rb +122 -0
  45. data/spec/data/calc.exe_sections.yml +49 -0
  46. data/spec/data/data_dir_15_entries.exe_sections.yml +95 -0
  47. data/spec/dllord_spec.rb +21 -0
  48. data/spec/foldedhdr_spec.rb +28 -0
  49. data/spec/imports_badterm_spec.rb +52 -0
  50. data/spec/imports_vterm_spec.rb +52 -0
  51. data/spec/loader/names_spec.rb +24 -0
  52. data/spec/loader/va_spec.rb +44 -0
  53. data/spec/manyimportsW7_spec.rb +22 -0
  54. data/spec/ne_spec.rb +125 -0
  55. data/spec/packer_spec.rb +17 -0
  56. data/spec/pe_spec.rb +67 -0
  57. data/spec/pedump_spec.rb +16 -4
  58. data/spec/sections_spec.rb +11 -0
  59. data/spec/sig_all_packers_spec.rb +15 -5
  60. data/spec/sig_spec.rb +6 -1
  61. data/spec/spec_helper.rb +15 -3
  62. data/spec/support/samples.rb +24 -0
  63. data/spec/unpackers/aspack_spec.rb +69 -0
  64. data/spec/unpackers/find_spec.rb +21 -0
  65. data/spec/virtsectblXP_spec.rb +12 -0
  66. data/tmp/.keep +0 -0
  67. metadata +146 -35
  68. data/README.md.tpl +0 -90
  69. data/samples/calc.7z +0 -0
  70. data/samples/zlib.dll +0 -0
@@ -1,11 +1,30 @@
1
1
  require 'pedump'
2
2
  require 'pedump/packer'
3
+ require 'pedump/version_info'
3
4
  require 'optparse'
4
5
 
5
- unless Object.instance_methods.include?(:try)
6
- class Object
7
- def try(*x)
8
- send(*x) if respond_to?(x.first)
6
+ begin
7
+ require 'shellwords' # from ruby 1.9.3
8
+ rescue LoadError
9
+ unless ''.respond_to?(:shellescape)
10
+ class String
11
+ # File shellwords.rb, line 72
12
+ def shellescape
13
+ # An empty argument will be skipped, so return empty quotes.
14
+ return "''" if self.empty?
15
+
16
+ str = self.dup
17
+
18
+ # Process as a single byte sequence because not all shell
19
+ # implementations are multibyte aware.
20
+ str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/, "\\\\\\1")
21
+
22
+ # A LF cannot be escaped with a backslash because a backslash + LF
23
+ # combo is regarded as line continuation and simply ignored.
24
+ str.gsub!(/\n/, "'\n'")
25
+
26
+ str
27
+ end
9
28
  end
10
29
  end
11
30
  end
@@ -14,11 +33,11 @@ class PEdump::CLI
14
33
  attr_accessor :data, :argv
15
34
 
16
35
  KNOWN_ACTIONS = (
17
- %w'mz dos_stub rich pe data_directory sections' +
18
- %w'strings resources resource_directory imports exports version_info packer web packer_only'
36
+ %w'mz dos_stub rich pe ne data_directory sections tls security' +
37
+ %w'strings resources resource_directory imports exports version_info packer web console packer_only'
19
38
  ).map(&:to_sym)
20
39
 
21
- DEFAULT_ALL_ACTIONS = KNOWN_ACTIONS - %w'resource_directory web packer_only'.map(&:to_sym)
40
+ DEFAULT_ALL_ACTIONS = KNOWN_ACTIONS - %w'resource_directory web packer_only console'.map(&:to_sym)
22
41
 
23
42
  URL_BASE = "http://pedump.me"
24
43
 
@@ -46,8 +65,8 @@ class PEdump::CLI
46
65
  @options[:force] ||= 0
47
66
  @options[:force] += 1
48
67
  end
49
- opts.on "-f", "--format FORMAT", [:binary, :c, :dump, :hex, :inspect, :table],
50
- "Output format: bin,c,dump,hex,inspect,table","(default: table)" do |v|
68
+ opts.on "-f", "--format FORMAT", [:binary, :c, :dump, :hex, :inspect, :table, :yaml],
69
+ "Output format: bin,c,dump,hex,inspect,table,yaml","(default: table)" do |v|
51
70
  @options[:format] = v
52
71
  end
53
72
  KNOWN_ACTIONS.each do |t|
@@ -70,15 +89,25 @@ class PEdump::CLI
70
89
  @actions << :packer_only
71
90
  end
72
91
 
92
+ opts.on '-r', "--recursive", "recurse dirs in packer detect" do
93
+ @options[:recursive] = true
94
+ end
95
+
73
96
  opts.on "--all", "Dump all but resource-directory (default)" do
74
97
  @actions = DEFAULT_ALL_ACTIONS
75
98
  end
76
99
  opts.on "--va2file VA", "Convert RVA to file offset" do |va|
77
100
  @actions << [:va2file,va]
78
101
  end
102
+
103
+ opts.separator ''
104
+
79
105
  opts.on "-W", "--web", "Uploads files to a #{URL_BASE}","for a nice HTML tables with image previews,","candies & stuff" do
80
106
  @actions << :web
81
107
  end
108
+ opts.on "-C", "--console", "opens IRB console with specified file loaded" do
109
+ @actions << :console
110
+ end
82
111
  end
83
112
 
84
113
  if (@argv = optparser.parse(@argv)).empty?
@@ -109,8 +138,9 @@ class PEdump::CLI
109
138
  next if !@options[:force] && !@pedump.mz(f)
110
139
 
111
140
  @actions.each do |action|
112
- if action == :web
113
- upload f
141
+ case action
142
+ when :web; upload f
143
+ when :console; console f
114
144
  else
115
145
  dump_action action,f
116
146
  end
@@ -145,12 +175,20 @@ class PEdump::CLI
145
175
  def dump_packer_only fnames
146
176
  max_fname_len = fnames.map(&:size).max
147
177
  fnames.each do |fname|
148
- File.open(fname,'rb') do |f|
149
- @pedump = create_pedump fname
150
- packers = @pedump.packers(f)
151
- pname = Array(packers).first.try(:packer).try(:name)
152
- pname ||= "unknown" if @options[:verbose] > 0
153
- printf("%-*s %s\n", max_fname_len+1, "#{fname}:", pname) if pname
178
+ if File.directory?(fname)
179
+ if @options[:recursive]
180
+ dump_packer_only(Dir[File.join(fname.shellescape,"*")])
181
+ else
182
+ STDERR.puts "[?] #{fname} is a directory, and recursive flag is not set"
183
+ end
184
+ else
185
+ File.open(fname,'rb') do |f|
186
+ @pedump = create_pedump fname
187
+ packers = @pedump.packers(f)
188
+ pname = Array(packers).first.try(:packer).try(:name)
189
+ pname ||= "unknown" if @options[:verbose] > 0
190
+ printf("%-*s %s\n", max_fname_len+1, "#{fname}:", pname) if pname
191
+ end
154
192
  end
155
193
  end
156
194
  end
@@ -172,7 +210,7 @@ class PEdump::CLI
172
210
  @file.send *args
173
211
  end
174
212
  def respond_to? *args
175
- @file.respond_to?(*args) || super(*args)
213
+ @file.respond_to?(args.first) || super(*args)
176
214
  end
177
215
  end
178
216
 
@@ -184,6 +222,7 @@ class PEdump::CLI
184
222
 
185
223
  require 'digest/md5'
186
224
  require 'open-uri'
225
+ require 'net/http'
187
226
  require 'net/http/post/multipart'
188
227
  require 'progressbar'
189
228
 
@@ -194,16 +233,19 @@ class PEdump::CLI
194
233
  @pedump.logger.info "[.] md5: #{md5}"
195
234
  file_url = "#{URL_BASE}/#{md5}/"
196
235
 
197
- @pedump.logger.info "[.] checking if file already uploaded.."
198
- begin
199
- if (r=open(file_url).read) == "OK"
236
+ @pedump.logger.warn "[.] checking if file already uploaded.."
237
+ Net::HTTP.start('pedump.me') do |http|
238
+ http.open_timeout = 10
239
+ http.read_timeout = 10
240
+ # doing HTTP HEAD is a lot faster than open-uri
241
+ h = http.head("/#{md5}/")
242
+ if h.code.to_i == 200 && h.content_type.to_s.strip.downcase == "text/html"
200
243
  @pedump.logger.warn "[.] file already uploaded: #{file_url}"
201
244
  return
202
- else
203
- raise "invalid server response: #{r}"
245
+ elsif h.code.to_i != 404 # 404 means that there's no such file and we're OK to upload
246
+ @pedump.logger.fatal "[!] invalid server response: \"#{h.code} #{h.msg}\" (#{h.content_type})"
247
+ exit(1)
204
248
  end
205
- rescue OpenURI::HTTPError
206
- raise unless $!.to_s == "404 Not Found"
207
249
  end
208
250
 
209
251
  f.rewind
@@ -228,6 +270,29 @@ class PEdump::CLI
228
270
  STDOUT.sync = stdout_sync
229
271
  end
230
272
 
273
+ def console f
274
+ require 'pedump/loader'
275
+ require 'pp'
276
+
277
+ ARGV.clear # clear ARGV so IRB is not confused
278
+ require 'irb'
279
+ f.rewind
280
+ ldr = @ldr = PEdump::Loader.new(f)
281
+
282
+ # override IRB.setup, called from IRB.start
283
+ m0 = IRB.method(:setup)
284
+ IRB.define_singleton_method :setup do |*args|
285
+ m0.call *args
286
+ conf[:IRB_RC] = Proc.new do |context|
287
+ context.main.instance_variable_set '@ldr', ldr
288
+ context.main.define_singleton_method(:ldr){ @ldr }
289
+ end
290
+ end
291
+
292
+ puts "[.] ldr = PEdump::Loader.new(open(#{f.path.inspect}))".gray
293
+ IRB.start
294
+ end
295
+
231
296
  def action_title action
232
297
  if @need_fname_header
233
298
  @need_fname_header = false
@@ -259,16 +324,14 @@ class PEdump::CLI
259
324
  data = @pedump.send(action, f)
260
325
  return if !data || (data.respond_to?(:empty?) && data.empty?)
261
326
 
262
- puts action_title(action)
327
+ puts action_title(action) unless @options[:format] == :binary
263
328
 
264
- return dump(data) if [:inspect, :table].include?(@options[:format])
329
+ return dump(data) if [:inspect, :table, :yaml].include?(@options[:format])
265
330
 
266
331
  dump_opts = {:name => action}
267
332
  case action
268
333
  when :pe
269
- @pedump.pe.ifh.TimeDateStamp = @pedump.pe.ifh.TimeDateStamp.to_i
270
- data = @pedump.pe.signature + (@pedump.pe.ifh.try(:pack)||'') + (@pedump.pe.ioh.try(:pack)||'')
271
- @pedump.pe.ifh.TimeDateStamp = Time.at(@pedump.pe.ifh.TimeDateStamp)
334
+ data = @pedump.pe.pack
272
335
  when :resources
273
336
  return dump_resources(data)
274
337
  when :strings
@@ -292,7 +355,7 @@ class PEdump::CLI
292
355
  def dump data, opts = {}
293
356
  case opts[:format] || @options[:format] || :dump
294
357
  when :dump, :hexdump
295
- puts hexdump(data)
358
+ data.hexdump
296
359
  when :hex
297
360
  puts data.each_byte.map{ |x| "%02x" % x }.join(' ')
298
361
  when :binary
@@ -310,6 +373,9 @@ class PEdump::CLI
310
373
  pp data
311
374
  when :table
312
375
  dump_table data
376
+ when :yaml
377
+ require 'yaml'
378
+ puts data.to_yaml
313
379
  end
314
380
  end
315
381
 
@@ -352,7 +418,7 @@ class PEdump::CLI
352
418
  printf "%30s: %24s\n", k.to_s.sub('Major',''), "#{v}.#{data[k.to_s.sub('Major','Minor')]}"
353
419
  when /\AMinor.*Version\Z/
354
420
  when /TimeDateStamp/
355
- printf "%30s: %24s\n", k, Time.at(v).strftime('"%Y-%m-%d %H:%M:%S"')
421
+ printf "%30s: %24s\n", k, Time.at(v).utc.strftime('"%Y-%m-%d %H:%M:%S"')
356
422
  else
357
423
  comment = ''
358
424
  if COMMENTS[k]
@@ -394,17 +460,23 @@ class PEdump::CLI
394
460
  dump_resources data
395
461
  when PEdump::STRING
396
462
  dump_strings data
397
- when PEdump::IMAGE_IMPORT_DESCRIPTOR
463
+ when PEdump::IMAGE_IMPORT_DESCRIPTOR, PEdump::ImportedFunction
398
464
  dump_imports data
399
465
  when PEdump::Packer::Match
400
466
  dump_packers data
401
- when PEdump::VS_VERSIONINFO
467
+ when PEdump::VS_VERSIONINFO, PEdump::NE::VS_VERSIONINFO
402
468
  dump_version_info data
469
+ when PEdump::IMAGE_TLS_DIRECTORY32, PEdump::IMAGE_TLS_DIRECTORY64
470
+ dump_tls data
471
+ when PEdump::WIN_CERTIFICATE
472
+ dump_security data
473
+ when PEdump::NE::Segment
474
+ dump_ne_segments data
403
475
  else
404
476
  puts "[?] don't know how to dump: #{data.inspect[0,50]}" unless data.empty?
405
477
  end
406
478
  elsif data.is_a?(PEdump::DOSStub)
407
- puts hexdump(data)
479
+ data.hexdump
408
480
  elsif data.is_a?(PEdump::RichHdr)
409
481
  dump_rich_hdr data
410
482
  else
@@ -412,6 +484,34 @@ class PEdump::CLI
412
484
  end
413
485
  end
414
486
 
487
+ def dump_security data
488
+ return unless data
489
+ data.each do |win_cert|
490
+ if win_cert.data.respond_to?(:certificates)
491
+ win_cert.data.certificates.each do |cert|
492
+ puts cert.to_text
493
+ puts
494
+ end
495
+ else
496
+ @pedump.logger.error "[?] no certificates in #{win_cert.class}"
497
+ end
498
+ end
499
+ end
500
+
501
+ def dump_tls data
502
+ fmt = "%10x %10x %8x %8x %8x %8x\n"
503
+ printf fmt.tr('x','s'), *%w'RAW_START RAW_END INDEX CALLBKS ZEROFILL FLAGS'
504
+ data.each do |tls|
505
+ printf fmt,
506
+ tls.StartAddressOfRawData.to_i,
507
+ tls.EndAddressOfRawData.to_i,
508
+ tls.AddressOfIndex.to_i,
509
+ tls.AddressOfCallBacks.to_i,
510
+ tls.SizeOfZeroFill.to_i,
511
+ tls.Characteristics.to_i
512
+ end
513
+ end
514
+
415
515
  def dump_version_info data
416
516
  if @options[:format] != :table
417
517
  File.open(@file_name,'rb') do |f|
@@ -429,38 +529,38 @@ class PEdump::CLI
429
529
  puts "# VS_FIXEDFILEINFO:"
430
530
 
431
531
  if @options[:verbose] > 0 || vi.Value.dwSignature != 0xfeef04bd
432
- printf(fmt, "Signature", "0x#{vi.Value.dwSignature.to_s(16)}")
532
+ printf(fmt, "Signature", "0x#{vi.Value.dwSignature.to_i.to_s(16)}")
433
533
  end
434
534
 
435
535
  printf fmt, 'FileVersion', [
436
- vi.Value.dwFileVersionMS >> 16,
437
- vi.Value.dwFileVersionMS & 0xffff,
438
- vi.Value.dwFileVersionLS >> 16,
439
- vi.Value.dwFileVersionLS & 0xffff
536
+ vi.Value.dwFileVersionMS.to_i >> 16,
537
+ vi.Value.dwFileVersionMS.to_i & 0xffff,
538
+ vi.Value.dwFileVersionLS.to_i >> 16,
539
+ vi.Value.dwFileVersionLS.to_i & 0xffff
440
540
  ].join('.')
441
541
 
442
542
  printf fmt, 'ProductVersion', [
443
- vi.Value.dwProductVersionMS >> 16,
444
- vi.Value.dwProductVersionMS & 0xffff,
445
- vi.Value.dwProductVersionLS >> 16,
446
- vi.Value.dwProductVersionLS & 0xffff
543
+ vi.Value.dwProductVersionMS.to_i >> 16,
544
+ vi.Value.dwProductVersionMS.to_i & 0xffff,
545
+ vi.Value.dwProductVersionLS.to_i >> 16,
546
+ vi.Value.dwProductVersionLS.to_i & 0xffff
447
547
  ].join('.')
448
548
 
449
549
  vi.Value.each_pair do |k,v|
450
550
  next if k[/[ML]S$/] || k == :valid || k == :dwSignature
451
- printf fmt, k.to_s.sub(/^dw/,''), v > 9 ? "0x#{v.to_s(16)}" : v
551
+ printf fmt, k.to_s.sub(/^dw/,''), v.to_i > 9 ? "0x#{v.to_s(16)}" : v
452
552
  end
453
553
 
454
554
  vi.Children.each do |file_info|
455
555
  case file_info
456
- when PEdump::StringFileInfo
556
+ when PEdump::StringFileInfo, PEdump::NE::StringFileInfo
457
557
  file_info.Children.each do |string_table|
458
558
  puts "\n# StringTable #{string_table.szKey}:"
459
559
  string_table.Children.each do |string|
460
560
  printf fmt, string.szKey, string.Value.inspect
461
561
  end
462
562
  end
463
- when PEdump::VarFileInfo
563
+ when PEdump::VarFileInfo, PEdump::NE::VarFileInfo
464
564
  puts
465
565
  printf fmt, "VarFileInfo", '[ 0x' + file_info.Children.Value.map{|v| v.to_s(16)}.join(", 0x") + ' ]'
466
566
  else
@@ -482,57 +582,68 @@ class PEdump::CLI
482
582
  end
483
583
 
484
584
  def dump_exports data
485
- printf "# module %s\n# flags=0x%x ts=%s version=%d.%d ord_base=%d\n",
486
- data.name.inspect,
487
- data.Characteristics.to_i,
488
- Time.at(data.TimeDateStamp.to_i).strftime('"%Y-%m-%d %H:%M:%S"'),
489
- data.MajorVersion, data.MinorVersion,
490
- data.Base
585
+ printf "# module %s\n", data.name.inspect
586
+ printf "# description %s\n", data.description.inspect if data.description
587
+
588
+ if data.Characteristics || data.TimeDateStamp || data.MajorVersion || data.MinorVersion || data.Base
589
+ printf "# flags=0x%x ts=%s version=%d.%d ord_base=%d\n",
590
+ data.Characteristics.to_i,
591
+ Time.at(data.TimeDateStamp.to_i).utc.strftime('"%Y-%m-%d %H:%M:%S"'),
592
+ data.MajorVersion.to_i, data.MinorVersion.to_i,
593
+ data.Base.to_i
594
+ end
491
595
 
492
596
  if @options[:verbose] > 0
493
597
  [%w'Names', %w'EntryPoints Functions', %w'Ordinals NameOrdinals'].each do |x|
494
598
  va = data["AddressOf"+x.last]
495
599
  ofs = @pedump.va2file(va) || '?'
496
- printf "# %-12s rva=0x%08x file_offset=%8s\n", x.first, va, ofs
600
+ printf("# %-12s rva=0x%08x file_offset=%8s\n", x.first, va, ofs) if va
497
601
  end
498
602
  end
499
603
 
500
- printf "# nFuncs=%d nNames=%d\n",
501
- data.NumberOfFunctions,
502
- data.NumberOfNames
503
-
504
- return unless data.name_ordinals.any? || data.entry_points.any? || data.names.any?
505
-
506
- puts
507
-
508
- ord2name = {}
509
- data.NumberOfNames.times do |i|
510
- ord2name[data.name_ordinals[i]] ||= []
511
- ord2name[data.name_ordinals[i]] << data.names[i]
604
+ if data.NumberOfFunctions || data.NumberOfNames
605
+ printf "# nFuncs=%d nNames=%d\n", data.NumberOfFunctions.to_i, data.NumberOfNames.to_i
512
606
  end
513
607
 
514
- printf "%5s %8s %s\n", "ORD", "ENTRY_VA", "NAME"
515
- data.NumberOfFunctions.times do |i|
516
- ep = data.entry_points[i]
517
- names = ord2name[i+data.Base].try(:join,', ')
518
- next if ep.to_i == 0 && names.nil?
519
- printf "%5d %8x %s\n", i + data.Base, ep, names
608
+ if data.functions && data.functions.any?
609
+ puts
610
+ if @pedump.ne?
611
+ printf "%5s %9s %s\n", "ORD", "SEG:OFFS", "NAME"
612
+ data.functions.each do |f|
613
+ printf "%5x %4x:%04x %s\n", f.ord, f.va>>16, f.va&0xffff, f.name
614
+ end
615
+ else
616
+ printf "%5s %8s %s\n", "ORD", "ENTRY_VA", "NAME"
617
+ data.functions.each do |f|
618
+ printf "%5x %8x %s\n", f.ord, f.va, f.name
619
+ end
620
+ end
520
621
  end
521
622
  end
522
623
 
523
624
  def dump_imports data
524
625
  fmt = "%-15s %5s %5s %s\n"
525
626
  printf fmt, "MODULE_NAME", "HINT", "ORD", "FUNCTION_NAME"
526
- data.each do |iid|
527
- # image import descriptor
528
- (Array(iid.original_first_thunk) + Array(iid.first_thunk)).uniq.each do |f|
529
- next unless f
530
- # imported function
627
+ data.each do |x|
628
+ case x
629
+ when PEdump::IMAGE_IMPORT_DESCRIPTOR
630
+ (Array(x.original_first_thunk) + Array(x.first_thunk)).uniq.each do |f|
631
+ next unless f
632
+ # imported function
633
+ printf fmt,
634
+ x.module_name,
635
+ f.hint ? f.hint.to_s(16) : '',
636
+ f.ordinal ? f.ordinal.to_s(16) : '',
637
+ f.name
638
+ end
639
+ when PEdump::ImportedFunction
531
640
  printf fmt,
532
- iid.module_name,
533
- f.hint ? f.hint.to_s(16) : '',
534
- f.ordinal ? f.ordinal.to_s(16) : '',
535
- f.name
641
+ x.module_name,
642
+ x.hint ? x.hint.to_s(16) : '',
643
+ x.ordinal ? x.ordinal.to_s(16) : '',
644
+ x.name
645
+ else
646
+ raise "invalid #{x.inspect}"
536
647
  end
537
648
  end
538
649
  end
@@ -542,7 +653,7 @@ class PEdump::CLI
542
653
  prev_lang = nil
543
654
  data.sort_by{|s| [s.lang, s.id] }.each do |s|
544
655
  #puts if prev_lang && prev_lang != s.lang
545
- printf "%5d %5x %4x %s\n", s.id, s.id, s.lang, s.value.inspect
656
+ printf "%5d %5x %4s %s\n", s.id, s.id, s.lang && s.lang.to_s(16), s.value.inspect
546
657
  prev_lang = s.lang
547
658
  end
548
659
  end
@@ -629,11 +740,15 @@ class PEdump::CLI
629
740
  printf fmt.join.tr('dx','s'), *keys.map(&:to_s).map(&:upcase)
630
741
  data.each do |res|
631
742
  fmt.each_with_index do |f,i|
632
- v = res.send(keys[i])
633
- if f['x']
634
- printf f.tr('x','s'), v.to_i < 10 ? v.to_s : "0x#{v.to_s(16)}"
743
+ if v = res.send(keys[i])
744
+ if f['x']
745
+ printf f.tr('x','s'), v.to_i < 10 ? v.to_s : "0x#{v.to_s(16)}"
746
+ else
747
+ printf f, v
748
+ end
635
749
  else
636
- printf f, v
750
+ # NULL value
751
+ printf f.tr('xd','s'), ''
637
752
  end
638
753
  end
639
754
  end
@@ -654,6 +769,16 @@ class PEdump::CLI
654
769
  end
655
770
  end
656
771
 
772
+ def dump_ne_segments data
773
+ fmt = "%2x %6x %6x %9x %9x %6x %s\n"
774
+ printf fmt.tr('x','s'), *%w'# OFFSET SIZE MIN_ALLOC FILE_OFFS FLAGS', ''
775
+ data.each_with_index do |seg,idx|
776
+ printf fmt, idx+1, seg.offset, seg.size, seg.min_alloc_size, seg.file_offset, seg.flags,
777
+ seg.flags_desc
778
+ end
779
+ end
780
+
781
+
657
782
  def dump_data_dir data
658
783
  data.each do |row|
659
784
  printf " %-12s rva:0x%8x size:0x %8x\n", row.type, row.va.to_i, row.size.to_i
@@ -669,35 +794,11 @@ class PEdump::CLI
669
794
  end
670
795
  else
671
796
  puts "# raw:"
672
- puts hexdump(data)
797
+ data.hexdump
673
798
  puts
674
799
  puts "# dexored:"
675
- puts hexdump(data.dexor)
800
+ data.dexor.hexdump
676
801
  end
677
802
  end
678
803
 
679
- def hexdump data, h = {}
680
- offset = h[:offset] || 0
681
- add = h[:add] || 0
682
- size = h[:size] || (data.size-offset)
683
- tail = h[:tail] || "\n"
684
- width = h[:width] || 0x10 # row width, in bytes
685
-
686
- size = data.size-offset if size+offset > data.size
687
-
688
- r = ''; s = ''
689
- r << "%08x: " % (offset + add)
690
- ascii = ''
691
- size.times do |i|
692
- if i%width==0 && i>0
693
- r << "%s |%s|\n%08x: " % [s, ascii, offset + add + i]
694
- ascii = ''; s = ''
695
- end
696
- s << " " if i%width%8==0
697
- c = data[offset+i].ord
698
- s << "%02x " % c
699
- ascii << ((32..126).include?(c) ? c.chr : '.')
700
- end
701
- r << "%-*s |%-*s|%s" % [width*3+width/8+(width%8==0?0:1), s, width, ascii, tail]
702
- end
703
- end
804
+ end # class PEdump::CLI