rex-bin_tools 0.1.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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +52 -0
- data/Gemfile +4 -0
- data/LICENSE +27 -0
- data/README.md +22 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/msfbinscan +284 -0
- data/bin/msfelfscan +120 -0
- data/bin/msfmachscan +100 -0
- data/bin/msfpescan +184 -0
- data/bin/setup +8 -0
- data/data/identify.txt +3043 -0
- data/lib/rex/assembly/nasm.rb +104 -0
- data/lib/rex/bin_tools.rb +13 -0
- data/lib/rex/bin_tools/version.rb +5 -0
- data/lib/rex/elfparsey.rb +9 -0
- data/lib/rex/elfparsey/elf.rb +121 -0
- data/lib/rex/elfparsey/elfbase.rb +265 -0
- data/lib/rex/elfparsey/exceptions.rb +25 -0
- data/lib/rex/elfscan.rb +10 -0
- data/lib/rex/elfscan/scanner.rb +226 -0
- data/lib/rex/elfscan/search.rb +44 -0
- data/lib/rex/image_source.rb +10 -0
- data/lib/rex/image_source/disk.rb +58 -0
- data/lib/rex/image_source/image_source.rb +48 -0
- data/lib/rex/image_source/memory.rb +35 -0
- data/lib/rex/machparsey.rb +9 -0
- data/lib/rex/machparsey/exceptions.rb +31 -0
- data/lib/rex/machparsey/mach.rb +209 -0
- data/lib/rex/machparsey/machbase.rb +408 -0
- data/lib/rex/machscan.rb +9 -0
- data/lib/rex/machscan/scanner.rb +217 -0
- data/lib/rex/peparsey.rb +10 -0
- data/lib/rex/peparsey/exceptions.rb +30 -0
- data/lib/rex/peparsey/pe.rb +210 -0
- data/lib/rex/peparsey/pe_memdump.rb +61 -0
- data/lib/rex/peparsey/pebase.rb +1662 -0
- data/lib/rex/peparsey/section.rb +128 -0
- data/lib/rex/pescan.rb +11 -0
- data/lib/rex/pescan/analyze.rb +366 -0
- data/lib/rex/pescan/scanner.rb +230 -0
- data/lib/rex/pescan/search.rb +68 -0
- data/rex-bin_tools.gemspec +32 -0
- metadata +284 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/image_source'
|
4
|
+
require 'rex/peparsey/exceptions'
|
5
|
+
require 'rex/peparsey/pebase'
|
6
|
+
require 'rex/peparsey/section'
|
7
|
+
require 'rex/struct2'
|
8
|
+
|
9
|
+
#
|
10
|
+
# This class is for use with memdump.exe generated dump images. It basically
|
11
|
+
# just lies, gets the ImageBase from the file name, and generates 1 big
|
12
|
+
# header_section with all of the data in it...
|
13
|
+
#
|
14
|
+
|
15
|
+
module Rex
|
16
|
+
module PeParsey
|
17
|
+
class PeMemDump < Pe
|
18
|
+
|
19
|
+
def self.new_from_string(data)
|
20
|
+
raise NotImplementError
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.new_from_file(filename, disk_backed = false)
|
24
|
+
|
25
|
+
if filename[-4, 4] != '.rng'
|
26
|
+
raise "Not a .rng file: #{filename}"
|
27
|
+
end
|
28
|
+
|
29
|
+
if filename[-9, 9] == "index.rng"
|
30
|
+
raise SkipError
|
31
|
+
end
|
32
|
+
|
33
|
+
file = File.open(filename, 'rb')
|
34
|
+
|
35
|
+
if disk_backed
|
36
|
+
obj = ImageSource::Disk.new(file)
|
37
|
+
else
|
38
|
+
obj = ImageSource::Memory.new(file.read)
|
39
|
+
obj.close
|
40
|
+
end
|
41
|
+
|
42
|
+
return self.new(obj, filename.gsub(/.*[\/\\]/, '')[0,8].hex)
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(isource, base)
|
46
|
+
self._isource = isource
|
47
|
+
self.header_section = Section.new(isource, base, nil)
|
48
|
+
self.sections = [ self.header_section ]
|
49
|
+
self.image_base = 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def all_sections
|
53
|
+
self.sections
|
54
|
+
end
|
55
|
+
|
56
|
+
# No 64-bit support
|
57
|
+
def ptr_64?
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
end end end
|
@@ -0,0 +1,1662 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/peparsey/exceptions'
|
4
|
+
require 'rex/struct2'
|
5
|
+
|
6
|
+
module Rex
|
7
|
+
module PeParsey
|
8
|
+
class PeBase
|
9
|
+
|
10
|
+
|
11
|
+
# #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
|
12
|
+
IMAGE_DOS_SIGNATURE = 0x5a4d
|
13
|
+
|
14
|
+
IMAGE_DOS_HEADER_SIZE = 64
|
15
|
+
# Struct
|
16
|
+
# typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
|
17
|
+
# WORD e_magic; // Magic number
|
18
|
+
# WORD e_cblp; // Bytes on last page of file
|
19
|
+
# WORD e_cp; // Pages in file
|
20
|
+
# WORD e_crlc; // Relocations
|
21
|
+
# WORD e_cparhdr; // Size of header in paragraphs
|
22
|
+
# WORD e_minalloc; // Minimum extra paragraphs needed
|
23
|
+
# WORD e_maxalloc; // Maximum extra paragraphs needed
|
24
|
+
# WORD e_ss; // Initial (relative) SS value
|
25
|
+
# WORD e_sp; // Initial SP value
|
26
|
+
# WORD e_csum; // Checksum
|
27
|
+
# WORD e_ip; // Initial IP value
|
28
|
+
# WORD e_cs; // Initial (relative) CS value
|
29
|
+
# WORD e_lfarlc; // File address of relocation table
|
30
|
+
# WORD e_ovno; // Overlay number
|
31
|
+
# WORD e_res[4]; // Reserved words
|
32
|
+
# WORD e_oemid; // OEM identifier (for e_oeminfo)
|
33
|
+
# WORD e_oeminfo; // OEM information; e_oemid specific
|
34
|
+
# WORD e_res2[10]; // Reserved words
|
35
|
+
# LONG e_lfanew; // File address of new exe header
|
36
|
+
# } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
|
37
|
+
IMAGE_DOS_HEADER = Rex::Struct2::CStructTemplate.new(
|
38
|
+
[ 'uint16v', 'e_magic', IMAGE_DOS_SIGNATURE ],
|
39
|
+
[ 'uint16v', 'e_cblp', 0 ],
|
40
|
+
[ 'uint16v', 'e_cp', 0 ],
|
41
|
+
[ 'uint16v', 'e_crlc', 0 ],
|
42
|
+
[ 'uint16v', 'e_cparhdr', 0 ],
|
43
|
+
[ 'uint16v', 'e_minalloc', 0 ],
|
44
|
+
[ 'uint16v', 'e_maxalloc', 0 ],
|
45
|
+
[ 'uint16v', 'e_ss', 0 ],
|
46
|
+
[ 'uint16v', 'e_sp', 0 ],
|
47
|
+
[ 'uint16v', 'e_csum', 0 ],
|
48
|
+
[ 'uint16v', 'e_ip', 0 ],
|
49
|
+
[ 'uint16v', 'e_cs', 0 ],
|
50
|
+
[ 'uint16v', 'e_lfarlc', 0 ],
|
51
|
+
[ 'uint16v', 'e_ovno', 0 ],
|
52
|
+
[ 'template', 'e_res', Rex::Struct2::CStructTemplate.new(
|
53
|
+
[ 'uint16v', 'e_res_0', 0 ],
|
54
|
+
[ 'uint16v', 'e_res_1', 0 ],
|
55
|
+
[ 'uint16v', 'e_res_2', 0 ],
|
56
|
+
[ 'uint16v', 'e_res_3', 0 ]
|
57
|
+
)],
|
58
|
+
[ 'uint16v', 'e_oemid', 0 ],
|
59
|
+
[ 'uint16v', 'e_oeminfo', 0 ],
|
60
|
+
[ 'template', 'e_res2', Rex::Struct2::CStructTemplate.new(
|
61
|
+
[ 'uint16v', 'e_res2_0', 0 ],
|
62
|
+
[ 'uint16v', 'e_res2_1', 0 ],
|
63
|
+
[ 'uint16v', 'e_res2_2', 0 ],
|
64
|
+
[ 'uint16v', 'e_res2_3', 0 ],
|
65
|
+
[ 'uint16v', 'e_res2_4', 0 ],
|
66
|
+
[ 'uint16v', 'e_res2_5', 0 ],
|
67
|
+
[ 'uint16v', 'e_res2_6', 0 ],
|
68
|
+
[ 'uint16v', 'e_res2_7', 0 ],
|
69
|
+
[ 'uint16v', 'e_res2_8', 0 ],
|
70
|
+
[ 'uint16v', 'e_res2_9', 0 ]
|
71
|
+
)],
|
72
|
+
[ 'uint32v', 'e_lfanew', 0 ]
|
73
|
+
)
|
74
|
+
|
75
|
+
|
76
|
+
class HeaderAccessor
|
77
|
+
attr_accessor :dos, :file, :opt, :sections, :config, :exceptions, :tls
|
78
|
+
def initialize
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class GenericStruct
|
83
|
+
attr_accessor :struct
|
84
|
+
def initialize(_struct)
|
85
|
+
self.struct = _struct
|
86
|
+
end
|
87
|
+
|
88
|
+
# The following methods are just pass-throughs for struct
|
89
|
+
|
90
|
+
# Access a value
|
91
|
+
def v
|
92
|
+
struct.v
|
93
|
+
end
|
94
|
+
|
95
|
+
# Access a value by array
|
96
|
+
def [](*args)
|
97
|
+
struct[*args]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Obtain an array of all fields
|
101
|
+
def keys
|
102
|
+
struct.keys
|
103
|
+
end
|
104
|
+
|
105
|
+
def method_missing(meth, *args)
|
106
|
+
v[meth.to_s] || (raise NoMethodError.new, meth)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class GenericHeader < GenericStruct
|
111
|
+
end
|
112
|
+
|
113
|
+
class DosHeader < GenericHeader
|
114
|
+
|
115
|
+
def initialize(rawdata)
|
116
|
+
dos_header = IMAGE_DOS_HEADER.make_struct
|
117
|
+
|
118
|
+
if !dos_header.from_s(rawdata)
|
119
|
+
raise DosHeaderError, "Couldn't parse IMAGE_DOS_HEADER", caller
|
120
|
+
end
|
121
|
+
|
122
|
+
if dos_header.v['e_magic'] != IMAGE_DOS_SIGNATURE
|
123
|
+
raise DosHeaderError, "Couldn't find DOS e_magic", caller
|
124
|
+
end
|
125
|
+
|
126
|
+
self.struct = dos_header
|
127
|
+
end
|
128
|
+
|
129
|
+
def e_lfanew
|
130
|
+
v['e_lfanew']
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def self._parse_dos_header(rawdata)
|
136
|
+
return DosHeader.new(rawdata)
|
137
|
+
end
|
138
|
+
|
139
|
+
# #define IMAGE_NT_SIGNATURE 0x00004550 // PE00
|
140
|
+
IMAGE_NT_SIGNATURE = 0x00004550
|
141
|
+
# #define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
|
142
|
+
IMAGE_FILE_MACHINE_I386 = 0x014c
|
143
|
+
# #define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
|
144
|
+
IMAGE_FILE_MACHINE_IA64 = 0x0200
|
145
|
+
# #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
|
146
|
+
IMAGE_FILE_MACHINE_ALPHA64 = 0x0284
|
147
|
+
# #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
|
148
|
+
IMAGE_FILE_MACHINE_AMD64 = 0x8664
|
149
|
+
# #define IMAGE_SIZEOF_FILE_HEADER 20
|
150
|
+
IMAGE_FILE_HEADER_SIZE = 20+4 # because we include the signature
|
151
|
+
|
152
|
+
# C struct defining the PE file header
|
153
|
+
# typedef struct _IMAGE_FILE_HEADER {
|
154
|
+
# WORD Machine;
|
155
|
+
# WORD NumberOfSections;
|
156
|
+
# DWORD TimeDateStamp;
|
157
|
+
# DWORD PointerToSymbolTable;
|
158
|
+
# DWORD NumberOfSymbols;
|
159
|
+
# WORD SizeOfOptionalHeader;
|
160
|
+
# WORD Characteristics;
|
161
|
+
# } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
|
162
|
+
IMAGE_FILE_HEADER = Rex::Struct2::CStructTemplate.new(
|
163
|
+
# not really in the header, but easier for us this way
|
164
|
+
[ 'uint32v', 'NtSignature', 0 ],
|
165
|
+
[ 'uint16v', 'Machine', 0 ],
|
166
|
+
[ 'uint16v', 'NumberOfSections', 0 ],
|
167
|
+
[ 'uint32v', 'TimeDateStamp', 0 ],
|
168
|
+
[ 'uint32v', 'PointerToSymbolTable', 0 ],
|
169
|
+
[ 'uint32v', 'NumberOfSymbols', 0 ],
|
170
|
+
[ 'uint16v', 'SizeOfOptionalHeader', 0 ],
|
171
|
+
[ 'uint16v', 'Characteristics', 0 ]
|
172
|
+
)
|
173
|
+
|
174
|
+
SUPPORTED_MACHINES = [
|
175
|
+
IMAGE_FILE_MACHINE_I386,
|
176
|
+
IMAGE_FILE_MACHINE_IA64,
|
177
|
+
IMAGE_FILE_MACHINE_ALPHA64,
|
178
|
+
IMAGE_FILE_MACHINE_AMD64
|
179
|
+
]
|
180
|
+
|
181
|
+
class FileHeader < GenericHeader
|
182
|
+
def initialize(rawdata)
|
183
|
+
file_header = IMAGE_FILE_HEADER.make_struct
|
184
|
+
|
185
|
+
if !file_header.from_s(rawdata)
|
186
|
+
raise FileHeaderError, "Couldn't parse IMAGE_FILE_HEADER", caller
|
187
|
+
end
|
188
|
+
|
189
|
+
if file_header.v['NtSignature'] != IMAGE_NT_SIGNATURE
|
190
|
+
raise FileHeaderError, "Couldn't find the PE magic!"
|
191
|
+
end
|
192
|
+
|
193
|
+
if SUPPORTED_MACHINES.include?(file_header.v['Machine']) == false
|
194
|
+
raise FileHeaderError, "Unsupported machine type: #{file_header.v['Machine']}", caller
|
195
|
+
end
|
196
|
+
|
197
|
+
self.struct = file_header
|
198
|
+
end
|
199
|
+
|
200
|
+
def Machine
|
201
|
+
v['Machine']
|
202
|
+
end
|
203
|
+
|
204
|
+
def SizeOfOptionalHeader
|
205
|
+
v['SizeOfOptionalHeader']
|
206
|
+
end
|
207
|
+
|
208
|
+
def NumberOfSections
|
209
|
+
v['NumberOfSections']
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def self._parse_file_header(rawdata)
|
214
|
+
return FileHeader.new(rawdata)
|
215
|
+
end
|
216
|
+
|
217
|
+
IMAGE_ORDINAL_FLAG32 = 0x80000000
|
218
|
+
IMAGE_IMPORT_DESCRIPTOR_SIZE = 20
|
219
|
+
# Struct
|
220
|
+
# typedef struct _IMAGE_IMPORT_DESCRIPTOR {
|
221
|
+
# union {
|
222
|
+
# DWORD Characteristics; // 0 for terminating null import descriptor
|
223
|
+
# DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
|
224
|
+
# };
|
225
|
+
# DWORD TimeDateStamp; // 0 if not bound,
|
226
|
+
# // -1 if bound, and real date\time stamp
|
227
|
+
# // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
|
228
|
+
# // O.W. date/time stamp of DLL bound to (Old BIND)
|
229
|
+
#
|
230
|
+
# DWORD ForwarderChain; // -1 if no forwarders
|
231
|
+
# DWORD Name;
|
232
|
+
# DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
|
233
|
+
# } IMAGE_IMPORT_DESCRIPTOR;
|
234
|
+
IMAGE_IMPORT_DESCRIPTOR = Rex::Struct2::CStructTemplate.new(
|
235
|
+
[ 'uint32v', 'OriginalFirstThunk', 0 ],
|
236
|
+
[ 'uint32v', 'TimeDateStamp', 0 ],
|
237
|
+
[ 'uint32v', 'ForwarderChain', 0 ],
|
238
|
+
[ 'uint32v', 'Name', 0 ],
|
239
|
+
[ 'uint32v', 'FirstThunk', 0 ]
|
240
|
+
)
|
241
|
+
|
242
|
+
# typedef struct _IMAGE_IMPORT_BY_NAME {
|
243
|
+
# WORD Hint;
|
244
|
+
# BYTE Name[1];
|
245
|
+
# } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
|
246
|
+
#
|
247
|
+
|
248
|
+
class ImportDescriptor
|
249
|
+
attr_accessor :name, :entries
|
250
|
+
def initialize(_name, _entries)
|
251
|
+
self.name = _name
|
252
|
+
self.entries = _entries
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class ImportEntry
|
257
|
+
attr_accessor :name, :ordinal
|
258
|
+
def initialize(_name, _ordinal)
|
259
|
+
self.name = _name
|
260
|
+
self.ordinal = _ordinal
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# sizeof(struct _IMAGE_EXPORT_DESCRIPTOR)
|
265
|
+
IMAGE_EXPORT_DESCRIPTOR_SIZE = 40
|
266
|
+
# Struct defining the export table
|
267
|
+
# typedef struct _IMAGE_EXPORT_DIRECTORY {
|
268
|
+
# DWORD Characteristics;
|
269
|
+
# DWORD TimeDateStamp;
|
270
|
+
# WORD MajorVersion;
|
271
|
+
# WORD MinorVersion;
|
272
|
+
# DWORD Name;
|
273
|
+
# DWORD Base;
|
274
|
+
# DWORD NumberOfFunctions;
|
275
|
+
# DWORD NumberOfNames;
|
276
|
+
# DWORD AddressOfFunctions; // RVA from base of image
|
277
|
+
# DWORD AddressOfNames; // RVA from base of image
|
278
|
+
# DWORD AddressOfNameOrdinals; // RVA from base of image
|
279
|
+
# } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
|
280
|
+
IMAGE_EXPORT_DESCRIPTOR = Rex::Struct2::CStructTemplate.new(
|
281
|
+
[ 'uint32v', 'Characteristics', 0 ],
|
282
|
+
[ 'uint32v', 'TimeDateStamp', 0 ],
|
283
|
+
[ 'uint16v', 'MajorVersion', 0 ],
|
284
|
+
[ 'uint16v', 'MinorVersion', 0 ],
|
285
|
+
[ 'uint32v', 'Name', 0 ],
|
286
|
+
[ 'uint32v', 'Base', 0 ],
|
287
|
+
[ 'uint32v', 'NumberOfFunctions', 0 ],
|
288
|
+
[ 'uint32v', 'NumberOfNames', 0 ],
|
289
|
+
[ 'uint32v', 'AddressOfFunctions', 0 ],
|
290
|
+
[ 'uint32v', 'AddressOfNames', 0 ],
|
291
|
+
[ 'uint32v', 'AddressOfNameOrdinals', 0 ]
|
292
|
+
)
|
293
|
+
|
294
|
+
class ExportDirectory
|
295
|
+
attr_accessor :name, :entries, :base
|
296
|
+
|
297
|
+
def initialize(_name, _entries, _base)
|
298
|
+
self.name = _name
|
299
|
+
self.entries = _entries
|
300
|
+
self.base = _base
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
class ExportEntry
|
305
|
+
attr_accessor :name, :ordinal, :rva
|
306
|
+
def initialize(_name, _ordinal, _rva)
|
307
|
+
self.name = _name
|
308
|
+
self.ordinal = _ordinal
|
309
|
+
self.rva = _rva
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16
|
314
|
+
IMAGE_DATA_DIRECTORY_SIZE = 8
|
315
|
+
IMAGE_DIRECTORY_ENTRY_EXPORT = 0
|
316
|
+
IMAGE_DIRECTORY_ENTRY_IMPORT = 1
|
317
|
+
IMAGE_DIRECTORY_ENTRY_RESOURCE = 2
|
318
|
+
IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3
|
319
|
+
IMAGE_DIRECTORY_ENTRY_SECURITY = 4
|
320
|
+
IMAGE_DIRECTORY_ENTRY_BASERELOC = 5
|
321
|
+
IMAGE_DIRECTORY_ENTRY_DEBUG = 6
|
322
|
+
IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7
|
323
|
+
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7
|
324
|
+
IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8
|
325
|
+
IMAGE_DIRECTORY_ENTRY_TLS = 9
|
326
|
+
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10
|
327
|
+
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11
|
328
|
+
IMAGE_DIRECTORY_ENTRY_IAT = 12
|
329
|
+
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13
|
330
|
+
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
|
331
|
+
# Struct
|
332
|
+
# typedef struct _IMAGE_DATA_DIRECTORY {
|
333
|
+
# DWORD VirtualAddress;
|
334
|
+
# DWORD Size;
|
335
|
+
# } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
|
336
|
+
IMAGE_DATA_DIRECTORY = Rex::Struct2::CStructTemplate.new(
|
337
|
+
[ 'uint32v', 'VirtualAddress', 0 ],
|
338
|
+
[ 'uint32v', 'Size', 0 ]
|
339
|
+
)
|
340
|
+
|
341
|
+
# Struct
|
342
|
+
# typedef struct _IMAGE_OPTIONAL_HEADER {
|
343
|
+
# //
|
344
|
+
# // Standard fields.
|
345
|
+
# //
|
346
|
+
#
|
347
|
+
# WORD Magic;
|
348
|
+
# BYTE MajorLinkerVersion;
|
349
|
+
# BYTE MinorLinkerVersion;
|
350
|
+
# DWORD SizeOfCode;
|
351
|
+
# DWORD SizeOfInitializedData;
|
352
|
+
# DWORD SizeOfUninitializedData;
|
353
|
+
# DWORD AddressOfEntryPoint;
|
354
|
+
# DWORD BaseOfCode;
|
355
|
+
# DWORD BaseOfData;
|
356
|
+
#
|
357
|
+
# //
|
358
|
+
# // NT additional fields.
|
359
|
+
# //
|
360
|
+
#
|
361
|
+
# DWORD ImageBase;
|
362
|
+
# DWORD SectionAlignment;
|
363
|
+
# DWORD FileAlignment;
|
364
|
+
# WORD MajorOperatingSystemVersion;
|
365
|
+
# WORD MinorOperatingSystemVersion;
|
366
|
+
# WORD MajorImageVersion;
|
367
|
+
# WORD MinorImageVersion;
|
368
|
+
# WORD MajorSubsystemVersion;
|
369
|
+
# WORD MinorSubsystemVersion;
|
370
|
+
# DWORD Win32VersionValue;
|
371
|
+
# DWORD SizeOfImage;
|
372
|
+
# DWORD SizeOfHeaders;
|
373
|
+
# DWORD CheckSum;
|
374
|
+
# WORD Subsystem;
|
375
|
+
# WORD DllCharacteristics;
|
376
|
+
# DWORD SizeOfStackReserve;
|
377
|
+
# DWORD SizeOfStackCommit;
|
378
|
+
# DWORD SizeOfHeapReserve;
|
379
|
+
# DWORD SizeOfHeapCommit;
|
380
|
+
# DWORD LoaderFlags;
|
381
|
+
# DWORD NumberOfRvaAndSizes;
|
382
|
+
# IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
383
|
+
# } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
|
384
|
+
#
|
385
|
+
# #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
|
386
|
+
# #define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224
|
387
|
+
#
|
388
|
+
|
389
|
+
IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b
|
390
|
+
IMAGE_SIZEOF_NT_OPTIONAL32_HEADER = 224
|
391
|
+
IMAGE_OPTIONAL_HEADER32 = Rex::Struct2::CStructTemplate.new(
|
392
|
+
[ 'uint16v', 'Magic', 0 ],
|
393
|
+
[ 'uint8', 'MajorLinkerVersion', 0 ],
|
394
|
+
[ 'uint8', 'MinorLinkerVersion', 0 ],
|
395
|
+
[ 'uint32v', 'SizeOfCode', 0 ],
|
396
|
+
[ 'uint32v', 'SizeOfInitializeData', 0 ],
|
397
|
+
[ 'uint32v', 'SizeOfUninitializeData', 0 ],
|
398
|
+
[ 'uint32v', 'AddressOfEntryPoint', 0 ],
|
399
|
+
[ 'uint32v', 'BaseOfCode', 0 ],
|
400
|
+
[ 'uint32v', 'BaseOfData', 0 ],
|
401
|
+
[ 'uint32v', 'ImageBase', 0 ],
|
402
|
+
[ 'uint32v', 'SectionAlignment', 0 ],
|
403
|
+
[ 'uint32v', 'FileAlignment', 0 ],
|
404
|
+
[ 'uint16v', 'MajorOperatingSystemVersion', 0 ],
|
405
|
+
[ 'uint16v', 'MinorOperatingSystemVersion', 0 ],
|
406
|
+
[ 'uint16v', 'MajorImageVersion', 0 ],
|
407
|
+
[ 'uint16v', 'MinorImageVersion', 0 ],
|
408
|
+
[ 'uint16v', 'MajorSubsystemVersion', 0 ],
|
409
|
+
[ 'uint16v', 'MinorSubsystemVersion', 0 ],
|
410
|
+
[ 'uint32v', 'Win32VersionValue', 0 ],
|
411
|
+
[ 'uint32v', 'SizeOfImage', 0 ],
|
412
|
+
[ 'uint32v', 'SizeOfHeaders', 0 ],
|
413
|
+
[ 'uint32v', 'CheckSum', 0 ],
|
414
|
+
[ 'uint16v', 'Subsystem', 0 ],
|
415
|
+
[ 'uint16v', 'DllCharacteristics', 0 ],
|
416
|
+
[ 'uint32v', 'SizeOfStackReserve', 0 ],
|
417
|
+
[ 'uint32v', 'SizeOfStackCommit', 0 ],
|
418
|
+
[ 'uint32v', 'SizeOfHeapReserve', 0 ],
|
419
|
+
[ 'uint32v', 'SizeOfHeapCommit', 0 ],
|
420
|
+
[ 'uint32v', 'LoaderFlags', 0 ],
|
421
|
+
[ 'uint32v', 'NumberOfRvaAndSizes', 0 ],
|
422
|
+
[ 'template', 'DataDirectory', Rex::Struct2::CStructTemplate.new(
|
423
|
+
[ 'template', 'DataDirectoryEntry_0', IMAGE_DATA_DIRECTORY ],
|
424
|
+
[ 'template', 'DataDirectoryEntry_1', IMAGE_DATA_DIRECTORY ],
|
425
|
+
[ 'template', 'DataDirectoryEntry_2', IMAGE_DATA_DIRECTORY ],
|
426
|
+
[ 'template', 'DataDirectoryEntry_3', IMAGE_DATA_DIRECTORY ],
|
427
|
+
[ 'template', 'DataDirectoryEntry_4', IMAGE_DATA_DIRECTORY ],
|
428
|
+
[ 'template', 'DataDirectoryEntry_5', IMAGE_DATA_DIRECTORY ],
|
429
|
+
[ 'template', 'DataDirectoryEntry_6', IMAGE_DATA_DIRECTORY ],
|
430
|
+
[ 'template', 'DataDirectoryEntry_7', IMAGE_DATA_DIRECTORY ],
|
431
|
+
[ 'template', 'DataDirectoryEntry_8', IMAGE_DATA_DIRECTORY ],
|
432
|
+
[ 'template', 'DataDirectoryEntry_9', IMAGE_DATA_DIRECTORY ],
|
433
|
+
[ 'template', 'DataDirectoryEntry_10', IMAGE_DATA_DIRECTORY ],
|
434
|
+
[ 'template', 'DataDirectoryEntry_11', IMAGE_DATA_DIRECTORY ],
|
435
|
+
[ 'template', 'DataDirectoryEntry_12', IMAGE_DATA_DIRECTORY ],
|
436
|
+
[ 'template', 'DataDirectoryEntry_13', IMAGE_DATA_DIRECTORY ],
|
437
|
+
[ 'template', 'DataDirectoryEntry_14', IMAGE_DATA_DIRECTORY ],
|
438
|
+
[ 'template', 'DataDirectoryEntry_15', IMAGE_DATA_DIRECTORY ]
|
439
|
+
)]
|
440
|
+
)
|
441
|
+
|
442
|
+
# #define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240
|
443
|
+
IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
|
444
|
+
# #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
|
445
|
+
IMAGE_SIZEOF_NT_OPTIONAL64_HEADER = 240
|
446
|
+
|
447
|
+
# Struct
|
448
|
+
# typedef struct _IMAGE_OPTIONAL_HEADER64 {
|
449
|
+
# USHORT Magic;
|
450
|
+
# UCHAR MajorLinkerVersion;
|
451
|
+
# UCHAR MinorLinkerVersion;
|
452
|
+
# ULONG SizeOfCode;
|
453
|
+
# ULONG SizeOfInitializedData;
|
454
|
+
# ULONG SizeOfUninitializedData;
|
455
|
+
# ULONG AddressOfEntryPoint;
|
456
|
+
# ULONG BaseOfCode;
|
457
|
+
# ULONGLONG ImageBase;
|
458
|
+
# ULONG SectionAlignment;
|
459
|
+
# ULONG FileAlignment;
|
460
|
+
# USHORT MajorOperatingSystemVersion;
|
461
|
+
# USHORT MinorOperatingSystemVersion;
|
462
|
+
# USHORT MajorImageVersion;
|
463
|
+
# USHORT MinorImageVersion;
|
464
|
+
# USHORT MajorSubsystemVersion;
|
465
|
+
# USHORT MinorSubsystemVersion;
|
466
|
+
# ULONG Win32VersionValue;
|
467
|
+
# ULONG SizeOfImage;
|
468
|
+
# ULONG SizeOfHeaders;
|
469
|
+
# ULONG CheckSum;
|
470
|
+
# USHORT Subsystem;
|
471
|
+
# USHORT DllCharacteristics;
|
472
|
+
# ULONGLONG SizeOfStackReserve;
|
473
|
+
# ULONGLONG SizeOfStackCommit;
|
474
|
+
# ULONGLONG SizeOfHeapReserve;
|
475
|
+
# ULONGLONG SizeOfHeapCommit;
|
476
|
+
# ULONG LoaderFlags;
|
477
|
+
# ULONG NumberOfRvaAndSizes;
|
478
|
+
# IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
479
|
+
# } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
|
480
|
+
IMAGE_OPTIONAL_HEADER64 = Rex::Struct2::CStructTemplate.new(
|
481
|
+
[ 'uint16v', 'Magic', 0 ],
|
482
|
+
[ 'uint8', 'MajorLinkerVersion', 0 ],
|
483
|
+
[ 'uint8', 'MinorLinkerVersion', 0 ],
|
484
|
+
[ 'uint32v', 'SizeOfCode', 0 ],
|
485
|
+
[ 'uint32v', 'SizeOfInitializeData', 0 ],
|
486
|
+
[ 'uint32v', 'SizeOfUninitializeData', 0 ],
|
487
|
+
[ 'uint32v', 'AddressOfEntryPoint', 0 ],
|
488
|
+
[ 'uint32v', 'BaseOfCode', 0 ],
|
489
|
+
[ 'uint64v', 'ImageBase', 0 ],
|
490
|
+
[ 'uint32v', 'SectionAlignment', 0 ],
|
491
|
+
[ 'uint32v', 'FileAlignment', 0 ],
|
492
|
+
[ 'uint16v', 'MajorOperatingsystemVersion', 0 ],
|
493
|
+
[ 'uint16v', 'MinorOperatingsystemVersion', 0 ],
|
494
|
+
[ 'uint16v', 'MajorImageVersion', 0 ],
|
495
|
+
[ 'uint16v', 'MinorImageVersion', 0 ],
|
496
|
+
[ 'uint16v', 'MajorSubsystemVersion', 0 ],
|
497
|
+
[ 'uint16v', 'MinorSubsystemVersion', 0 ],
|
498
|
+
[ 'uint32v', 'Win32VersionValue', 0 ],
|
499
|
+
[ 'uint32v', 'SizeOfImage', 0 ],
|
500
|
+
[ 'uint32v', 'SizeOfHeaders', 0 ],
|
501
|
+
[ 'uint32v', 'CheckSum', 0 ],
|
502
|
+
[ 'uint16v', 'Subsystem', 0 ],
|
503
|
+
[ 'uint16v', 'DllCharacteristics', 0 ],
|
504
|
+
[ 'uint64v', 'SizeOfStackReserve', 0 ],
|
505
|
+
[ 'uint64v', 'SizeOfStackCommit', 0 ],
|
506
|
+
[ 'uint64v', 'SizeOfHeapReserve', 0 ],
|
507
|
+
[ 'uint64v', 'SizeOfHeapCommit', 0 ],
|
508
|
+
[ 'uint32v', 'LoaderFlags', 0 ],
|
509
|
+
[ 'uint32v', 'NumberOfRvaAndSizes', 0 ],
|
510
|
+
[ 'template', 'DataDirectory', Rex::Struct2::CStructTemplate.new(
|
511
|
+
[ 'template', 'DataDirectoryEntry_0', IMAGE_DATA_DIRECTORY ],
|
512
|
+
[ 'template', 'DataDirectoryEntry_1', IMAGE_DATA_DIRECTORY ],
|
513
|
+
[ 'template', 'DataDirectoryEntry_2', IMAGE_DATA_DIRECTORY ],
|
514
|
+
[ 'template', 'DataDirectoryEntry_3', IMAGE_DATA_DIRECTORY ],
|
515
|
+
[ 'template', 'DataDirectoryEntry_4', IMAGE_DATA_DIRECTORY ],
|
516
|
+
[ 'template', 'DataDirectoryEntry_5', IMAGE_DATA_DIRECTORY ],
|
517
|
+
[ 'template', 'DataDirectoryEntry_6', IMAGE_DATA_DIRECTORY ],
|
518
|
+
[ 'template', 'DataDirectoryEntry_7', IMAGE_DATA_DIRECTORY ],
|
519
|
+
[ 'template', 'DataDirectoryEntry_8', IMAGE_DATA_DIRECTORY ],
|
520
|
+
[ 'template', 'DataDirectoryEntry_9', IMAGE_DATA_DIRECTORY ],
|
521
|
+
[ 'template', 'DataDirectoryEntry_10', IMAGE_DATA_DIRECTORY ],
|
522
|
+
[ 'template', 'DataDirectoryEntry_11', IMAGE_DATA_DIRECTORY ],
|
523
|
+
[ 'template', 'DataDirectoryEntry_12', IMAGE_DATA_DIRECTORY ],
|
524
|
+
[ 'template', 'DataDirectoryEntry_13', IMAGE_DATA_DIRECTORY ],
|
525
|
+
[ 'template', 'DataDirectoryEntry_14', IMAGE_DATA_DIRECTORY ],
|
526
|
+
[ 'template', 'DataDirectoryEntry_15', IMAGE_DATA_DIRECTORY ]
|
527
|
+
)]
|
528
|
+
)
|
529
|
+
|
530
|
+
class OptionalHeader < GenericHeader
|
531
|
+
def ImageBase
|
532
|
+
v['ImageBase']
|
533
|
+
end
|
534
|
+
def FileAlignment
|
535
|
+
v['FileAlignment']
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
class OptionalHeader32 < OptionalHeader
|
540
|
+
def initialize(rawdata)
|
541
|
+
optional_header = IMAGE_OPTIONAL_HEADER32.make_struct
|
542
|
+
|
543
|
+
if !optional_header.from_s(rawdata)
|
544
|
+
raise OptionalHeaderError, "Couldn't parse IMAGE_OPTIONAL_HEADER32", caller
|
545
|
+
end
|
546
|
+
|
547
|
+
if optional_header.v['Magic'] != IMAGE_NT_OPTIONAL_HDR32_MAGIC
|
548
|
+
raise OptionalHeaderError, "Magic did not match!", caller()
|
549
|
+
end
|
550
|
+
|
551
|
+
self.struct = optional_header
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
class OptionalHeader64 < OptionalHeader
|
556
|
+
def initialize(rawdata)
|
557
|
+
optional_header = IMAGE_OPTIONAL_HEADER64.make_struct
|
558
|
+
|
559
|
+
if !optional_header.from_s(rawdata)
|
560
|
+
raise OptionalHeaderError, "Couldn't parse IMAGE_OPTIONAL_HEADER64", caller
|
561
|
+
end
|
562
|
+
|
563
|
+
if optional_header.v['Magic'] != IMAGE_NT_OPTIONAL_HDR64_MAGIC
|
564
|
+
raise OptionalHeaderError, "Magic did not match!", caller()
|
565
|
+
end
|
566
|
+
|
567
|
+
self.struct = optional_header
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
def self._parse_optional_header(rawdata)
|
572
|
+
case rawdata.length
|
573
|
+
# no optional header
|
574
|
+
when 0
|
575
|
+
return nil
|
576
|
+
|
577
|
+
# good, good
|
578
|
+
when IMAGE_SIZEOF_NT_OPTIONAL32_HEADER
|
579
|
+
return OptionalHeader32.new(rawdata)
|
580
|
+
|
581
|
+
when IMAGE_SIZEOF_NT_OPTIONAL64_HEADER
|
582
|
+
return OptionalHeader64.new(rawdata)
|
583
|
+
|
584
|
+
# bad, bad
|
585
|
+
else
|
586
|
+
raise OptionalHeaderError, "I don't know this header size, #{rawdata.length}", caller
|
587
|
+
end
|
588
|
+
|
589
|
+
end
|
590
|
+
|
591
|
+
# #define IMAGE_SIZEOF_SECTION_HEADER 40
|
592
|
+
IMAGE_SIZEOF_SECTION_HEADER = 40
|
593
|
+
# Struct
|
594
|
+
# typedef struct _IMAGE_SECTION_HEADER {
|
595
|
+
# BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
|
596
|
+
# union {
|
597
|
+
# DWORD PhysicalAddress;
|
598
|
+
# DWORD VirtualSize;
|
599
|
+
# } Misc;
|
600
|
+
# DWORD VirtualAddress;
|
601
|
+
# DWORD SizeOfRawData;
|
602
|
+
# DWORD PointerToRawData;
|
603
|
+
# DWORD PointerToRelocations;
|
604
|
+
# DWORD PointerToLinenumbers;
|
605
|
+
# WORD NumberOfRelocations;
|
606
|
+
# WORD NumberOfLinenumbers;
|
607
|
+
# DWORD Characteristics;
|
608
|
+
# } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
|
609
|
+
IMAGE_SECTION_HEADER = Rex::Struct2::CStructTemplate.new(
|
610
|
+
[ 'string', 'Name', 8, '' ],
|
611
|
+
[ 'uint32v', 'Misc', 0 ],
|
612
|
+
[ 'uint32v', 'VirtualAddress', 0 ],
|
613
|
+
[ 'uint32v', 'SizeOfRawData', 0 ],
|
614
|
+
[ 'uint32v', 'PointerToRawData', 0 ],
|
615
|
+
[ 'uint32v', 'PointerToRelocations', 0 ],
|
616
|
+
[ 'uint32v', 'NumberOfRelocations', 0 ],
|
617
|
+
[ 'uint32v', 'NumberOfLineNumbers', 0 ],
|
618
|
+
[ 'uint32v', 'Characteristics', 0 ]
|
619
|
+
)
|
620
|
+
|
621
|
+
class SectionHeader < GenericHeader
|
622
|
+
def initialize(rawdata)
|
623
|
+
section_header = IMAGE_SECTION_HEADER.make_struct
|
624
|
+
|
625
|
+
if !section_header.from_s(rawdata)
|
626
|
+
raise SectionHeaderError, "Could not parse header", caller
|
627
|
+
end
|
628
|
+
|
629
|
+
self.struct = section_header
|
630
|
+
end
|
631
|
+
|
632
|
+
def VirtualAddress
|
633
|
+
v['VirtualAddress']
|
634
|
+
end
|
635
|
+
def SizeOfRawData
|
636
|
+
v['SizeOfRawData']
|
637
|
+
end
|
638
|
+
def PointerToRawData
|
639
|
+
v['PointerToRawData']
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
def self._parse_section_headers(rawdata)
|
644
|
+
section_headers = [ ]
|
645
|
+
size = IMAGE_SIZEOF_SECTION_HEADER
|
646
|
+
numsections = rawdata.length / size
|
647
|
+
|
648
|
+
numsections.times do |i|
|
649
|
+
data = rawdata[i * size, size]
|
650
|
+
section_headers << SectionHeader.new(data)
|
651
|
+
end
|
652
|
+
|
653
|
+
return section_headers
|
654
|
+
end
|
655
|
+
|
656
|
+
# #define IMAGE_SIZEOF_BASE_RELOCATION 8
|
657
|
+
IMAGE_SIZEOF_BASE_RELOCATION = 8
|
658
|
+
|
659
|
+
# Struct
|
660
|
+
# typedef struct _IMAGE_BASE_RELOCATION {
|
661
|
+
# DWORD VirtualAddress;
|
662
|
+
# DWORD SizeOfBlock;
|
663
|
+
# // WORD TypeOffset[1];
|
664
|
+
# } IMAGE_BASE_RELOCATION;
|
665
|
+
# typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
|
666
|
+
IMAGE_BASE_RELOCATION = Rex::Struct2::CStructTemplate.new(
|
667
|
+
[ 'uint32v', 'VirtualAddress', 0 ],
|
668
|
+
[ 'uint32v', 'SizeOfBlock', 0 ]
|
669
|
+
)
|
670
|
+
IMAGE_BASE_RELOCATION_TYPE_OFFSET = Rex::Struct2::CStructTemplate.new(
|
671
|
+
[ 'uint16v', 'TypeOffset', 0 ]
|
672
|
+
)
|
673
|
+
|
674
|
+
class RelocationDirectory
|
675
|
+
attr_accessor :entries, :rva
|
676
|
+
|
677
|
+
def initialize(rva, entries)
|
678
|
+
self.rva = rva
|
679
|
+
self.entries = entries
|
680
|
+
self.name = name
|
681
|
+
self.characteristics = chars
|
682
|
+
self.timedate = timedate
|
683
|
+
self.version = version
|
684
|
+
self.entries = []
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
class RelocationEntry
|
689
|
+
attr_accessor :rva, :reltype
|
690
|
+
|
691
|
+
def initialize(_rva, _type)
|
692
|
+
self.rva = _rva
|
693
|
+
self.reltype = _type
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
|
698
|
+
class ResourceDirectory
|
699
|
+
attr_accessor :entries, :name
|
700
|
+
|
701
|
+
def initialize(name, entries)
|
702
|
+
self.name = name
|
703
|
+
self.entries = entries
|
704
|
+
end
|
705
|
+
end
|
706
|
+
|
707
|
+
class ResourceEntry
|
708
|
+
attr_accessor :path, :lang, :code, :rva, :size, :pe, :file
|
709
|
+
|
710
|
+
def initialize(pe, path, lang, code, rva, size, file)
|
711
|
+
self.pe = pe
|
712
|
+
self.path = path
|
713
|
+
self.lang = lang
|
714
|
+
self.code = code
|
715
|
+
self.rva = rva
|
716
|
+
self.size = size
|
717
|
+
self.file = file.to_s
|
718
|
+
end
|
719
|
+
|
720
|
+
def data
|
721
|
+
pe._isource.read(pe.rva_to_file_offset(rva), size)
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
# Struct
|
726
|
+
# typedef struct {
|
727
|
+
# DWORD Size;
|
728
|
+
# DWORD TimeDateStamp;
|
729
|
+
# WORD MajorVersion;
|
730
|
+
# WORD MinorVersion;
|
731
|
+
# DWORD GlobalFlagsClear;
|
732
|
+
# DWORD GlobalFlagsSet;
|
733
|
+
# DWORD CriticalSectionDefaultTimeout;
|
734
|
+
# DWORD DeCommitFreeBlockThreshold;
|
735
|
+
# DWORD DeCommitTotalFreeThreshold;
|
736
|
+
# DWORD LockPrefixTable; // VA
|
737
|
+
# DWORD MaximumAllocationSize;
|
738
|
+
# DWORD VirtualMemoryThreshold;
|
739
|
+
# DWORD ProcessHeapFlags;
|
740
|
+
# DWORD ProcessAffinityMask;
|
741
|
+
# WORD CSDVersion;
|
742
|
+
# WORD Reserved1;
|
743
|
+
# DWORD EditList; // VA
|
744
|
+
# DWORD SecurityCookie; // VA
|
745
|
+
# DWORD SEHandlerTable; // VA
|
746
|
+
# DWORD SEHandlerCount;
|
747
|
+
# } IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;
|
748
|
+
#
|
749
|
+
IMAGE_LOAD_CONFIG_DIRECTORY32 = Rex::Struct2::CStructTemplate.new(
|
750
|
+
[ 'uint32v', 'Size', 0 ],
|
751
|
+
[ 'uint32v', 'TimeDateStamp', 0 ],
|
752
|
+
[ 'uint16v', 'MajorVersion', 0 ],
|
753
|
+
[ 'uint16v', 'MinorVersion', 0 ],
|
754
|
+
[ 'uint32v', 'GlobalFlagsClear', 0 ],
|
755
|
+
[ 'uint32v', 'GlobalFlagsSet', 0 ],
|
756
|
+
[ 'uint32v', 'CriticalSectionDefaultTimeout', 0 ],
|
757
|
+
[ 'uint32v', 'DeCommitFreeBlockThreshold', 0 ],
|
758
|
+
[ 'uint32v', 'DeCommitTotalFreeThreshold', 0 ],
|
759
|
+
[ 'uint32v', 'LockPrefixTable', 0 ],
|
760
|
+
[ 'uint32v', 'MaximumAllocationSize', 0 ],
|
761
|
+
[ 'uint32v', 'VirtualMemoryThreshold', 0 ],
|
762
|
+
[ 'uint32v', 'ProcessHeapFlags', 0 ],
|
763
|
+
[ 'uint32v', 'ProcessAffinityMask', 0 ],
|
764
|
+
[ 'uint16v', 'CSDVersion', 0 ],
|
765
|
+
[ 'uint16v', 'Reserved1', 0 ],
|
766
|
+
[ 'uint32v', 'EditList', 0 ],
|
767
|
+
[ 'uint32v', 'SecurityCookie', 0 ],
|
768
|
+
[ 'uint32v', 'SEHandlerTable', 0 ],
|
769
|
+
[ 'uint32v', 'SEHandlerCount', 0 ]
|
770
|
+
)
|
771
|
+
|
772
|
+
# Struct
|
773
|
+
# typedef struct {
|
774
|
+
# ULONG Size;
|
775
|
+
# ULONG TimeDateStamp;
|
776
|
+
# USHORT MajorVersion;
|
777
|
+
# USHORT MinorVersion;
|
778
|
+
# ULONG GlobalFlagsClear;
|
779
|
+
# ULONG GlobalFlagsSet;
|
780
|
+
# ULONG CriticalSectionDefaultTimeout;
|
781
|
+
# ULONGLONG DeCommitFreeBlockThreshold;
|
782
|
+
# ULONGLONG DeCommitTotalFreeThreshold;
|
783
|
+
# ULONGLONG LockPrefixTable; // VA
|
784
|
+
# ULONGLONG MaximumAllocationSize;
|
785
|
+
# ULONGLONG VirtualMemoryThreshold;
|
786
|
+
# ULONGLONG ProcessAffinityMask;
|
787
|
+
# ULONG ProcessHeapFlags;
|
788
|
+
# USHORT CSDVersion;
|
789
|
+
# USHORT Reserved1;
|
790
|
+
# ULONGLONG EditList; // VA
|
791
|
+
# ULONGLONG SecurityCookie; // VA
|
792
|
+
# ULONGLONG SEHandlerTable; // VA
|
793
|
+
# ULONGLONG SEHandlerCount;
|
794
|
+
# } IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;
|
795
|
+
IMAGE_LOAD_CONFIG_DIRECTORY64 = Rex::Struct2::CStructTemplate.new(
|
796
|
+
[ 'uint32v', 'Size', 0 ],
|
797
|
+
[ 'uint32v', 'TimeDateStamp', 0 ],
|
798
|
+
[ 'uint16v', 'MajorVersion', 0 ],
|
799
|
+
[ 'uint16v', 'MinorVersion', 0 ],
|
800
|
+
[ 'uint32v', 'GlobalFlagsClear', 0 ],
|
801
|
+
[ 'uint32v', 'GlobalFlagsSet', 0 ],
|
802
|
+
[ 'uint32v', 'CriticalSectionDefaultTimeout', 0 ],
|
803
|
+
[ 'uint64v', 'DeCommitFreeBlockThreshold', 0 ],
|
804
|
+
[ 'uint64v', 'DeCommitTotalFreeThreshold', 0 ],
|
805
|
+
[ 'uint64v', 'LockPrefixTable', 0 ],
|
806
|
+
[ 'uint64v', 'MaximumAllocationSize', 0 ],
|
807
|
+
[ 'uint64v', 'VirtualMemoryThreshold', 0 ],
|
808
|
+
[ 'uint64v', 'ProcessAffinityMask', 0 ],
|
809
|
+
[ 'uint32v', 'ProcessHeapFlags', 0 ],
|
810
|
+
[ 'uint16v', 'CSDVersion', 0 ],
|
811
|
+
[ 'uint16v', 'Reserved1', 0 ],
|
812
|
+
[ 'uint64v', 'EditList', 0 ],
|
813
|
+
[ 'uint64v', 'SecurityCookie', 0 ],
|
814
|
+
[ 'uint64v', 'SEHandlerTable', 0 ],
|
815
|
+
[ 'uint64v', 'SEHandlerCount', 0 ]
|
816
|
+
)
|
817
|
+
|
818
|
+
|
819
|
+
class ConfigHeader < GenericHeader
|
820
|
+
|
821
|
+
end
|
822
|
+
|
823
|
+
#--
|
824
|
+
# doesn't seem to be used -- not compatible with 64-bit
|
825
|
+
#def self._parse_config_header(rawdata)
|
826
|
+
# header = IMAGE_LOAD_CONFIG_DIRECTORY32.make_struct
|
827
|
+
# header.from_s(rawdata)
|
828
|
+
# ConfigHeader.new(header)
|
829
|
+
#end
|
830
|
+
#++
|
831
|
+
|
832
|
+
def _parse_config_header
|
833
|
+
|
834
|
+
#
|
835
|
+
# Get the data directory entry, size, etc
|
836
|
+
#
|
837
|
+
exports_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]
|
838
|
+
rva = exports_entry.v['VirtualAddress']
|
839
|
+
size = exports_entry.v['Size']
|
840
|
+
|
841
|
+
return nil if size == 0
|
842
|
+
|
843
|
+
#
|
844
|
+
# Ok, so we have the data directory, now lets parse it
|
845
|
+
#
|
846
|
+
|
847
|
+
dirdata = _isource.read(rva_to_file_offset(rva), size)
|
848
|
+
klass = (ptr_64?) ? IMAGE_LOAD_CONFIG_DIRECTORY64 : IMAGE_LOAD_CONFIG_DIRECTORY32
|
849
|
+
header = klass.make_struct
|
850
|
+
|
851
|
+
header.from_s(dirdata)
|
852
|
+
|
853
|
+
@config = ConfigHeader.new(header)
|
854
|
+
end
|
855
|
+
|
856
|
+
|
857
|
+
def config
|
858
|
+
_parse_config_header if @config.nil?
|
859
|
+
@config
|
860
|
+
end
|
861
|
+
|
862
|
+
#
|
863
|
+
# TLS Directory
|
864
|
+
#
|
865
|
+
|
866
|
+
# Struct
|
867
|
+
# typedef struct {
|
868
|
+
# DWORD Size;
|
869
|
+
# DWORD TimeDateStamp;
|
870
|
+
# WORD MajorVersion;
|
871
|
+
# WORD MinorVersion;
|
872
|
+
# DWORD GlobalFlagsClear;
|
873
|
+
# DWORD GlobalFlagsSet;
|
874
|
+
# DWORD CriticalSectionDefaultTimeout;
|
875
|
+
# DWORD DeCommitFreeBlockThreshold;
|
876
|
+
# DWORD DeCommitTotalFreeThreshold;
|
877
|
+
# DWORD LockPrefixTable; // VA
|
878
|
+
# DWORD MaximumAllocationSize;
|
879
|
+
# DWORD VirtualMemoryThreshold;
|
880
|
+
# DWORD ProcessHeapFlags;
|
881
|
+
# DWORD ProcessAffinityMask;
|
882
|
+
# WORD CSDVersion;
|
883
|
+
# WORD Reserved1;
|
884
|
+
# DWORD EditList; // VA
|
885
|
+
# DWORD SecurityCookie; // VA
|
886
|
+
# DWORD SEHandlerTable; // VA
|
887
|
+
# DWORD SEHandlerCount;
|
888
|
+
# } IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;
|
889
|
+
IMAGE_LOAD_TLS_DIRECTORY32 = Rex::Struct2::CStructTemplate.new(
|
890
|
+
[ 'uint32v', 'Size', 0 ],
|
891
|
+
[ 'uint32v', 'TimeDateStamp', 0 ],
|
892
|
+
[ 'uint16v', 'MajorVersion', 0 ],
|
893
|
+
[ 'uint16v', 'MinorVersion', 0 ],
|
894
|
+
[ 'uint32v', 'GlobalFlagsClear', 0 ],
|
895
|
+
[ 'uint32v', 'GlobalFlagsSet', 0 ],
|
896
|
+
[ 'uint32v', 'CriticalSectionDefaultTimeout', 0 ],
|
897
|
+
[ 'uint32v', 'DeCommitFreeBlockThreshold', 0 ],
|
898
|
+
[ 'uint32v', 'DeCommitTotalFreeThreshold', 0 ],
|
899
|
+
[ 'uint32v', 'LockPrefixTable', 0 ],
|
900
|
+
[ 'uint32v', 'MaximumAllocationSize', 0 ],
|
901
|
+
[ 'uint32v', 'VirtualMemoryThreshold', 0 ],
|
902
|
+
[ 'uint32v', 'ProcessHeapFlags', 0 ],
|
903
|
+
[ 'uint32v', 'ProcessAffinityMask', 0 ],
|
904
|
+
[ 'uint16v', 'CSDVersion', 0 ],
|
905
|
+
[ 'uint16v', 'Reserved1', 0 ],
|
906
|
+
[ 'uint32v', 'EditList', 0 ],
|
907
|
+
[ 'uint32v', 'SecurityCookie', 0 ],
|
908
|
+
[ 'uint32v', 'SEHandlerTable', 0 ],
|
909
|
+
[ 'uint32v', 'SEHandlerCount', 0 ]
|
910
|
+
)
|
911
|
+
|
912
|
+
# Struct
|
913
|
+
# typedef struct {
|
914
|
+
# ULONG Size;
|
915
|
+
# ULONG TimeDateStamp;
|
916
|
+
# USHORT MajorVersion;
|
917
|
+
# USHORT MinorVersion;
|
918
|
+
# ULONG GlobalFlagsClear;
|
919
|
+
# ULONG GlobalFlagsSet;
|
920
|
+
# ULONG CriticalSectionDefaultTimeout;
|
921
|
+
# ULONGLONG DeCommitFreeBlockThreshold;
|
922
|
+
# ULONGLONG DeCommitTotalFreeThreshold;
|
923
|
+
# ULONGLONG LockPrefixTable; // VA
|
924
|
+
# ULONGLONG MaximumAllocationSize;
|
925
|
+
# ULONGLONG VirtualMemoryThreshold;
|
926
|
+
# ULONGLONG ProcessAffinityMask;
|
927
|
+
# ULONG ProcessHeapFlags;
|
928
|
+
# USHORT CSDVersion;
|
929
|
+
# USHORT Reserved1;
|
930
|
+
# ULONGLONG EditList; // VA
|
931
|
+
# ULONGLONG SecurityCookie; // VA
|
932
|
+
# ULONGLONG SEHandlerTable; // VA
|
933
|
+
# ULONGLONG SEHandlerCount;
|
934
|
+
# } IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;
|
935
|
+
IMAGE_LOAD_TLS_DIRECTORY64 = Rex::Struct2::CStructTemplate.new(
|
936
|
+
[ 'uint32v', 'Size', 0 ],
|
937
|
+
[ 'uint32v', 'TimeDateStamp', 0 ],
|
938
|
+
[ 'uint16v', 'MajorVersion', 0 ],
|
939
|
+
[ 'uint16v', 'MinorVersion', 0 ],
|
940
|
+
[ 'uint32v', 'GlobalFlagsClear', 0 ],
|
941
|
+
[ 'uint32v', 'GlobalFlagsSet', 0 ],
|
942
|
+
[ 'uint32v', 'CriticalSectionDefaultTimeout', 0 ],
|
943
|
+
[ 'uint64v', 'DeCommitFreeBlockThreshold', 0 ],
|
944
|
+
[ 'uint64v', 'DeCommitTotalFreeThreshold', 0 ],
|
945
|
+
[ 'uint64v', 'LockPrefixTable', 0 ],
|
946
|
+
[ 'uint64v', 'MaximumAllocationSize', 0 ],
|
947
|
+
[ 'uint64v', 'VirtualMemoryThreshold', 0 ],
|
948
|
+
[ 'uint64v', 'ProcessAffinityMask', 0 ],
|
949
|
+
[ 'uint32v', 'ProcessHeapFlags', 0 ],
|
950
|
+
[ 'uint16v', 'CSDVersion', 0 ],
|
951
|
+
[ 'uint16v', 'Reserved1', 0 ],
|
952
|
+
[ 'uint64v', 'EditList', 0 ],
|
953
|
+
[ 'uint64v', 'SecurityCookie', 0 ],
|
954
|
+
[ 'uint64v', 'SEHandlerTable', 0 ],
|
955
|
+
[ 'uint64v', 'SEHandlerCount', 0 ]
|
956
|
+
)
|
957
|
+
|
958
|
+
|
959
|
+
class TLSHeader < GenericHeader
|
960
|
+
|
961
|
+
end
|
962
|
+
|
963
|
+
def _parse_tls_header
|
964
|
+
|
965
|
+
#
|
966
|
+
# Get the data directory entry, size, etc
|
967
|
+
#
|
968
|
+
exports_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_TLS]
|
969
|
+
rva = exports_entry.v['VirtualAddress']
|
970
|
+
size = exports_entry.v['Size']
|
971
|
+
|
972
|
+
return nil if size == 0
|
973
|
+
|
974
|
+
#
|
975
|
+
# Ok, so we have the data directory, now lets parse it
|
976
|
+
#
|
977
|
+
|
978
|
+
dirdata = _isource.read(rva_to_file_offset(rva), size)
|
979
|
+
klass = (ptr_64?) ? IMAGE_LOAD_TLS_DIRECTORY64 : IMAGE_LOAD_TLS_DIRECTORY32
|
980
|
+
header = klass.make_struct
|
981
|
+
|
982
|
+
header.from_s(dirdata)
|
983
|
+
|
984
|
+
@tls = TLSHeader.new(header)
|
985
|
+
end
|
986
|
+
|
987
|
+
|
988
|
+
def tls
|
989
|
+
_parse_config_header if @tls.nil?
|
990
|
+
@tls
|
991
|
+
end
|
992
|
+
|
993
|
+
##
|
994
|
+
#
|
995
|
+
# Exception directory
|
996
|
+
#
|
997
|
+
##
|
998
|
+
|
999
|
+
IMAGE_RUNTIME_FUNCTION_ENTRY_SZ = 12
|
1000
|
+
# Struct
|
1001
|
+
# typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
|
1002
|
+
# DWORD BeginAddress;
|
1003
|
+
# DWORD EndAddress;
|
1004
|
+
# DWORD UnwindInfoAddress;
|
1005
|
+
# } _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY;
|
1006
|
+
IMAGE_RUNTIME_FUNCTION_ENTRY = Rex::Struct2::CStructTemplate.new(
|
1007
|
+
[ 'uint32v', 'BeginAddress', 0 ],
|
1008
|
+
[ 'uint32v', 'EndAddress', 0 ],
|
1009
|
+
[ 'uint32v', 'UnwindInfoAddress', 0 ]
|
1010
|
+
)
|
1011
|
+
|
1012
|
+
UNWIND_INFO_HEADER_SZ = 4
|
1013
|
+
UNWIND_INFO_HEADER = Rex::Struct2::CStructTemplate.new(
|
1014
|
+
[ 'uint8', 'VersionFlags', 0 ],
|
1015
|
+
[ 'uint8', 'SizeOfProlog', 0 ],
|
1016
|
+
[ 'uint8', 'CountOfCodes', 0 ],
|
1017
|
+
[ 'uint8', 'FrameRegisterAndOffset', 0 ]
|
1018
|
+
)
|
1019
|
+
|
1020
|
+
UWOP_PUSH_NONVOL = 0 # 1 node
|
1021
|
+
UWOP_ALLOC_LARGE = 1 # 2 or 3 nodes
|
1022
|
+
UWOP_ALLOC_SMALL = 2 # 1 node
|
1023
|
+
UWOP_SET_FPREG = 3 # 1 node
|
1024
|
+
UWOP_SAVE_NONVOL = 4 # 2 nodes
|
1025
|
+
UWOP_SAVE_NONVOL_FAR = 5 # 3 nodes
|
1026
|
+
UWOP_SAVE_XMM128 = 8 # 2 nodes
|
1027
|
+
UWOP_SAVE_XMM128_FAR = 9 # 3 nodes
|
1028
|
+
UWOP_PUSH_MACHFRAME = 10 # 1 node
|
1029
|
+
|
1030
|
+
UNW_FLAG_EHANDLER = 1
|
1031
|
+
UNW_FLAG_UHANDLER = 2
|
1032
|
+
UNW_FLAG_CHAININFO = 4
|
1033
|
+
|
1034
|
+
class UnwindCode
|
1035
|
+
def initialize(data)
|
1036
|
+
|
1037
|
+
self.code_offset = data[0].to_i
|
1038
|
+
self.unwind_op = data[1].to_i & 0xf
|
1039
|
+
self.op_info = data[1].to_i >> 4
|
1040
|
+
self.frame_offset = data[2..3].unpack("v")[0]
|
1041
|
+
|
1042
|
+
data.slice!(0, 4)
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
attr_reader :code_offset, :unwind_op, :op_info, :frame_offset
|
1046
|
+
attr_writer :code_offset, :unwind_op, :op_info, :frame_offset
|
1047
|
+
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
class UnwindInfo
|
1051
|
+
def initialize(pe, unwind_rva)
|
1052
|
+
data = pe.read_rva(unwind_rva, UNWIND_INFO_HEADER_SZ)
|
1053
|
+
|
1054
|
+
unwind = UNWIND_INFO_HEADER.make_struct
|
1055
|
+
unwind.from_s(data)
|
1056
|
+
|
1057
|
+
@version = unwind.v['VersionFlags'] & 0x7
|
1058
|
+
@flags = unwind.v['VersionFlags'] >> 3
|
1059
|
+
@size_of_prolog = unwind.v['SizeOfProlog']
|
1060
|
+
@count_of_codes = unwind.v['CountOfCodes']
|
1061
|
+
@frame_register = unwind.v['FrameRegisterAndOffset'] & 0xf
|
1062
|
+
@frame_register_offset = unwind.v['FrameRegisterAndOffset'] >> 4
|
1063
|
+
|
1064
|
+
# Parse unwind codes
|
1065
|
+
clist = pe.read_rva(unwind_rva + UNWIND_INFO_HEADER_SZ, count_of_codes * 4)
|
1066
|
+
|
1067
|
+
@unwind_codes = []
|
1068
|
+
|
1069
|
+
while clist.length > 0
|
1070
|
+
@unwind_codes << UnwindCode.new(clist)
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
attr_reader :version, :flags, :size_of_prolog, :count_of_codes
|
1075
|
+
attr_reader :frame_register, :frame_register_offset
|
1076
|
+
|
1077
|
+
def unwind_codes
|
1078
|
+
@unwind_codes
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
class RuntimeFunctionEntry
|
1084
|
+
|
1085
|
+
def initialize(pe, data)
|
1086
|
+
@pe = pe
|
1087
|
+
@begin_address, @end_address, @unwind_info_address = data.unpack("VVV");
|
1088
|
+
self.unwind_info = UnwindInfo.new(pe, unwind_info_address)
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
attr_reader :begin_address, :end_address, :unwind_info_address
|
1092
|
+
attr_reader :unwind_info
|
1093
|
+
attr_writer :unwind_info
|
1094
|
+
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
def _load_exception_directory
|
1098
|
+
@exception = []
|
1099
|
+
|
1100
|
+
exception_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_EXCEPTION]
|
1101
|
+
rva = exception_entry.v['VirtualAddress']
|
1102
|
+
size = exception_entry.v['Size']
|
1103
|
+
|
1104
|
+
return if (rva == 0)
|
1105
|
+
|
1106
|
+
data = _isource.read(rva_to_file_offset(rva), size)
|
1107
|
+
|
1108
|
+
case hdr.file.Machine
|
1109
|
+
when IMAGE_FILE_MACHINE_AMD64
|
1110
|
+
count = data.length / IMAGE_RUNTIME_FUNCTION_ENTRY_SZ
|
1111
|
+
|
1112
|
+
count.times { |current|
|
1113
|
+
@exception << RuntimeFunctionEntry.new(self,
|
1114
|
+
data.slice!(0, IMAGE_RUNTIME_FUNCTION_ENTRY_SZ))
|
1115
|
+
}
|
1116
|
+
else
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
return @exception
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
|
1123
|
+
def exception
|
1124
|
+
_load_exception_directory if @exception.nil?
|
1125
|
+
@exception
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
#
|
1129
|
+
# Just a stupid routine to round an offset up to it's alignment.
|
1130
|
+
#
|
1131
|
+
# For example, you're going to want this for FileAlignment and
|
1132
|
+
# SectionAlignment, etc...
|
1133
|
+
#
|
1134
|
+
def self._align_offset(offset, alignment)
|
1135
|
+
offset += alignment - 1
|
1136
|
+
offset -= offset % alignment
|
1137
|
+
return offset
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
#
|
1141
|
+
# instance stuff
|
1142
|
+
#
|
1143
|
+
|
1144
|
+
attr_accessor :_isource
|
1145
|
+
attr_accessor :_dos_header, :_file_header, :_optional_header,
|
1146
|
+
:_section_headers, :_config_header, :_tls_header, :_exception_header
|
1147
|
+
|
1148
|
+
attr_accessor :sections, :header_section, :image_base
|
1149
|
+
|
1150
|
+
attr_accessor :_imports_cache, :_imports_cached
|
1151
|
+
attr_accessor :_exports_cache, :_exports_cached
|
1152
|
+
attr_accessor :_relocations_cache, :_relocations_cached
|
1153
|
+
attr_accessor :_resources_cache, :_resources_cached
|
1154
|
+
|
1155
|
+
attr_accessor :hdr
|
1156
|
+
|
1157
|
+
def self.new_from_file(filename, disk_backed = false)
|
1158
|
+
|
1159
|
+
file = ::File.new(filename)
|
1160
|
+
file.binmode # windows... :\
|
1161
|
+
|
1162
|
+
if disk_backed
|
1163
|
+
return self.new(ImageSource::Disk.new(file))
|
1164
|
+
else
|
1165
|
+
obj = new_from_string(file.read)
|
1166
|
+
file.close
|
1167
|
+
return obj
|
1168
|
+
end
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
def self.new_from_string(data)
|
1172
|
+
return self.new(ImageSource::Memory.new(data))
|
1173
|
+
end
|
1174
|
+
|
1175
|
+
def close
|
1176
|
+
_isource.close
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
#
|
1180
|
+
#
|
1181
|
+
# Random rva, vma, file offset, section offset, etc
|
1182
|
+
# conversion routines...
|
1183
|
+
#
|
1184
|
+
#
|
1185
|
+
def rva_to_vma(rva)
|
1186
|
+
return rva + image_base
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
def vma_to_rva(vma)
|
1190
|
+
return vma - image_base
|
1191
|
+
end
|
1192
|
+
|
1193
|
+
def rva_to_file_offset(rva)
|
1194
|
+
all_sections.each do |section|
|
1195
|
+
if section.contains_rva?(rva)
|
1196
|
+
return section.rva_to_file_offset(rva)
|
1197
|
+
end
|
1198
|
+
end
|
1199
|
+
raise PeParseyError, "No section contains RVA", caller
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
def vma_to_file_offset(vma)
|
1203
|
+
return rva_to_file_offset(vma_to_rva(vma))
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
def file_offset_to_rva(foffset)
|
1207
|
+
if foffset < 0
|
1208
|
+
raise PeParseyError, "Offset should not be less than 0. The value is: #{foffset}", caller
|
1209
|
+
end
|
1210
|
+
|
1211
|
+
all_sections.each do |section|
|
1212
|
+
if section.contains_file_offset?(foffset)
|
1213
|
+
return section.file_offset_to_rva(foffset)
|
1214
|
+
end
|
1215
|
+
end
|
1216
|
+
|
1217
|
+
raise PeParseyError, "No section contains file offset #{foffset}", caller
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
def file_offset_to_vma(foffset)
|
1221
|
+
return rva_to_vma(file_offset_to_rva(foffset))
|
1222
|
+
end
|
1223
|
+
|
1224
|
+
#
|
1225
|
+
#
|
1226
|
+
# Some routines to find which section something belongs
|
1227
|
+
# to. These will search all_sections (so including
|
1228
|
+
# our fake header section, etc...
|
1229
|
+
#
|
1230
|
+
#
|
1231
|
+
|
1232
|
+
#
|
1233
|
+
# Find a section by an RVA
|
1234
|
+
#
|
1235
|
+
def _find_section_by_rva(rva)
|
1236
|
+
all_sections.each do |section|
|
1237
|
+
if section.contains_rva?(rva)
|
1238
|
+
return section
|
1239
|
+
end
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
return nil
|
1243
|
+
end
|
1244
|
+
def find_section_by_rva(rva)
|
1245
|
+
section = _find_section_by_rva(rva)
|
1246
|
+
|
1247
|
+
if !section
|
1248
|
+
raise PeParseyError, "Cannot find rva! #{rva}", caller
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
return section
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
#
|
1255
|
+
# Find a section by a VMA
|
1256
|
+
#
|
1257
|
+
def find_section_by_vma(vma)
|
1258
|
+
return find_section_by_rva(vma_to_rva(vma))
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
def valid_rva?(rva)
|
1262
|
+
_find_section_by_rva(rva) != nil
|
1263
|
+
end
|
1264
|
+
def valid_vma?(vma)
|
1265
|
+
_find_section_by_rva(vma_to_rva(vma)) != nil
|
1266
|
+
end
|
1267
|
+
|
1268
|
+
#
|
1269
|
+
#
|
1270
|
+
# Some convenient methods to read a vma/rva without having
|
1271
|
+
# the section... (inefficent though I suppose...)
|
1272
|
+
#
|
1273
|
+
#
|
1274
|
+
|
1275
|
+
def read_rva(rva, length)
|
1276
|
+
return find_section_by_rva(rva).read_rva(rva, length)
|
1277
|
+
end
|
1278
|
+
|
1279
|
+
def read_vma(vma, length)
|
1280
|
+
return read_rva(vma_to_rva(vma), length)
|
1281
|
+
end
|
1282
|
+
|
1283
|
+
def read_asciiz_rva(rva)
|
1284
|
+
return find_section_by_rva(rva).read_asciiz_rva(rva)
|
1285
|
+
end
|
1286
|
+
|
1287
|
+
def read_asciiz_vma(vma)
|
1288
|
+
return read_asciiz_rva(vma_to_rva(vma))
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
#
|
1292
|
+
#
|
1293
|
+
# Imports, exports, and other stuff!
|
1294
|
+
#
|
1295
|
+
#
|
1296
|
+
|
1297
|
+
#
|
1298
|
+
# We lazily parse the imports, and then cache it
|
1299
|
+
#
|
1300
|
+
def imports
|
1301
|
+
if !_imports_cached
|
1302
|
+
self._imports_cache = _load_imports
|
1303
|
+
self._imports_cached = true
|
1304
|
+
end
|
1305
|
+
return _imports_cache
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
def _load_imports
|
1309
|
+
#
|
1310
|
+
# Get the data directory entry, size, etc
|
1311
|
+
#
|
1312
|
+
imports_entry = _optional_header['DataDirectory'][1]
|
1313
|
+
rva = imports_entry.v['VirtualAddress']
|
1314
|
+
size = imports_entry.v['Size']
|
1315
|
+
|
1316
|
+
return nil if size == 0
|
1317
|
+
|
1318
|
+
#
|
1319
|
+
# Ok, so we have the data directory, now lets parse it
|
1320
|
+
#
|
1321
|
+
|
1322
|
+
imports = [ ]
|
1323
|
+
|
1324
|
+
descriptors_data = _isource.read(rva_to_file_offset(rva), size)
|
1325
|
+
|
1326
|
+
while descriptors_data.length >= IMAGE_IMPORT_DESCRIPTOR_SIZE
|
1327
|
+
descriptor = IMAGE_IMPORT_DESCRIPTOR.make_struct
|
1328
|
+
descriptor.from_s(descriptors_data)
|
1329
|
+
descriptors_data = descriptor.leftover
|
1330
|
+
|
1331
|
+
othunk = descriptor.v['OriginalFirstThunk']
|
1332
|
+
fthunk = descriptor.v['FirstThunk']
|
1333
|
+
|
1334
|
+
break if fthunk == 0
|
1335
|
+
|
1336
|
+
dllname = _isource.read_asciiz(rva_to_file_offset(descriptor.v['Name']))
|
1337
|
+
|
1338
|
+
import = ImportDescriptor.new(dllname, [ ])
|
1339
|
+
|
1340
|
+
# we prefer the Characteristics/OriginalFirstThunk...
|
1341
|
+
thunk_off = rva_to_file_offset(othunk == 0 ? fthunk : othunk)
|
1342
|
+
|
1343
|
+
while (orgrva = _isource.read(thunk_off, 4).unpack('V')[0]) != 0
|
1344
|
+
hint = nil
|
1345
|
+
name = nil
|
1346
|
+
|
1347
|
+
if (orgrva & IMAGE_ORDINAL_FLAG32) != 0
|
1348
|
+
hint = orgrva & 0xffff
|
1349
|
+
else
|
1350
|
+
foff = rva_to_file_offset(orgrva)
|
1351
|
+
hint = _isource.read(foff, 2).unpack('v')[0]
|
1352
|
+
name = _isource.read_asciiz(foff + 2)
|
1353
|
+
end
|
1354
|
+
|
1355
|
+
import.entries << ImportEntry.new(name, hint)
|
1356
|
+
|
1357
|
+
thunk_off += 4
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
imports << import
|
1361
|
+
end
|
1362
|
+
|
1363
|
+
return imports
|
1364
|
+
end
|
1365
|
+
|
1366
|
+
|
1367
|
+
|
1368
|
+
#
|
1369
|
+
# We lazily parse the exports, and then cache it
|
1370
|
+
#
|
1371
|
+
def exports
|
1372
|
+
if !_exports_cached
|
1373
|
+
self._exports_cache = _load_exports
|
1374
|
+
self._exports_cached = true
|
1375
|
+
end
|
1376
|
+
return _exports_cache
|
1377
|
+
end
|
1378
|
+
|
1379
|
+
def _load_exports
|
1380
|
+
|
1381
|
+
#
|
1382
|
+
# Get the data directory entry, size, etc
|
1383
|
+
#
|
1384
|
+
exports_entry = _optional_header['DataDirectory'][0]
|
1385
|
+
rva = exports_entry.v['VirtualAddress']
|
1386
|
+
size = exports_entry.v['Size']
|
1387
|
+
|
1388
|
+
return nil if size == 0
|
1389
|
+
|
1390
|
+
#
|
1391
|
+
# Ok, so we have the data directory, now lets parse it
|
1392
|
+
#
|
1393
|
+
|
1394
|
+
directory = IMAGE_EXPORT_DESCRIPTOR.make_struct
|
1395
|
+
directory.from_s(_isource.read(rva_to_file_offset(rva), IMAGE_EXPORT_DESCRIPTOR_SIZE))
|
1396
|
+
|
1397
|
+
#
|
1398
|
+
# We can have nameless exports, so we need to do the whole
|
1399
|
+
# NumberOfFunctions NumberOfNames foo
|
1400
|
+
#
|
1401
|
+
num_functions = directory.v['NumberOfFunctions']
|
1402
|
+
num_names = directory.v['NumberOfNames']
|
1403
|
+
|
1404
|
+
dllname_rva = directory.v['Name']
|
1405
|
+
dllname = _isource.read_asciiz(rva_to_file_offset(dllname_rva))
|
1406
|
+
|
1407
|
+
# FIXME Base, etc
|
1408
|
+
fun_off = rva_to_file_offset(directory.v['AddressOfFunctions'])
|
1409
|
+
name_off = rva_to_file_offset(directory.v['AddressOfNames'])
|
1410
|
+
ord_off = rva_to_file_offset(directory.v['AddressOfNameOrdinals'])
|
1411
|
+
base = directory.v['Base']
|
1412
|
+
|
1413
|
+
# Allocate the list of names
|
1414
|
+
names = Array.new(num_functions)
|
1415
|
+
|
1416
|
+
#
|
1417
|
+
# Iterate the names and name/ordinal list, getting the names
|
1418
|
+
# and storing them in the name list...
|
1419
|
+
#
|
1420
|
+
num_names.times do |i|
|
1421
|
+
name_rva = _isource.read(name_off + (i * 4), 4).unpack('V')[0]
|
1422
|
+
ordinal = _isource.read(ord_off + (i * 2), 2).unpack('v')[0]
|
1423
|
+
name = _isource.read_asciiz(rva_to_file_offset(name_rva))
|
1424
|
+
|
1425
|
+
# store the exported name in the name list
|
1426
|
+
names[ordinal] = name
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
exports = ExportDirectory.new(dllname, [ ], base)
|
1430
|
+
|
1431
|
+
#
|
1432
|
+
# Now just iterate the functions (rvas) list..
|
1433
|
+
#
|
1434
|
+
num_functions.times do |i|
|
1435
|
+
rva = _isource.read(fun_off + (i * 4), 4).unpack('V')[0]
|
1436
|
+
|
1437
|
+
# ExportEntry.new(name, ordinal, rva)
|
1438
|
+
exports.entries << ExportEntry.new(names[i], i + base, rva)
|
1439
|
+
end
|
1440
|
+
|
1441
|
+
return exports
|
1442
|
+
end
|
1443
|
+
|
1444
|
+
#
|
1445
|
+
# Base relocations in the hizzy
|
1446
|
+
#
|
1447
|
+
def relocations
|
1448
|
+
if !_relocations_cached
|
1449
|
+
self._relocations_cache = _load_relocations
|
1450
|
+
self._relocations_cached = true
|
1451
|
+
end
|
1452
|
+
return _relocations_cache
|
1453
|
+
end
|
1454
|
+
|
1455
|
+
def _load_relocations
|
1456
|
+
|
1457
|
+
#
|
1458
|
+
# Get the data directory entry, size, etc
|
1459
|
+
#
|
1460
|
+
exports_entry = _optional_header['DataDirectory'][5]
|
1461
|
+
rva = exports_entry.v['VirtualAddress']
|
1462
|
+
size = exports_entry.v['Size']
|
1463
|
+
|
1464
|
+
return nil if size == 0
|
1465
|
+
|
1466
|
+
#
|
1467
|
+
# Ok, so we have the data directory, now lets parse it
|
1468
|
+
#
|
1469
|
+
|
1470
|
+
dirdata = _isource.read(rva_to_file_offset(rva), size)
|
1471
|
+
|
1472
|
+
relocdirs = [ ]
|
1473
|
+
|
1474
|
+
while dirdata.length >= IMAGE_SIZEOF_BASE_RELOCATION
|
1475
|
+
header = IMAGE_BASE_RELOCATION.make_struct
|
1476
|
+
header.from_s(dirdata)
|
1477
|
+
dirdata = header.leftover
|
1478
|
+
|
1479
|
+
numrelocs = (header.v['SizeOfBlock'] - IMAGE_SIZEOF_BASE_RELOCATION) / 2
|
1480
|
+
|
1481
|
+
relocbase = header.v['VirtualAddress']
|
1482
|
+
|
1483
|
+
relocdir = RelocationDirectory.new(relocbase, [ ])
|
1484
|
+
|
1485
|
+
numrelocs.times do
|
1486
|
+
reloc = IMAGE_BASE_RELOCATION_TYPE_OFFSET.make_struct
|
1487
|
+
reloc.from_s(dirdata)
|
1488
|
+
dirdata = reloc.leftover
|
1489
|
+
|
1490
|
+
typeoffset = reloc.v['TypeOffset']
|
1491
|
+
|
1492
|
+
relocrva = relocbase + (typeoffset & 0xfff)
|
1493
|
+
reloctype = (typeoffset >> 12) & 0xf
|
1494
|
+
|
1495
|
+
relocdir.entries << RelocationEntry.new(relocrva, reloctype)
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
relocdirs << relocdir
|
1499
|
+
end
|
1500
|
+
|
1501
|
+
return relocdirs
|
1502
|
+
end
|
1503
|
+
|
1504
|
+
|
1505
|
+
#
|
1506
|
+
# We lazily parse the resources, and then cache them
|
1507
|
+
#
|
1508
|
+
def resources
|
1509
|
+
if !_resources_cached
|
1510
|
+
_load_resources
|
1511
|
+
self._resources_cached = true
|
1512
|
+
end
|
1513
|
+
|
1514
|
+
return self._resources_cache
|
1515
|
+
end
|
1516
|
+
|
1517
|
+
def _load_resources
|
1518
|
+
#
|
1519
|
+
# Get the data directory entry, size, etc
|
1520
|
+
#
|
1521
|
+
rsrc_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_RESOURCE]
|
1522
|
+
rva = rsrc_entry.v['VirtualAddress']
|
1523
|
+
size = rsrc_entry.v['Size']
|
1524
|
+
|
1525
|
+
return nil if size == 0
|
1526
|
+
|
1527
|
+
#
|
1528
|
+
# Ok, so we have the data directory, now lets parse it
|
1529
|
+
#
|
1530
|
+
data = _isource.read(rva_to_file_offset(rva), size)
|
1531
|
+
|
1532
|
+
self._resources_cache = {}
|
1533
|
+
_parse_resource_directory(data)
|
1534
|
+
end
|
1535
|
+
|
1536
|
+
def _parse_resource_directory(data, rname=0, rvalue=0x80000000, path='0', pname=nil)
|
1537
|
+
|
1538
|
+
pname = _parse_resource_name(data, rname)
|
1539
|
+
if (path.scan('/').length == 1)
|
1540
|
+
if (pname !~ /^\d+/)
|
1541
|
+
path = "/" + pname
|
1542
|
+
else
|
1543
|
+
path = "/" + _resource_lookup( (rname & ~0x80000000).to_s)
|
1544
|
+
end
|
1545
|
+
end
|
1546
|
+
|
1547
|
+
|
1548
|
+
rvalue &= ~0x80000000
|
1549
|
+
vals = data[rvalue, 16].unpack('VVvvvv')
|
1550
|
+
|
1551
|
+
chars = vals[0]
|
1552
|
+
tdate = vals[1]
|
1553
|
+
vers = "#{vals[2]}#{vals[3]}"
|
1554
|
+
count = vals[4] + vals[5]
|
1555
|
+
|
1556
|
+
0.upto(count-1) do |i|
|
1557
|
+
|
1558
|
+
ename, evalue = data[rvalue + 16 + ( i * 8), 8].unpack('VV')
|
1559
|
+
epath = path + '/' + i.to_s
|
1560
|
+
|
1561
|
+
if (ename & 0x80000000 != 0)
|
1562
|
+
pname = _parse_resource_name(data, ename)
|
1563
|
+
end
|
1564
|
+
|
1565
|
+
if (evalue & 0x80000000 != 0)
|
1566
|
+
# This is a subdirectory
|
1567
|
+
_parse_resource_directory(data, ename, evalue, epath, pname)
|
1568
|
+
else
|
1569
|
+
# This is an entry
|
1570
|
+
_parse_resource_entry(data, ename, evalue, epath, pname)
|
1571
|
+
end
|
1572
|
+
end
|
1573
|
+
|
1574
|
+
end
|
1575
|
+
|
1576
|
+
def _resource_lookup(i)
|
1577
|
+
tbl = {
|
1578
|
+
'1' => 'RT_CURSOR',
|
1579
|
+
'2' => 'RT_BITMAP',
|
1580
|
+
'3' => 'RT_ICON',
|
1581
|
+
'4' => 'RT_MENU',
|
1582
|
+
'5' => 'RT_DIALOG',
|
1583
|
+
'6' => 'RT_STRING',
|
1584
|
+
'7' => 'RT_FONTDIR',
|
1585
|
+
'8' => 'RT_FONT',
|
1586
|
+
'9' => 'RT_ACCELERATORS',
|
1587
|
+
'10' => 'RT_RCDATA',
|
1588
|
+
'11' => 'RT_MESSAGETABLE',
|
1589
|
+
'12' => 'RT_GROUP_CURSOR',
|
1590
|
+
'14' => 'RT_GROUP_ICON',
|
1591
|
+
'16' => 'RT_VERSION',
|
1592
|
+
'17' => 'RT_DLGINCLUDE',
|
1593
|
+
'19' => 'RT_PLUGPLAY',
|
1594
|
+
'20' => 'RT_VXD',
|
1595
|
+
'21' => 'RT_ANICURSOR',
|
1596
|
+
'22' => 'RT_ANIICON',
|
1597
|
+
'23' => 'RT_HTML',
|
1598
|
+
'24' => 'RT_MANIFEST',
|
1599
|
+
'32767' => 'RT_ERROR',
|
1600
|
+
'8192' => 'RT_NEWRESOURCE',
|
1601
|
+
'8194' => 'RT_NEWBITMAP',
|
1602
|
+
'8196' => 'RT_NEWMENU',
|
1603
|
+
'8197' => 'RT_NEWDIALOG'
|
1604
|
+
}
|
1605
|
+
tbl[i] || i
|
1606
|
+
end
|
1607
|
+
|
1608
|
+
def _parse_resource_entry(data, rname, rvalue, path, pname)
|
1609
|
+
|
1610
|
+
rva, size, code = data[rvalue, 12].unpack('VVV')
|
1611
|
+
lang = _parse_resource_name(data, rname)
|
1612
|
+
|
1613
|
+
ent = ResourceEntry.new(
|
1614
|
+
self,
|
1615
|
+
path,
|
1616
|
+
lang,
|
1617
|
+
code,
|
1618
|
+
rva,
|
1619
|
+
size,
|
1620
|
+
pname
|
1621
|
+
)
|
1622
|
+
self._resources_cache[path] = ent
|
1623
|
+
end
|
1624
|
+
|
1625
|
+
def _parse_resource_name(data, rname)
|
1626
|
+
if (rname & 0x80000000 != 0)
|
1627
|
+
rname &= ~0x80000000
|
1628
|
+
unistr = data[rname+2, 2 * data[rname,2].unpack('v')[0] ]
|
1629
|
+
unistr, trash = unistr.split(/\x00\x00/n, 2)
|
1630
|
+
return unistr ? unistr.gsub(/\x00/n, '') : nil
|
1631
|
+
end
|
1632
|
+
|
1633
|
+
rname.to_s
|
1634
|
+
end
|
1635
|
+
|
1636
|
+
def update_checksum
|
1637
|
+
off = _dos_header.e_lfanew + IMAGE_FILE_HEADER_SIZE + 0x40
|
1638
|
+
_isource.rawdata[off, 4] = [0].pack('V')
|
1639
|
+
|
1640
|
+
rem = _isource.size % 4
|
1641
|
+
sum_me = ''
|
1642
|
+
sum_me << _isource.rawdata
|
1643
|
+
sum_me << "\x00" * (4 - rem) if rem > 0
|
1644
|
+
|
1645
|
+
cksum = 0
|
1646
|
+
sum_me.unpack('V*').each { |el|
|
1647
|
+
cksum = (cksum & 0xffffffff) + (cksum >> 32) + el
|
1648
|
+
if cksum > 2**32
|
1649
|
+
cksum = (cksum & 0xffffffff) + (cksum >> 32)
|
1650
|
+
end
|
1651
|
+
}
|
1652
|
+
|
1653
|
+
cksum = (cksum & 0xffff) + (cksum >> 16)
|
1654
|
+
cksum += (cksum >> 16)
|
1655
|
+
cksum &= 0xffff
|
1656
|
+
|
1657
|
+
cksum += _isource.size
|
1658
|
+
|
1659
|
+
_isource.rawdata[off, 4] = [cksum].pack('V')
|
1660
|
+
end
|
1661
|
+
|
1662
|
+
end end end
|