pedump 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.github/FUNDING.yml +2 -0
  3. data/.github/dependabot.yml +8 -0
  4. data/CODE_OF_CONDUCT.md +76 -0
  5. data/Gemfile +11 -16
  6. data/Gemfile.lock +73 -27
  7. data/README.md +15 -6
  8. data/Rakefile +5 -44
  9. data/VERSION +1 -1
  10. data/lib/pedump.rb +101 -29
  11. data/lib/pedump/cli.rb +29 -18
  12. data/lib/pedump/loader.rb +1 -1
  13. data/lib/pedump/loader/minidump.rb +195 -31
  14. data/lib/pedump/ne.rb +1 -1
  15. data/lib/pedump/pe.rb +63 -54
  16. data/lib/pedump/te.rb +51 -0
  17. data/lib/pedump/unpacker/aspack.rb +1 -1
  18. data/lib/pedump/version.rb +2 -5
  19. data/misc/aspack/aspack_unlzx.c +5 -3
  20. data/pedump.gemspec +47 -74
  21. metadata +50 -101
  22. data/.document +0 -5
  23. data/.rspec +0 -1
  24. data/.travis.yml +0 -4
  25. data/samples/bad/68.exe +0 -0
  26. data/samples/bad/data_dir_15_entries.exe +0 -0
  27. data/spec/65535sects_spec.rb +0 -8
  28. data/spec/bad_imports_spec.rb +0 -20
  29. data/spec/bad_samples_spec.rb +0 -13
  30. data/spec/composite_io_spec.rb +0 -122
  31. data/spec/data/calc.exe_sections.yml +0 -49
  32. data/spec/data/data_dir_15_entries.exe_sections.yml +0 -95
  33. data/spec/dllord_spec.rb +0 -21
  34. data/spec/foldedhdr_spec.rb +0 -28
  35. data/spec/imports_badterm_spec.rb +0 -52
  36. data/spec/imports_vterm_spec.rb +0 -52
  37. data/spec/loader/names_spec.rb +0 -24
  38. data/spec/loader/va_spec.rb +0 -44
  39. data/spec/manyimportsW7_spec.rb +0 -22
  40. data/spec/ne_spec.rb +0 -125
  41. data/spec/packer_spec.rb +0 -17
  42. data/spec/pe_spec.rb +0 -67
  43. data/spec/pedump_spec.rb +0 -19
  44. data/spec/resource_spec.rb +0 -13
  45. data/spec/sections_spec.rb +0 -11
  46. data/spec/sig_all_packers_spec.rb +0 -24
  47. data/spec/sig_spec.rb +0 -68
  48. data/spec/spec_helper.rb +0 -24
  49. data/spec/support/samples.rb +0 -24
  50. data/spec/unpackers/aspack_spec.rb +0 -69
  51. data/spec/unpackers/find_spec.rb +0 -21
  52. data/spec/virtsectblXP_spec.rb +0 -12
  53. data/tmp/.keep +0 -0
@@ -33,7 +33,7 @@ class PEdump::CLI
33
33
  attr_accessor :data, :argv
34
34
 
35
35
  KNOWN_ACTIONS = (
36
- %w'mz dos_stub rich pe ne data_directory sections tls security' +
36
+ %w'mz dos_stub rich pe ne te data_directory sections tls security' +
37
37
  %w'strings resources resource_directory imports exports version_info packer web console packer_only'
38
38
  ).map(&:to_sym)
39
39
 
@@ -65,8 +65,8 @@ class PEdump::CLI
65
65
  @options[:force] ||= 0
66
66
  @options[:force] += 1
67
67
  end
68
- opts.on "-f", "--format FORMAT", [:binary, :c, :dump, :hex, :inspect, :table, :yaml],
69
- "Output format: bin,c,dump,hex,inspect,table,yaml","(default: table)" do |v|
68
+ opts.on "-f", "--format FORMAT", [:binary, :c, :dump, :hex, :inspect, :json, :table, :yaml],
69
+ "Output format: bin,c,dump,hex,inspect,json,table,yaml","(default: table)" do |v|
70
70
  @options[:format] = v
71
71
  end
72
72
  KNOWN_ACTIONS.each do |t|
