fileshunter 0.1.0.20130725
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +3 -0
- data/ChangeLog +5 -0
- data/Credits +21 -0
- data/LICENSE +31 -0
- data/README +15 -0
- data/README.md +11 -0
- data/Rakefile +7 -0
- data/ReleaseInfo +8 -0
- data/bin/fileshunt +216 -0
- data/ext/fileshunter/Decoders/_FLAC.c +233 -0
- data/ext/fileshunter/Decoders/extconf.rb +3 -0
- data/lib/fileshunter/BeginPatternDecoder.rb +218 -0
- data/lib/fileshunter/Decoder.rb +66 -0
- data/lib/fileshunter/Decoders/ASF.rb +50 -0
- data/lib/fileshunter/Decoders/BMP.rb +118 -0
- data/lib/fileshunter/Decoders/CAB.rb +140 -0
- data/lib/fileshunter/Decoders/CFBF.rb +92 -0
- data/lib/fileshunter/Decoders/EBML.rb +369 -0
- data/lib/fileshunter/Decoders/EXE.rb +505 -0
- data/lib/fileshunter/Decoders/FLAC.rb +387 -0
- data/lib/fileshunter/Decoders/ICO.rb +71 -0
- data/lib/fileshunter/Decoders/JPEG.rb +247 -0
- data/lib/fileshunter/Decoders/M2V.rb +30 -0
- data/lib/fileshunter/Decoders/MP3.rb +341 -0
- data/lib/fileshunter/Decoders/MP4.rb +620 -0
- data/lib/fileshunter/Decoders/MPG_Video.rb +30 -0
- data/lib/fileshunter/Decoders/OGG.rb +74 -0
- data/lib/fileshunter/Decoders/RIFF.rb +437 -0
- data/lib/fileshunter/Decoders/TIFF.rb +350 -0
- data/lib/fileshunter/Decoders/Text.rb +240 -0
- data/lib/fileshunter/Segment.rb +50 -0
- data/lib/fileshunter/SegmentsAnalyzer.rb +251 -0
- data/lib/fileshunter.rb +15 -0
- metadata +130 -0
@@ -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
|