pedump 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
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!")