@@ -135,7 +135,7 @@ class PEdump::CLI
135
135
  File.open(fname,'rb') do |f|
136
136
  @pedump = create_pedump fname
137
137
 
138
- next if !@options[:force] && !@pedump.mz(f)
138
+ next if !@options[:force] && !@pedump.supported_file?(f)
139
139
 
140
140
  @actions.each do |action|
141
141
  case action
@@ -194,16 +194,14 @@ class PEdump::CLI
194
194
  end
195
195
 
196
196
  class ProgressProxy
197
- attr_reader :pbar
198
-
199
- def initialize file
200
- @file = file
201
- @pbar = ProgressBar.new("[.] uploading", file.size, STDOUT)
202
- @pbar.try(:file_transfer_mode)
203
- @pbar.bar_mark = '='
197
+ def initialize file, prefix = "[.] uploading: ", io = STDOUT
198
+ @file = file
199
+ @io = io
200
+ @prefix = prefix
204
201
  end
205
202
  def read *args
206
- @pbar.inc args.first
203
+ @io.write("\r#{@prefix}#{@file.tell}/#{@file.size} ")
204
+ @io.flush
207
205
  @file.read *args
208
206
  end
209
207
  def method_missing *args
@@ -212,6 +210,10 @@ class PEdump::CLI
212
210
  def respond_to? *args
213
211
  @file.respond_to?(args.first) || super(*args)
214
212
  end
213
+
214
+ def finish!
215
+ @io.write("\r#{@prefix}#{@file.size}/#{@file.size} \n")
216
+ end
215
217
  end
216
218
 
217
219
  def upload f
@@ -224,7 +226,6 @@ class PEdump::CLI
224
226
  require 'open-uri'
225
227
  require 'net/http'
226
228
  require 'net/http/post/multipart'
227
- require 'progressbar'
228
229
 
229
230
  stdout_sync = STDOUT.sync
230
231
  STDOUT.sync = true
@@ -250,15 +251,15 @@ class PEdump::CLI
250
251
 
251
252
  f.rewind
252
253
 
253
- # upload with progressbar
254
+ # upload with progress
254
255
  post_url = URI.parse(URL_BASE+'/')
256
+ # UploadIO is from multipart-post
255
257
  uio = UploadIO.new(f, "application/octet-stream", File.basename(f.path))
256
258
  ppx = ProgressProxy.new(uio)
257
259
  req = Net::HTTP::Post::Multipart.new post_url.path, "file" => ppx
258
260
  res = Net::HTTP.start(post_url.host, post_url.port){ |http| http.request(req) }
259
- ppx.pbar.finish
261
+ ppx.finish!
260
262
 
261
- puts
262
263
  puts "[.] analyzing..."
263
264
 
264
265
  if (r=open(File.join(URL_BASE,md5,'analyze')).read) != "OK"
@@ -326,7 +327,7 @@ class PEdump::CLI
326
327
 
327
328
  puts action_title(action) unless @options[:format] == :binary
328
329
 
329
- return dump(data) if [:inspect, :table, :yaml].include?(@options[:format])
330
+ return dump(data) if [:inspect, :table, :json, :yaml].include?(@options[:format])
330
331
 
331
332
  dump_opts = {:name => action}
332
333
  case action
@@ -376,6 +377,9 @@ class PEdump::CLI
376
377
  when :yaml
377
378
  require 'yaml'
378
379
  puts data.to_yaml
380
+ when :json
381
+ require 'json'
382
+ puts data.to_json
379
383
  end
380
384
  end
381
385
 
@@ -454,6 +458,8 @@ class PEdump::CLI
454
458
  case data.first
455
459
  when PEdump::IMAGE_DATA_DIRECTORY
456
460
  dump_data_dir data
461
+ when PEdump::EFI_IMAGE_DATA_DIRECTORY
462
+ dump_efi_data_dir data
457
463
  when PEdump::IMAGE_SECTION_HEADER
458
464
  dump_sections data
459
465
  when PEdump::Resource
@@ -778,13 +784,18 @@ class PEdump::CLI
778
784
  end
779
785
  end
780
786
 
781
-
782
787
  def dump_data_dir data
783
788
  data.each do |row|
