fileshunter 0.1.0.20130725
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|