pedump 0.7.3 → 0.7.4

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: dd0f244a4510c9dd2d331be3789b3deae796e4b87c68a50c5ab21e5a757d1341
4
- data.tar.gz: f90e27cecf5b25275e2f53b92d8dd894bc5d10cc61ead2a2f7e6d174fe45c4ed
3
+ metadata.gz: 0a9b3066ff9e670b8562e068856e45b94e82cbcaf27f95626da87abc09b94f8f
4
+ data.tar.gz: 6f05ee901ce249c363ccafd0f54a04e693c8fcefd4c6ecca2663169a6db2cefd
5
5
  SHA512:
6
- metadata.gz: ca89ec6a27c7f7a0d25756bdcacddbd0e0edcf98d33dd7869ee4404d1c40f47610388d6516d120ef3367075185ec13e560f4835022ab20d35f650243cebce167
7
- data.tar.gz: fcc1b0194cd9d3ea39ad44e0f95f0d50432c697d45c5d6608bfeeb98214fef97d27a5660fa6cacdcd718c0a53fe3c043a8b628207be1834cdffb5e0f0f78459d
6
+ metadata.gz: c8a3eae0788ed2e1723324d1c4409f88f922ab23db56e899b1624847879506677cd98a437ce0f5980012fd6c1d6f70cae43bec9f9f8f75ad9ca09e7aad2e9cb5
7
+ data.tar.gz: 410622db1bc1052d2bbb114ea6e2d92989004a06e72ebbf9efaade47e4bc95d15ca028122901eba2ed087d40c97df765bc0e68bd38c4a0527d10925dc1c3954f
data/Gemfile CHANGED
@@ -3,7 +3,7 @@ source "https://rubygems.org"
3
3
 
4
4
  gem 'rainbow'
5
5
  gem "awesome_print"
6
- gem "iostruct", ">= 0.5.0"
6
+ gem "iostruct", ">= 0.7.0"
7
7
  gem "multipart-post", ">= 2.0.0"
8
8
  gem "zhexdump", ">= 0.0.2"
9
9
 
data/Gemfile.lock CHANGED
@@ -1,33 +1,33 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
- activesupport (8.0.1)
4
+ activesupport (8.1.2)
5
5
  base64
6
- benchmark (>= 0.3)
7
6
  bigdecimal
8
7
  concurrent-ruby (~> 1.0, >= 1.3.1)
9
8
  connection_pool (>= 2.2.5)
10
9
  drb
11
10
  i18n (>= 1.6, < 2)
11
+ json
12
12
  logger (>= 1.4.2)
13
13
  minitest (>= 5.1)
14
14
  securerandom (>= 0.3)
15
15
  tzinfo (~> 2.0, >= 2.0.5)
16
16
  uri (>= 0.13.1)
17
- addressable (2.8.7)
18
- public_suffix (>= 2.0.2, < 7.0)
17
+ addressable (2.8.8)
18
+ public_suffix (>= 2.0.2, < 8.0)
19
19
  awesome_print (1.9.2)
20
- base64 (0.2.0)
21
- benchmark (0.4.0)
22
- bigdecimal (3.1.9)
20
+ base64 (0.3.0)
21
+ bigdecimal (4.0.1)
23
22
  builder (3.3.0)
24
- concurrent-ruby (1.3.5)
25
- connection_pool (2.5.0)
26
- date (3.4.1)
23
+ concurrent-ruby (1.3.6)
24
+ connection_pool (3.0.2)
25
+ date (3.5.1)
27
26
  descendants_tracker (0.0.4)
28
27
  thread_safe (~> 0.3, >= 0.3.1)
29
- diff-lcs (1.6.0)
30
- drb (2.2.1)
28
+ diff-lcs (1.6.2)
29
+ drb (2.2.3)
30
+ erb (6.0.1)
31
31
  faraday (1.10.4)
32
32
  faraday-em_http (~> 1.0)
33
33
  faraday-em_synchrony (~> 1.0)
@@ -41,21 +41,21 @@ GEM
41
41
  faraday-retry (~> 1.0)
42
42
  ruby2_keywords (>= 0.0.4)
43
43
  faraday-em_http (1.0.0)
44
- faraday-em_synchrony (1.0.0)
44
+ faraday-em_synchrony (1.0.1)
45
45
  faraday-excon (1.1.0)
46
46
  faraday-httpclient (1.0.1)
47
- faraday-multipart (1.1.0)
47
+ faraday-multipart (1.2.0)
48
48
  multipart-post (~> 2.0)
49
49
  faraday-net_http (1.0.2)
50
50
  faraday-net_http_persistent (1.2.0)
51
51
  faraday-patron (1.0.0)
52
52
  faraday-rack (1.0.0)
53
53
  faraday-retry (1.0.3)
54
- git (2.3.3)
54
+ git (4.3.0)
55
55
  activesupport (>= 5.0)