784
789
  printf " %-12s rva:0x%8x size:0x %8x\n", row.type, row.va.to_i, row.size.to_i
785
790
  end
786
791
  end
787
792
 
793
+ def dump_efi_data_dir data
794
+ data.each_with_index do |row, idx|
795
+ printf " %-12s rva:0x%8x size:0x %8x\n", PEdump::EFI_IMAGE_DATA_DIRECTORY::TYPES[idx], row.va.to_i, row.size.to_i
796
+ end
797
+ end
798
+
788
799
  def dump_rich_hdr data
789
800
  if decoded = data.decode
790
801
  puts " LIB_ID VERSION TIMES_USED "
@@ -263,7 +263,7 @@ class PEdump::Loader
263
263
  @pedump.imports.each do |iid| # Image Import Descriptor
264
264
  va = iid.FirstThunk + @image_base
265
265
  (Array(iid.original_first_thunk) + Array(iid.first_thunk)).uniq.each do |func|
266
- name = func.name || "##{func.ordinal}"
266
+ name = "__imp_" + (func.name || "#{func.ordinal}")
267
267
  @names[va] = name
268
268
  va += 4
269
269
  end
@@ -53,6 +53,24 @@ class PEdump
53
53
  end
54
54
  end
55
55
 
56
+ MINIDUMP_MEMORY_DESCRIPTOR = IOStruct.new 'QLL',
57
+ :StartOfMemoryRange,
58
+ :DataSize,
59
+ :Rva
60
+
61
+ class MINIDUMP_MEMORY_LIST < IOStruct.new 'L',
62
+ :NumberOfMemoryRanges,
63
+ :MemoryRanges
64
+
65
+ def self.read io
66
+ r = super
67
+ r.MemoryRanges = r.NumberOfMemoryRanges.times.map{ MINIDUMP_MEMORY_DESCRIPTOR.read(io) }
68
+ r
69
+ end
70
+
71
+ def entries; self.MemoryRanges; end
72
+ end
73
+
56
74
  MINIDUMP_MEMORY_DESCRIPTOR64 = IOStruct.new 'QQ',
57
75
  :StartOfMemoryRange,
58
76
  :DataSize
@@ -78,7 +96,7 @@ class PEdump
78
96
  2 => :ReservedStream1,
79
97
  3 => :ThreadListStream,
80
98
  4 => :ModuleListStream,
81
- 5 => :MemoryListStream,
99
+ 5 => :MemoryListStream, # MINIDUMP_MEMORY_LIST
82
100
  6 => :ExceptionStream,
83
101
  7 => :SystemInfoStream,
84
102
  8 => :ThreadExListStream,
@@ -92,7 +110,34 @@ class PEdump
92
110
  16 => :MemoryInfoListStream, # MINIDUMP_MEMORY_INFO_LIST
93
111
  17 => :ThreadInfoListStream,
94
112
  18 => :HandleOperationListStream,
95
- 0xffff => :LastReservedStream
113
+ 0xffff => :LastReservedStream,
114
+
115
+ # Special types saved by google breakpad
116
+ # https://chromium.googlesource.com/breakpad/breakpad/+/846b6335c5b0ba46dfa2ed96fccfa3f7a02fa2f1/src/google_breakpad/common/minidump_format.h#311
117
+ 0x47670001 => :BreakpadInfoStream,
118
+ 0x47670002 => :BreakpadAssertionInfoStream,
119
+ 0x47670003 => :BreakpadLinuxCpuInfo,
120
+ 0x47670004 => :BreakpadLinuxProcStatus,
121
+ 0x47670005 => :BreakpadLinuxLsbRelease,
122
+ 0x47670006 => :BreakpadLinuxCmdLine,
123
+ 0x47670007 => :BreakpadLinuxEnviron,
124
+ 0x47670008 => :BreakpadLinuxAuxv,
125
+ 0x47670009 => :BreakpadLinuxMaps,
126
+ 0x4767000A => :BreakpadLinuxDsoDebug,
127
+
128
+ # Saved by crashpad
129
+ # https://chromium.googlesource.com/crashpad/crashpad/+/doc/minidump/minidump_extensions.h#95
130
+ 0x43500001 => :CrashpadInfo,
131
+
132
+ # Saved by Syzyasan
133
+ # https://github.com/google/syzygy/blob/c8bb4927f07fec0de8834c4774ddaafef0bc099f/syzygy/kasko/api/client.h#L28
134
+ # https://github.com/google/syzygy/blob/master/syzygy/crashdata/crashdata.proto
135
+ 0x4B6B0001 => :SyzyasanCrashdata,
136
+
137
+ # Saved by Chromium
138
+ 0x4B6B0002 => :ChromiumStabilityReport,
139
+ 0x4B6B0003 => :ChromiumSystemProfile,
140
+ 0x4B6B0004 => :ChromiumGwpAsanData,
96
141
  }
