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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +1 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +9 -0
  5. data/.rspec +2 -0
  6. data/.travis.yml +5 -0
  7. data/CODE_OF_CONDUCT.md +52 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE +27 -0
  10. data/README.md +22 -0
  11. data/Rakefile +6 -0
  12. data/bin/console +14 -0
  13. data/bin/msfbinscan +284 -0
  14. data/bin/msfelfscan +120 -0
  15. data/bin/msfmachscan +100 -0
  16. data/bin/msfpescan +184 -0
  17. data/bin/setup +8 -0
  18. data/data/identify.txt +3043 -0
  19. data/lib/rex/assembly/nasm.rb +104 -0
  20. data/lib/rex/bin_tools.rb +13 -0
  21. data/lib/rex/bin_tools/version.rb +5 -0
  22. data/lib/rex/elfparsey.rb +9 -0
  23. data/lib/rex/elfparsey/elf.rb +121 -0
  24. data/lib/rex/elfparsey/elfbase.rb +265 -0
  25. data/lib/rex/elfparsey/exceptions.rb +25 -0
  26. data/lib/rex/elfscan.rb +10 -0
  27. data/lib/rex/elfscan/scanner.rb +226 -0
  28. data/lib/rex/elfscan/search.rb +44 -0
  29. data/lib/rex/image_source.rb +10 -0
  30. data/lib/rex/image_source/disk.rb +58 -0
  31. data/lib/rex/image_source/image_source.rb +48 -0
  32. data/lib/rex/image_source/memory.rb +35 -0
  33. data/lib/rex/machparsey.rb +9 -0
  34. data/lib/rex/machparsey/exceptions.rb +31 -0
  35. data/lib/rex/machparsey/mach.rb +209 -0
  36. data/lib/rex/machparsey/machbase.rb +408 -0
  37. data/lib/rex/machscan.rb +9 -0
  38. data/lib/rex/machscan/scanner.rb +217 -0
  39. data/lib/rex/peparsey.rb +10 -0
  40. data/lib/rex/peparsey/exceptions.rb +30 -0
  41. data/lib/rex/peparsey/pe.rb +210 -0
  42. data/lib/rex/peparsey/pe_memdump.rb +61 -0
  43. data/lib/rex/peparsey/pebase.rb +1662 -0
  44. data/lib/rex/peparsey/section.rb +128 -0
  45. data/lib/rex/pescan.rb +11 -0
  46. data/lib/rex/pescan/analyze.rb +366 -0
  47. data/lib/rex/pescan/scanner.rb +230 -0
  48. data/lib/rex/pescan/search.rb +68 -0
  49. data/rex-bin_tools.gemspec +32 -0
  50. metadata +284 -0
  51. 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