pedump 0.6.1 → 0.6.2
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/.github/workflows/rubocop-analysis.yml +39 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +22 -18
- data/README.md +96 -10
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/lib/pedump.rb +1 -1
- data/lib/pedump/cli.rb +116 -17
- data/pedump.gemspec +18 -30
- metadata +9 -12
- data/.github/FUNDING.yml +0 -2
- data/.github/dependabot.yml +0 -8
- data/rich.py +0 -353
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9d4f9c13c95df2d30baf18bba07765fa26f1d4066a8abde228cba5cd29bc9df0
|
|
4
|
+
data.tar.gz: b034a68704793f502843db9ec791ca636e404b20258ae144a349e718eaf8a6b6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5b3187809523a111b8cf6ed608047f19044a4e616591297991ae6f97aabd7a783113b8cbf1c1a04d7968cbff6baa5f188c2aec504540ca305117fa38e7c61273
|
|
7
|
+
data.tar.gz: b870e93e3cc90785836ed6719599f855e20c026489bec925d4859e493f4c3a65b1b7c60ca15a8040f8be652ed1884171b302009c2ed5a16d6a3887b2d00ed36c
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: "Rubocop"
|
|
2
|
+
|
|
3
|
+
on: push
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
rubocop:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
strategy:
|
|
9
|
+
fail-fast: false
|
|
10
|
+
|
|
11
|
+
steps:
|
|
12
|
+
- name: Checkout repository
|
|
13
|
+
uses: actions/checkout@v2
|
|
14
|
+
|
|
15
|
+
# If running on a self-hosted runner, check it meets the requirements
|
|
16
|
+
# listed at https://github.com/ruby/setup-ruby#using-self-hosted-runners
|
|
17
|
+
- name: Set up Ruby
|
|
18
|
+
uses: ruby/setup-ruby@v1
|
|
19
|
+
with:
|
|
20
|
+
ruby-version: 2.6
|
|
21
|
+
|
|
22
|
+
# This step is not necessary if you add the gem to your Gemfile
|
|
23
|
+
- name: Install Code Scanning integration
|
|
24
|
+
run: bundle add code-scanning-rubocop --version 0.3.0 --skip-install
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: bundle install
|
|
28
|
+
|
|
29
|
+
- name: Rubocop run
|
|
30
|
+
run: |
|
|
31
|
+
bash -c "
|
|
32
|
+
bundle exec rubocop --require code_scanning --format CodeScanning::SarifFormatter -o rubocop.sarif
|
|
33
|
+
[[ $? -ne 2 ]]
|
|
34
|
+
"
|
|
35
|
+
|
|
36
|
+
- name: Upload Sarif output
|
|
37
|
+
uses: github/codeql-action/upload-sarif@v1
|
|
38
|
+
with:
|
|
39
|
+
sarif_file: rubocop.sarif
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -6,10 +6,11 @@ GEM
|
|
|
6
6
|
builder (3.2.4)
|
|
7
7
|
descendants_tracker (0.0.4)
|
|
8
8
|
thread_safe (~> 0.3, >= 0.3.1)
|
|
9
|
-
diff-lcs (1.
|
|
9
|
+
diff-lcs (1.4.4)
|
|
10
10
|
faraday (0.9.2)
|
|
11
11
|
multipart-post (>= 1.2, < 3)
|
|
12
|
-
git (1.
|
|
12
|
+
git (1.8.1)
|
|
13
|
+
rchardet (~> 1.8)
|
|
13
14
|
github_api (0.16.0)
|
|
14
15
|
addressable (~> 2.4.0)
|
|
15
16
|
descendants_tracker (~> 0.0.4)
|
|
@@ -17,7 +18,7 @@ GEM
|
|
|
17
18
|
hashie (>= 3.4)
|
|
18
19
|
mime-types (>= 1.16, < 3.0)
|
|
19
20
|
oauth2 (~> 1.0)
|
|
20
|
-
hashie (4.
|
|
21
|
+
hashie (4.1.0)
|
|
21
22
|
highline (2.0.3)
|
|
22
23
|
iostruct (0.0.4)
|
|
23
24
|
jeweler (2.3.9)
|
|
@@ -31,32 +32,35 @@ GEM
|
|
|
31
32
|
rake
|
|
32
33
|
rdoc
|
|
33
34
|
semver2
|
|
34
|
-
jwt (2.2.
|
|
35
|
+
jwt (2.2.2)
|
|
35
36
|
mime-types (2.99.3)
|
|
36
|
-
mini_portile2 (2.
|
|
37
|
-
multi_json (1.
|
|
37
|
+
mini_portile2 (2.5.0)
|
|
38
|
+
multi_json (1.15.0)
|
|
38
39
|
multi_xml (0.6.0)
|
|
39
40
|
multipart-post (2.1.1)
|
|
40
|
-
nokogiri (1.
|
|
41
|
-
mini_portile2 (~> 2.
|
|
42
|
-
|
|
41
|
+
nokogiri (1.11.1)
|
|
42
|
+
mini_portile2 (~> 2.5.0)
|
|
43
|
+
racc (~> 1.4)
|
|
44
|
+
oauth2 (1.4.4)
|
|
43
45
|
faraday (>= 0.8, < 2.0)
|
|
44
46
|
jwt (>= 1.0, < 3.0)
|
|
45
47
|
multi_json (~> 1.3)
|
|
46
48
|
multi_xml (~> 0.5)
|
|
47
49
|
rack (>= 1.2, < 3)
|
|
48
|
-
psych (3.
|
|
50
|
+
psych (3.3.0)
|
|
51
|
+
racc (1.5.2)
|
|
49
52
|
rack (2.2.3)
|
|
50
53
|
rainbow (3.0.0)
|
|
51
|
-
rake (13.0.
|
|
52
|
-
|
|
54
|
+
rake (13.0.3)
|
|
55
|
+
rchardet (1.8.0)
|
|
56
|
+
rdoc (6.3.0)
|
|
53
57
|
rspec (3.9.0)
|
|
54
58
|
rspec-core (~> 3.9.0)
|
|
55
59
|
rspec-expectations (~> 3.9.0)
|
|
56
60
|
rspec-mocks (~> 3.9.0)
|
|
57
|
-
rspec-core (3.9.
|
|
58
|
-
rspec-support (~> 3.9.
|
|
59
|
-
rspec-expectations (3.9.
|
|
61
|
+
rspec-core (3.9.3)
|
|
62
|
+
rspec-support (~> 3.9.3)
|
|
63
|
+
rspec-expectations (3.9.4)
|
|
60
64
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
61
65
|
rspec-support (~> 3.9.0)
|
|
62
66
|
rspec-its (1.3.0)
|
|
@@ -65,7 +69,7 @@ GEM
|
|
|
65
69
|
rspec-mocks (3.9.1)
|
|
66
70
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
67
71
|
rspec-support (~> 3.9.0)
|
|
68
|
-
rspec-support (3.9.
|
|
72
|
+
rspec-support (3.9.4)
|
|
69
73
|
semver2 (3.4.2)
|
|
70
74
|
thread_safe (0.3.6)
|
|
71
75
|
zhexdump (0.0.2)
|
|
@@ -75,7 +79,7 @@ PLATFORMS
|
|
|
75
79
|
|
|
76
80
|
DEPENDENCIES
|
|
77
81
|
awesome_print
|
|
78
|
-
bundler (~> 2.
|
|
82
|
+
bundler (~> 2.2.3)
|
|
79
83
|
iostruct (>= 0.0.4)
|
|
80
84
|
jeweler (~> 2.3.9)
|
|
81
85
|
multipart-post (>= 2.0.0)
|
|
@@ -85,4 +89,4 @@ DEPENDENCIES
|
|
|
85
89
|
zhexdump (>= 0.0.2)
|
|
86
90
|
|
|
87
91
|
BUNDLED WITH
|
|
88
|
-
2.
|
|
92
|
+
2.2.3
|
data/README.md
CHANGED
|
@@ -3,8 +3,14 @@ pedump [
|
|
82
|
+
|
|
83
|
+
--extract ID Extract a resource/section/data_dir
|
|
84
|
+
ID: datadir:EXPORT - datadir by type
|
|
85
|
+
ID: resource:0x98478 - resource by offset
|
|
86
|
+
ID: resource:ICON/#1 - resource by type & name
|
|
87
|
+
ID: section:.text - section by name
|
|
88
|
+
ID: section:rva/0x1000 - section by RVA
|
|
89
|
+
ID: section:raw/0x400 - section by RAW_PTR
|
|
76
90
|
--va2file VA Convert RVA to file offset
|
|
77
91
|
|
|
78
|
-
-W, --web Uploads files to a
|
|
92
|
+
-W, --web Uploads files to a https://pedump.me
|
|
79
93
|
for a nice HTML tables with image previews,
|
|
80
94
|
candies & stuff
|
|
81
95
|
-C, --console opens IRB console with specified file loaded
|
|
@@ -127,14 +141,14 @@ Usage
|
|
|
127
141
|
|
|
128
142
|
=== RICH Header ===
|
|
129
143
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
144
|
+
ID VER COUNT DESCRIPTION
|
|
145
|
+
95 521e 9 [ASM] VS2008 build 21022
|
|
146
|
+
1 0 367 [---] Unmarked objects
|
|
147
|
+
93 521e 29 [IMP] VS2008 build 21022
|
|
148
|
+
84 521e 129 [C++] VS2008 build 21022
|
|
149
|
+
83 521e 25 [ C ] VS2008 build 21022
|
|
150
|
+
94 521e 1 [RES] VS2008 build 21022
|
|
151
|
+
91 521e 1 [LNK] VS2008 build 21022
|
|
138
152
|
|
|
139
153
|
### PE Header
|
|
140
154
|
|
|
@@ -414,6 +428,78 @@ Usage
|
|
|
414
428
|
samples/unpackme.exe: ASProtect 1.33 - 2.1 Registered (Alexey Solodovnikov)
|
|
415
429
|
samples/zlib.dll: Microsoft Visual C v2.0
|
|
416
430
|
|
|
431
|
+
### Extracting
|
|
432
|
+
|
|
433
|
+
#### Resources
|
|
434
|
+
|
|
435
|
+
by name:
|
|
436
|
+
|
|
437
|
+
# pedump calc.exe --extract resource:VERSION/#1 | hexdump -C | head
|
|
438
|
+
|
|
439
|
+
00000000 78 03 34 00 00 00 56 00 53 00 5f 00 56 00 45 00 |x.4...V.S._.V.E.|
|
|
440
|
+
00000010 52 00 53 00 49 00 4f 00 4e 00 5f 00 49 00 4e 00 |R.S.I.O.N._.I.N.|
|
|
441
|
+
00000020 46 00 4f 00 00 00 00 00 bd 04 ef fe 00 00 01 00 |F.O.............|
|
|
442
|
+
00000030 01 00 06 00 00 00 91 1a 01 00 06 00 00 00 91 1a |................|
|
|
443
|
+
00000040 3f 00 00 00 00 00 00 00 04 00 04 00 01 00 00 00 |?...............|
|
|
444
|
+
00000050 00 00 00 00 00 00 00 00 00 00 00 00 d6 02 00 00 |................|
|
|
445
|
+
00000060 01 00 53 00 74 00 72 00 69 00 6e 00 67 00 46 00 |..S.t.r.i.n.g.F.|
|
|
446
|
+
00000070 69 00 6c 00 65 00 49 00 6e 00 66 00 6f 00 00 00 |i.l.e.I.n.f.o...|
|
|
447
|
+
00000080 b2 02 00 00 01 00 30 00 34 00 30 00 39 00 30 00 |......0.4.0.9.0.|
|
|
448
|
+
00000090 34 00 42 00 30 00 00 00 4c 00 16 00 01 00 43 00 |4.B.0...L.....C.|
|
|
449
|
+
|
|
450
|
+
by offset:
|
|
451
|
+
|
|
452
|
+
# pedump calc.exe --extract resource:0x98478 | head
|
|
453
|
+
|
|
454
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
455
|
+
<!-- Copyright (c) Microsoft Corporation -->
|
|
456
|
+
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
|
457
|
+
<assemblyIdentity
|
|
458
|
+
name="Microsoft.Windows.Shell.calc"
|
|
459
|
+
processorArchitecture="x86"
|
|
460
|
+
version="5.1.0.0"
|
|
461
|
+
type="win32"/>
|
|
462
|
+
<description>Windows Shell</description>
|
|
463
|
+
<dependency>
|
|
464
|
+
|
|
465
|
+
#### Sections
|
|
466
|
+
|
|
467
|
+
by name:
|
|
468
|
+
|
|
469
|
+
# pedump calc.exe --extract section:.text | hexdump -C | head -4
|
|
470
|
+
|
|
471
|
+
00000000 0b aa cb 77 f7 c4 cc 77 a4 c4 cc 77 c4 c4 cc 77 |...w...w...w...w|
|
|
472
|
+
00000010 3e d7 ca 77 ec b4 cb 77 69 9c f0 77 dc c4 cc 77 |>..w...wi..w...w|
|
|
473
|
+
00000020 12 9c cb 77 4d af cb 77 b4 c4 cc 77 6e a8 ee 77 |...wM..w...wn..w|
|
|
474
|
+
00000030 14 fc f0 77 00 00 00 00 2c 92 04 76 09 62 04 76 |...w....,..v.b.v|
|
|
475
|
+
|
|
476
|
+
by RVA:
|
|
477
|
+
|
|
478
|
+
# pedump calc.exe --extract section:rva/0x1000 | hexdump -C | head -4
|
|
479
|
+
|
|
480
|
+
00000000 0b aa cb 77 f7 c4 cc 77 a4 c4 cc 77 c4 c4 cc 77 |...w...w...w...w|
|
|
481
|
+
00000010 3e d7 ca 77 ec b4 cb 77 69 9c f0 77 dc c4 cc 77 |>..w...wi..w...w|
|
|
482
|
+
00000020 12 9c cb 77 4d af cb 77 b4 c4 cc 77 6e a8 ee 77 |...wM..w...wn..w|
|
|
483
|
+
00000030 14 fc f0 77 00 00 00 00 2c 92 04 76 09 62 04 76 |...w....,..v.b.v|
|
|
484
|
+
|
|
485
|
+
by RAW_PTR (file offset):
|
|
486
|
+
|
|
487
|
+
# pedump calc.exe --extract section:raw/0x400 | hexdump -C | head -4
|
|
488
|
+
|
|
489
|
+
00000000 0b aa cb 77 f7 c4 cc 77 a4 c4 cc 77 c4 c4 cc 77 |...w...w...w...w|
|
|
490
|
+
00000010 3e d7 ca 77 ec b4 cb 77 69 9c f0 77 dc c4 cc 77 |>..w...wi..w...w|
|
|
491
|
+
00000020 12 9c cb 77 4d af cb 77 b4 c4 cc 77 6e a8 ee 77 |...wM..w...wn..w|
|
|
492
|
+
00000030 14 fc f0 77 00 00 00 00 2c 92 04 76 09 62 04 76 |...w....,..v.b.v|
|
|
493
|
+
|
|
494
|
+
#### Data Directory
|
|
495
|
+
|
|
496
|
+
# pedump calc.exe --extract datadir:IMPORT | hexdump -C | head -4
|
|
497
|
+
|
|
498
|
+
00000000 90 9f 04 00 ff ff ff ff ff ff ff ff dc a2 04 00 |................|
|
|
499
|
+
00000010 48 12 00 00 f4 a0 04 00 ff ff ff ff ff ff ff ff |H...............|
|
|
500
|
+
00000020 10 a5 04 00 ac 13 00 00 48 9d 04 00 ff ff ff ff |........H.......|
|
|
501
|
+
00000030 ff ff ff ff f6 a5 04 00 00 10 00 00 5c 9f 04 00 |............\...|
|
|
502
|
+
|
|
417
503
|
License
|
|
418
504
|
-------
|
|
419
505
|
Released under the MIT License. See the [LICENSE](https://github.com/zed-0xff/pedump/blob/master/LICENSE.txt) file for further details.
|
data/Rakefile
CHANGED
|
@@ -23,7 +23,7 @@ Jeweler::Tasks.new do |gem|
|
|
|
23
23
|
gem.authors = ["Andrey \"Zed\" Zaikin"]
|
|
24
24
|
gem.executables = %w'pedump'
|
|
25
25
|
gem.files.include "lib/**/*.rb"
|
|
26
|
-
gem.files.exclude %w'samples/**/* spec/**/* tmp/**/* tmp/.keep .* README.md.tpl'
|
|
26
|
+
gem.files.exclude %w'samples/**/* spec/**/* tmp/**/* tmp/.keep .* README.md.tpl .github/*'
|
|
27
27
|
gem.extra_rdoc_files.exclude 'README.md.tpl'
|
|
28
28
|
# dependencies defined in Gemfile
|
|
29
29
|
end
|
|
@@ -35,7 +35,7 @@ require 'rspec/core/rake_task'
|
|
|
35
35
|
desc "run specs"
|
|
36
36
|
RSpec::Core::RakeTask.new
|
|
37
37
|
|
|
38
|
-
task :default => :spec
|
|
38
|
+
task :default => [:spec, :readme]
|
|
39
39
|
|
|
40
40
|
namespace :test do
|
|
41
41
|
desc "test on all files in given path"
|
|
@@ -85,7 +85,7 @@ def check_file url, params = {}
|
|
|
85
85
|
fname = File.join 'data', (prefix ? "#{prefix}-" : '') + File.basename(url)
|
|
86
86
|
existing_md5 = File.exist?(fname) ? Digest::MD5.file(fname).hexdigest : ''
|
|
87
87
|
print "[.] fetching #{url} .. "
|
|
88
|
-
remote_data
|
|
88
|
+
remote_data = URI.open(url).read.force_encoding('cp1252').encode('utf-8')
|
|
89
89
|
puts "#{remote_data.size} bytes"
|
|
90
90
|
raise "too small remote data (#{remote_data.size})" if remote_data.size < params[:min_size]
|
|
91
91
|
remote_md5 = Digest::MD5.hexdigest(remote_data)
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.6.
|
|
1
|
+
0.6.2
|
data/lib/pedump.rb
CHANGED
|
@@ -30,7 +30,7 @@ class PEdump
|
|
|
30
30
|
VERSION = Version::STRING
|
|
31
31
|
MAX_ERRORS = 100
|
|
32
32
|
MAX_IMAGE_IMPORT_DESCRIPTORS = 1000
|
|
33
|
-
MAX_EXPORT_NUMBER_OF_NAMES = 16384 # got 7977 in
|
|
33
|
+
MAX_EXPORT_NUMBER_OF_NAMES = 16384 # got 7977 in https://pedump.me/03ad7400080678c6b1984f995d36fd04
|
|
34
34
|
GOOD_FUNCTION_NAME_RE = /\A[\x21-\x7f]+\Z/
|
|
35
35
|
SUPPORTED_SIGNATURES = ['MZ', 'ZM', 'VZ']
|
|
36
36
|
|
data/lib/pedump/cli.rb
CHANGED
|
@@ -35,12 +35,13 @@ class PEdump::CLI
|
|
|
35
35
|
|
|
36
36
|
KNOWN_ACTIONS = (
|
|
37
37
|
%w'mz dos_stub rich pe ne te data_directory sections tls security' +
|
|
38
|
-
%w'strings resources resource_directory imports exports version_info packer web console packer_only'
|
|
38
|
+
%w'strings resources resource_directory imports exports version_info packer web console packer_only' +
|
|
39
|
+
%w'extract' # 'disasm'
|
|
39
40
|
).map(&:to_sym)
|
|
40
41
|
|
|
41
|
-
DEFAULT_ALL_ACTIONS = KNOWN_ACTIONS - %w'resource_directory web packer_only console'.map(&:to_sym)
|
|
42
|
+
DEFAULT_ALL_ACTIONS = KNOWN_ACTIONS - %w'resource_directory web packer_only console extract disasm'.map(&:to_sym)
|
|
42
43
|
|
|
43
|
-
URL_BASE = "
|
|
44
|
+
URL_BASE = "https://pedump.me"
|
|
44
45
|
|
|
45
46
|
def initialize argv = ARGV
|
|
46
47
|
@argv = argv
|
|
@@ -97,8 +98,24 @@ class PEdump::CLI
|
|
|
97
98
|
opts.on "--all", "Dump all but resource-directory (default)" do
|
|
98
99
|
@actions = DEFAULT_ALL_ACTIONS
|
|
99
100
|
end
|
|
101
|
+
|
|
102
|
+
opts.separator ''
|
|
103
|
+
|
|
104
|
+
# opts.on "--disasm [X]", "Disassemble a symbol/VA" do |v|
|
|
105
|
+
# @actions << [:disasm, v]
|
|
106
|
+
# end
|
|
107
|
+
opts.on("--extract ID", "Extract a resource/section/data_dir",
|
|
108
|
+
"ID: datadir:EXPORT - datadir by type",
|
|
109
|
+
"ID: resource:0x98478 - resource by offset",
|
|
110
|
+
"ID: resource:ICON/#1 - resource by type & name",
|
|
111
|
+
"ID: section:.text - section by name",
|
|
112
|
+
"ID: section:rva/0x1000 - section by RVA",
|
|
113
|
+
"ID: section:raw/0x400 - section by RAW_PTR",
|
|
114
|
+
) do |v|
|
|
115
|
+
@actions << [:extract, v]
|
|
116
|
+
end
|
|
100
117
|
opts.on "--va2file VA", "Convert RVA to file offset" do |va|
|
|
101
|
-
@actions << [:va2file,va]
|
|
118
|
+
@actions << [:va2file, va]
|
|
102
119
|
end
|
|
103
120
|
|
|
104
121
|
opts.separator ''
|
|
@@ -134,7 +151,7 @@ class PEdump::CLI
|
|
|
134
151
|
@file_name = fname
|
|
135
152
|
|
|
136
153
|
File.open(fname,'rb') do |f|
|
|
137
|
-
@pedump = create_pedump
|
|
154
|
+
@pedump = create_pedump f
|
|
138
155
|
|
|
139
156
|
next if !@options[:force] && !@pedump.supported_file?(f)
|
|
140
157
|
|
|
@@ -153,8 +170,8 @@ class PEdump::CLI
|
|
|
153
170
|
# prevents a 'Broken pipe - <STDOUT> (Errno::EPIPE)' message
|
|
154
171
|
end
|
|
155
172
|
|
|
156
|
-
def create_pedump
|
|
157
|
-
PEdump.new(
|
|
173
|
+
def create_pedump io
|
|
174
|
+
PEdump.new(io, :force => @options[:force]).tap do |x|
|
|
158
175
|
x.logger.level =
|
|
159
176
|
case @options[:verbose]
|
|
160
177
|
when -100..-3
|
|
@@ -195,7 +212,7 @@ class PEdump::CLI
|
|
|
195
212
|
end
|
|
196
213
|
|
|
197
214
|
class ProgressProxy
|
|
198
|
-
def initialize file, prefix = "[.] uploading: ", io =
|
|
215
|
+
def initialize file, prefix = "[.] uploading: ", io = $stdout
|
|
199
216
|
@file = file
|
|
200
217
|
@io = io
|
|
201
218
|
@prefix = prefix
|
|
@@ -228,15 +245,16 @@ class PEdump::CLI
|
|
|
228
245
|
require 'net/http'
|
|
229
246
|
require 'net/http/post/multipart'
|
|
230
247
|
|
|
231
|
-
stdout_sync =
|
|
232
|
-
|
|
248
|
+
stdout_sync = $stdout.sync
|
|
249
|
+
$stdout.sync = true
|
|
233
250
|
|
|
234
251
|
md5 = Digest::MD5.file(f.path).hexdigest
|
|
235
252
|
@pedump.logger.info "[.] md5: #{md5}"
|
|
236
253
|
file_url = "#{URL_BASE}/#{md5}/"
|
|
237
254
|
|
|
238
255
|
@pedump.logger.warn "[.] checking if file already uploaded.."
|
|
239
|
-
|
|
256
|
+
uri = URI.parse URL_BASE
|
|
257
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: (uri.scheme == 'https')) do |http|
|
|
240
258
|
http.open_timeout = 10
|
|
241
259
|
http.read_timeout = 10
|
|
242
260
|
# doing HTTP HEAD is a lot faster than open-uri
|
|
@@ -258,18 +276,20 @@ class PEdump::CLI
|
|
|
258
276
|
uio = UploadIO.new(f, "application/octet-stream", File.basename(f.path))
|
|
259
277
|
ppx = ProgressProxy.new(uio)
|
|
260
278
|
req = Net::HTTP::Post::Multipart.new post_url.path, "file" => ppx
|
|
261
|
-
res = Net::HTTP.start(post_url.host, post_url.port)
|
|
279
|
+
res = Net::HTTP.start(post_url.host, post_url.port, use_ssl: (post_url.scheme == 'https')) do |http|
|
|
280
|
+
http.request(req)
|
|
281
|
+
end
|
|
262
282
|
ppx.finish!
|
|
263
283
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
284
|
+
unless [200, 302, 303].include?(res.code.to_i)
|
|
285
|
+
@pedump.logger.fatal "[!] invalid server response: #{res.code} #{res.msg}"
|
|
286
|
+
@pedump.logger.fatal res.body unless res.body.empty?
|
|
287
|
+
exit(1)
|
|
268
288
|
end
|
|
269
289
|
|
|
270
290
|
puts "[.] uploaded: #{file_url}"
|
|
271
291
|
ensure
|
|
272
|
-
|
|
292
|
+
$stdout.sync = stdout_sync
|
|
273
293
|
end
|
|
274
294
|
|
|
275
295
|
def console f
|
|
@@ -313,6 +333,10 @@ class PEdump::CLI
|
|
|
313
333
|
def dump_action action, f
|
|
314
334
|
if action.is_a?(Array)
|
|
315
335
|
case action[0]
|
|
336
|
+
when :disasm
|
|
337
|
+
return
|
|
338
|
+
when :extract
|
|
339
|
+
return extract action[1]
|
|
316
340
|
when :va2file
|
|
317
341
|
@pedump.sections(f)
|
|
318
342
|
va = action[1] =~ /(^0x)|(h$)/i ? action[1].to_i(16) : action[1].to_i
|
|
@@ -815,4 +839,79 @@ class PEdump::CLI
|
|
|
815
839
|
end
|
|
816
840
|
end
|
|
817
841
|
|
|
842
|
+
def disasm x
|
|
843
|
+
puts "TODO"
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
def extract x
|
|
847
|
+
a = x.split(':',2)
|
|
848
|
+
case a[0]
|
|
849
|
+
when 'datadir'
|
|
850
|
+
extract_datadir a[1]
|
|
851
|
+
when 'resource'
|
|
852
|
+
extract_resource a[1]
|
|
853
|
+
when 'section'
|
|
854
|
+
extract_section a[1]
|
|
855
|
+
else
|
|
856
|
+
raise "invalid #{x.inspect}"
|
|
857
|
+
end
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
def extract_datadir id
|
|
861
|
+
entry = @pedump.data_directory.find{ |x| x.type == id }
|
|
862
|
+
unless entry
|
|
863
|
+
@pedump.logger.fatal "[!] entry #{id.inspect} not found"
|
|
864
|
+
exit(1)
|
|
865
|
+
end
|
|
866
|
+
if entry.size != 0
|
|
867
|
+
IO::copy_stream @pedump.io, $stdout, entry.size, @pedump.va2file(entry.va)
|
|
868
|
+
end
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
def extract_resource id
|
|
872
|
+
res = nil
|
|
873
|
+
if id =~ /\A0x\h+\Z/
|
|
874
|
+
needle = id.to_i(16)
|
|
875
|
+
res = @pedump.resources.find{ |r| r.file_offset == needle }
|
|
876
|
+
elsif id =~ /\A\d+\Z/
|
|
877
|
+
needle = id.to_i(10)
|
|
878
|
+
res = @pedump.resources.find{ |r| r.file_offset == needle }
|
|
879
|
+
elsif id['/']
|
|
880
|
+
type, name = id.split('/', 2)
|
|
881
|
+
res = @pedump.resources.find{ |r| r.type == type && r.name == name }
|
|
882
|
+
else
|
|
883
|
+
@pedump.logger.fatal "[!] invalid resource id #{id.inspect}"
|
|
884
|
+
exit(1)
|
|
885
|
+
end
|
|
886
|
+
unless res
|
|
887
|
+
@pedump.logger.fatal "[!] resource #{id.inspect} not found"
|
|
888
|
+
exit(1)
|
|
889
|
+
end
|
|
890
|
+
IO::copy_stream @pedump.io, $stdout, res.size, res.file_offset
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
def extract_section id
|
|
894
|
+
section = nil
|
|
895
|
+
if id['/']
|
|
896
|
+
a = id.split('/',2)
|
|
897
|
+
if a[0] == 'rva'
|
|
898
|
+
value = a[1].to_i(0) # auto hex/dec, but also can parse oct and bin
|
|
899
|
+
section = @pedump.sections.find{ |s| s.VirtualAddress == value }
|
|
900
|
+
elsif a[0] == 'raw'
|
|
901
|
+
value = a[1].to_i(0) # auto hex/dec, but also can parse oct and bin
|
|
902
|
+
section = @pedump.sections.find{ |s| s.PointerToRawData == value }
|
|
903
|
+
else
|
|
904
|
+
@pedump.logger.fatal "[!] invalid section id #{id.inspect}"
|
|
905
|
+
exit(1)
|
|
906
|
+
end
|
|
907
|
+
else
|
|
908
|
+
section = @pedump.sections.find{ |s| s.Name == id }
|
|
909
|
+
end
|
|
910
|
+
unless section
|
|
911
|
+
@pedump.logger.fatal "[!] section #{id.inspect} not found"
|
|
912
|
+
exit(1)
|
|
913
|
+
end
|
|
914
|
+
IO::copy_stream @pedump.io, $stdout, section.SizeOfRawData, section.PointerToRawData
|
|
915
|
+
end
|
|
916
|
+
|
|
818
917
|
end # class PEdump::CLI
|
data/pedump.gemspec
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
|
5
|
-
# stub: pedump 0.6.
|
|
5
|
+
# stub: pedump 0.6.2 ruby lib
|
|
6
6
|
|
|
7
7
|
Gem::Specification.new do |s|
|
|
8
8
|
s.name = "pedump".freeze
|
|
9
|
-
s.version = "0.6.
|
|
9
|
+
s.version = "0.6.2"
|
|
10
10
|
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
|
12
12
|
s.require_paths = ["lib".freeze]
|
|
13
13
|
s.authors = ["Andrey \"Zed\" Zaikin".freeze]
|
|
14
|
-
s.date = "
|
|
14
|
+
s.date = "2021-02-18"
|
|
15
15
|
s.description = "dump headers, sections, extract resources of win32 PE exe,dll,etc".freeze
|
|
16
16
|
s.email = "zed.0xff@gmail.com".freeze
|
|
17
17
|
s.executables = ["pedump".freeze]
|
|
@@ -20,8 +20,7 @@ Gem::Specification.new do |s|
|
|
|
20
20
|
"README.md"
|
|
21
21
|
]
|
|
22
22
|
s.files = [
|
|
23
|
-
".github/
|
|
24
|
-
".github/dependabot.yml",
|
|
23
|
+
".github/workflows/rubocop-analysis.yml",
|
|
25
24
|
"CODE_OF_CONDUCT.md",
|
|
26
25
|
"Gemfile",
|
|
27
26
|
"Gemfile.lock",
|
|
@@ -66,38 +65,27 @@ Gem::Specification.new do |s|
|
|
|
66
65
|
"misc/aspack/lzxdec.c",
|
|
67
66
|
"misc/aspack/lzxdec.h",
|
|
68
67
|
"misc/nedump.c",
|
|
69
|
-
"pedump.gemspec"
|
|
70
|
-
"rich.py"
|
|
68
|
+
"pedump.gemspec"
|
|
71
69
|
]
|
|
72
70
|
s.homepage = "http://github.com/zed-0xff/pedump".freeze
|
|
73
71
|
s.licenses = ["MIT".freeze]
|
|
74
|
-
s.rubygems_version = "2.
|
|
72
|
+
s.rubygems_version = "3.2.3".freeze
|
|
75
73
|
s.summary = "dump win32 PE executable files with a pure ruby".freeze
|
|
76
74
|
|
|
77
75
|
if s.respond_to? :specification_version then
|
|
78
76
|
s.specification_version = 4
|
|
77
|
+
end
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
else
|
|
91
|
-
s.add_dependency(%q<rainbow>.freeze, [">= 0"])
|
|
92
|
-
s.add_dependency(%q<awesome_print>.freeze, [">= 0"])
|
|
93
|
-
s.add_dependency(%q<iostruct>.freeze, [">= 0.0.4"])
|
|
94
|
-
s.add_dependency(%q<multipart-post>.freeze, [">= 2.0.0"])
|
|
95
|
-
s.add_dependency(%q<zhexdump>.freeze, [">= 0.0.2"])
|
|
96
|
-
s.add_dependency(%q<rspec>.freeze, ["~> 3.9.0"])
|
|
97
|
-
s.add_dependency(%q<rspec-its>.freeze, ["~> 1.3.0"])
|
|
98
|
-
s.add_dependency(%q<bundler>.freeze, ["~> 2.1.4"])
|
|
99
|
-
s.add_dependency(%q<jeweler>.freeze, ["~> 2.3.9"])
|
|
100
|
-
end
|
|
79
|
+
if s.respond_to? :add_runtime_dependency then
|
|
80
|
+
s.add_runtime_dependency(%q<rainbow>.freeze, [">= 0"])
|
|
81
|
+
s.add_runtime_dependency(%q<awesome_print>.freeze, [">= 0"])
|
|
82
|
+
s.add_runtime_dependency(%q<iostruct>.freeze, [">= 0.0.4"])
|
|
83
|
+
s.add_runtime_dependency(%q<multipart-post>.freeze, [">= 2.0.0"])
|
|
84
|
+
s.add_runtime_dependency(%q<zhexdump>.freeze, [">= 0.0.2"])
|
|
85
|
+
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.9.0"])
|
|
86
|
+
s.add_development_dependency(%q<rspec-its>.freeze, ["~> 1.3.0"])
|
|
87
|
+
s.add_development_dependency(%q<bundler>.freeze, ["~> 2.2.3"])
|
|
88
|
+
s.add_development_dependency(%q<jeweler>.freeze, ["~> 2.3.9"])
|
|
101
89
|
else
|
|
102
90
|
s.add_dependency(%q<rainbow>.freeze, [">= 0"])
|
|
103
91
|
s.add_dependency(%q<awesome_print>.freeze, [">= 0"])
|
|
@@ -106,7 +94,7 @@ Gem::Specification.new do |s|
|
|
|
106
94
|
s.add_dependency(%q<zhexdump>.freeze, [">= 0.0.2"])
|
|
107
95
|
s.add_dependency(%q<rspec>.freeze, ["~> 3.9.0"])
|
|
108
96
|
s.add_dependency(%q<rspec-its>.freeze, ["~> 1.3.0"])
|
|
109
|
-
s.add_dependency(%q<bundler>.freeze, ["~> 2.
|
|
97
|
+
s.add_dependency(%q<bundler>.freeze, ["~> 2.2.3"])
|
|
110
98
|
s.add_dependency(%q<jeweler>.freeze, ["~> 2.3.9"])
|
|
111
99
|
end
|
|
112
100
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pedump
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.
|
|
4
|
+
version: 0.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrey "Zed" Zaikin
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-02-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rainbow
|
|
@@ -114,14 +114,14 @@ dependencies:
|
|
|
114
114
|
requirements:
|
|
115
115
|
- - "~>"
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: 2.
|
|
117
|
+
version: 2.2.3
|
|
118
118
|
type: :development
|
|
119
119
|
prerelease: false
|
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
121
|
requirements:
|
|
122
122
|
- - "~>"
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: 2.
|
|
124
|
+
version: 2.2.3
|
|
125
125
|
- !ruby/object:Gem::Dependency
|
|
126
126
|
name: jeweler
|
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -145,8 +145,7 @@ extra_rdoc_files:
|
|
|
145
145
|
- LICENSE.txt
|
|
146
146
|
- README.md
|
|
147
147
|
files:
|
|
148
|
-
- ".github/
|
|
149
|
-
- ".github/dependabot.yml"
|
|
148
|
+
- ".github/workflows/rubocop-analysis.yml"
|
|
150
149
|
- CODE_OF_CONDUCT.md
|
|
151
150
|
- Gemfile
|
|
152
151
|
- Gemfile.lock
|
|
@@ -192,12 +191,11 @@ files:
|
|
|
192
191
|
- misc/aspack/lzxdec.h
|
|
193
192
|
- misc/nedump.c
|
|
194
193
|
- pedump.gemspec
|
|
195
|
-
- rich.py
|
|
196
194
|
homepage: http://github.com/zed-0xff/pedump
|
|
197
195
|
licenses:
|
|
198
196
|
- MIT
|
|
199
197
|
metadata: {}
|
|
200
|
-
post_install_message:
|
|
198
|
+
post_install_message:
|
|
201
199
|
rdoc_options: []
|
|
202
200
|
require_paths:
|
|
203
201
|
- lib
|
|
@@ -212,9 +210,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
212
210
|
- !ruby/object:Gem::Version
|
|
213
211
|
version: '0'
|
|
214
212
|
requirements: []
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
signing_key:
|
|
213
|
+
rubygems_version: 3.2.3
|
|
214
|
+
signing_key:
|
|
218
215
|
specification_version: 4
|
|
219
216
|
summary: dump win32 PE executable files with a pure ruby
|
|
220
217
|
test_files: []
|
data/.github/FUNDING.yml
DELETED
data/.github/dependabot.yml
DELETED
data/rich.py
DELETED
|
@@ -1,353 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# based on code from http://trendystephen.blogspot.be/2008/01/rich-header.html
|
|
3
|
-
import sys
|
|
4
|
-
import struct
|
|
5
|
-
|
|
6
|
-
# I'm trying not to bury the magic number...
|
|
7
|
-
CHECKSUM_MASK = 0x536e6144 # DanS (actuall SnaD)
|
|
8
|
-
RICH_TEXT = 'Rich'
|
|
9
|
-
RICH_TEXT_LENGTH = len(RICH_TEXT)
|
|
10
|
-
PE_START = 0x3c
|
|
11
|
-
PE_FIELD_LENGTH = 4
|
|
12
|
-
|
|
13
|
-
# most of values up to AliasObj900 are from old MSVC leak with private PDBs;
|
|
14
|
-
# rest is from guesses/observations
|
|
15
|
-
PRODID_MAP = {
|
|
16
|
-
0: "Unknown",
|
|
17
|
-
1: "Import0",
|
|
18
|
-
2: "Linker510",
|
|
19
|
-
3: "Cvtomf510",
|
|
20
|
-
4: "Linker600",
|
|
21
|
-
5: "Cvtomf600",
|
|
22
|
-
6: "Cvtres500",
|
|
23
|
-
7: "Utc11_Basic",
|
|
24
|
-
8: "Utc11_C",
|
|
25
|
-
9: "Utc12_Basic",
|
|
26
|
-
10: "Utc12_C",
|
|
27
|
-
11: "Utc12_CPP",
|
|
28
|
-
12: "AliasObj60",
|
|
29
|
-
13: "VisualBasic60",
|
|
30
|
-
14: "Masm613",
|
|
31
|
-
15: "Masm710",
|
|
32
|
-
16: "Linker511",
|
|
33
|
-
17: "Cvtomf511",
|
|
34
|
-
18: "Masm614",
|
|
35
|
-
19: "Linker512",
|
|
36
|
-
20: "Cvtomf512",
|
|
37
|
-
21: "Utc12_C_Std",
|
|
38
|
-
22: "Utc12_CPP_Std",
|
|
39
|
-
23: "Utc12_C_Book",
|
|
40
|
-
24: "Utc12_CPP_Book",
|
|
41
|
-
25: "Implib700",
|
|
42
|
-
26: "Cvtomf700",
|
|
43
|
-
27: "Utc13_Basic",
|
|
44
|
-
28: "Utc13_C",
|
|
45
|
-
29: "Utc13_CPP",
|
|
46
|
-
30: "Linker610",
|
|
47
|
-
31: "Cvtomf610",
|
|
48
|
-
32: "Linker601",
|
|
49
|
-
33: "Cvtomf601",
|
|
50
|
-
34: "Utc12_1_Basic",
|
|
51
|
-
35: "Utc12_1_C",
|
|
52
|
-
36: "Utc12_1_CPP",
|
|
53
|
-
37: "Linker620",
|
|
54
|
-
38: "Cvtomf620",
|
|
55
|
-
39: "AliasObj70",
|
|
56
|
-
40: "Linker621",
|
|
57
|
-
41: "Cvtomf621",
|
|
58
|
-
42: "Masm615",
|
|
59
|
-
43: "Utc13_LTCG_C",
|
|
60
|
-
44: "Utc13_LTCG_CPP",
|
|
61
|
-
45: "Masm620",
|
|
62
|
-
46: "ILAsm100",
|
|
63
|
-
47: "Utc12_2_Basic",
|
|
64
|
-
48: "Utc12_2_C",
|
|
65
|
-
49: "Utc12_2_CPP",
|
|
66
|
-
50: "Utc12_2_C_Std",
|
|
67
|
-
51: "Utc12_2_CPP_Std",
|
|
68
|
-
52: "Utc12_2_C_Book",
|
|
69
|
-
53: "Utc12_2_CPP_Book",
|
|
70
|
-
54: "Implib622",
|
|
71
|
-
55: "Cvtomf622",
|
|
72
|
-
56: "Cvtres501",
|
|
73
|
-
57: "Utc13_C_Std",
|
|
74
|
-
58: "Utc13_CPP_Std",
|
|
75
|
-
59: "Cvtpgd1300",
|
|
76
|
-
60: "Linker622",
|
|
77
|
-
61: "Linker700",
|
|
78
|
-
62: "Export622",
|
|
79
|
-
63: "Export700",
|
|
80
|
-
64: "Masm700",
|
|
81
|
-
65: "Utc13_POGO_I_C",
|
|
82
|
-
66: "Utc13_POGO_I_CPP",
|
|
83
|
-
67: "Utc13_POGO_O_C",
|
|
84
|
-
68: "Utc13_POGO_O_CPP",
|
|
85
|
-
69: "Cvtres700",
|
|
86
|
-
70: "Cvtres710p",
|
|
87
|
-
71: "Linker710p",
|
|
88
|
-
72: "Cvtomf710p",
|
|
89
|
-
73: "Export710p",
|
|
90
|
-
74: "Implib710p",
|
|
91
|
-
75: "Masm710p",
|
|
92
|
-
76: "Utc1310p_C",
|
|
93
|
-
77: "Utc1310p_CPP",
|
|
94
|
-
78: "Utc1310p_C_Std",
|
|
95
|
-
79: "Utc1310p_CPP_Std",
|
|
96
|
-
80: "Utc1310p_LTCG_C",
|
|
97
|
-
81: "Utc1310p_LTCG_CPP",
|
|
98
|
-
82: "Utc1310p_POGO_I_C",
|
|
99
|
-
83: "Utc1310p_POGO_I_CPP",
|
|
100
|
-
84: "Utc1310p_POGO_O_C",
|
|
101
|
-
85: "Utc1310p_POGO_O_CPP",
|
|
102
|
-
86: "Linker624",
|
|
103
|
-
87: "Cvtomf624",
|
|
104
|
-
88: "Export624",
|
|
105
|
-
89: "Implib624",
|
|
106
|
-
90: "Linker710",
|
|
107
|
-
91: "Cvtomf710",
|
|
108
|
-
92: "Export710",
|
|
109
|
-
93: "Implib710",
|
|
110
|
-
94: "Cvtres710",
|
|
111
|
-
95: "Utc1310_C",
|
|
112
|
-
96: "Utc1310_CPP",
|
|
113
|
-
97: "Utc1310_C_Std",
|
|
114
|
-
98: "Utc1310_CPP_Std",
|
|
115
|
-
99: "Utc1310_LTCG_C",
|
|
116
|
-
100: "Utc1310_LTCG_CPP",
|
|
117
|
-
101: "Utc1310_POGO_I_C",
|
|
118
|
-
102: "Utc1310_POGO_I_CPP",
|
|
119
|
-
103: "Utc1310_POGO_O_C",
|
|
120
|
-
104: "Utc1310_POGO_O_CPP",
|
|
121
|
-
105: "AliasObj710",
|
|
122
|
-
106: "AliasObj710p",
|
|
123
|
-
107: "Cvtpgd1310",
|
|
124
|
-
108: "Cvtpgd1310p",
|
|
125
|
-
109: "Utc1400_C",
|
|
126
|
-
110: "Utc1400_CPP",
|
|
127
|
-
111: "Utc1400_C_Std",
|
|
128
|
-
112: "Utc1400_CPP_Std",
|
|
129
|
-
113: "Utc1400_LTCG_C",
|
|
130
|
-
114: "Utc1400_LTCG_CPP",
|
|
131
|
-
115: "Utc1400_POGO_I_C",
|
|
132
|
-
116: "Utc1400_POGO_I_CPP",
|
|
133
|
-
117: "Utc1400_POGO_O_C",
|
|
134
|
-
118: "Utc1400_POGO_O_CPP",
|
|
135
|
-
119: "Cvtpgd1400",
|
|
136
|
-
120: "Linker800",
|
|
137
|
-
121: "Cvtomf800",
|
|
138
|
-
122: "Export800",
|
|
139
|
-
123: "Implib800",
|
|
140
|
-
124: "Cvtres800",
|
|
141
|
-
125: "Masm800",
|
|
142
|
-
126: "AliasObj800",
|
|
143
|
-
127: "PhoenixPrerelease",
|
|
144
|
-
128: "Utc1400_CVTCIL_C",
|
|
145
|
-
129: "Utc1400_CVTCIL_CPP",
|
|
146
|
-
130: "Utc1400_LTCG_MSIL",
|
|
147
|
-
131: "Utc1500_C",
|
|
148
|
-
132: "Utc1500_CPP",
|
|
149
|
-
133: "Utc1500_C_Std",
|
|
150
|
-
134: "Utc1500_CPP_Std",
|
|
151
|
-
135: "Utc1500_CVTCIL_C",
|
|
152
|
-
136: "Utc1500_CVTCIL_CPP",
|
|
153
|
-
137: "Utc1500_LTCG_C",
|
|
154
|
-
138: "Utc1500_LTCG_CPP",
|
|
155
|
-
139: "Utc1500_LTCG_MSIL",
|
|
156
|
-
140: "Utc1500_POGO_I_C",
|
|
157
|
-
141: "Utc1500_POGO_I_CPP",
|
|
158
|
-
142: "Utc1500_POGO_O_C",
|
|
159
|
-
143: "Utc1500_POGO_O_CPP",
|
|
160
|
-
|
|
161
|
-
144: "Cvtpgd1500",
|
|
162
|
-
145: "Linker900",
|
|
163
|
-
146: "Export900",
|
|
164
|
-
147: "Implib900",
|
|
165
|
-
148: "Cvtres900",
|
|
166
|
-
149: "Masm900",
|
|
167
|
-
150: "AliasObj900",
|
|
168
|
-
151: "Resource900",
|
|
169
|
-
|
|
170
|
-
152: "AliasObj1000",
|
|
171
|
-
154: "Cvtres1000",
|
|
172
|
-
155: "Export1000",
|
|
173
|
-
156: "Implib1000",
|
|
174
|
-
157: "Linker1000",
|
|
175
|
-
158: "Masm1000",
|
|
176
|
-
|
|
177
|
-
170: "Utc1600_C",
|
|
178
|
-
171: "Utc1600_CPP",
|
|
179
|
-
172: "Utc1600_CVTCIL_C",
|
|
180
|
-
173: "Utc1600_CVTCIL_CPP",
|
|
181
|
-
174: "Utc1600_LTCG_C ",
|
|
182
|
-
175: "Utc1600_LTCG_CPP",
|
|
183
|
-
176: "Utc1600_LTCG_MSIL",
|
|
184
|
-
177: "Utc1600_POGO_I_C",
|
|
185
|
-
178: "Utc1600_POGO_I_CPP",
|
|
186
|
-
179: "Utc1600_POGO_O_C",
|
|
187
|
-
180: "Utc1600_POGO_O_CPP",
|
|
188
|
-
|
|
189
|
-
# vvv
|
|
190
|
-
183: "Linker1010",
|
|
191
|
-
184: "Export1010",
|
|
192
|
-
185: "Implib1010",
|
|
193
|
-
186: "Cvtres1010",
|
|
194
|
-
187: "Masm1010",
|
|
195
|
-
188: "AliasObj1010",
|
|
196
|
-
# ^^^
|
|
197
|
-
|
|
198
|
-
199: "AliasObj1100",
|
|
199
|
-
201: "Cvtres1100",
|
|
200
|
-
202: "Export1100",
|
|
201
|
-
203: "Implib1100",
|
|
202
|
-
204: "Linker1100",
|
|
203
|
-
205: "Masm1100",
|
|
204
|
-
|
|
205
|
-
206: "Utc1700_C",
|
|
206
|
-
207: "Utc1700_CPP",
|
|
207
|
-
208: "Utc1700_CVTCIL_C",
|
|
208
|
-
209: "Utc1700_CVTCIL_CPP",
|
|
209
|
-
210: "Utc1700_LTCG_C ",
|
|
210
|
-
211: "Utc1700_LTCG_CPP",
|
|
211
|
-
212: "Utc1700_LTCG_MSIL",
|
|
212
|
-
213: "Utc1700_POGO_I_C",
|
|
213
|
-
214: "Utc1700_POGO_I_CPP",
|
|
214
|
-
215: "Utc1700_POGO_O_C",
|
|
215
|
-
216: "Utc1700_POGO_O_CPP",
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
##
|
|
219
|
-
# A convenient exception to raise if the Rich Header doesn't exist.
|
|
220
|
-
class RichHeaderNotFoundException(Exception):
|
|
221
|
-
def __init__(self):
|
|
222
|
-
Exception.__init__(self, "Rich footer does not appear to exist")
|
|
223
|
-
|
|
224
|
-
##
|
|
225
|
-
# Locate the body of the data that contains the rich header This will be
|
|
226
|
-
# (roughly) between 0x3c and the beginning of the PE header, but the entire
|
|
227
|
-
# thing up to the last checksum will be needed in order to verify the header.
|
|
228
|
-
def get_file_header(file_name):
|
|
229
|
-
f = open(file_name,'rb')
|
|
230
|
-
|
|
231
|
-
#start with 0x3c
|
|
232
|
-
f.seek(PE_START)
|
|
233
|
-
data = f.read(PE_FIELD_LENGTH)
|
|
234
|
-
|
|
235
|
-
if data == '': #File is empty, bail
|
|
236
|
-
raise RichHeaderNotFoundException()
|
|
237
|
-
end = struct.unpack('<L',data)[0] # get the value at 0x3c
|
|
238
|
-
|
|
239
|
-
f.seek(0)
|
|
240
|
-
data = f.read( end ) # read until that value is reached
|
|
241
|
-
f.close()
|
|
242
|
-
|
|
243
|
-
return data
|
|
244
|
-
|
|
245
|
-
##
|
|
246
|
-
# This class assists in parsing the Rich Header from PE Files.
|
|
247
|
-
# The Rich Header is the section in the PE file following the dos stub but
|
|
248
|
-
# preceding the lfa_new header which is inserted by link.exe when building with
|
|
249
|
-
# the Microsoft Compilers. The Rich Heder contains the following:
|
|
250
|
-
# <pre>
|
|
251
|
-
# marker, checksum, checksum, checksum,
|
|
252
|
-
# R_compid_i, R_occurrence_i,
|
|
253
|
-
# R_compid_i+1, R_occurrence_i+1, ...
|
|
254
|
-
# R_compid_N-1, R_occurrence_N-1, Rich, marker
|
|
255
|
-
#
|
|
256
|
-
# marker = checksum XOR 0x536e6144
|
|
257
|
-
# R_compid_i is the ith compid XORed with the checksum
|
|
258
|
-
# R_occurrence_i is the ith occurrence XORed with the checksum
|
|
259
|
-
# Rich = the text string 'Rich'
|
|
260
|
-
# The checksum is the sum of all the PE Header values rotated by their
|
|
261
|
-
# offset and the sum of all compids rotated by their occurrence counts.
|
|
262
|
-
# </pre>
|
|
263
|
-
# @see _validate_checksum code for checksum calculation
|
|
264
|
-
class ParsedRichHeader:
|
|
265
|
-
##
|
|
266
|
-
# Creates a ParsedRichHeader from the specified PE File.
|
|
267
|
-
# @throws RichHeaderNotFoundException if the file does not contain a rich header
|
|
268
|
-
# @param file_name The PE File to be parsed
|
|
269
|
-
def __init__(self, file_name):
|
|
270
|
-
## The file that was parsed
|
|
271
|
-
self.file_name = file_name
|
|
272
|
-
self._parse( file_name )
|
|
273
|
-
|
|
274
|
-
##
|
|
275
|
-
# Used internally to parse the PE File and extract Rich Header data.
|
|
276
|
-
# Initializes self.compids and self.valid_checksum.
|
|
277
|
-
# @param file_name The PE File to be parsed
|
|
278
|
-
# @throws RichHeaderNotFoundException if the file does not contain a rich header
|
|
279
|
-
def _parse(self,file_name):
|
|
280
|
-
#make sure there is a header:
|
|
281
|
-
data = get_file_header( file_name )
|
|
282
|
-
|
|
283
|
-
compid_end_index = data.find(RICH_TEXT)
|
|
284
|
-
if compid_end_index == -1:
|
|
285
|
-
raise RichHeaderNotFoundException()
|
|
286
|
-
|
|
287
|
-
rich_offset = compid_end_index + RICH_TEXT_LENGTH
|
|
288
|
-
|
|
289
|
-
checksum_text = data[rich_offset:rich_offset+4]
|
|
290
|
-
checksum_value = struct.unpack('<L', checksum_text)[0]
|
|
291
|
-
#start marker denotes the beginning of the rich header
|
|
292
|
-
start_marker = struct.pack('<LLLL',checksum_value ^ CHECKSUM_MASK, checksum_value, checksum_value, checksum_value )[0]
|
|
293
|
-
|
|
294
|
-
rich_header_start = data.find(start_marker)
|
|
295
|
-
if rich_header_start == -1:
|
|
296
|
-
raise RichHeaderNotFoundException()
|
|
297
|
-
|
|
298
|
-
compid_start_index = rich_header_start + 16 # move past the marker and 3 checksums
|
|
299
|
-
|
|
300
|
-
compids = dict()
|
|
301
|
-
for i in range(compid_start_index, compid_end_index, 8):
|
|
302
|
-
compid = struct.unpack('<L',data[i:i+4])[0] ^ checksum_value
|
|
303
|
-
count = struct.unpack('<L',data[i+4:i+8])[0] ^ checksum_value
|
|
304
|
-
compids[compid]=count
|
|
305
|
-
|
|
306
|
-
## A dictionary of compids and their occurrence counts
|
|
307
|
-
self.compids = compids
|
|
308
|
-
## A value for later reference to see if the checksum was valid
|
|
309
|
-
self.valid_checksum = self._validate_checksum( data, rich_header_start, checksum_value )
|
|
310
|
-
|
|
311
|
-
##
|
|
312
|
-
# Compute the checksum value and see if it matches the checksum stored in
|
|
313
|
-
# the Rich Header.
|
|
314
|
-
# The checksum is the sum of all the PE Header values rotated by their
|
|
315
|
-
# offset and the sum of all compids rotated by their occurrence counts
|
|
316
|
-
# @param data A blob of binary data that corresponds to the PE Header data
|
|
317
|
-
# @param rich_header_start The offset to marker, checksum, checksum, checksum
|
|
318
|
-
# @returns True if the checksum is valid, false otherwise
|
|
319
|
-
def _validate_checksum(self, data, rich_header_start, checksum):
|
|
320
|
-
|
|
321
|
-
#initialize the checksum offset at which the rich header is located
|
|
322
|
-
cksum = rich_header_start
|
|
323
|
-
|
|
324
|
-
#add the value from the pe header after rotating the value by its offset in the pe header
|
|
325
|
-
for i in range(0,rich_header_start):
|
|
326
|
-
if PE_START <= i <= PE_START+PE_FIELD_LENGTH-1:
|
|
327
|
-
continue
|
|
328
|
-
temp = ord(data[i])
|
|
329
|
-
cksum+= ((temp << (i%32)) | (temp >> (32-(i%32))) & 0xff)
|
|
330
|
-
cksum &=0xffffffff
|
|
331
|
-
|
|
332
|
-
#add each compid to the checksum after rotating it by its occurrence count
|
|
333
|
-
for k in self.compids.keys():
|
|
334
|
-
cksum += (k << self.compids[k]%32 | k >> ( 32 - (self.compids[k]%32)))
|
|
335
|
-
cksum &=0xffffffff
|
|
336
|
-
|
|
337
|
-
## A convenient place for storing the checksum that was computing during checksum validation
|
|
338
|
-
self.checksum = cksum
|
|
339
|
-
|
|
340
|
-
return cksum == checksum
|
|
341
|
-
|
|
342
|
-
if __name__ == "__main__":
|
|
343
|
-
ph = ParsedRichHeader(sys.argv[1])
|
|
344
|
-
print ("PRODID name build count")
|
|
345
|
-
for key in ph.compids.keys():
|
|
346
|
-
count = ph.compids[key]
|
|
347
|
-
prodid, build = (key>>16), key&0xFFFF
|
|
348
|
-
prodid_name = PRODID_MAP[prodid] if prodid in PRODID_MAP else "<unknown>"
|
|
349
|
-
print ('%6d %-15s %5d %5d' % (prodid, prodid_name, build, count))
|
|
350
|
-
if ph.valid_checksum:
|
|
351
|
-
print ("Checksum valid")
|
|
352
|
-
else:
|
|
353
|
-
print("Checksum not valid!")
|