97
142
 
98
143
  class Loader
@@ -116,17 +161,32 @@ class PEdump
116
161
  end
117
162
  end
118
163
 
164
+ def stream_by_name(name)
165
+ type = MINIDUMP_STREAM_TYPE.invert[name]
166
+ raise "Unknown type symbol #{name}!" if !type
167
+
168
+ streams.find { |s| s.StreamType == type }
169
+ end
170
+
119
171
  def memory_info_list
120
172
  # MINIDUMP_MEMORY_INFO_LIST
121
- stream = streams.find{ |s| s.StreamType == 16 }
173
+ stream = stream_by_name(:MemoryInfoListStream)
122
174
  return nil unless stream
123
175
  io.seek stream.Location.Rva
124
176
  MINIDUMP_MEMORY_INFO_LIST.read io
125
177
  end
126
178
 
127
179
  def memory_list
180
+ # MINIDUMP_MEMORY_LIST
181
+ stream = stream_by_name(:MemoryListStream)
182
+ return nil unless stream
183
+ io.seek stream.Location.Rva
184
+ MINIDUMP_MEMORY_LIST.read io
185
+ end
186
+
187
+ def memory64_list
128
188
  # MINIDUMP_MEMORY64_LIST
129
- stream = streams.find{ |s| s.StreamType == 9 }
189
+ stream = stream_by_name(:Memory64ListStream)
130
190
  return nil unless stream
131
191
  io.seek stream.Location.Rva
132
192
  MINIDUMP_MEMORY64_LIST.read io
@@ -136,27 +196,50 @@ class PEdump
136
196
 
137
197
  # set options[:merge] = true to merge adjacent memory ranges
138
198
  def memory_ranges options = {}
139
- ml = memory_list
140
- file_offset = ml.BaseRva
141
- r = []
142
- if options[:merge]
143
- ml.entries.each do |x|
144
- if r.last && r.last.va + r.last.size == x.StartOfMemoryRange
145
- # if section VA == prev_section.VA + prev_section.SIZE
146
- # then just increase the size of previous section
147
- r.last.size += x.DataSize
148
- else
199
+ if memory64_list
200
+ ml = memory64_list
201
+ file_offset = ml.BaseRva
202
+ r = []
203
+ if options[:merge]
204
+ ml.entries.each do |x|
205
+ if r.last && r.last.va + r.last.size == x.StartOfMemoryRange
206
+ # if section VA == prev_section.VA + prev_section.SIZE
207
+ # then just increase the size of previous section
208
+ r.last.size += x.DataSize
209
+ else
210
+ r << MemoryRange.new( file_offset, x.StartOfMemoryRange, x.DataSize )
211
+ end
212
+ file_offset += x.DataSize
213
+ end
214
+ else
215
+ ml.entries.each do |x|
149
216
  r << MemoryRange.new( file_offset, x.StartOfMemoryRange, x.DataSize )
217
+ file_offset += x.DataSize
150
218
  end
151
- file_offset += x.DataSize
152
219
  end
153
- else
154
- ml.entries.each do |x|
155
- r << MemoryRange.new( file_offset, x.StartOfMemoryRange, x.DataSize )
156
- file_offset += x.DataSize
220
+ return r
221
+ elsif memory_list
222
+ ml = memory_list
223
+ r = []
224
+ if options[:merge]
225
+ ml.entries.each do |x|
226
+ if r.last && r.last.va + r.last.size == x.StartOfMemoryRange
227
+ # if section VA == prev_section.VA + prev_section.SIZE
228
+ # then just increase the size of previous section
229
+ r.last.size += x.DataSize
230
+ else
231
+ r << MemoryRange.new( x.Rva, x.StartOfMemoryRange, x.DataSize )
232
+ end
233
+ end
234
+ else
235
+ ml.entries.each do |x|
236
+ r << MemoryRange.new( x.Rva, x.StartOfMemoryRange, x.DataSize )
237
+ end
157
238
  end
