pedump 0.4.16 → 0.5.0

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.
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'iostruct'
4
+
5
+ class PEdump
6
+
7
+ # http://msdn.microsoft.com/en-us/library/windows/desktop/ms680378(v=vs.85).aspx
8
+ class MINIDUMP_HEADER < IOStruct.new 'a4LLLLLQ',
9
+ :Signature,
10
+ :Version,
11
+ :NumberOfStreams,
12
+ :StreamDirectoryRva,
13
+ :CheckSum,
14
+ :TimeDateStamp,
15
+ :Flags
16
+
17
+ def valid?
18
+ self.Signature == 'MDMP'
19
+ end
20
+ end
21
+
22
+ MINIDUMP_LOCATION_DESCRIPTOR = IOStruct.new 'LL', :DataSize, :Rva
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
31
+
32
+ MINIDUMP_MEMORY_INFO = IOStruct.new 'QQLLQLLLL',
33
+ :BaseAddress,
34
+ :AllocationBase,
35
+ :AllocationProtect,
36
+ :__alignment1,
37
+ :RegionSize,
38
+ :State,
39
+ :Protect,
40
+ :Type,
41
+ :__alignment2
42
+
43
+ class MINIDUMP_MEMORY_INFO_LIST < IOStruct.new 'LLQ',
44
+ :SizeOfHeader,
45
+ :SizeOfEntry,
46
+ :NumberOfEntries,
47
+ :entries
48
+
49
+ def self.read io
50
+ r = super
51
+ r.entries = r.NumberOfEntries.times.map{ MINIDUMP_MEMORY_INFO.read(io) }
52
+ r
53
+ end
54
+ end
55
+
56
+ MINIDUMP_MEMORY_DESCRIPTOR64 = IOStruct.new 'QQ',
57
+ :StartOfMemoryRange,
58
+ :DataSize
59
+
60
+ class MINIDUMP_MEMORY64_LIST < IOStruct.new 'QQ',
61
+ :NumberOfMemoryRanges,
62
+ :BaseRva,
63
+ :MemoryRanges
64
+
65
+ def self.read io
66
+ r = super
67
+ r.MemoryRanges = r.NumberOfMemoryRanges.times.map{ MINIDUMP_MEMORY_DESCRIPTOR64.read(io) }
68
+ r
69
+ end
70
+
71
+ def entries; self.MemoryRanges; end
72
+ end
73
+
74
+ # http://msdn.microsoft.com/en-us/library/windows/desktop/ms680394(v=vs.85).aspx
75
+ MINIDUMP_STREAM_TYPE = {
76
+ 0 => :UnusedStream,
77
+ 1 => :ReservedStream0,
78
+ 2 => :ReservedStream1,
79
+ 3 => :ThreadListStream,
80
+ 4 => :ModuleListStream,
81
+ 5 => :MemoryListStream,
82
+ 6 => :ExceptionStream,
83
+ 7 => :SystemInfoStream,
84
+ 8 => :ThreadExListStream,
85
+ 9 => :Memory64ListStream, # MINIDUMP_MEMORY64_LIST
86
+ 10 => :CommentStreamA,
87
+ 11 => :CommentStreamW,
88
+ 12 => :HandleDataStream,
89
+ 13 => :FunctionTableStream,
90
+ 14 => :UnloadedModuleListStream,
91
+ 15 => :MiscInfoStream,
92
+ 16 => :MemoryInfoListStream, # MINIDUMP_MEMORY_INFO_LIST
93
+ 17 => :ThreadInfoListStream,
94
+ 18 => :HandleOperationListStream,
95
+ 0xffff => :LastReservedStream
96
+ }
97
+
98
+ class Loader
99
+ class Minidump
100
+ attr_accessor :hdr, :streams, :io
101
+
102
+ def initialize io
103
+ @io = io
104
+ @hdr = MINIDUMP_HEADER.read(@io)
105
+ raise "invalid minidump" unless @hdr.valid?
106
+ end
107
+
108
+ def streams
109
+ @streams ||=
110
+ begin
111
+ @io.seek(@hdr.StreamDirectoryRva)
112
+ @hdr.NumberOfStreams.times.map do
113
+ dir = MINIDUMP_DIRECTORY.read(io)
114
+ dir.Location.empty? ? nil : dir
115
+ end.compact
116
+ end
117
+ end
118
+
119
+ def memory_info_list
120
+ # MINIDUMP_MEMORY_INFO_LIST
121
+ stream = streams.find{ |s| s.StreamType == 16 }
122
+ return nil unless stream
123
+ io.seek stream.Location.Rva
124
+ MINIDUMP_MEMORY_INFO_LIST.read io
125
+ end
126
+
127
+ def memory_list
128
+ # MINIDUMP_MEMORY64_LIST
129
+ stream = streams.find{ |s| s.StreamType == 9 }
130
+ return nil unless stream
131
+ io.seek stream.Location.Rva
132
+ MINIDUMP_MEMORY64_LIST.read io
133
+ end
134
+
135
+ MemoryRange = Struct.new :file_offset, :va, :size
136
+
137
+ # set options[:merge] = true to merge adjacent memory ranges
138
+ 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
149
+ r << MemoryRange.new( file_offset, x.StartOfMemoryRange, x.DataSize )
150
+ end
151
+ file_offset += x.DataSize
152
+ end
153
+ else
154
+ ml.entries.each do |x|
155
+ r << MemoryRange.new( file_offset, x.StartOfMemoryRange, x.DataSize )
156
+ file_offset += x.DataSize
157
+ end
158
+ end
159
+ r
160
+ end
161
+
162
+ end # class Minidump
163
+ end # class Loader
164
+ end # module PEdump
165
+
166
+ ##############################################
167
+
168
+ if $0 == __FILE__
169
+ require 'pp'
170
+
171
+ raise "gimme a fname" if ARGV.empty?
172
+ io = open(ARGV.first,"rb")
173
+
174
+ 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
+
181
+ # pp md.memory_info_list
182
+ # pp md.memory_list
183
+
184
+ md.memory_ranges(:merge => true).each do |mr|
185
+ printf "[.] %8x %8x %8x\n", mr.file_offset, mr.va, mr.size
186
+ end
187
+ end
@@ -13,10 +13,12 @@ class PEdump::Loader
13
13
  @deferred_load_io = args[:deferred_load_io]