56
56
  addressable (~> 2.8)
57
- process_executer (~> 1.1)
58
- rchardet (~> 1.8)
57
+ process_executer (~> 4.0)
58
+ rchardet (~> 1.9)
59
59
  github_api (0.19.0)
60
60
  addressable (~> 2.4)
61
61
  descendants_tracker (~> 0.0.4)
@@ -65,10 +65,11 @@ GEM
65
65
  hashie (3.6.0)
66
66
  highline (3.1.2)
67
67
  reline
68
- i18n (1.14.7)
68
+ i18n (1.14.8)
69
69
  concurrent-ruby (~> 1.0)
70
- io-console (0.8.0)
71
- iostruct (0.5.0)
70
+ io-console (0.8.2)
71
+ iostruct (0.7.0)
72
+ json (2.18.0)
72
73
  juwelier (2.4.9)
73
74
  builder
74
75
  bundler
@@ -81,29 +82,30 @@ GEM
81
82
  rake
82
83
  rdoc
83
84
  semver2
84
- jwt (2.10.1)
85
+ jwt (2.10.2)
85
86
  base64
86
87
  kamelcase (0.0.2)
87
88
  semver2 (~> 3)
88
- logger (1.6.6)
89
- mini_portile2 (2.8.8)
90
- minitest (5.25.4)
91
- multi_json (1.15.0)
92
- multi_xml (0.7.1)
93
- bigdecimal (~> 3.1)
89
+ logger (1.7.0)
90
+ mini_portile2 (2.8.9)
91
+ minitest (6.0.1)
92
+ prism (~> 1.5)
93
+ multi_json (1.19.1)
94
+ multi_xml (0.8.1)
95
+ bigdecimal (>= 3.1, < 5)
94
96
  multipart-post (2.4.1)
95
- nokogiri (1.18.4)
97
+ nokogiri (1.19.0)
96
98
  mini_portile2 (~> 2.8.2)
97
99
  racc (~> 1.4)
98
- nokogiri (1.18.4-aarch64-linux-gnu)
100
+ nokogiri (1.19.0-aarch64-linux-gnu)
99
101
  racc (~> 1.4)
100
- nokogiri (1.18.4-arm-linux-gnu)
102
+ nokogiri (1.19.0-arm-linux-gnu)
101
103
  racc (~> 1.4)
102
- nokogiri (1.18.4-arm64-darwin)
104
+ nokogiri (1.19.0-arm64-darwin)
103
105
  racc (~> 1.4)
104
- nokogiri (1.18.4-x86_64-darwin)
106
+ nokogiri (1.19.0-x86_64-darwin)
105
107
  racc (~> 1.4)
106
- nokogiri (1.18.4-x86_64-linux-gnu)
108
+ nokogiri (1.19.0-x86_64-linux-gnu)
107
109
  racc (~> 1.4)
108
110
  oauth2 (1.4.11)
109
111
  faraday (>= 0.17.3, < 3.0)
@@ -111,45 +113,51 @@ GEM
111
113
  multi_json (~> 1.3)
112
114
  multi_xml (~> 0.5)
113
115
  rack (>= 1.2, < 4)
114
- process_executer (1.3.0)
115
- psych (5.2.3)
116
+ prism (1.9.0)
117
+ process_executer (4.0.2)
118
+ track_open_instances (~> 0.1)
119
+ psych (5.3.1)
116
120
  date
117
121
  stringio
118
- public_suffix (6.0.1)
122
+ public_suffix (7.0.2)
119
123
  racc (1.8.1)
120
- rack (3.1.12)
124
+ rack (3.2.4)
121
125
  rainbow (3.1.1)
122
- rake (13.2.1)
123
- rchardet (1.9.0)
124
- rdoc (6.12.0)
126
+ rake (13.3.1)
127
+ rchardet (1.10.0)
128
+ rdoc (7.1.0)
129
+ erb
125
130
  psych (>= 4.0.0)
126
- reline (0.6.0)
131
+ tsort
132
+ reline (0.6.3)
127
133
  io-console (~> 0.5)
128
- rspec (3.13.0)
134
+ rspec (3.13.2)
129
135
  rspec-core (~> 3.13.0)
130
136
  rspec-expectations (~> 3.13.0)
131
137
  rspec-mocks (~> 3.13.0)
132
- rspec-core (3.13.3)
138
+ rspec-core (3.13.6)
133
139
  rspec-support (~> 3.13.0)
134
- rspec-expectations (3.13.3)
140
+ rspec-expectations (3.13.5)
135
141
  diff-lcs (>= 1.2.0, < 2.0)
136
142
  rspec-support (~> 3.13.0)
137
143
  rspec-its (2.0.0)
138
144
  rspec-core (>= 3.13.0)
139
145
  rspec-expectations (>= 3.13.0)
140
- rspec-mocks (3.13.2)
146
+ rspec-mocks (3.13.7)
141
147
  diff-lcs (>= 1.2.0, < 2.0)