239
+ return r
240
+ else
241
+ raise "Could not find memory ranges"
158
242
  end
159
- r
160
243
  end
161
244
 
162
245
  end # class Minidump
@@ -167,21 +250,102 @@ end # module PEdump
167
250
 
168
251
  if $0 == __FILE__
169
252
  require 'pp'
253
+ require 'optparse'
170
254
 
171
- raise "gimme a fname" if ARGV.empty?
172
- io = open(ARGV.first,"rb")
255
+ options = {}
256
+ opt_parse = OptionParser.new do |opts|
257
+ opts.banner = "Usage: #{$0} [options] <minidump>"
173
258
 
259
+ opts.on("--all", "Print all of the following sections") do
260
+ options[:all] = true
261
+ end
262
+ opts.on("--header", "Print minidump header") do
263
+ options[:header] = true
264
+ end
265
+ opts.on("--streams", "Print out the streams present") do
266
+ options[:streams] = true
267
+ end
268
+ opts.on("--memory-ranges", "Print out memory ranges included in the minidump") do
269
+ options[:memory_ranges] = true
270
+ end
271
+ opts.on("--breakpad", "Print out breakpad text sections if present") do
272
+ options[:breakpad] = true
273
+ end
274
+ opts.separator ''
275
+
276
+ opts.on("--memory <address>", "Print the memory range beginning at address") do |m|
277
+ options[:memory] = m.hex
278
+ end
279
+ opts.separator ''
280
+
281
+ opts.on("-h", "--help", "Help") do
282
+ puts opts
283
+ exit 0
284
+ end
285
+ end
286
+
287
+ opt_parse.parse!
288
+
289
+ if ARGV.empty?
290
+ $stderr.puts opt_parse.help
291
+ exit 1
292
+ end
293
+
294
+ io = open(ARGV.first, "rb")
174
295
  md = PEdump::Loader::Minidump.new io
175
- pp md.hdr
176
- puts
177
- puts "[.] #{md.memory_ranges.size} memory ranges"
178
- puts "[.] #{md.memory_ranges(:merge => true).size} merged memory ranges"
179
- puts
180
296
 
181
- # pp md.memory_info_list
182
- # pp md.memory_list
297
+ if options[:all] || options[:header]
298
+ pp md.hdr
299
+ puts
300
+ end
301
+
302
+ if options[:all] || options[:streams]
303
+ puts "[.] Streams present in the minidump:"
304
+ md.streams.each do |s|
305
+ if PEdump::MINIDUMP_STREAM_TYPE[s.StreamType]
306
+ puts "[.] #{PEdump::MINIDUMP_STREAM_TYPE[s.StreamType]}"
307
+ else
308
+ puts "[.] Unknown stream type #{s.StreamType}"
309
+ end
310
+ end
311
+ puts
312
+ end
313
+
314
+ if options[:all] || options[:breakpad]
315
+ [ :BreakpadLinuxCpuInfo, :BreakpadLinuxProcStatus, :BreakpadLinuxMaps,
316
+ :BreakpadLinuxCmdLine, :BreakpadLinuxEnviron ].each { |name|
317
+ stream = md.stream_by_name(name)
318
+ next if !stream
319
+
320
+ io.seek stream.Location.Rva
321
+ contents = io.read(stream.Location.DataSize)
322
+
323
+ if contents !~ /[^[:print:][:space:]]/
324
+ puts "[.] Section #{name}:"
325
+ puts contents
326
+ else
327
+ puts "[.] Section #{name}: #{contents.inspect}"
328
+ end
329
+ puts
330
+ }
331
+ end
332
+
333
+ if options[:all] || options[:memory_ranges]
334
+ puts "[.] #{md.memory_ranges.size} memory ranges"
335
+ puts "[.] #{md.memory_ranges(:merge => true).size} merged memory ranges"
336
+ puts
337
+
338
+ printf "[.] %16s %8s\n", "addr", "size"
339
+ md.memory_ranges(:merge => true).sort_by { |mr| mr.va }.each do |mr|
340
+ printf "[.] %16x %8x\n", mr.va, mr.size
341
+ end
342
+ end
343
+
344
+ if options[:memory]
345
+ mr = md.memory_ranges(:merge => true).find { |r| r.va == options[:memory] }
346
+ raise "Could not find the specified region" if !mr
183
347
 
