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.
- data/.travis.yml +4 -0
- data/Gemfile +10 -6
- data/Gemfile.lock +27 -19
- data/README.md +37 -25
- data/Rakefile +45 -6
- data/VERSION +1 -1
- data/data/fs.txt +37 -1408
- data/data/jc-userdb.txt +14371 -0
- data/data/sig.bin +0 -0
- data/lib/pedump.rb +355 -618
- data/lib/pedump/cli.rb +214 -113
- data/lib/pedump/comparer.rb +147 -0
- data/lib/pedump/composite_io.rb +56 -0
- data/lib/pedump/core.rb +38 -0
- data/lib/pedump/core_ext/try.rb +57 -0
- data/lib/pedump/loader.rb +393 -0
- data/lib/pedump/loader/minidump.rb +187 -0
- data/lib/pedump/loader/section.rb +57 -0
- data/lib/pedump/logger.rb +67 -0
- data/lib/pedump/ne.rb +425 -0
- data/lib/pedump/ne/version_info.rb +171 -0
- data/lib/pedump/packer.rb +50 -2
- data/lib/pedump/pe.rb +121 -0
- data/lib/pedump/resources.rb +436 -0
- data/lib/pedump/security.rb +58 -0
- data/lib/pedump/sig_parser.rb +145 -24
- data/lib/pedump/tls.rb +17 -0
- data/lib/pedump/unpacker.rb +26 -0
- data/lib/pedump/unpacker/aspack.rb +858 -0
- data/lib/pedump/unpacker/upx.rb +13 -0
- data/lib/pedump/version.rb +1 -1
- data/lib/pedump/version_info.rb +15 -10
- data/misc/aspack/Makefile +3 -0
- data/misc/aspack/aspack_unlzx.c +92 -0
- data/misc/aspack/lzxdec.c +479 -0
- data/misc/aspack/lzxdec.h +56 -0
- data/misc/nedump.c +751 -0
- data/pedump.gemspec +75 -25
- data/samples/bad/68.exe +0 -0
- data/samples/bad/data_dir_15_entries.exe +0 -0
- data/spec/65535sects_spec.rb +8 -0
- data/spec/bad_imports_spec.rb +20 -0
- data/spec/bad_samples_spec.rb +13 -0
- data/spec/composite_io_spec.rb +122 -0
- data/spec/data/calc.exe_sections.yml +49 -0
- data/spec/data/data_dir_15_entries.exe_sections.yml +95 -0
- data/spec/dllord_spec.rb +21 -0
- data/spec/foldedhdr_spec.rb +28 -0
- data/spec/imports_badterm_spec.rb +52 -0
- data/spec/imports_vterm_spec.rb +52 -0
- data/spec/loader/names_spec.rb +24 -0
- data/spec/loader/va_spec.rb +44 -0
- data/spec/manyimportsW7_spec.rb +22 -0
- data/spec/ne_spec.rb +125 -0
- data/spec/packer_spec.rb +17 -0
- data/spec/pe_spec.rb +67 -0
- data/spec/pedump_spec.rb +16 -4
- data/spec/sections_spec.rb +11 -0
- data/spec/sig_all_packers_spec.rb +15 -5
- data/spec/sig_spec.rb +6 -1
- data/spec/spec_helper.rb +15 -3
- data/spec/support/samples.rb +24 -0
- data/spec/unpackers/aspack_spec.rb +69 -0
- data/spec/unpackers/find_spec.rb +21 -0
- data/spec/virtsectblXP_spec.rb +12 -0
- data/tmp/.keep +0 -0
- metadata +146 -35
- data/README.md.tpl +0 -90
- data/samples/calc.7z +0 -0
- data/samples/zlib.dll +0 -0
data/lib/pedump/cli.rb
CHANGED
@@ -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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
113
|
-
|
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.
|
149
|
-
@
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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?(
|
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.
|
198
|
-
|
199
|
-
|
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
|
-
|
203
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
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
|
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
|
-
|
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
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
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 |
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
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
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
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 %
|
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
|
-
|
634
|
-
|
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
|
-
|
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
|
-
|
797
|
+
data.hexdump
|
673
798
|
puts
|
674
799
|
puts "# dexored:"
|
675
|
-
|
800
|
+
data.dexor.hexdump
|
676
801
|
end
|
677
802
|
end
|
678
803
|
|
679
|
-
|
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
|