142
148
  rspec-support (~> 3.13.0)
143
- rspec-support (3.13.2)
149
+ rspec-support (3.13.6)
144
150
  ruby2_keywords (0.0.5)
145
151
  securerandom (0.4.1)
146
152
  semver2 (3.4.2)
147
- stringio (3.1.5)
153
+ stringio (3.2.0)
148
154
  thread_safe (0.3.6)
155
+ track_open_instances (0.1.15)
156
+ tsort (0.2.0)
149
157
  tzinfo (2.0.6)
150
158
  concurrent-ruby (~> 1.0)
151
- uri (1.0.3)
152
- zhexdump (0.2.0)
159
+ uri (1.1.1)
160
+ zhexdump (0.3.0)
153
161
 
154
162
  PLATFORMS
155
163
  aarch64-linux
@@ -162,7 +170,7 @@ PLATFORMS
162
170
  DEPENDENCIES
163
171
  awesome_print
164
172
  bundler
165
- iostruct (>= 0.5.0)
173
+ iostruct (>= 0.7.0)
166
174
  juwelier
167
175
  multipart-post (>= 2.0.0)
168
176
  rainbow
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 Andrey "Zed" Zaikin
1
+ Copyright (c) 2011-2025 Andrey "Zed" Zaikin
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -4,6 +4,8 @@ pedump [![Build Status](https://travis-ci.org/zed-0xff/pedump.png?branch=mast
4
4
  News
5
5
  ----
6
6
  ```
7
+ 2026.01.28 - 0.7.4; update iostruct
8
+ 2025.11.11 - 0.7.3; CLI: fix --file2va command :]
7
9
  2025.11.11 - 0.7.1; CLI: add --file2va command
8
10
  2025.03.16 - added .NET CLR parsing
9
11
  2024.04.20 - cli: add --set-dll-char to patch dll characteristics
@@ -111,6 +113,8 @@ Usage
111
113
 
112
114
  --va2file VA Convert VA to file offset
113
115
  --file2va OFFSET Convert file offset to VA
116
+ --rva2file RVA Convert RVA to file offset
117
+ --file2rva OFFSET Convert file offset to RVA
114
118
 
115
119
  --set-os-version VER Patch OS version in PE header
116
120
  --set-dll-char X Patch IMAGE_OPTIONAL_HEADER32.DllCharacteristics
@@ -221,6 +225,28 @@ Usage
221
225
  LoaderFlags: 0
222
226
  NumberOfRvaAndSizes: 16 10
223
227
 
228
+ ### Convert (R)VA to file offset and back
229
+
230
+ # pedump --rva2file 0x4c000 calc.exe
231
+
232
+ rva2file(0x4c000) = 0x4ae00 (306688)
233
+
234
+ # pedump --file2rva 0x4ae00 calc.exe
235
+
236
+ file2rva(0x4ae00) = 0x4c000 (311296)
237
+
238
+ # pedump --va2file 0x104c000 calc.exe
239
+
240
+ va2file(0x104c000) = 0x4ae00 (306688)
241
+
242
+ # pedump --file2va 0x4ae00 calc.exe
243
+
244
+ file2va(0x4ae00) = 0x104c000 (17088512)
245
+
246
+ # pedump --file2va 0x4ae00 calc.exe --format hex
247
+
248
+ 104c000
249
+
224
250
  ### Data Directory
225
251
 
226
252
  # pedump --data-directory calc.exe
data/Rakefile CHANGED
@@ -37,11 +37,15 @@ RSpec::Core::RakeTask.new
37
37
 
38
38
  task :default => [:spec, :readme]
39
39
 
40
+ task :init do
41
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
42
+ require 'pedump'
43
+ require 'pedump/cli'
44
+ end
45
+
40
46
  namespace :test do
41
47
  desc "test on all files in given path"
42
- task :all_files do
43
- require './lib/pedump'
44
- require './lib/pedump/cli'
48
+ task :all_files => :init do
45
49
  path = ENV['path'] || raise("run me with path=...")
46
50
  `find #{path} -type f`.split("\n").each do |fname|
47
51
  puts "\n### #{fname}\n"
@@ -51,9 +55,7 @@ namespace :test do
51
55
 
52
56
  namespace :all_files do
53
57
  desc "output file name to stderr, use with stdout redirection"
54
- task :stderr do
55
- require './lib/pedump'
56
- require './lib/pedump/cli'
58
+ task :stderr => :init do
57
59
  path = ENV['path'] || raise("run me with path=...")
58
60
  `find #{path} -type f`.split("\n").each do |fname|
59
61
  STDERR.puts "\n### #{fname}\n"
@@ -63,9 +65,7 @@ namespace :test do
63
65
  end
64
66
 
65
67
  desc "test on corkami binaries"
66
- task :corkami do
67
- require './lib/pedump'
68
- require './lib/pedump/cli'
68
+ task :corkami => :init do
69
69
  path = "samples/corkami"
70
70
  `find #{path} -type f`.split("\n").each do |fname|
71
71
  STDERR.puts "\n### #{fname}\n"
@@ -183,7 +183,7 @@ task :readme do
183
183
  r << "\n"
184
184
  end
185
185
  Dir.chdir 'samples'
186
- result = ERB.new(tpl,nil,'%>').result
186
+ result = ERB.new(tpl, trim_mode: '%>').result
187
187
  Dir.chdir '..'
188
188
  File.open('README.md','w'){ |f| f << result }
189
189
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.3
1
+ 0.7.4
data/lib/pedump/cli.rb CHANGED
@@ -145,6 +145,12 @@ class PEdump::CLI
145
145
  opts.on "--file2va OFFSET", "Convert file offset to VA" do |offset|
146
146
  @actions << [:file2va, offset]
147
147
  end
148
+ opts.on "--rva2file RVA", "Convert RVA to file offset" do |va|
149
+ @actions << [:rva2file, va]
150
+ end
151
+ opts.on "--file2rva OFFSET", "Convert file offset to RVA" do |offset|
152
+ @actions << [:file2rva, offset]
153
+ end
148
154
 
149
155
  opts.separator ''
150
156
  opts.on "--set-os-version VER", "Patch OS version in PE header" do |ver|
@@ -385,13 +391,17 @@ class PEdump::CLI
385
391
  case action[0]
386
392
  when :disasm
387
393
  return
388
- when :va2file, :file2va
394
+ when :rva2file, :file2rva, :va2file, :file2va
389
395
  cmd = action[0]
390
396
  @pedump.sections(f)
391
- va = action[1] =~ /(^0x)|(h$)/i ? action[1].to_i(16) : action[1].to_i
392
- file_offset = @pedump.send(cmd, va)
393
- if file_offset
394
- printf("%s(0x%x) = 0x%x (%d)\n", cmd, va, file_offset, file_offset)
397
+ arg = action[1] =~ /(^0x)|(h$)/i ? action[1].to_i(16) : action[1].to_i
398
+ result = @pedump.send(cmd, arg)
399
+ if result
400
+ if @options[:format] == :hex
401
+ puts result.to_s(16)
402
+ else
403
+ printf("%s(0x%x) = 0x%x (%d)\n", cmd, arg, result, result)
404
+ end
395
405
  else
396
406
  @success = false
397
407
  end
@@ -652,7 +662,7 @@ class PEdump::CLI
652
662
 
653
663
  def dump_clr_streams data
654
664
  clr_header = @pedump.clr_header
655
- clr_data_file_ofs = clr_header.MetaData.va.to_i > 0 && @pedump.va2file(clr_header.MetaData.va)
665
+ clr_data_file_ofs = clr_header.MetaData.va.to_i > 0 && @pedump.rva2file(clr_header.MetaData.va)
656
666
 
657
667
  fmt = "%8x %8x %-32s\n"
658
668
  printf fmt.tr('x','s'), *%w'offset size name'
@@ -675,7 +685,7 @@ class PEdump::CLI
675
685
  blob_stream = @pedump.clr_streams.find{ |s| s.name == "#Blob" }
676
686
 
677
687
  clr_header = @pedump.clr_header
678
- clr_data_file_ofs = clr_header.MetaData.va.to_i > 0 && @pedump.va2file(clr_header.MetaData.va)
688
+ clr_data_file_ofs = clr_header.MetaData.va.to_i > 0 && @pedump.rva2file(clr_header.MetaData.va)
679
689
  blob_file_ofs = blob_stream.offset + clr_data_file_ofs if blob_stream
680
690
  blob_size = blob_stream&.size
681
691
 
@@ -892,7 +902,7 @@ class PEdump::CLI
892
902
  if @options[:verbose] > 0
893
903
  [%w'Names', %w'EntryPoints Functions', %w'Ordinals NameOrdinals'].each do |x|
894
904
  va = data["AddressOf"+x.last]
895
- ofs = @pedump.va2file(va) || '?'
905
+ ofs = @pedump.rva2file(va) || '?'
896
906
  printf("# %-12s rva=0x%08x file_offset=%8s\n", x.first, va, ofs) if va
897
907
  end
898
908
  end
@@ -1132,7 +1142,7 @@ class PEdump::CLI
1132
1142
  exit(1)
1133
1143
  end
1134
1144
  if entry.size != 0
1135
- _copy_stream @pedump.io, $stdout, entry.size, @pedump.va2file(entry.va)
1145
+ _copy_stream @pedump.io, $stdout, entry.size, @pedump.rva2file(entry.va)
1136
1146
  end
1137
1147
  end
1138
1148
 
@@ -102,7 +102,7 @@ class PEdump
102
102
  dir = hdr.ManagedNativeHeader
103
103
  return nil if !dir || (dir.va.to_i == 0 && dir.size.to_i == 0)
104
104
 
105
- file_offset = va2file(dir.va)
105
+ file_offset = rva2file(dir.va)
106
106
  return nil unless file_offset
107
107
 
108
108
  f.seek(file_offset)
data/lib/pedump/clr.rb CHANGED
@@ -584,7 +584,7 @@ class PEdump
584
584
  dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::CLR_Header]
585
585
  return nil if !dir || (dir.va == 0 && dir.size == 0)
586
586
 
587
- file_offset = va2file(dir.va)
587
+ file_offset = rva2file(dir.va)
588
588
  return nil unless file_offset
589
589
 
590
590
  if f.checked_seek(file_offset)
@@ -601,7 +601,7 @@ class PEdump
601
601
  dir = hdr&.MetaData
602
602
  return nil if !dir || (dir.va.to_i == 0 || dir.size.to_i == 0)
603
603
 
604
- file_offset = va2file(dir.va)
604
+ file_offset = rva2file(dir.va)
605
605
  return nil unless file_offset
606
606
 
607
607
  if f.checked_seek(file_offset)
@@ -635,7 +635,7 @@ class PEdump
635
635
  streams.each do |stream|
636
636
  next unless stream.name == '#Strings'
637
637
 
638
- unless f.checked_seek(va2file(dir.va) + stream.offset)
638
+ unless f.checked_seek(rva2file(dir.va) + stream.offset)
639
639
  logger.warn "[?] Error seeking to CLR strings stream"
640
640
  return nil
641
641
  end
@@ -678,7 +678,7 @@ class PEdump
678
678
  streams.each do |stream|
679
679
  next if stream.name != '#~' && stream.name != '#-' # Metadata Table Stream
680
680
 
681
- unless f.checked_seek(va2file(dir.va) + stream.offset)
681
+ unless f.checked_seek(rva2file(dir.va) + stream.offset)
682
682
  logger.warn "[?] Error seeking to CLR table stream"
683
683
  return nil
684
684
  end
@@ -21,13 +21,13 @@ class PEdump
21
21
 
22
22
  MINIDUMP_LOCATION_DESCRIPTOR = IOStruct.new 'LL', :DataSize, :Rva
23
23
 
24
- class MINIDUMP_DIRECTORY < IOStruct.new 'L', :StreamType, :Location
25
- def self.read io
26
- r = super
27
- r.Location = MINIDUMP_LOCATION_DESCRIPTOR.read(io)
28
- r
29
- end
30
- end
24
+ # Using nested struct - Location is automatically parsed
25
+ MINIDUMP_DIRECTORY = IOStruct.new(
26
+ fields: {
27
+ StreamType: 'uint32_t',
28
+ Location: MINIDUMP_LOCATION_DESCRIPTOR,
29
+ }
30
+ )
31
31
 
32
32
  MINIDUMP_MEMORY_INFO = IOStruct.new 'QQLLQLLLL',
33
33
  :BaseAddress,
data/lib/pedump/packer.rb CHANGED
@@ -73,7 +73,7 @@ class PEdump
73
73
  elsif va == 0 && pe.dll?
74
74
  pedump.logger.debug "[.] it's a DLL with no EntryPoint"
75
75
  nil
76
- elsif !(ofs = pedump.va2file(va))
76
+ elsif !(ofs = pedump.rva2file(va))
77
77
  pedump.logger.error "[?] can't find EntryPoint RVA (0x#{va.to_s(16)}) file offset"
78
78
  nil
79
79
  else
@@ -403,7 +403,7 @@ class PEdump
403
403
  end
404
404
  end
405
405
  when IMAGE_RESOURCE_DATA_ENTRY
406
- file_offset = va2file(entry.data.OffsetToData, :quiet => (@pe_res_errors > MAX_ERRORS))
406
+ file_offset = rva2file(entry.data.OffsetToData, :quiet => (@pe_res_errors > MAX_ERRORS))
407
407
  unless file_offset
408
408
  @pe_res_errors += 1
409
409
  if @pe_res_errors > MAX_ERRORS
data/lib/pedump/te.rb CHANGED
@@ -4,33 +4,33 @@ class PEdump
4
4
  # https://formats.kaitai.io/uefi_te/index.html
5
5
  # http://ho.ax/tag/efi/
6
6
  # https://github.com/gdbinit/TELoader
7
-
8
- EFI_IMAGE_DATA_DIRECTORY = IOStruct.new( "VV", :va, :size )
7
+
8
+ EFI_IMAGE_DATA_DIRECTORY = IOStruct.new("VV", :va, :size)
9
9
  EFI_IMAGE_DATA_DIRECTORY::TYPES = %w'BASERELOC DEBUG'
10
- EFI_IMAGE_DATA_DIRECTORY::TYPES.each_with_index do |type,idx|
11
- EFI_IMAGE_DATA_DIRECTORY.const_set(type,idx)
10
+ EFI_IMAGE_DATA_DIRECTORY::TYPES.each_with_index do |type, idx|
11
+ EFI_IMAGE_DATA_DIRECTORY.const_set(type, idx)
12
12
  end
13
13
 
14
- class EFI_TE_IMAGE_HEADER < IOStruct.new 'vvCCvVVQ',
15
- :Signature,
16
- :Machine,
17
- :NumberOfSections,
18
- :Subsystem,
19
- :StrippedSize,
20
- :AddressOfEntryPoint,
21
- :BaseOfCode,
22
- :ImageBase,
23
- :DataDirectory # readed manually: EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]
24
-
25
- REAL_SIZE = SIZE + EFI_IMAGE_DATA_DIRECTORY::SIZE * 2
14
+ # Using hash format with nested struct array for DataDirectory
15
+ class EFI_TE_IMAGE_HEADER < IOStruct.new(
16
+ fields: {
17
+ Signature: 'uint16_t',
18
+ Machine: 'uint16_t',
19
+ NumberOfSections: 'uint8_t',
20
+ Subsystem: 'uint8_t',
21
+ StrippedSize: 'uint16_t',
22
+ AddressOfEntryPoint: 'uint32_t',
23
+ BaseOfCode: 'uint32_t',
24
+ ImageBase: 'uint64_t',
25
+ DataDirectory: { type: EFI_IMAGE_DATA_DIRECTORY, count: 2 },
26
+ }
27
+ )
28
+ REAL_SIZE = SIZE
26
29
 
27
30
  attr_accessor :sections
28
31
 
29
32
  def self.read io, args = {}
30
33
  super(io).tap do |te|
31
- te.DataDirectory = 2.times.map do
32
- EFI_IMAGE_DATA_DIRECTORY.read(io)
33
- end
34
34
  te.sections = PE.read_sections(io, te.NumberOfSections, args)
35
35
  end
36
36
  end
data/lib/pedump/tls.rb CHANGED
@@ -1,17 +1,15 @@
1
1
  class PEdump
2
- IMAGE_TLS_DIRECTORY32 = IOStruct.new 'V6',
3
- :StartAddressOfRawData,
4
- :EndAddressOfRawData,
5
- :AddressOfIndex,
6
- :AddressOfCallBacks,
7
- :SizeOfZeroFill,
8
- :Characteristics
2
+ TLS_DIRECTORY_FIELDS = %i[
3
+ StartAddressOfRawData
4
+ EndAddressOfRawData
5
+ AddressOfIndex
6
+ AddressOfCallBacks
7
+ SizeOfZeroFill
8
+ Characteristics
9
+ ].freeze
9
10
 
10
- IMAGE_TLS_DIRECTORY64 = IOStruct.new 'Q4V2',
11
- :StartAddressOfRawData,
12
- :EndAddressOfRawData,
13
- :AddressOfIndex,
14
- :AddressOfCallBacks,
15
- :SizeOfZeroFill,
16
- :Characteristics
11
+ # 32-bit: all fields are 32-bit (V6)
12
+ # 64-bit: first 4 fields are 64-bit pointers (Q4), last 2 are 32-bit (V2)
13
+ IMAGE_TLS_DIRECTORY32 = IOStruct.new('V6', *TLS_DIRECTORY_FIELDS)
14
+ IMAGE_TLS_DIRECTORY64 = IOStruct.new('Q4V2', *TLS_DIRECTORY_FIELDS)
17
15
  end
@@ -788,13 +788,13 @@ class PEdump::Unpacker::ASPack
788
788
  ###
789
789
 
790
790
  rebuild_tls :step => 1
791
- sorted_obj_tbl = @obj_tbl.sort_by{ |x| @ldr.pedump.va2file(x.va) }
791
+ sorted_obj_tbl = @obj_tbl.sort_by{ |x| @ldr.pedump.rva2file(x.va) }
792
792
  sorted_obj_tbl.each_with_index do |obj,idx|
793
793
  # restore section flags, if any
794
794
  @ldr.va2section(obj.va).flags = obj.flags if obj.flags
795
795
 
796
796
  next if obj.size < 0 # empty section
797
- #file_offset = @ldr.pedump.va2file(obj.va)
797
+ #file_offset = @ldr.pedump.rva2file(obj.va)
798
798
  #@io.seek file_offset
799
799
  packed_size =
800
800
  if idx == sorted_obj_tbl.size - 1
@@ -802,7 +802,7 @@ class PEdump::Unpacker::ASPack
802
802
  obj.size
803
803
  else
804
804
  # subtract this file_offset from next object file_offset
805
- @ldr.pedump.va2file(sorted_obj_tbl[idx+1].va) - @ldr.pedump.va2file(obj.va)
805
+ @ldr.pedump.rva2file(sorted_obj_tbl[idx+1].va) - @ldr.pedump.rva2file(obj.va)
806
806
  end
807
807
  #packed_data = @io.read packed_size
808
808
  packed_data = @ldr[obj.va, packed_size]
data/lib/pedump.rb CHANGED
@@ -397,7 +397,7 @@ class PEdump
397
397
  alias :rich_header :rich_hdr
398
398
  alias :rich :rich_hdr
399
399
 
400
- def va2file va, h={}
400
+ def rva2file va, h={}
401
401
  return nil if va.nil?
402
402
 
403
403
  va0 = va # save for log output of original addr
@@ -445,7 +445,11 @@ class PEdump
445
445
  nil
446
446
  end
447
447
 
448
- def file2va offset, h = {}
448
+ def va2file va, h = {}
449
+ va && rva2file(va - @pe.ioh.ImageBase.to_i, h)
450
+ end
451
+
452
+ def file2rva offset, h = {}
449
453
  return nil if offset.nil?
450
454
 
451
455
  # a special case - PE without sections
@@ -465,6 +469,11 @@ class PEdump
465
469
  nil
466
470
  end
467
471
 
472
+ def file2va offset, h = {}
473
+ va = file2rva(offset, h)
474
+ va && (va + @pe.ioh.ImageBase.to_i)
475
+ end
476
+
468
477
  # OPTIONAL: assigns @mz, @rich_hdr, @pe, etc
469
478
  def dump f=@io
470
479
  if f.is_a?(String)
@@ -601,7 +610,7 @@ class PEdump
601
610
  return nil unless pe(f) && pe(f).ioh && f
602
611
 
603
612
  imports = imports(f)
604
- return nil if imports.empty?
613
+ return nil if imports.nil? || imports.empty?
605
614
 
606
615
  a = []
607
616
  imports.each do |iid|
@@ -628,7 +637,7 @@ class PEdump
628
637
  dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::IMPORT]