184
- md.memory_ranges(:merge => true).each do |mr|
185
- printf "[.] %8x %8x %8x\n", mr.file_offset, mr.va, mr.size
348
+ io.seek(mr.file_offset)
349
+ print io.read(mr.size)
186
350
  end
187
351
  end
@@ -405,7 +405,7 @@ class PEdump
405
405
  begin
406
406
  ne_offset = mz(f) && mz(f).lfanew
407
407
  if ne_offset.nil?
408
- logger.fatal "[!] NULL NE offset (e_lfanew)."
408
+ logger.debug "[!] NULL NE offset (e_lfanew)."
409
409
  nil
410
410
  elsif ne_offset > f.size
411
411
  logger.fatal "[!] NE offset beyond EOF."
@@ -24,78 +24,87 @@ class PEdump
24
24
  signature + ifh.pack + ioh.pack
25
25
  end
26
26
 
27
- def self.read f, args = {}
27
+ def self.read_sections f, nToRead, args = {}
28
28
  force = args[:force]
29
29
 
30
+ if nToRead > 0xffff
31
+ if force.is_a?(Numeric) && force > 1
32
+ PEdump.logger.warn "[!] too many sections (#{nToRead}). forced. reading all"
33
+ else
34
+ PEdump.logger.warn "[!] too many sections (#{nToRead}). not forced, reading first 65535"
35
+ nToRead = 65535
36
+ end
37
+ end
38
+
39
+ sections = []
40
+ nToRead.times do
41
+ break if f.eof?
42
+ sections << IMAGE_SECTION_HEADER.read(f)
43
+ end
44
+
45
+ if sections.any?
46
+ # zero all missing values of last section
47
+ sections.last.tap do |last_section|
48
+ last_section.each_pair do |k,v|
49
+ last_section[k] = 0 if v.nil?
50
+ end
51
+ end
52
+ end
53
+
54
+ sections
55
+ end
56
+
57
+ def self.read f, args = {}
30
58
  pe_offset = f.tell
31
59
  pe_sig = f.read 4
32
60
  #logger.error "[!] 'NE' format is not supported!" if pe_sig == "NE\x00\x00"
33
61
  if pe_sig != "PE\x00\x00"
34
- if force
62
+ if args[:force]
35
63
  logger.warn "[?] no PE signature (want: 'PE\\x00\\x00', got: #{pe_sig.inspect})"
36
64
  else
37
65
  logger.debug "[?] no PE signature (want: 'PE\\x00\\x00', got: #{pe_sig.inspect}). (not forced)"
38
66
  return nil
39
67
  end
40
68
  end
41
- PE.new(pe_sig).tap do |pe|
42
- pe.image_file_header = IMAGE_FILE_HEADER.read(f)
43
- ioh_offset = f.tell # offset to IMAGE_OPTIONAL_HEADER
44
- if pe.ifh.SizeOfOptionalHeader.to_i > 0
45
- if pe.x64?
46
- pe.image_optional_header = IMAGE_OPTIONAL_HEADER64.read(f, pe.ifh.SizeOfOptionalHeader)
47
- else
48
- pe.image_optional_header = IMAGE_OPTIONAL_HEADER32.read(f, pe.ifh.SizeOfOptionalHeader)
49
- end
69
+ pe = PE.new(pe_sig)
70
+ pe.image_file_header = IMAGE_FILE_HEADER.read(f)
71
+ ioh_offset = f.tell # offset to IMAGE_OPTIONAL_HEADER
72
+ if pe.ifh.SizeOfOptionalHeader.to_i > 0
73
+ if pe.x64?
74
+ pe.image_optional_header = IMAGE_OPTIONAL_HEADER64.read(f, pe.ifh.SizeOfOptionalHeader)
75
+ else
76
+ pe.image_optional_header = IMAGE_OPTIONAL_HEADER32.read(f, pe.ifh.SizeOfOptionalHeader)
50
77
  end