14
14
  @deferred_load_pos = args[:deferred_load_pos] || (@hdr && @hdr.PointerToRawData)
15
15
  @deferred_load_size = args[:deferred_load_size] || (@hdr && @hdr.SizeOfRawData)
16
+ @image_base = args[:image_base] || 0
16
17
  end
17
18
 
18
19
  def name; @hdr.Name; end
19
- def va ; @hdr.VirtualAddress; end
20
+ def va ; @hdr.VirtualAddress + @image_base; end
21
+ def rva ; @hdr.VirtualAddress; end
20
22
  def vsize; @hdr.VirtualSize; end
21
23
  def flags; @hdr.Characteristics; end
22
24
  def flags= f; @hdr.Characteristics= f; end
@@ -42,10 +44,14 @@ class PEdump::Loader
42
44
  end
43
45
 
44
46
  def inspect
45
- "#<Section name=%-10s va=%8x vsize=%8x rawsize=%8s>" % [
46
- name.inspect, va, vsize,
47
+ r = "#<Section"
48
+ r << (" name=%-10s" % name.inspect) if name
49
+ r << " va=%8x vsize=%8x rawsize=%8s" % [
50
+ va, vsize,
47
51
  @data.size > 0 ? @data.size.to_s(16) : (@deferred_load_io ? "<defer>" : 0)
48
52
  ]
53
+ r << (" dlpos=%8x" % @deferred_load_pos) if @deferred_load_pos
54
+ r << ">"
49
55
  end
50
56
  end
51
57
  end
@@ -1,6 +1,6 @@
1
1
  class PEdump
2
2
  # from wine's winnt.h
3
- class NE < PEdump.create_struct 'a2CCvvVv4VVv8Vv3CCv4',
3
+ class NE < IOStruct.new 'a2CCvvVv4VVv8Vv3CCv4',
4
4
  :ne_magic, # 00 NE signature 'NE'
5
5
  :ne_ver, # 02 Linker version number
6
6
  :ne_rev, # 03 Linker revision number
@@ -52,7 +52,7 @@ class PEdump
52
52
  end
53
53
  end
54
54
 
55
- class Segment < PEdump.create_struct 'v4',
55
+ class Segment < IOStruct.new 'v4',
56
56
  :offset, :size, :flags, :min_alloc_size,
57
57
  # manual:
58
58
  :file_offset, :relocs
@@ -86,7 +86,7 @@ class PEdump
86
86
  end
87
87
  end
88
88
 
89
- class Reloc < PEdump.create_struct 'CCvvv',
89
+ class Reloc < IOStruct.new 'CCvvv',
90
90
  :source, :type,
91
91
  :offset, # offset of the relocation item within the segment
92
92
 
@@ -121,7 +121,7 @@ class PEdump
121
121
  end
122
122
  end
123
123
 
124
- class ResourceGroup < PEdump.create_struct 'vvV',
124
+ class ResourceGroup < IOStruct.new 'vvV',
125
125
  :type_id, :count, :reserved,
126
126
  # manual:
127
127
  :type, :children
@@ -143,7 +143,7 @@ class PEdump
143
143
  end
144
144
  end
145
145
 
146
- class ResourceInfo < PEdump.create_struct 'v4V',
146
+ class ResourceInfo < IOStruct.new 'v4V',
147
147
  :offset, :size, :flags, :name_offset, :reserved,
148
148
  # manual:
149
149
  :name
@@ -338,11 +338,11 @@ class PEdump
338
338
  # 0xFE = the entry does not refer to a segment but refers to a constant defined within the module.
339
339
  # else it is a segment index.
340
340
 
341
- class Bundle < PEdump.create_struct 'CC', :num_entries, :seg_idx,
341
+ class Bundle < IOStruct.new 'CC', :num_entries, :seg_idx,
342
342
  :entries # manual
343
343
 
344
- FixedEntry = PEdump.create_struct 'Cv', :flag, :offset
345
- MovableEntry = PEdump.create_struct 'CvCv', :flag, :int3F, :seg_idx, :offset
344
+ FixedEntry = IOStruct.new 'Cv', :flag, :offset
345
+ MovableEntry = IOStruct.new 'CvCv', :flag, :int3F, :seg_idx, :offset
346
346
 
347
347
  def movable?
348
348
  seg_idx == 0xff
@@ -1,7 +1,7 @@
1
1
  class PEdump; end
2
2
 
3
3
  class PEdump::NE
4
- class VS_VERSIONINFO < PEdump.create_struct( 'v2a16',
4
+ class VS_VERSIONINFO < IOStruct.new( 'v2a16',
5
5
  :wLength,
6
6
  :wValueLength,
7
7
  :szKey, # ASCII string "VS_VERSION_INFO".
@@ -41,7 +41,7 @@ class PEdump::NE
41
41
  end
42
42
  end
43
43
 
44
- class VS_FIXEDFILEINFO < PEdump.create_struct( 'V13',
44
+ class VS_FIXEDFILEINFO < IOStruct.new( 'V13',
45
45
  :dwSignature,
46
46
  :dwStrucVersion,
47
47
  :dwFileVersionMS,
@@ -65,7 +65,7 @@ class PEdump::NE
65
65
  end
66
66
  end
67
67
 
68
- class StringFileInfo < PEdump.create_struct( 'v2a15',
68
+ class StringFileInfo < IOStruct.new( 'v2a15',
69
69
  :wLength,
70
70
  :wValueLength, # always 0
71
71
  :szKey, # The ASCII string "StringFileInfo"
@@ -85,7 +85,7 @@ class PEdump::NE
85
85
  end
86
86
  end
87
87
 
88
- class StringTable < PEdump.create_struct( 'v2a9',
88
+ class StringTable < IOStruct.new( 'v2a9',
89
89
  :wLength, # The length, in bytes, of this StringTable structure,
90
90
  # including all structures indicated by the Children member.
91
91
  :wValueLength, # always 0
@@ -106,7 +106,7 @@ class PEdump::NE
106
106
  end
107
107
  end
108
108
 
109
- class VersionString < PEdump.create_struct( 'v2',
109
+ class VersionString < IOStruct.new( 'v2',
110
110
  :wLength, # The length, in bytes, of this String structure.
111
111
  :wValueLength, # The size, in words, of the Value member
112
112
  :szKey, # An arbitrary ASCII string
@@ -137,7 +137,7 @@ class PEdump::NE
137
137
  end
138
138
  end
139
139
 
140
- class VarFileInfo < PEdump.create_struct( 'v2a12',
140
+ class VarFileInfo < IOStruct.new( 'v2a12',
141
141
  :wLength,
142
142
  :wValueLength, # always 0
143
143
  :szKey, # The ASCII string "VarFileInfo"
@@ -153,7 +153,7 @@ class PEdump::NE
153
153
  end
154
154
  end
155
155
 
156
- class Var < PEdump.create_struct( 'v2a12',
156
+ class Var < IOStruct.new( 'v2a12',
157
157
  :wLength,
158
158
  :wValueLength, # The length, in bytes, of the Value member
159
159
  :szKey, # The ASCII string "Translation"
@@ -8,7 +8,9 @@ class PEdump
8
8
  :section_table
9
9
  )
10
10
  alias :ifh :image_file_header
11
+ alias :ifh= :image_file_header=
11
12
  alias :ioh :image_optional_header
13
+ alias :ioh= :image_optional_header=
12
14
  alias :sections :section_table
13
15
  alias :sections= :section_table=
14
16
  def x64?
@@ -236,7 +236,7 @@ class PEdump
236
236
 
237
237
  # see also http://www.informit.com/articles/article.aspx?p=1186882 about icons format
238
238
 
239
- class BITMAPINFOHEADER < create_struct 'V3v2V6',
239
+ class BITMAPINFOHEADER < IOStruct.new 'V3v2V6',
240
240
  :biSize, # BITMAPINFOHEADER::SIZE
241
241
  :biWidth,
242
242
  :biHeight,
@@ -255,13 +255,13 @@ class PEdump
255
255
  end
256
256
 
257
257
  # http://www.devsource.com/c/a/Architecture/Resources-From-PE-I/2/
258
- CUR_ICO_HEADER = create_struct('v3',
258
+ CUR_ICO_HEADER = IOStruct.new('v3',
259
259
  :wReserved, # always 0
260
260
  :wResID, # always 2
261
261
  :wNumImages # Number of cursor images/directory entries
262
262
  )
263
263
 
264
- CURDIRENTRY = create_struct 'v4Vv',
264
+ CURDIRENTRY = IOStruct.new 'v4Vv',
265
265
  :wWidth,
266
266
  :wHeight, # Divide by 2 to get the actual height.
267
267
  :wPlanes,
@@ -269,9 +269,9 @@ class PEdump
269
269
  :dwBytesInImage,
270
270
  :wID
271
271
 
272
- CURSOR_HOTSPOT = create_struct 'v2', :x, :y
272
+ CURSOR_HOTSPOT = IOStruct.new 'v2', :x, :y
273
273
 
274
- ICODIRENTRY = create_struct 'C4v2Vv',
274
+ ICODIRENTRY = IOStruct.new 'C4v2Vv',
275
275
  :bWidth,
276
276
  :bHeight,
277
277
  :bColors,
@@ -286,14 +286,14 @@ class PEdump
286
286
  %w'MESSAGETABLE GROUP_CURSOR' + [nil] + %w'GROUP_ICON' + [nil] +
287
287
  %w'VERSION DLGINCLUDE' + [nil] + %w'PLUGPLAY VXD ANICURSOR ANIICON HTML MANIFEST'
288
288
 
289
- IMAGE_RESOURCE_DIRECTORY_ENTRY = create_struct 'V2',
289
+ IMAGE_RESOURCE_DIRECTORY_ENTRY = IOStruct.new 'V2',
290
290
  :Name, :OffsetToData,
291
291
  :name, :data
292
292
 
293
- IMAGE_RESOURCE_DATA_ENTRY = create_struct 'V4',
293
+ IMAGE_RESOURCE_DATA_ENTRY = IOStruct.new 'V4',
294
294
  :OffsetToData, :Size, :CodePage, :Reserved
295
295
 
296
- IMAGE_RESOURCE_DIRECTORY = create_struct 'V2v4',
296
+ IMAGE_RESOURCE_DIRECTORY = IOStruct.new 'V2v4',
297
297
  :Characteristics, :TimeDateStamp, # 2dw
298
298
  :MajorVersion, :MinorVersion, :NumberOfNamedEntries, :NumberOfIdEntries, # 4w
299
299
  :entries # manual
@@ -27,7 +27,7 @@ class PEdump
27
27
  # WIN_CERT_TYPE_PKCS1_SIGN (0x0009) bCertificate contains PKCS1_MODULE_SIGN fields.
28
28
 
29
29
  # http://msdn.microsoft.com/en-us/library/aa447037.aspx
30
- class WIN_CERTIFICATE < create_struct 'Vvv',
30
+ class WIN_CERTIFICATE < IOStruct.new 'Vvv',
31
31
  :dwLength,
32
32
  :wRevision,
33
33
  :wCertificateType,
@@ -1,5 +1,5 @@
1
1
  class PEdump
2
- IMAGE_TLS_DIRECTORY32 = create_struct 'V6',
2
+ IMAGE_TLS_DIRECTORY32 = IOStruct.new 'V6',
3
3
  :StartAddressOfRawData,
4
4
  :EndAddressOfRawData,
5
5
  :AddressOfIndex,
@@ -7,7 +7,7 @@ class PEdump
7
7
  :SizeOfZeroFill,
8
8
  :Characteristics
9
9
 
10
- IMAGE_TLS_DIRECTORY64 = create_struct 'Q4V2',
10
+ IMAGE_TLS_DIRECTORY64 = IOStruct.new 'Q4V2',
11
11
  :StartAddressOfRawData,
12
12
  :EndAddressOfRawData,
13
13
  :AddressOfIndex,
@@ -22,7 +22,12 @@ class PEdump::Unpacker::ASPack
22
22
  attr_accessor :logger
23
23
 
24
24
  def initialize io, params = {}
25
- params[:logger] ||= PEdump::Logger.create(params)
25
+ params[:logger] ||= PEdump::Logger.create(params)
26
+
27
+ # XXX aspack unpacker code does not distinguish RVA from VA, so set
28
+ # image base to zero for RVA be equal VA
29
+ params[:image_base] ||= 0
30
+
26
31
  @logger = params[:logger]
27
32
  @ldr = PEdump::Loader.new(io, params)
28
33
  @io = io
@@ -311,7 +316,7 @@ class PEdump::Unpacker::ASPack
311
316
  74 jz short exit_relocs_loop
312
317
  EOC
313
318
 
314
- SECTION_INFO = PEdump.create_struct 'VlV', :va, :size, :flags
319
+ SECTION_INFO = IOStruct.new 'VlV', :va, :size, :flags
315
320
 
316
321
  ########################################################################
317
322