629
638
  return [] if !dir || (dir.va == 0 && dir.size == 0)
630
639
 
631
- file_offset = va2file(dir.va)
640
+ file_offset = rva2file(dir.va)
632
641
  return nil unless file_offset
633
642
 
634
643
  # scan TLS first, to catch many fake imports trick from
@@ -636,7 +645,7 @@ class PEdump
636
645
  tls_aoi = nil
637
646
  if (tls = tls(f)) && tls.any?
638
647
  tls_aoi = tls.first.AddressOfIndex.to_i - @pe.ioh.ImageBase.to_i
639
- tls_aoi = tls_aoi > 0 ? va2file(tls_aoi) : nil
648
+ tls_aoi = tls_aoi > 0 ? rva2file(tls_aoi) : nil
640
649
  end
641
650
 
642
651
  r = []; t = nil
@@ -672,7 +681,7 @@ class PEdump
672
681
  @imports = @imports[0,iidx]
673
682
  break
674
683
  end
675
- if x.Name.to_i != 0 && (ofs = va2file(x.Name))
684
+ if x.Name.to_i != 0 && (ofs = rva2file(x.Name))
676
685
  begin
677
686
  f.seek ofs
678
687
  rescue
@@ -683,7 +692,7 @@ class PEdump
683
692
  end
