pedump 0.7.3 → 0.7.5
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.
- checksums.yaml +4 -4
- data/Gemfile +7 -12
- data/Gemfile.lock +21 -152
- data/LICENSE.txt +1 -1
- data/README.md +27 -0
- data/Rakefile +80 -112
- data/data/jc-userdb.txt +2 -6
- data/data/sig.bin +0 -0
- data/lib/pedump/cli.rb +40 -16
- data/lib/pedump/clr/readytorun.rb +1 -1
- data/lib/pedump/clr.rb +4 -4
- data/lib/pedump/colors.rb +29 -0
- data/lib/pedump/comparer.rb +12 -9
- data/lib/pedump/loader/minidump.rb +7 -7
- data/lib/pedump/logger.rb +4 -2
- data/lib/pedump/multipart.rb +56 -0
- data/lib/pedump/packer.rb +1 -1
- data/lib/pedump/resources.rb +1 -1
- data/lib/pedump/sig_parser.rb +11 -55
- data/lib/pedump/te.rb +19 -19
- data/lib/pedump/tls.rb +12 -14
- data/lib/pedump/unpacker/aspack.rb +4 -4
- data/lib/pedump/version.rb +3 -5
- data/lib/pedump.rb +29 -17
- data/pedump.gemspec +29 -88
- metadata +8 -90
- data/VERSION +0 -1
data/lib/pedump/cli.rb
CHANGED
|
@@ -145,6 +145,12 @@ class PEdump::CLI
|
|
|
145
145
|
opts.on "--file2va OFFSET", "Convert file offset to VA" do |offset|
|
|
146
146
|
@actions << [:file2va, offset]
|
|
147
147
|
end
|
|
148
|
+
opts.on "--rva2file RVA", "Convert RVA to file offset" do |va|
|
|
149
|
+
@actions << [:rva2file, va]
|
|
150
|
+
end
|
|
151
|
+
opts.on "--file2rva OFFSET", "Convert file offset to RVA" do |offset|
|
|
152
|
+
@actions << [:file2rva, offset]
|
|
153
|
+
end
|
|
148
154
|
|
|
149
155
|
opts.separator ''
|
|
150
156
|
opts.on "--set-os-version VER", "Patch OS version in PE header" do |ver|
|
|
@@ -287,7 +293,7 @@ class PEdump::CLI
|
|
|
287
293
|
require 'digest/md5'
|
|
288
294
|
require 'open-uri'
|
|
289
295
|
require 'net/http'
|
|
290
|
-
require '
|
|
296
|
+
require 'pedump/multipart'
|
|
291
297
|
|
|
292
298
|
stdout_sync = $stdout.sync
|
|
293
299
|
$stdout.sync = true
|
|
@@ -314,12 +320,26 @@ class PEdump::CLI
|
|
|
314
320
|
|
|
315
321
|
f.rewind
|
|
316
322
|
|
|
317
|
-
# upload with progress
|
|
323
|
+
# upload with progress using manual multipart POST
|
|
318
324
|
post_url = URI.parse(URL_BASE+'/upload')
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
325
|
+
boundary = MultipartBody.generate_boundary
|
|
326
|
+
filename = File.basename(f.path)
|
|
327
|
+
|
|
328
|
+
# Build multipart body parts
|
|
329
|
+
header_part = "--#{boundary}\r\n" \
|
|
330
|
+
"Content-Disposition: form-data; name=\"file\"; filename=\"#{filename}\"\r\n" \
|
|
331
|
+
"Content-Type: application/octet-stream\r\n\r\n"
|
|
332
|
+
footer_part = "\r\n--#{boundary}--\r\n"
|
|
333
|
+
|
|
334
|
+
content_length = header_part.bytesize + f.size + footer_part.bytesize
|
|
335
|
+
|
|
336
|
+
req = Net::HTTP::Post.new(post_url.path)
|
|
337
|
+
req['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
|
|
338
|
+
req['Content-Length'] = content_length
|
|
339
|
+
|
|
340
|
+
ppx = ProgressProxy.new(f)
|
|
341
|
+
req.body_stream = MultipartBody.new(header_part, ppx, footer_part, content_length)
|
|
342
|
+
|
|
323
343
|
res = Net::HTTP.start(post_url.host, post_url.port, use_ssl: (post_url.scheme == 'https')) do |http|
|
|
324
344
|
http.request(req)
|
|
325
345
|
end
|
|
@@ -355,7 +375,7 @@ class PEdump::CLI
|
|
|
355
375
|
end
|
|
356
376
|
end
|
|
357
377
|
|
|
358
|
-
puts "[.] ldr = PEdump::Loader.new(open(#{f.path.inspect}))"
|
|
378
|
+
puts "[.] ldr = PEdump::Loader.new(open(#{f.path.inspect}))"
|
|
359
379
|
IRB.start
|
|
360
380
|
end
|
|
361
381
|
|
|
@@ -385,13 +405,17 @@ class PEdump::CLI
|
|
|
385
405
|
case action[0]
|
|
386
406
|
when :disasm
|
|
387
407
|
return
|
|
388
|
-
when :va2file, :file2va
|
|
408
|
+
when :rva2file, :file2rva, :va2file, :file2va
|
|
389
409
|
cmd = action[0]
|
|
390
410
|
@pedump.sections(f)
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
if
|
|
394
|
-
|
|
411
|
+
arg = action[1] =~ /(^0x)|(h$)/i ? action[1].to_i(16) : action[1].to_i
|
|
412
|
+
result = @pedump.send(cmd, arg)
|
|
413
|
+
if result
|
|
414
|
+
if @options[:format] == :hex
|
|
415
|
+
puts result.to_s(16)
|
|
416
|
+
else
|
|
417
|
+
printf("%s(0x%x) = 0x%x (%d)\n", cmd, arg, result, result)
|
|
418
|
+
end
|
|
395
419
|
else
|
|
396
420
|
@success = false
|
|
397
421
|
end
|
|
@@ -652,7 +676,7 @@ class PEdump::CLI
|
|
|
652
676
|
|
|
653
677
|
def dump_clr_streams data
|
|
654
678
|
clr_header = @pedump.clr_header
|
|
655
|
-
clr_data_file_ofs = clr_header.MetaData.va.to_i > 0 && @pedump.
|
|
679
|
+
clr_data_file_ofs = clr_header.MetaData.va.to_i > 0 && @pedump.rva2file(clr_header.MetaData.va)
|
|
656
680
|
|
|
657
681
|
fmt = "%8x %8x %-32s\n"
|
|
658
682
|
printf fmt.tr('x','s'), *%w'offset size name'
|
|
@@ -675,7 +699,7 @@ class PEdump::CLI
|
|
|
675
699
|
blob_stream = @pedump.clr_streams.find{ |s| s.name == "#Blob" }
|
|
676
700
|
|
|
677
701
|
clr_header = @pedump.clr_header
|
|
678
|
-
clr_data_file_ofs = clr_header.MetaData.va.to_i > 0 && @pedump.
|
|
702
|
+
clr_data_file_ofs = clr_header.MetaData.va.to_i > 0 && @pedump.rva2file(clr_header.MetaData.va)
|
|
679
703
|
blob_file_ofs = blob_stream.offset + clr_data_file_ofs if blob_stream
|
|
680
704
|
blob_size = blob_stream&.size
|
|
681
705
|
|
|
@@ -892,7 +916,7 @@ class PEdump::CLI
|
|
|
892
916
|
if @options[:verbose] > 0
|
|
893
917
|
[%w'Names', %w'EntryPoints Functions', %w'Ordinals NameOrdinals'].each do |x|
|
|
894
918
|
va = data["AddressOf"+x.last]
|
|
895
|
-
ofs = @pedump.
|
|
919
|
+
ofs = @pedump.rva2file(va) || '?'
|
|
896
920
|
printf("# %-12s rva=0x%08x file_offset=%8s\n", x.first, va, ofs) if va
|
|
897
921
|
end
|
|
898
922
|
end
|
|
@@ -1132,7 +1156,7 @@ class PEdump::CLI
|
|
|
1132
1156
|
exit(1)
|
|
1133
1157
|
end
|
|
1134
1158
|
if entry.size != 0
|
|
1135
|
-
_copy_stream @pedump.io, $stdout, entry.size, @pedump.
|
|
1159
|
+
_copy_stream @pedump.io, $stdout, entry.size, @pedump.rva2file(entry.va)
|
|
1136
1160
|
end
|
|
1137
1161
|
end
|
|
1138
1162
|
|
data/lib/pedump/clr.rb
CHANGED
|
@@ -584,7 +584,7 @@ class PEdump
|
|
|
584
584
|
dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::CLR_Header]
|
|
585
585
|
return nil if !dir || (dir.va == 0 && dir.size == 0)
|
|
586
586
|
|
|
587
|
-
file_offset =
|
|
587
|
+
file_offset = rva2file(dir.va)
|
|
588
588
|
return nil unless file_offset
|
|
589
589
|
|
|
590
590
|
if f.checked_seek(file_offset)
|
|
@@ -601,7 +601,7 @@ class PEdump
|
|
|
601
601
|
dir = hdr&.MetaData
|
|
602
602
|
return nil if !dir || (dir.va.to_i == 0 || dir.size.to_i == 0)
|
|
603
603
|
|
|
604
|
-
file_offset =
|
|
604
|
+
file_offset = rva2file(dir.va)
|
|
605
605
|
return nil unless file_offset
|
|
606
606
|
|
|
607
607
|
if f.checked_seek(file_offset)
|
|
@@ -635,7 +635,7 @@ class PEdump
|
|
|
635
635
|
streams.each do |stream|
|
|
636
636
|
next unless stream.name == '#Strings'
|
|
637
637
|
|
|
638
|
-
unless f.checked_seek(
|
|
638
|
+
unless f.checked_seek(rva2file(dir.va) + stream.offset)
|
|
639
639
|
logger.warn "[?] Error seeking to CLR strings stream"
|
|
640
640
|
return nil
|
|
641
641
|
end
|
|
@@ -678,7 +678,7 @@ class PEdump
|
|
|
678
678
|
streams.each do |stream|
|
|
679
679
|
next if stream.name != '#~' && stream.name != '#-' # Metadata Table Stream
|
|
680
680
|
|
|
681
|
-
unless f.checked_seek(
|
|
681
|
+
unless f.checked_seek(rva2file(dir.va) + stream.offset)
|
|
682
682
|
logger.warn "[?] Error seeking to CLR table stream"
|
|
683
683
|
return nil
|
|
684
684
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module PEdump::Colors
|
|
2
|
+
def gray(str)
|
|
3
|
+
"\e[1;30m#{str}\e[0m"
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def red(str)
|
|
7
|
+
"\e[1;31m#{str}\e[0m"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def green(str)
|
|
11
|
+
"\e[1;32m#{str}\e[0m"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def yellow(str)
|
|
15
|
+
"\e[1;33m#{str}\e[0m"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def redish(str)
|
|
19
|
+
"\e[0;31m#{str}\e[0m"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def greenish(str)
|
|
23
|
+
"\e[0;32m#{str}\e[0m"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def yellowish(str)
|
|
27
|
+
"\e[0;33m#{str}\e[0m"
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/pedump/comparer.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'pedump'
|
|
2
|
+
require 'pedump/colors'
|
|
2
3
|
require 'pedump/loader'
|
|
3
4
|
|
|
4
5
|
########################################################################
|
|
@@ -9,6 +10,8 @@ class PEdump::Comparer
|
|
|
9
10
|
attr_accessor :verbose
|
|
10
11
|
attr_accessor :ignored_data_dirs, :ignored_sections
|
|
11
12
|
|
|
13
|
+
include PEdump::Colors
|
|
14
|
+
|
|
12
15
|
METHODS = [:sections, :data_dirs, :imports, :resources, :pe_hdr]
|
|
13
16
|
|
|
14
17
|
def initialize ldr1, ldr2
|
|
@@ -53,12 +56,12 @@ class PEdump::Comparer
|
|
|
53
56
|
|
|
54
57
|
if !s2
|
|
55
58
|
r = false
|
|
56
|
-
printf "[!] extra section %-12s in %s\n"
|
|
59
|
+
printf red("[!] extra section %-12s in %s\n"), s1.name.inspect, f1
|
|
57
60
|
elsif s1.data == s2.data
|
|
58
|
-
printf "[.] section: %s == %s\n"
|
|
61
|
+
printf green("[.] section: %s == %s\n"), s1.name, s2.name if @verbose
|
|
59
62
|
else
|
|
60
63
|
r = false
|
|
61
|
-
printf "[!] section: %s != %s\n"
|
|
64
|
+
printf red("[!] section: %s != %s\n"), s1.name, s2.name
|
|
62
65
|
self.class.cmp_ios *[s1,s2].map{ |section| StringIO.new(section.data) }
|
|
63
66
|
end
|
|
64
67
|
end
|
|
@@ -81,14 +84,14 @@ class PEdump::Comparer
|
|
|
81
84
|
|
|
82
85
|
if d1.va != d2.va && d1.size != d2.size
|
|
83
86
|
r = false
|
|
84
|
-
printf "[!] data_dir: %-12s: SIZE & VA: %6x %6x | %6x %6x\n"
|
|
87
|
+
printf red("[!] data_dir: %-12s: SIZE & VA: %6x %6x | %6x %6x\n"), d1.type,
|
|
85
88
|
d1.va, d1.size, d2.va, d2.size
|
|
86
89
|
elsif d1.va != d2.va
|
|
87
90
|
r = false
|
|
88
|
-
printf "[!] data_dir: %-12s: VA : %x != %x\n"
|
|
91
|
+
printf red("[!] data_dir: %-12s: VA : %x != %x\n"), d1.type, d1.va, d2.va
|
|
89
92
|
elsif d1.size != d2.size
|
|
90
93
|
r = false
|
|
91
|
-
printf "[!] data_dir: %-12s: SIZE : %x != %x\n"
|
|
94
|
+
printf red("[!] data_dir: %-12s: SIZE : %x != %x\n"), d1.type, d1.size, d2.size
|
|
92
95
|
end
|
|
93
96
|
end
|
|
94
97
|
r
|
|
@@ -98,7 +101,7 @@ class PEdump::Comparer
|
|
|
98
101
|
@ldr1.pedump.imports.each_with_index do |iid1,idx|
|
|
99
102
|
iid2 = @ldr2.pedump.imports[idx]
|
|
100
103
|
if iid1 != iid2
|
|
101
|
-
puts "[!] diff imports"
|
|
104
|
+
puts red("[!] diff imports")
|
|
102
105
|
return false
|
|
103
106
|
end
|
|
104
107
|
end
|
|
@@ -133,9 +136,9 @@ class PEdump::Comparer
|
|
|
133
136
|
bytes = ios.map(&:readbyte)
|
|
134
137
|
if bytes.uniq.size > 1
|
|
135
138
|
ndiff += 1
|
|
136
|
-
printf
|
|
139
|
+
printf(yellow("\t%08x:"+" %02x"*ios.size)+"\n", ios[0].pos-1, *bytes)
|
|
137
140
|
if ndiff >= 5
|
|
138
|
-
puts "\t..."
|
|
141
|
+
puts yellow("\t...")
|
|
139
142
|
break
|
|
140
143
|
end
|
|
141
144
|
end
|
|
@@ -21,13 +21,13 @@ class PEdump
|
|
|
21
21
|
|
|
22
22
|
MINIDUMP_LOCATION_DESCRIPTOR = IOStruct.new 'LL', :DataSize, :Rva
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
# Using nested struct - Location is automatically parsed
|
|
25
|
+
MINIDUMP_DIRECTORY = IOStruct.new(
|
|
26
|
+
fields: {
|
|
27
|
+
StreamType: 'uint32_t',
|
|
28
|
+
Location: MINIDUMP_LOCATION_DESCRIPTOR,
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
31
|
|
|
32
32
|
MINIDUMP_MEMORY_INFO = IOStruct.new 'QQLLQLLLL',
|
|
33
33
|
:BaseAddress,
|
data/lib/pedump/logger.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'pedump/colors'
|
|
2
2
|
|
|
3
3
|
class PEdump
|
|
4
4
|
class Logger < ::Logger
|
|
@@ -39,6 +39,8 @@ class PEdump
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
class ColoredLogger < ::Logger
|
|
42
|
+
include PEdump::Colors
|
|
43
|
+
|
|
42
44
|
def initialize *args
|
|
43
45
|
super
|
|
44
46
|
@formatter = proc do |severity,_,_,msg|
|
|
@@ -58,7 +60,7 @@ class PEdump
|
|
|
58
60
|
when 'DEBUG'
|
|
59
61
|
:gray
|
|
60
62
|
end
|
|
61
|
-
"#{color ?
|
|
63
|
+
"#{color ? send(color, msg) : msg}\n"
|
|
62
64
|
end
|
|
63
65
|
end
|
|
64
66
|
@level = WARN
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class PEdump
|
|
4
|
+
class CLI
|
|
5
|
+
# Streaming multipart body for file uploads
|
|
6
|
+
class MultipartBody
|
|
7
|
+
BOUNDARY_CHARS = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
|
|
8
|
+
|
|
9
|
+
def self.generate_boundary
|
|
10
|
+
"----PEdumpUpload#{Array.new(32) { BOUNDARY_CHARS.sample }.join}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def initialize(header, file_io, footer, total_size)
|
|
14
|
+
@parts = [
|
|
15
|
+
StringIO.new(header),
|
|
16
|
+
file_io,
|
|
17
|
+
StringIO.new(footer)
|
|
18
|
+
]
|
|
19
|
+
@part_index = 0
|
|
20
|
+
@size = total_size
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_reader :size
|
|
24
|
+
|
|
25
|
+
def read(length = nil, outbuf = nil)
|
|
26
|
+
outbuf ||= String.new
|
|
27
|
+
outbuf.clear
|
|
28
|
+
outbuf.force_encoding(Encoding::BINARY)
|
|
29
|
+
|
|
30
|
+
return nil if @part_index >= @parts.length
|
|
31
|
+
|
|
32
|
+
while @part_index < @parts.length
|
|
33
|
+
chunk = if length
|
|
34
|
+
@parts[@part_index].read(length - outbuf.bytesize)
|
|
35
|
+
else
|
|
36
|
+
@parts[@part_index].read
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if chunk
|
|
40
|
+
outbuf << chunk
|
|
41
|
+
break if length && outbuf.bytesize >= length
|
|
42
|
+
else
|
|
43
|
+
@part_index += 1
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
outbuf.empty? && length ? nil : outbuf
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def rewind
|
|
51
|
+
@parts.each(&:rewind)
|
|
52
|
+
@part_index = 0
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
data/lib/pedump/packer.rb
CHANGED
|
@@ -73,7 +73,7 @@ class PEdump
|
|
|
73
73
|
elsif va == 0 && pe.dll?
|
|
74
74
|
pedump.logger.debug "[.] it's a DLL with no EntryPoint"
|
|
75
75
|
nil
|
|
76
|
-
elsif !(ofs = pedump.
|
|
76
|
+
elsif !(ofs = pedump.rva2file(va))
|
|
77
77
|
pedump.logger.error "[?] can't find EntryPoint RVA (0x#{va.to_s(16)}) file offset"
|
|
78
78
|
nil
|
|
79
79
|
else
|
data/lib/pedump/resources.rb
CHANGED
|
@@ -403,7 +403,7 @@ class PEdump
|
|
|
403
403
|
end
|
|
404
404
|
end
|
|
405
405
|
when IMAGE_RESOURCE_DATA_ENTRY
|
|
406
|
-
file_offset =
|
|
406
|
+
file_offset = rva2file(entry.data.OffsetToData, :quiet => (@pe_res_errors > MAX_ERRORS))
|
|
407
407
|
unless file_offset
|
|
408
408
|
@pe_res_errors += 1
|
|
409
409
|
if @pe_res_errors > MAX_ERRORS
|
data/lib/pedump/sig_parser.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
#coding: binary
|
|
2
|
+
|
|
1
3
|
class PEdump
|
|
2
4
|
module SigParser
|
|
3
5
|
|
|
@@ -47,8 +49,6 @@ class PEdump
|
|
|
47
49
|
puts "[=] #{sigs.size-n0} sigs from #{File.basename(fname)}\n\n" if args[:verbose]
|
|
48
50
|
end
|
|
49
51
|
|
|
50
|
-
bins = Hash.new{ |k,v| k[v] = ''.force_encoding('binary') }
|
|
51
|
-
|
|
52
52
|
# convert strings to Regexps
|
|
53
53
|
sigs = sigs.values
|
|
54
54
|
sigs.each_with_index do |sig,idx|
|
|
@@ -57,16 +57,14 @@ class PEdump
|
|
|
57
57
|
sig.size = a.size
|
|
58
58
|
end.map do |x|
|
|
59
59
|
case x
|
|
60
|
-
when /\A\?\?\
|
|
61
|
-
bins[sig] << '.'
|
|
62
|
-
'.'
|
|
63
|
-
when /\A.\?/,/\?.\Z/
|
|
64
|
-
puts "[?] #{x.inspect} -> \"??\" in #{sig.name}" if args[:verbose]
|
|
65
|
-
bins[sig] << '.'
|
|
60
|
+
when /\A\?\?\z/
|
|
66
61
|
'.'
|
|
67
|
-
when /\A
|
|
62
|
+
when /\A\h\?\z/ # 'f?'
|
|
63
|
+
"[\\x#{x[0]}0-\\x#{x[0]}f]"
|
|
64
|
+
when /\A\?\h\z/ # '?4'
|
|
65
|
+
'[' + (0..15).map{ |i| "\\x#{i.to_s(16)}#{x[1]}" }.join + ']'
|
|
66
|
+
when /\A[a-f0-9]{2}\z/i
|
|
68
67
|
x = x.to_i(16).chr
|
|
69
|
-
bins[sig] << x
|
|
70
68
|
if args[:raw]
|
|
71
69
|
x
|
|
72
70
|
elsif args[:raword]
|
|
@@ -89,34 +87,6 @@ class PEdump
|
|
|
89
87
|
sigs.delete_if{ |sig| !sig.re || sig.re.index('BAD_RE') }
|
|
90
88
|
return sigs if args[:raw] || args[:raword]
|
|
91
89
|
|
|
92
|
-
# require 'awesome_print'
|
|
93
|
-
# bins.each do |bin_sig, bin|
|
|
94
|
-
# next if bin.size < 5
|
|
95
|
-
# #next unless bin_sig.name['UPX']
|
|
96
|
-
#
|
|
97
|
-
# bin_re = Regexp.new(bin_sig.re.join, Regexp::MULTILINE)
|
|
98
|
-
# was = false
|
|
99
|
-
# sigs.each do |sig|
|
|
100
|
-
# next if sig.size < 5 || sig == bin_sig
|
|
101
|
-
# #next unless sig.name['UPX']
|
|
102
|
-
#
|
|
103
|
-
# re = Regexp.new(sig.re.join, Regexp::MULTILINE)
|
|
104
|
-
# if bin.index(re) == 0
|
|
105
|
-
# rd = _re_diff(bin_re.source, re.source)
|
|
106
|
-
# if rd.any? && rd.size <= 4
|
|
107
|
-
# #if sig.name.split.first.upcase != bin_sig.name.split.first.upcase
|
|
108
|
-
# puts "\n[.] #{bin_sig.name.yellow}\n#{bin_re.source.inspect.red}" unless was
|
|
109
|
-
# puts "[=] #{sig.name}"
|
|
110
|
-
# puts re.source.inspect.green
|
|
111
|
-
# p rd
|
|
112
|
-
# was = true
|
|
113
|
-
# #end
|
|
114
|
-
# end
|
|
115
|
-
# end
|
|
116
|
-
# end
|
|
117
|
-
# end
|
|
118
|
-
|
|
119
|
-
|
|
120
90
|
optimize sigs if args[:optimize]
|
|
121
91
|
|
|
122
92
|
# convert re-arrays to Regexps
|
|
@@ -141,6 +111,7 @@ class PEdump
|
|
|
141
111
|
return if sig.name == "JAR Archive"
|
|
142
112
|
return if sig.name == "Turbo / Borland Pascal v7.x Unit"
|
|
143
113
|
return if sig.re == "54 68 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 6D 6F" # dos stub
|
|
114
|
+
return if sig.re =~ /T RU E/
|
|
144
115
|
|
|
145
116
|
sig.name.sub!(/^\*\s+/, '')
|
|
146
117
|
sig.name.sub!(/\s+\(h\)$/, '')
|
|
@@ -172,8 +143,8 @@ class PEdump
|
|
|
172
143
|
|
|
173
144
|
# too short signatures
|
|
174
145
|
if sig.re.split.delete_if{ |x| x['?'] }.size < 3
|
|
175
|
-
|
|
176
|
-
|
|
146
|
+
puts "[?] too short signature: #{sig.inspect}" if args[:verbose]
|
|
147
|
+
return
|
|
177
148
|
end
|
|
178
149
|
|
|
179
150
|
# fs.txt contains a lot of signatures that copied from other sources
|
|
@@ -223,12 +194,6 @@ class PEdump
|
|
|
223
194
|
return if d.all?(&:empty?) # no different words => can keep ANY name
|
|
224
195
|
|
|
225
196
|
|
|
226
|
-
# if name1 =~ /pecompact/i
|
|
227
|
-
# require 'awesome_print'
|
|
228
|
-
# puts "[d] #{name1}".yellow
|
|
229
|
-
# puts "[d] #{name2}".yellow
|
|
230
|
-
# end
|
|
231
|
-
|
|
232
197
|
# [["v1.14/v1.20"], ["v1.14,", "v1.20"]]]
|
|
233
198
|
# [["EXEShield", "v0.3b/v0.3", "v0.6"], ["Shield", "v0.3b,", "v0.3"]]]
|
|
234
199
|
2.times do |i|
|
|
@@ -241,9 +206,6 @@ class PEdump
|
|
|
241
206
|
end
|
|
242
207
|
end
|
|
243
208
|
|
|
244
|
-
# require 'awesome_print'
|
|
245
|
-
# puts "[d] #{name1.yellow} #{name2.green}"
|
|
246
|
-
|
|
247
209
|
a = name1.split
|
|
248
210
|
b = name2.split
|
|
249
211
|
|
|
@@ -282,12 +244,6 @@ class PEdump
|
|
|
282
244
|
new_name = new_name_head
|
|
283
245
|
new_name << [a.join(' '), b.join(' ')].delete_if{|x| x.empty?}.join(' / ')
|
|
284
246
|
new_name += new_name_tail
|
|
285
|
-
# if name1 =~ /pecompact/i
|
|
286
|
-
# p a
|
|
287
|
-
# p b
|
|
288
|
-
# p new_name_tail
|
|
289
|
-
# puts "[=] #{new_name.inspect}".red
|
|
290
|
-
# end
|
|
291
247
|
new_name = new_name.join(' ')
|
|
292
248
|
end
|
|
293
249
|
|
data/lib/pedump/te.rb
CHANGED
|
@@ -4,33 +4,33 @@ class PEdump
|
|
|
4
4
|
# https://formats.kaitai.io/uefi_te/index.html
|
|
5
5
|
# http://ho.ax/tag/efi/
|
|
6
6
|
# https://github.com/gdbinit/TELoader
|
|
7
|
-
|
|
8
|
-
EFI_IMAGE_DATA_DIRECTORY = IOStruct.new(
|
|
7
|
+
|
|
8
|
+
EFI_IMAGE_DATA_DIRECTORY = IOStruct.new("VV", :va, :size)
|
|
9
9
|
EFI_IMAGE_DATA_DIRECTORY::TYPES = %w'BASERELOC DEBUG'
|
|
10
|
-
EFI_IMAGE_DATA_DIRECTORY::TYPES.each_with_index do |type,idx|
|
|
11
|
-
EFI_IMAGE_DATA_DIRECTORY.const_set(type,idx)
|
|
10
|
+
EFI_IMAGE_DATA_DIRECTORY::TYPES.each_with_index do |type, idx|
|
|
11
|
+
EFI_IMAGE_DATA_DIRECTORY.const_set(type, idx)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
# Using hash format with nested struct array for DataDirectory
|
|
15
|
+
class EFI_TE_IMAGE_HEADER < IOStruct.new(
|
|
16
|
+
fields: {
|
|
17
|
+
Signature: 'uint16_t',
|
|
18
|
+
Machine: 'uint16_t',
|
|
19
|
+
NumberOfSections: 'uint8_t',
|
|
20
|
+
Subsystem: 'uint8_t',
|
|
21
|
+
StrippedSize: 'uint16_t',
|
|
22
|
+
AddressOfEntryPoint: 'uint32_t',
|
|
23
|
+
BaseOfCode: 'uint32_t',
|
|
24
|
+
ImageBase: 'uint64_t',
|
|
25
|
+
DataDirectory: { type: EFI_IMAGE_DATA_DIRECTORY, count: 2 },
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
REAL_SIZE = SIZE
|
|
26
29
|
|
|
27
30
|
attr_accessor :sections
|
|
28
31
|
|
|
29
32
|
def self.read io, args = {}
|
|
30
33
|
super(io).tap do |te|
|
|
31
|
-
te.DataDirectory = 2.times.map do
|
|
32
|
-
EFI_IMAGE_DATA_DIRECTORY.read(io)
|
|
33
|
-
end
|
|
34
34
|
te.sections = PE.read_sections(io, te.NumberOfSections, args)
|
|
35
35
|
end
|
|
36
36
|
end
|
data/lib/pedump/tls.rb
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
class PEdump
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
TLS_DIRECTORY_FIELDS = %i[
|
|
3
|
+
StartAddressOfRawData
|
|
4
|
+
EndAddressOfRawData
|
|
5
|
+
AddressOfIndex
|
|
6
|
+
AddressOfCallBacks
|
|
7
|
+
SizeOfZeroFill
|
|
8
|
+
Characteristics
|
|
9
|
+
].freeze
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
:AddressOfCallBacks,
|
|
15
|
-
:SizeOfZeroFill,
|
|
16
|
-
:Characteristics
|
|
11
|
+
# 32-bit: all fields are 32-bit (V6)
|
|
12
|
+
# 64-bit: first 4 fields are 64-bit pointers (Q4), last 2 are 32-bit (V2)
|
|
13
|
+
IMAGE_TLS_DIRECTORY32 = IOStruct.new('V6', *TLS_DIRECTORY_FIELDS)
|
|
14
|
+
IMAGE_TLS_DIRECTORY64 = IOStruct.new('Q4V2', *TLS_DIRECTORY_FIELDS)
|
|
17
15
|
end
|
|
@@ -788,13 +788,13 @@ class PEdump::Unpacker::ASPack
|
|
|
788
788
|
###
|
|
789
789
|
|
|
790
790
|
rebuild_tls :step => 1
|
|
791
|
-
sorted_obj_tbl = @obj_tbl.sort_by{ |x| @ldr.pedump.
|
|
791
|
+
sorted_obj_tbl = @obj_tbl.sort_by{ |x| @ldr.pedump.rva2file(x.va) }
|
|
792
792
|
sorted_obj_tbl.each_with_index do |obj,idx|
|
|
793
793
|
# restore section flags, if any
|
|
794
794
|
@ldr.va2section(obj.va).flags = obj.flags if obj.flags
|
|
795
795
|
|
|
796
796
|
next if obj.size < 0 # empty section
|
|
797
|
-
#file_offset = @ldr.pedump.
|
|
797
|
+
#file_offset = @ldr.pedump.rva2file(obj.va)
|
|
798
798
|
#@io.seek file_offset
|
|
799
799
|
packed_size =
|
|
800
800
|
if idx == sorted_obj_tbl.size - 1
|
|
@@ -802,7 +802,7 @@ class PEdump::Unpacker::ASPack
|
|
|
802
802
|
obj.size
|
|
803
803
|
else
|
|
804
804
|
# subtract this file_offset from next object file_offset
|
|
805
|
-
@ldr.pedump.
|
|
805
|
+
@ldr.pedump.rva2file(sorted_obj_tbl[idx+1].va) - @ldr.pedump.rva2file(obj.va)
|
|
806
806
|
end
|
|
807
807
|
#packed_data = @io.read packed_size
|
|
808
808
|
packed_data = @ldr[obj.va, packed_size]
|
|
@@ -840,7 +840,7 @@ if __FILE__ == $0
|
|
|
840
840
|
next unless packer = Array(pedump.packer(f)).first
|
|
841
841
|
next unless packer.name =~ /aspack/i
|
|
842
842
|
|
|
843
|
-
STDERR.puts "\n=== #{fname}"
|
|
843
|
+
STDERR.puts "\n=== #{fname}"
|
|
844
844
|
|
|
845
845
|
f.rewind
|
|
846
846
|
unpacker = PEdump::Unpacker::ASPack.new(f,
|
data/lib/pedump/version.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class PEdump
|
|
2
|
-
|
|
3
|
-
STRING = File.read(File.join(File.dirname(File.dirname(File.dirname(__FILE__))), 'VERSION')).strip
|
|
4
|
-
MAJOR, MINOR, PATCH = STRING.split('.').map(&:to_i)
|
|
5
|
-
BUILD = nil
|
|
6
|
-
end
|
|
4
|
+
VERSION = '0.7.5'
|
|
7
5
|
end
|