pedump 0.4.16 → 0.5.0

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