684
693
  [:original_first_thunk, :first_thunk].each do |tbl|
685
694
  camel = tbl.capitalize.to_s.gsub(/_./){ |char| char[1..-1].upcase}
686
- if x[camel].to_i != 0 && (ofs = va2file(x[camel])) && f.checked_seek(ofs)
695
+ if x[camel].to_i != 0 && (ofs = rva2file(x[camel])) && f.checked_seek(ofs)
687
696
  x[tbl] ||= []
688
697
  if pe.x64?
689
698
  x[tbl] << t while (t = f.read(8).to_s.unpack('Q').first).to_i != 0
@@ -701,7 +710,7 @@ class PEdump
701
710
  cache[t] ||=
702
711
  if t & mask > 0 # 0x8000_0000(_0000_0000)
703
712
  ImportedFunction.new(nil,nil,t & (mask-1),va) # 0x7fff_ffff(_ffff_ffff)
704
- elsif ofs=va2file(t, :quiet => true)
713
+ elsif ofs=rva2file(t, :quiet => true)
705
714
  if !f.checked_seek(ofs) || f.eof?
706
715
  logger.warn "[?] import ofs 0x#{ofs.to_s(16)} VA=0x#{t.to_s(16)} beyond EOF"
707
716
  nil
@@ -788,7 +797,7 @@ class PEdump
788
797
  dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::EXPORT]
