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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23748b86fb8ea0471bd4805e7bafda25f5bb6279cf2acf28f6d05ac5913a33d2
4
- data.tar.gz: 327d5c2e046a70d262a957ccc334d53adfc9ce6d55cba61c8b0efa4e3d70ef0c
3
+ metadata.gz: 9d4f9c13c95df2d30baf18bba07765fa26f1d4066a8abde228cba5cd29bc9df0
4
+ data.tar.gz: b034a68704793f502843db9ec791ca636e404b20258ae144a349e718eaf8a6b6
5
5
  SHA512:
6
- metadata.gz: ec5ef9e264bdcfb7d1b2c52be51d2c6fd5548fdd36a4f7e20570998740a5dfd624d546b82398326e339f42291e364d5dfdc156dfe348030a981bf071aee6722f
7
- data.tar.gz: a557ebc6dd98b211ff3096bf09fb8d8c4742c7b1cf2db965eeac4f74e77361e22c133a231a946b59ac28925ffc1188e70b110534775b0968438fa93e42163a8d
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
@@ -10,6 +10,6 @@ gem "zhexdump", ">= 0.0.2"
10
10
  group :development do
11
11
  gem "rspec", "~> 3.9.0"
12
12
  gem "rspec-its", "~> 1.3.0"
13
- gem "bundler", "~> 2.1.4"
13
+ gem "bundler", "~> 2.2.3"
14
14
  gem "jeweler", "~> 2.3.9"
15
15
  end
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.3)
9
+ diff-lcs (1.4.4)
10
10
  faraday (0.9.2)
11
11
  multipart-post (>= 1.2, < 3)
12
- git (1.5.0)
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.0.0)
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.1)
35
+ jwt (2.2.2)
35
36
  mime-types (2.99.3)
36
- mini_portile2 (2.4.0)
37
- multi_json (1.14.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.10.8)
41
- mini_portile2 (~> 2.4.0)
42
- oauth2 (1.4.2)
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.1.0)
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.1)
52
- rdoc (6.2.1)
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.1)
58
- rspec-support (~> 3.9.1)
59
- rspec-expectations (3.9.0)
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.2)
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.1.4)
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.1.4
92
+ 2.2.3
data/README.md CHANGED
@@ -3,8 +3,14 @@ pedump [![Build Status](https://travis-ci.org/zed-0xff/pedump.png?branch=mast
3
3
 
4
4
  News
5
5
  ----
6
+ ```
7
+ 2021.02.18 - updated gems; changed open-uri to URI.open; enabled SSL on https://pedump.me/
8
+ 2020.08.09 - CLI: added resource extracting with --extract ID
9
+ 2020.07.28 - 0.6.1; better RICH HDR parsing/output
10
+ 2020.07.27 - 0.6.0
6
11
  2020.07.26 - now travis autotests run on ARM and OSX too!
7
12
  2020.07.25 - added EFI TE parsing; removed 'progressbar' gem dependency
13
+ ```
8
14
 
9
15
  Description
10
16
  -----------
@@ -30,7 +36,7 @@ Can dump:
30
36
  * Imports & Exports
31
37
  * VS_VERSIONINFO parsing
32
38
  * PE Packer/Compiler detection
33
- * a convenient way to upload your PE's to http://pedump.me for a nice HTML tables with image previews, candies & stuff
39
+ * a convenient way to upload your PE's to https://pedump.me for a nice HTML tables with image previews, candies & stuff
34
40
 
35
41
  Installation
36
42
  ------------
@@ -73,9 +79,17 @@ Usage
73
79
  mimics 'file' command output
74
80
  -r, --recursive recurse dirs in packer detect
75
81
  --all Dump all but resource-directory (default)
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 http://pedump.me
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
- LIB_ID VERSION TIMES_USED
131
- 149 95 21022 521e 9 9
132
- 1 1 0 0 367 16f
133
- 147 93 21022 521e 29 1d
134
- 132 84 21022 521e 129 81
135
- 131 83 21022 521e 25 19
136
- 148 94 21022 521e 1 1
137
- 145 91 21022 521e 1 1
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 = open(url).read.force_encoding('cp1252').encode('utf-8')
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
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 http://pedump.me/03ad7400080678c6b1984f995d36fd04
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 = "http://pedump.me"
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 fname
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 fname
157
- PEdump.new(fname, :force => @options[:force]).tap do |x|
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 = STDOUT
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 = STDOUT.sync
232
- STDOUT.sync = true
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
- Net::HTTP.start('pedump.me') do |http|
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){ |http| http.request(req) }
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
- puts "[.] analyzing..."
265
-
266
- if (r=open(File.join(URL_BASE,md5,'analyze')).read) != "OK"
267
- raise "invalid server response: #{r}"
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
- STDOUT.sync = stdout_sync
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.1 ruby lib
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.1"
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 = "2020-07-28"
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/FUNDING.yml",
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.7.10".freeze
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
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
81
- s.add_runtime_dependency(%q<rainbow>.freeze, [">= 0"])
82
- s.add_runtime_dependency(%q<awesome_print>.freeze, [">= 0"])
83
- s.add_runtime_dependency(%q<iostruct>.freeze, [">= 0.0.4"])
84
- s.add_runtime_dependency(%q<multipart-post>.freeze, [">= 2.0.0"])
85
- s.add_runtime_dependency(%q<zhexdump>.freeze, [">= 0.0.2"])
86
- s.add_development_dependency(%q<rspec>.freeze, ["~> 3.9.0"])
87
- s.add_development_dependency(%q<rspec-its>.freeze, ["~> 1.3.0"])
88
- s.add_development_dependency(%q<bundler>.freeze, ["~> 2.1.4"])
89
- s.add_development_dependency(%q<jeweler>.freeze, ["~> 2.3.9"])
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.1.4"])
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.1
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: 2020-07-28 00:00:00.000000000 Z
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.1.4
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.1.4
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/FUNDING.yml"
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
- rubyforge_project:
216
- rubygems_version: 2.7.10
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
@@ -1,2 +0,0 @@
1
- #github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
2
- ko_fi: zed_0xff
@@ -1,8 +0,0 @@
1
- # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
2
-
3
- version: 2
4
- updates:
5
- - package-ecosystem: bundler
6
- directory: "/"
7
- schedule:
8
- interval: "weekly"
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!")