fileshunter 0.1.0.20130725

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,505 @@
1
+ module FilesHunter
2
+
3
+ module Decoders
4
+
5
+ class EXE < BeginPatternDecoder
6
+
7
+ BEGIN_PATTERN_EXE = Regexp.new("MZ....\x00\x00.\x00.\x00..\x00\x00..\x00\x00\x00\x00\x00\x00.\x00.\x00\x00\x00....\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00....\x00\x00\x00\x00\x00\x00\x00\x00", nil, 'n')
8
+
9
+ KNOWN_MACHINE_TYPES = [
10
+ "\x00\x00".force_encoding(Encoding::ASCII_8BIT),
11
+ "\xd3\x01".force_encoding(Encoding::ASCII_8BIT),
12
+ "\x64\x86".force_encoding(Encoding::ASCII_8BIT),
13
+ "\xc0\x01".force_encoding(Encoding::ASCII_8BIT),
14
+ "\xc4\x01".force_encoding(Encoding::ASCII_8BIT),
15
+ "\x64\xaa".force_encoding(Encoding::ASCII_8BIT),
16
+ "\xbc\x0e".force_encoding(Encoding::ASCII_8BIT),
17
+ "\x4c\x01".force_encoding(Encoding::ASCII_8BIT),
18
+ "\x00\x02".force_encoding(Encoding::ASCII_8BIT),
19
+ "\x41\x90".force_encoding(Encoding::ASCII_8BIT),
20
+ "\x66\x02".force_encoding(Encoding::ASCII_8BIT),
21
+ "\x66\x03".force_encoding(Encoding::ASCII_8BIT),
22
+ "\x66\x04".force_encoding(Encoding::ASCII_8BIT),
23
+ "\xf0\x01".force_encoding(Encoding::ASCII_8BIT),
24
+ "\xf1\x01".force_encoding(Encoding::ASCII_8BIT),
25
+ "\x66\x01".force_encoding(Encoding::ASCII_8BIT),
26
+ "\xa2\x01".force_encoding(Encoding::ASCII_8BIT),
27
+ "\xa3\x01".force_encoding(Encoding::ASCII_8BIT),
28
+ "\xa6\x01".force_encoding(Encoding::ASCII_8BIT),
29
+ "\xa8\x01".force_encoding(Encoding::ASCII_8BIT),
30
+ "\xc2\x01".force_encoding(Encoding::ASCII_8BIT),
31
+ "\x69\x01".force_encoding(Encoding::ASCII_8BIT)
32
+ ]
33
+
34
+ PE_SIGNATURE = "PE\x00\x00".force_encoding(Encoding::ASCII_8BIT)
35
+ NE_SIGNATURE = 'NE'.force_encoding(Encoding::ASCII_8BIT)
36
+ OPTIONAL_HEADER_ID = "\x0B".force_encoding(Encoding::ASCII_8BIT)
37
+ PE32_ID = "\x01".force_encoding(Encoding::ASCII_8BIT)
38
+ KNOWN_OPTIONAL_HEADER_TYPES = [
39
+ PE32_ID,
40
+ "\x02".force_encoding(Encoding::ASCII_8BIT)
41
+ ]
42
+ SECTION_TEXT_ID = ".text\x00\x00\x00".force_encoding(Encoding::ASCII_8BIT)
43
+
44
+ def get_begin_pattern
45
+ return BEGIN_PATTERN_EXE, { :offset_inc => 60, :max_regexp_size => 60 }
46
+ end
47
+
48
+ def decode(offset)
49
+ ending_offset = nil
50
+
51
+ # Go directly to the PE file header
52
+ cursor = offset + BinData::Uint32le.read(@data[offset+60..offset+63])
53
+ progress(cursor)
54
+ # Decode PE file header
55
+ invalid_data("@#{cursor} - Invalid PE/NE header") if ((@data[cursor..cursor+3] != PE_SIGNATURE) and (@data[cursor..cursor+1] != NE_SIGNATURE))
56
+ if (@data[cursor..cursor+1] == NE_SIGNATURE)
57
+ # NE format
58
+ # Reference: http://www.fileformat.info/format/exe/corion-ne.htm
59
+ # Reference: http://itee.uq.edu.au/~cristina/students/david/honoursThesis96/appendix.htm
60
+ # Reference: http://www.program-transformation.org/Transform/NeFormat
61
+ # Reference: http://www.chiark.greenend.org.uk/~sgtatham/fonts/dewinfont
62
+ ne_offset = cursor
63
+ cursor += 2
64
+ #linker_major_version = @data[cursor].ord
65
+ #linker_minor_version = @data[cursor+1].ord
66
+ entry_table_offset = BinData::Uint16le.read(@data[cursor+2..cursor+3])
67
+ entry_table_size = BinData::Uint16le.read(@data[cursor+4..cursor+5])
68
+ #file_load_crc = BinData::Uint32le.read(@data[cursor+6..cursor+9])
69
+ #program_flags = @data[cursor+10].ord
70
+ #application_flags = @data[cursor+11].ord
71
+ #auto_data_segment_index = BinData::Uint16le.read(@data[cursor+12..cursor+13])
72
+ #initial_local_heap_size = BinData::Uint16le.read(@data[cursor+14..cursor+15])
73
+ #initial_stack_size = BinData::Uint16le.read(@data[cursor+16..cursor+17])
74
+ #entry_point = BinData::Uint32le.read(@data[cursor+18..cursor+21])
75
+ #initial_stack_pointer = BinData::Uint32le.read(@data[cursor+22..cursor+25])
76
+ nbr_segments = BinData::Uint16le.read(@data[cursor+26..cursor+27])
77
+ nbr_module_reference = BinData::Uint16le.read(@data[cursor+28..cursor+29])
78
+ non_resident_names_table_size = BinData::Uint16le.read(@data[cursor+30..cursor+31])
79
+ segment_table_offset = BinData::Uint16le.read(@data[cursor+32..cursor+33])
80
+ resource_table_offset = BinData::Uint16le.read(@data[cursor+34..cursor+35])
81
+ resident_names_table_offset = BinData::Uint16le.read(@data[cursor+36..cursor+37])
82
+ module_reference_table_offset = BinData::Uint16le.read(@data[cursor+38..cursor+39])
83
+ imported_names_table_offset = BinData::Uint16le.read(@data[cursor+40..cursor+41])
84
+ non_resident_names_table_offset = BinData::Uint32le.read(@data[cursor+42..cursor+45])
85
+ #moveable_entry_point_count = BinData::Uint16le.read(@data[cursor+46..cursor+47])
86
+ #file_alignment = BinData::Uint16le.read(@data[cursor+48..cursor+49])
87
+ #nbr_resource_table_entries = BinData::Uint16le.read(@data[cursor+50..cursor+51])
88
+ #target_operating_system = @data[cursor+52].ord
89
+ #other_flags = @data[cursor+53].ord
90
+ #return_thunks_offset = BinData::Uint16le.read(@data[cursor+54..cursor+55])
91
+ #segment_reference_thunks_offset = BinData::Uint16le.read(@data[cursor+56..cursor+57])
92
+ #code_swap_area_size = BinData::Uint16le.read(@data[cursor+58..cursor+59])
93
+ #expected_win_version_minor = @data[cursor+60].ord
94
+ #expected_win_version_major = @data[cursor+61].ord
95
+ cursor += 62
96
+ progress(cursor)
97
+ log_debug "@#{cursor} - NE header: entry_table_offset=#{entry_table_offset} entry_table_size=#{entry_table_size} nbr_segments=#{nbr_segments} nbr_module_reference=#{nbr_module_reference} non_resident_names_table_size=#{non_resident_names_table_size} segment_table_offset=#{segment_table_offset} resource_table_offset=#{resource_table_offset} resident_names_table_offset=#{resident_names_table_offset} module_reference_table_offset=#{module_reference_table_offset} imported_names_table_offset=#{imported_names_table_offset} non_resident_names_table_offset=#{non_resident_names_table_offset}"
98
+ # Segment table
99
+ log_debug "@#{cursor} - Segment table"
100
+ invalid_data("@#{cursor} - Segment table offset (#{segment_table_offset}) should have been set here (#{cursor-ne_offset}).") if (segment_table_offset != cursor-ne_offset)
101
+ # map< SegmentOffset, SegmentSize >
102
+ segment_data = {}
103
+ nbr_segments.times do |idx_segment|
104
+ segment_data_offset = BinData::Uint16le.read(@data[cursor..cursor+1])
105
+ if (segment_data_offset > 0)
106
+ segment_data_size = BinData::Uint16le.read(@data[cursor+2..cursor+3])
107
+ segment_data_size = 65536 if (segment_data_size == 0)
108
+ segment_data[segment_data_offset] = segment_data_size
109
+ end
110
+ cursor += 8
111
+ end
112
+ progress(cursor)
113
+ # Now we track the maximal cursor encountered
114
+ max_cursor = cursor
115
+ # Resource table
116
+ log_debug "@#{cursor} - Resource table"
117
+ invalid_data("@#{cursor} - Resource table offset (#{resource_table_offset}) should have been set here (#{cursor-ne_offset}).") if (resource_table_offset != cursor-ne_offset)
118
+ # Ignore nbr_resource_table_entries
119
+ alignment_shift_count = BinData::Uint16le.read(@data[cursor..cursor+1])
120
+ offset_factor = (1 << alignment_shift_count)
121
+ # map< SegmentOffset, SegmentSize >
122
+ resource_data = {}
123
+ type_id = BinData::Uint16le.read(@data[cursor+2..cursor+3])
124
+ cursor += 4
125
+ while (type_id != 0)
126
+ # If the Type ID is a string, read it
127
+ if ((type_id & 0b10000000_00000000) == 0)
128
+ str_offset = ne_offset + resource_table_offset + type_id
129
+ end_str_cursor = str_offset + 1 + @data[str_offset].ord
130
+ max_cursor = end_str_cursor if (max_cursor < end_str_cursor)
131
+ end
132
+ nbr_resources_for_this_type = BinData::Uint16le.read(@data[cursor..cursor+1])
133
+ reserved = BinData::Uint32le.read(@data[cursor+2..cursor+5])
134
+ invalid_data("@#{cursor} - Reserved data should have been null: #{reserved}") if (reserved != 0)
135
+ cursor += 6
136
+ nbr_resources_for_this_type.times do |idx_resource_for_this_type|
137
+ resource_offset = BinData::Uint16le.read(@data[cursor..cursor+1])
138
+ resource_size = BinData::Uint16le.read(@data[cursor+2..cursor+3])
139
+ resource_flags = BinData::Uint16le.read(@data[cursor+4..cursor+5])
140
+ resource_id = BinData::Uint16le.read(@data[cursor+6..cursor+7])
141
+ real_offset = resource_offset * offset_factor
142
+ real_size = resource_size * offset_factor
143
+ log_debug "@#{cursor} - Found resource ##{resource_id} @#{real_offset} of size #{real_size} with flags #{resource_flags}"
144
+ reserved = BinData::Uint32le.read(@data[cursor+8..cursor+11])
145
+ invalid_data("@#{cursor} - Reserved data should have been null: #{reserved}") if (reserved != 0)
146
+ resource_data[real_offset] = real_size
147
+ # If the Resource ID is a string, read it
148
+ if ((resource_id & 0b10000000_00000000) == 0)
149
+ str_offset = ne_offset + resource_table_offset + resource_id
150
+ end_str_cursor = str_offset + 1 + @data[str_offset].ord
151
+ max_cursor = end_str_cursor if (max_cursor < end_str_cursor)
152
+ end
153
+ cursor += 12
154
+ progress(cursor)
155
+ end
156
+ type_id = BinData::Uint16le.read(@data[cursor..cursor+1])
157
+ cursor += 2
158
+ progress(cursor)
159
+ end
160
+ progress(cursor)
161
+ max_cursor = cursor if (max_cursor < cursor)
162
+ # Resident names table
163
+ cursor = ne_offset + resident_names_table_offset
164
+ log_debug "@#{cursor} - Resident names table"
165
+ next_string_length = @data[cursor].ord
166
+ cursor += 1
167
+ while (next_string_length > 0)
168
+ str_name = @data[cursor..cursor+next_string_length-1]
169
+ log_debug "@#{cursor} - Found resident name string: #{str_name.inspect}"
170
+ cursor += next_string_length
171
+ next_string_length = @data[cursor+2].ord
172
+ cursor += 3
173
+ progress(cursor)
174
+ end
175
+ max_cursor = cursor if (max_cursor < cursor)
176
+ # Module reference table
177
+ cursor = ne_offset + module_reference_table_offset
178
+ log_debug "@#{cursor} - Module reference table"
179
+ nbr_module_reference.times do |idx_module_reference|
180
+ cursor += 2
181
+ end
182
+ progress(cursor)
183
+ max_cursor = cursor if (max_cursor < cursor)
184
+ # Imported name table
185
+ cursor = ne_offset + imported_names_table_offset
186
+ log_debug "@#{cursor} - Imported names table"
187
+ next_string_length = @data[cursor].ord
188
+ cursor += 1
189
+ while (next_string_length > 0)
190
+ str_name = @data[cursor..cursor+next_string_length-1]
191
+ log_debug "@#{cursor} - Found imported name string: #{str_name.inspect}"
192
+ cursor += next_string_length
193
+ next_string_length = @data[cursor].ord
194
+ cursor += 1
195
+ progress(cursor)
196
+ end
197
+ max_cursor = cursor if (max_cursor < cursor)
198
+ # Entry table
199
+ cursor = ne_offset + entry_table_offset
200
+ log_debug "@#{cursor} - Entry table"
201
+ nbr_entries_in_bundle = @data[cursor].ord
202
+ #segment_indicator_for_bundle = @data[cursor+1].ord
203
+ cursor += 2
204
+ while (nbr_entries_in_bundle > 0)
205
+ # TODO
206
+ invalid_data("@#{cursor} - Cannot decode entry tables from NE executable files yet. Sorry.")
207
+
208
+ nbr_entries_in_bundle = @data[cursor].ord
209
+ end
210
+ invalid_data("@#{cursor} - Declared entry table size (#{entry_table_size}) is smaller than what has been read: #{cursor-ne_offset-entry_table_offset}") if (entry_table_size < cursor-ne_offset-entry_table_offset)
211
+ # Make sure we get padding too
212
+ cursor = ne_offset + entry_table_offset + entry_table_size
213
+ max_cursor = cursor if (max_cursor < cursor)
214
+ # Non resident names table
215
+ cursor = offset + non_resident_names_table_offset
216
+ log_debug "@#{cursor} - Non resident name table"
217
+ next_string_length = @data[cursor].ord
218
+ cursor += 1
219
+ while (next_string_length > 0)
220
+ str_name = @data[cursor..cursor+next_string_length-1]
221
+ log_debug "@#{cursor} - Found non resident name string: #{str_name.inspect}"
222
+ cursor += next_string_length
223
+ next_string_length = @data[cursor+2].ord
224
+ cursor += 3
225
+ progress(cursor)
226
+ end
227
+ invalid_data("@#{cursor} - Declared non resident name table size (#{non_resident_names_table_size}) is smaller than what has been read: #{cursor-offset-non_resident_names_table_offset}") if (non_resident_names_table_size < cursor-offset-non_resident_names_table_offset)
228
+ # Make sure we get padding too
229
+ cursor = offset + non_resident_names_table_offset + non_resident_names_table_size
230
+ max_cursor = cursor if (max_cursor < cursor)
231
+ # Data and resource segments
232
+ segment_data.merge(resource_data).each do |data_offset, data_size|
233
+ cursor = offset + data_offset
234
+ cursor += data_size
235
+ max_cursor = cursor if (max_cursor < cursor)
236
+ end
237
+ ending_offset = max_cursor
238
+ found_relevant_data(:fon)
239
+ else
240
+ # PE format
241
+ cursor += 4
242
+ target_machine = @data[cursor..cursor+1]
243
+ invalid_data("@#{cursor} - Invalid machine type: #{target_machine.inspect}") if (!KNOWN_MACHINE_TYPES.include?(target_machine))
244
+ nbr_sections = BinData::Uint16le.read(@data[cursor+2..cursor+3])
245
+ #creation_time = BinData::Uint32le.read(@data[cursor+4..cursor+7])
246
+ symbol_table_offset = BinData::Uint32le.read(@data[cursor+8..cursor+11])
247
+ nbr_symbols = BinData::Uint32le.read(@data[cursor+12..cursor+15])
248
+ optional_header_size = BinData::Uint16le.read(@data[cursor+16..cursor+17])
249
+ characteristics = BinData::Uint16le.read(@data[cursor+18..cursor+19])
250
+ invalid_data("@#{cursor+18} - Invalid characteristics #{characteristics}: bits should be 0") if ((characteristics & 80) != 0)
251
+ # We can have a first guess on the extension
252
+ file_type = ((characteristics & 8192) == 0) ? :exe : ((optional_header_size == 0) ? :obj : :dll)
253
+ found_relevant_data((file_type == :exe) ? [ :exe, :sys ] : ((file_type == :obj) ? :obj : [ :dll, :drv, :ocx ]))
254
+ metadata(
255
+ :target_machine => target_machine,
256
+ :nbr_sections => nbr_sections,
257
+ :symbol_table_offset => symbol_table_offset,
258
+ :nbr_symbols => nbr_symbols,
259
+ :optional_header_size => optional_header_size,
260
+ :characteristics => characteristics
261
+ )
262
+ cursor += 20
263
+ progress(cursor)
264
+ file_alignment = nil
265
+ certificate_table_offset = nil
266
+ certificate_table_size = nil
267
+ #delay_import_table_offset = nil
268
+ #delay_import_table_size = nil
269
+ # Decode optional header if any
270
+ optional_header_end_offset = cursor + optional_header_size
271
+ if (optional_header_size > 0)
272
+ c_1 = @data[cursor+1]
273
+ invalid_data("@#{cursor} - Invalid optional header") if ((@data[cursor] != OPTIONAL_HEADER_ID) or (!KNOWN_OPTIONAL_HEADER_TYPES.include?(c_1)))
274
+ mode_pe32 = (c_1 == PE32_ID)
275
+ #linker_version_major = @data[cursor+2].ord
276
+ #linker_version_minor = @data[cursor+3].ord
277
+ #code_size = BinData::Uint32le.read(@data[cursor+4..cursor+7])
278
+ #init_data_size = BinData::Uint32le.read(@data[cursor+8..cursor+11])
279
+ #uninit_data_size = BinData::Uint32le.read(@data[cursor+12..cursor+15])
280
+ #log_debug "@#{cursor} - code_size=#{code_size} init_data_size=#{init_data_size} uninit_data_size=#{uninit_data_size}"
281
+ #entry_point_address = BinData::Uint32le.read(@data[cursor+16..cursor+19])
282
+ #base_of_code = BinData::Uint32le.read(@data[cursor+20..cursor+23])
283
+ #if mode_pe32
284
+ #base_of_data = BinData::Uint32le.read(@data[cursor+24..cursor+27])
285
+ #image_base = BinData::Uint32le.read(@data[cursor+28..cursor+31])
286
+ #else
287
+ #image_base = BinData::Uint64le.read(@data[cursor+24..cursor+31])
288
+ #end
289
+ #section_alignment = BinData::Uint32le.read(@data[cursor+32..cursor+35])
290
+ file_alignment = BinData::Uint32le.read(@data[cursor+36..cursor+39])
291
+ #os_version_major = BinData::Uint16le.read(@data[cursor+40..cursor+41])
292
+ #os_version_minor = BinData::Uint16le.read(@data[cursor+42..cursor+43])
293
+ #image_version_major = BinData::Uint16le.read(@data[cursor+44..cursor+45])
294
+ #image_version_minor = BinData::Uint16le.read(@data[cursor+46..cursor+47])
295
+ #subsystem_version_major = BinData::Uint16le.read(@data[cursor+48..cursor+49])
296
+ #subsystem_version_minor = BinData::Uint16le.read(@data[cursor+50..cursor+51])
297
+ win32_version = BinData::Uint32le.read(@data[cursor+52..cursor+55])
298
+ invalid_data("@#{cursor+52} - Invalid Win32 version: #{win32_version}") if (win32_version != 0)
299
+ #image_size = BinData::Uint32le.read(@data[cursor+56..cursor+59])
300
+ headers_size = BinData::Uint32le.read(@data[cursor+60..cursor+64])
301
+ #checksum = BinData::Uint32le.read(@data[cursor+64..cursor+67])
302
+ subsystem = BinData::Uint16le.read(@data[cursor+68..cursor+69])
303
+ if (subsystem == 1)
304
+ case file_type
305
+ when :dll
306
+ file_type = :drv
307
+ found_relevant_data(:drv)
308
+ when :exe
309
+ file_type = :sys
310
+ found_relevant_data(:sys)
311
+ end
312
+ end
313
+ dll_characteristics = BinData::Uint16le.read(@data[cursor+70..cursor+71])
314
+ invalid_data("@#{cursor+70} - Invalid DLL characteristics #{dll_characteristics}: bits should be 0") if ((dll_characteristics & 4111) != 0)
315
+ nbr_rva_and_sizes = nil
316
+ if mode_pe32
317
+ # stack_reserve_size = BinData::Uint32le.read(@data[cursor+72..cursor+75])
318
+ # stack_commit_size = BinData::Uint32le.read(@data[cursor+76..cursor+79])
319
+ # heap_reserve_size = BinData::Uint32le.read(@data[cursor+80..cursor+83])
320
+ # heap_commit_size = BinData::Uint32le.read(@data[cursor+84..cursor+87])
321
+ # loader_flags = BinData::Uint32le.read(@data[cursor+88..cursor+91])
322
+ nbr_rva_and_sizes = BinData::Uint32le.read(@data[cursor+92..cursor+95])
323
+ cursor += 96
324
+ else
325
+ # stack_reserve_size = BinData::Uint64le.read(@data[cursor+72..cursor+79])
326
+ # stack_commit_size = BinData::Uint64le.read(@data[cursor+80..cursor+87])
327
+ # heap_reserve_size = BinData::Uint64le.read(@data[cursor+88..cursor+95])
328
+ # heap_commit_size = BinData::Uint64le.read(@data[cursor+96..cursor+103])
329
+ # loader_flags = BinData::Uint32le.read(@data[cursor+104..cursor+107])
330
+ nbr_rva_and_sizes = BinData::Uint32le.read(@data[cursor+108..cursor+111])
331
+ cursor += 112
332
+ end
333
+ # Get some info from the Data Directories
334
+ if (nbr_rva_and_sizes >= 5)
335
+ certificate_table_offset = BinData::Uint32le.read(@data[cursor+32..cursor+35])
336
+ certificate_table_size = BinData::Uint32le.read(@data[cursor+36..cursor+39])
337
+ end
338
+ #if (nbr_rva_and_sizes >= 14)
339
+ #delay_import_table_offset = BinData::Uint32le.read(@data[cursor+104..cursor+107])
340
+ #delay_import_table_size = BinData::Uint32le.read(@data[cursor+108..cursor+111])
341
+ #end
342
+ cursor += 8*nbr_rva_and_sizes
343
+ progress(cursor)
344
+ log_debug "@#{cursor} - Extended header: mode_pe32=#{mode_pe32} win32_version=#{win32_version} headers_size=#{headers_size} subsystem=#{subsystem} dll_characteristics=#{dll_characteristics} nbr_rva_and_sizes=#{nbr_rva_and_sizes}"
345
+ # We should have reached the end of optional header
346
+ # Sometimes optional_header_end_offset is invalid
347
+ invalid_data("@#{cursor} - Optional headers end at #{cursor} but were supposed to end at #{optional_header_end_offset}") if (cursor != optional_header_end_offset)
348
+ metadata(
349
+ :mode_pe32 => mode_pe32,
350
+ :file_alignment => file_alignment,
351
+ :win32_version => win32_version,
352
+ :headers_size => headers_size,
353
+ :subsystem => subsystem,
354
+ :dll_characteristics => dll_characteristics,
355
+ :nbr_rva_and_sizes => nbr_rva_and_sizes,
356
+ :certificate_table_offset => certificate_table_offset,
357
+ :certificate_table_size => certificate_table_size
358
+ )
359
+ end
360
+ log_debug "@#{cursor} - PE Header: nbr_sections=#{nbr_sections} file_alignment=#{file_alignment} symbol_table_offset=#{symbol_table_offset} nbr_symbols=#{nbr_symbols} certificate_table_offset=#{certificate_table_offset} certificate_table_size=#{certificate_table_size}"
361
+ # Now decode section headers
362
+ log_debug "@#{cursor} - Beginning of section headers"
363
+ # map<offset,size>
364
+ sections = {}
365
+ line_numbers = {}
366
+ text_section_offset = nil
367
+ nbr_sections.times do |idx_section|
368
+ name = @data[cursor..cursor+7]
369
+ #virtual_size = BinData::Uint32le.read(@data[cursor+8..cursor+11])
370
+ #virtual_address = BinData::Uint32le.read(@data[cursor+12..cursor+15])
371
+ raw_data_size = BinData::Uint32le.read(@data[cursor+16..cursor+19])
372
+ raw_data_offset = BinData::Uint32le.read(@data[cursor+20..cursor+23])
373
+ #relocations_offset = BinData::Uint32le.read(@data[cursor+24..cursor+27])
374
+ line_numbers_offset = BinData::Uint32le.read(@data[cursor+28..cursor+31])
375
+ #nbr_relocations = BinData::Uint16le.read(@data[cursor+32..cursor+33])
376
+ nbr_line_numbers = BinData::Uint16le.read(@data[cursor+34..cursor+35])
377
+ #section_characteristics = BinData::Uint32le.read(@data[cursor+36..cursor+39])
378
+ #invalid_data("@#{cursor+70} - Invalid Section characteristics #{section_characteristics}: bits should be 0") if ((section_characteristics & 18) != 0)
379
+ log_debug "@#{cursor} - Found section #{name}: raw_data_offset=#{raw_data_offset} raw_data_size=#{raw_data_size}"
380
+ # Remember the .text section
381
+ text_section_offset = raw_data_offset if (name == SECTION_TEXT_ID)
382
+ cursor += 40
383
+ progress(cursor)
384
+ sections[raw_data_offset] = raw_data_size if (raw_data_size > 0)
385
+ line_numbers[line_numbers_offset] = nbr_line_numbers if (nbr_line_numbers > 0)
386
+ end
387
+ # Get cursor directly at the end of the headers
388
+ cursor = offset + headers_size if (headers_size != nil)
389
+ progress(cursor)
390
+ # Starting from here, tables and sections might not be contiguous. Therefore we keep track of the maximal cursor encountered.
391
+ max_cursor = cursor
392
+ # Now read all sections defined
393
+ log_debug "@#{cursor} - Beginning of sections"
394
+ sections.keys.sort.each_with_index do |section_offset, idx_section|
395
+ # Align cursor on the next file_alignment
396
+ rest = (file_alignment == nil) ? 0 : ((cursor-offset) % file_alignment)
397
+ cursor += file_alignment - rest if (rest > 0)
398
+ # Check beginning of the section data
399
+ if ((cursor-offset) != section_offset)
400
+ log_debug("@#{cursor} - Section #{idx_section} should have been at offset #{cursor-offset}, but is declared at #{section_offset}")
401
+ cursor = offset + section_offset
402
+ end
403
+ # Check OCX
404
+ if ((text_section_offset == section_offset) and
405
+ (file_type == :dll) and
406
+ (@data.index('DllRegisterServer', cursor) != nil))
407
+ file_type = :ocx
408
+ found_relevant_data(:ocx)
409
+ end
410
+ cursor += sections[section_offset]
411
+ max_cursor = cursor if (cursor > max_cursor)
412
+ progress(cursor)
413
+ end
414
+ # Should have the COFF line numbers sections
415
+ log_debug "@#{cursor} - Beginning of COFF line numbers"
416
+ line_numbers.keys.sort.each do |line_number_offset|
417
+ if ((cursor-offset) != line_number_offset)
418
+ log_debug("@#{cursor} - COFF line number section should have been at offset #{cursor-offset}, but is declared at #{line_number_offset}")
419
+ # Have to realign cursor
420
+ cursor = offset + line_number_offset
421
+ end
422
+ cursor += 6*line_numbers[line_number_offset]
423
+ max_cursor = cursor if (cursor > max_cursor)
424
+ progress(cursor)
425
+ end
426
+ # Should have the symbol table
427
+ log_debug "@#{cursor} - Beginning of symbol tables"
428
+ if (symbol_table_offset > 0)
429
+ if ((cursor-offset) != symbol_table_offset)
430
+ log_debug("@#{cursor} - Symbol table should have been at offset #{cursor-offset}, but is declared at #{symbol_table_offset}")
431
+ cursor = offset + symbol_table_offset
432
+ end
433
+ nbr_symbols.times do |idx_symbol|
434
+ #name = @data[cursor..cursor+7]
435
+ #value = BinData::Uint32le.read(@data[cursor+8..cursor+11])
436
+ #section_number = BinData::Uint16le.read(@data[cursor+12..cursor+13])
437
+ #type = BinData::Uint16le.read(@data[cursor+14..cursor+15])
438
+ #storage_class = @data[cursor+16].ord
439
+ #nbr_auxiliary_symbols = @data[cursor+17].ord
440
+ cursor += 18
441
+ progress(cursor)
442
+ log_debug "@#{cursor} - Finished decoding symbol \##{idx_symbol}"
443
+ end
444
+ # Should have the COFF string table
445
+ log_debug "@#{cursor} - Beginning of COFF string table"
446
+ coff_string_table_size = BinData::Uint32le.read(@data[cursor..cursor+3])
447
+ # Should be greater than 4
448
+ invalid_data("@#{cursor} - COFF string table size should be >= 4 (#{coff_string_table_size})") if (coff_string_table_size < 4)
449
+ cursor += coff_string_table_size
450
+ max_cursor = cursor if (cursor > max_cursor)
451
+ progress(cursor)
452
+ end
453
+ # Should have the certificate table
454
+ log_debug "@#{cursor} - Beginning of certificate table"
455
+ if ((certificate_table_offset != nil) and
456
+ (certificate_table_offset > 0))
457
+ if ((cursor-offset) != certificate_table_offset)
458
+ log_debug("@#{cursor} - Certificate table should have been at offset #{cursor-offset}, but is declared at #{certificate_table_offset}")
459
+ cursor = offset + certificate_table_offset
460
+ end
461
+ while (cursor < offset + certificate_table_offset + certificate_table_size)
462
+ log_debug "@#{cursor} - Read certificate"
463
+ certificate_size = BinData::Uint32le.read(@data[cursor..cursor+3])
464
+ log_debug "@#{cursor} - Found certificate of size #{certificate_size}"
465
+ cursor += certificate_size
466
+ # Round to 8 bytes
467
+ rest = (cursor-offset) % 8
468
+ cursor += 8 - rest if (rest > 0)
469
+ progress(cursor)
470
+ end
471
+ max_cursor = cursor if (cursor > max_cursor)
472
+ end
473
+ # Delay import table is part of the .idata section already
474
+ # # Should have the delay import table
475
+ # log_debug "@#{cursor} - Beginning of delay import table"
476
+ # if ((delay_import_table_offset != nil) and
477
+ # (delay_import_table_offset > 0))
478
+ # if ((cursor-offset) != delay_import_table_offset)
479
+ # invalid_data("@#{cursor} - Delay import table should have been at offset #{cursor-offset}, but is declared at #{delay_import_table_offset}")
480
+ # cursor = offset + delay_import_table_offset
481
+ # end
482
+ # attributes = BinData::Uint32le.read(@data[cursor..cursor+3])
483
+ # invalid_data("@#{cursor} - Delay import attributes should be 0 (#{attributes})") if (attributes != 0)
484
+ # name_rva = BinData::Uint32le.read(@data[cursor+4..cursor+7])
485
+ # module_handle = BinData::Uint32le.read(@data[cursor+8..cursor+11])
486
+ # delay_import_address_rva = BinData::Uint32le.read(@data[cursor+12..cursor+15])
487
+ # delay_import_name_rva = BinData::Uint32le.read(@data[cursor+16..cursor+19])
488
+ # bound_delay_import_rva = BinData::Uint32le.read(@data[cursor+20..cursor+23])
489
+ # unload_delay_import_rva = BinData::Uint32le.read(@data[cursor+24..cursor+27])
490
+ # timestamp = BinData::Uint32le.read(@data[cursor+28..cursor+31])
491
+ # cursor += 32
492
+ # max_cursor = cursor if (cursor > max_cursor)
493
+ # end
494
+ # Should be the end
495
+ ending_offset = max_cursor
496
+ end
497
+
498
+ return ending_offset
499
+ end
500
+
501
+ end
502
+
503
+ end
504
+
505
+ end