789
798
  return nil if !dir || (dir.va == 0 && dir.size == 0)
790
799
  va = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::EXPORT].va
791
- file_offset = va2file(va)
800
+ file_offset = rva2file(va)
792
801
  return nil unless file_offset
793
802
  if !f.checked_seek(file_offset) || f.eof?
794
803
  logger.warn "[?] exports info beyond EOF"
@@ -798,7 +807,7 @@ class PEdump
798
807
  x.entry_points = []
799
808
  x.name_ordinals = []
800
809
  x.names = []
801
- if x.Name.to_i != 0 && (ofs = va2file(x.Name))
810
+ if x.Name.to_i != 0 && (ofs = rva2file(x.Name))
802
811
  f.seek ofs
803
812
  if f.eof?
804
813
  logger.warn "[?] export ofs 0x#{ofs.to_s(16)} beyond EOF"
@@ -808,7 +817,7 @@ class PEdump
808
817
  end
809
818
  end
810
819
  if x.NumberOfFunctions.to_i > 0
811
- if x.AddressOfFunctions.to_i !=0 && (ofs = va2file(x.AddressOfFunctions))
820
+ if x.AddressOfFunctions.to_i !=0 && (ofs = rva2file(x.AddressOfFunctions))
812
821
  f.seek ofs
