rex-bin_tools 0.1.0

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