78
+ end
51
79
 
52
- if (nToRead=pe.ifh.NumberOfSections.to_i) > 0xffff
53
- if force.is_a?(Numeric) && force > 1
54
- logger.warn "[!] too many sections (#{pe.ifh.NumberOfSections}). forced. reading all"
55
- else
56
- logger.warn "[!] too many sections (#{pe.ifh.NumberOfSections}). not forced, reading first 65535"
57
- nToRead = 65535
58
- end
59
- end
80
+ nToRead=pe.ifh.NumberOfSections.to_i
60
81
 
61
- # The Windows loader expects to find the PE section headers after the optional header. It calculates the address of the first section header by adding SizeOfOptionalHeader to the beginning of the optional header.
62
- # // http://www.phreedom.org/research/tinype/
63
- f.seek( ioh_offset + pe.ifh.SizeOfOptionalHeader.to_i )
64
- pe.sections = []
65
- nToRead.times do
66
- break if f.eof?
67
- pe.sections << IMAGE_SECTION_HEADER.read(f)
68
- end
82
+ # The Windows loader expects to find the PE section headers after the optional header. It calculates the address of the first section header by adding SizeOfOptionalHeader to the beginning of the optional header.
83
+ # // http://www.phreedom.org/research/tinype/
84
+ f.seek( ioh_offset + pe.ifh.SizeOfOptionalHeader.to_i )
85
+ pe.sections = read_sections(f, nToRead, args)
69
86
 
70
- if pe.sections.any?
71
- # zero all missing values of last section
72
- pe.sections.last.tap do |last_section|
73
- last_section.each_pair do |k,v|
74
- last_section[k] = 0 if v.nil?
75
- end
76
- end
77
- end
87
+ pe_end = f.tell
88
+ if s=pe.sections.find{ |s| (pe_offset...pe_end).include?(s.va) }
89
+ if args[:pass2]
90
+ # already called with CompositeIO ?
91
+ PEdump.logger.error "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! 2nd time?!"
78
92
 
79
- pe_end = f.tell
80
- if s=pe.sections.find{ |s| (pe_offset...pe_end).include?(s.va) }
81
- if args[:pass2]
82
- # already called with CompositeIO ?
83
- logger.error "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! 2nd time?!"
84
-
85
- elsif pe_end-pe_offset < 0x100_000
86
- logger.warn "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! trying to rebuild..."
87
- f.seek pe_offset
88
- data = f.read(s.va-pe_offset)
89
- f.seek s.PointerToRawData
90
- io = CompositeIO.new(StringIO.new(data), f)
91
- args1 = args.dup
92
- args1[:pass2] = true
93
- return PE.read(io, args1)
94
- else
95
- logger.error "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! too big to rebuild!"
96
- end
93
+ elsif pe_end-pe_offset < 0x100_000
94
+ PEdump.logger.warn "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! trying to rebuild..."
95
+ f.seek pe_offset
96
+ data = f.read(s.va-pe_offset)
97
+ f.seek s.PointerToRawData
98
+ io = CompositeIO.new(StringIO.new(data), f)
99
+ args1 = args.dup
100
+ args1[:pass2] = true
101
+ return PE.read(io, args1)
102
+ else
103
+ PEdump.logger.error "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! too big to rebuild!"
97
104
  end
98
105
  end
106
+
107
+ pe
99
108
  end
100
109
 
101
110
  def self.logger; PEdump.logger; end
@@ -106,7 +115,7 @@ class PEdump
106
115
  begin
107
116
  pe_offset = mz(f) && mz(f).lfanew
108
117
  if pe_offset.nil?
109
- logger.fatal "[!] NULL PE offset (e_lfanew). cannot continue."
118
+ logger.debug "[!] NULL PE offset (e_lfanew). cannot continue."
110
119
  nil
111
120
  elsif pe_offset > f.size
112
121
  logger.fatal "[!] PE offset beyond EOF. cannot continue."