813
822
  x.entry_points = []
814
823
  x.NumberOfFunctions.times do
@@ -819,7 +828,7 @@ class PEdump
819
828
  x.entry_points << f.read(4).unpack('V').first
820
829
  end
821
830
  end
822
- if x.AddressOfNameOrdinals.to_i !=0 && (ofs = va2file(x.AddressOfNameOrdinals))
831
+ if x.AddressOfNameOrdinals.to_i !=0 && (ofs = rva2file(x.AddressOfNameOrdinals))
823
832
  f.seek ofs
824
833
  x.name_ordinals = []
825
834
  x.NumberOfNames.times do
@@ -831,7 +840,7 @@ class PEdump
831
840
  end
832
841
  end
833
842
  end
834
- if x.NumberOfNames.to_i > 0 && x.AddressOfNames.to_i !=0 && (ofs = va2file(x.AddressOfNames))
843
+ if x.NumberOfNames.to_i > 0 && x.AddressOfNames.to_i !=0 && (ofs = rva2file(x.AddressOfNames))
835
844
  f.seek ofs
836
845
  x.names = []
837
846
  x.NumberOfNames.times do
@@ -844,7 +853,7 @@ class PEdump
844
853
  nErrors = 0
845
854
  x.names.size.times do |i|
846
855
  begin
847
- f.seek va2file(x.names[i])
856
+ f.seek rva2file(x.names[i])
848
857
  x.names[i] = f.gets("\x00").to_s.chomp("\x00")
849
858
  rescue
850
859
  nErrors += 1
@@ -890,7 +899,7 @@ class PEdump
890
899
  begin
891
900
  dir = @pe.ioh.DataDirectory[IMAGE_DATA_DIRECTORY::TLS]
892
901
  return nil if !dir || dir.va == 0
893
- return nil unless file_offset = va2file(dir.va)
902
+ return nil unless file_offset = rva2file(dir.va)
894
903
  f.seek file_offset
895
904
  if f.eof?
896
905
  logger.info "[?] TLS info beyond EOF"
@@ -947,7 +956,10 @@ class PEdump
947
956
  ##############################################################################
948
957
 
949
958
  def tail f=@io
950
- tail_start = sections(f).map{ |s| s.PointerToRawData + s.SizeOfRawData }.max
959
+ secs = sections(f)
960
+ return nil if secs.nil? || secs.empty?
961
+
962
+ tail_start = secs.map{ |s| s.PointerToRawData + s.SizeOfRawData }.max
951
963
  if tail_start && tail_start < f.size
952
964
  f.seek tail_start
953
965
  f
data/pedump.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: pedump 0.7.3 ruby lib
5
+ # stub: pedump 0.7.4 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "pedump".freeze
9
- s.version = "0.7.3".freeze
9
+ s.version = "0.7.4".freeze
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]
@@ -83,7 +83,7 @@ Gem::Specification.new do |s|
83
83
 
84
84
  s.add_runtime_dependency(%q<rainbow>.freeze, [">= 0".freeze])
85
85
  s.add_runtime_dependency(%q<awesome_print>.freeze, [">= 0".freeze])
86
- s.add_runtime_dependency(%q<iostruct>.freeze, [">= 0.5.0".freeze])
86
+ s.add_runtime_dependency(%q<iostruct>.freeze, [">= 0.7.0".freeze])
87
87
  s.add_runtime_dependency(%q<multipart-post>.freeze, [">= 2.0.0".freeze])
88
88
  s.add_runtime_dependency(%q<zhexdump>.freeze, [">= 0.0.2".freeze])
89
89
  s.add_development_dependency(%q<rspec>.freeze, [">= 0".freeze])
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pedump
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey "Zed" Zaikin
@@ -43,14 +43,14 @@ dependencies:
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 0.5.0
46
+ version: 0.7.0
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: 0.5.0
53
+ version: 0.7.0
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: multipart-post
56
56
  requirement: !ruby/object:Gem::Requirement