Skip to content

Commit f4ec6bd

Browse files
committed
- use non-native pack/unpack directives
- coding: binary - use constant for data_attribute
1 parent 68b735d commit f4ec6bd

File tree

1 file changed

+35
-33
lines changed

1 file changed

+35
-33
lines changed

lib/rex/parser/fs/ntfs.rb

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: binary -*-
12
module Rex
23
module Parser
34

@@ -11,11 +12,12 @@ class NTFS
1112
#
1213
# Initialize the NTFS class with an already open file handler
1314
#
15+
data_attribute = 128
1416
def initialize(file_handler)
1517
@file_handler = file_handler
1618
data = @file_handler.read(4096)
1719
# Boot sector reading
18-
@bytes_per_sector = data[11, 2].unpack("S")[0]
20+
@bytes_per_sector = data[11, 2].unpack("v")[0]
1921
@sector_per_cluster = data[13].unpack("C")[0]
2022
@cluster_per_mft_record = data[64].unpack("c")[0]
2123
if @cluster_per_mft_record < 0
@@ -25,7 +27,7 @@ def initialize(file_handler)
2527
@bytes_per_mft_record = @bytes_per_sector * @sector_per_cluster * @cluster_per_mft_record
2628
end
2729
@bytes_per_cluster = @sector_per_cluster * @bytes_per_sector
28-
@mft_logical_cluster_number = data[48, 8].unpack("Q")[0]
30+
@mft_logical_cluster_number = data[48, 8].unpack("Q<")[0]
2931
@mft_offset = @mft_logical_cluster_number * @sector_per_cluster * @bytes_per_sector
3032
@file_handler.seek(@mft_offset)
3133
@mft = @file_handler.read(@bytes_per_mft_record)
@@ -35,15 +37,15 @@ def initialize(file_handler)
3537
# Gather the MFT entry corresponding to his number
3638
#
3739
def mft_record_from_mft_num(mft_num)
38-
cluster_from_attribute_non_resident(mft_record_attribute(@mft)[128]["data"], mft_num * @cluster_per_mft_record, @bytes_per_mft_record)
40+
cluster_from_attribute_non_resident(mft_record_attribute(@mft)[data_attribute]["data"], mft_num * @cluster_per_mft_record, @bytes_per_mft_record)
3941
end
4042

4143
#
4244
# Get the size of the file in the $FILENAME (64) attribute
4345
#
4446
def real_size_from_filenameattribute(attribute)
4547
filename_attribute = attribute
46-
filename_attribute[48, 8].unpack("Q")[0]
48+
filename_attribute[48, 8].unpack("Q<")[0]
4749
end
4850

4951
#
@@ -66,10 +68,10 @@ def filename_from_filenameattribute(attribute)
6668
def file_content_from_mft_num(mft_num, size)
6769
mft_record = mft_record_from_mft_num(mft_num)
6870
attribute_list = mft_record_attribute(mft_record)
69-
if attribute_list[128]["resident"]
70-
return attribute_list[128]["data"]
71+
if attribute_list[data_attribute]["resident"]
72+
return attribute_list[data_attribute]["data"]
7173
else
72-
return cluster_from_attribute_non_resident(attribute_list[128]["data"])[0, size]
74+
return cluster_from_attribute_non_resident(attribute_list[data_attribute]["data"])[0, size]
7375
end
7476
end
7577

@@ -78,12 +80,12 @@ def file_content_from_mft_num(mft_num, size)
7880
#
7981
def parse_index(index_entry)
8082
res = {}
81-
filename_size = index_entry[10, 2].unpack("S")[0]
83+
filename_size = index_entry[10, 2].unpack("v")[0]
8284
filename_attribute = index_entry[16, filename_size]
8385
# Should be 8 bytes but it doesn't work
84-
# mft_offset = index_entry[0.unpack("Q",:8])[0]
86+
# mft_offset = index_entry[0.unpack("Q<",:8])[0]
8587
# work with 4 bytes
86-
mft_offset = index_entry[0, 4].unpack("<I")[0]
88+
mft_offset = index_entry[0, 4].unpack("V")[0]
8789
res[filename_from_filenameattribute(filename_attribute)] = { "mft_offset" => mft_offset, "file_size" => real_size_from_filenameattribute(filename_attribute) }
8890
res
8991
end
@@ -93,27 +95,27 @@ def parse_index(index_entry)
9395
# INDEX_ALLOCATION
9496
#
9597
def parse_index_list(index_record, index_allocation_attribute)
96-
offset_index_entry_list = index_record[0, 4].unpack("<I")[0]
97-
index_size = index_record[offset_index_entry_list + 8, 2].unpack("S")[0]
98+
offset_index_entry_list = index_record[0, 4].unpack("V")[0]
99+
index_size = index_record[offset_index_entry_list + 8, 2].unpack("v")[0]
98100
index_entry = index_record[offset_index_entry_list, index_size]
99101
res = {}
100-
while index_entry[12, 4].unpack("<I")[0] & 2 != 2
102+
while index_entry[12, 4].unpack("V")[0] & 2 != 2
101103
res.update(parse_index(index_entry))
102104
# if son
103-
if index_entry[12, 4].unpack("<I")[0] & 1 == 1
105+
if index_entry[12, 4].unpack("V")[0] & 1 == 1
104106
# should be 8 bytes length
105-
vcn = index_entry[-8, 4].unpack("I")[0]
107+
vcn = index_entry[-8, 4].unpack("V")[0]
106108
res_son = parse_index_list(index_allocation_attribute[vcn * @bytes_per_cluster + 24, index_size * @bytes_per_cluster], index_allocation_attribute)
107109
res.update(res_son)
108110
end
109111
offset_index_entry_list += index_size
110-
index_size = index_record[offset_index_entry_list + 8, 2].unpack("S")[0]
112+
index_size = index_record[offset_index_entry_list + 8, 2].unpack("v")[0]
111113
index_entry = index_record [offset_index_entry_list, index_size]
112114
end
113115
# if son on the last
114-
if index_entry[12, 4].unpack("<I")[0] & 1 == 1
116+
if index_entry[12, 4].unpack("V")[0] & 1 == 1
115117
# should be 8 bytes length
116-
vcn = index_entry[-8, 4].unpack("I")[0]
118+
vcn = index_entry[-8, 4].unpack("V")[0]
117119
res_son = parse_index_list(index_allocation_attribute[vcn * @bytes_per_cluster + 24, index_size * @bytes_per_cluster], index_allocation_attribute)
118120
res.update(res_son)
119121
end
@@ -134,10 +136,10 @@ def index_list_from_attributes(attributes)
134136
end
135137

136138
def cluster_from_attribute_non_resident(attribute, cluster_num = 0, size_max = ((2**31) - 1))
137-
lowvcn = attribute[16, 8].unpack("<Q")[0]
138-
highvcn = attribute[24, 8].unpack("<Q")[0]
139-
offset = attribute[32, 2].unpack("<S")[0]
140-
real_size = attribute[48, 8].unpack("<Q")[0]
139+
lowvcn = attribute[16, 8].unpack("Q<")[0]
140+
highvcn = attribute[24, 8].unpack("Q<")[0]
141+
offset = attribute[32, 2].unpack("v")[0]
142+
real_size = attribute[48, 8].unpack("Q<")[0]
141143
attribut = ""
142144
run_list_num = lowvcn
143145
old_offset = 0
@@ -148,16 +150,16 @@ def cluster_from_attribute_non_resident(attribute, cluster_num = 0, size_max = (
148150
run_length_size = first_runlist_byte & 15
149151
run_length = attribute[offset + 1, run_length_size]
150152
run_length += "\x00" * (8 - run_length_size)
151-
run_length = run_length.unpack("<Q")[0]
153+
run_length = run_length.unpack("Q<")[0]
152154

153155
offset_run_offset = offset + 1 + run_length_size
154156
run_offset = attribute[offset_run_offset, run_offset_size]
155157
if run_offset[-1].ord & 128 == 128
156-
run_offset += "\xFF".force_encoding("BINARY") * (8 - run_offset_size)
158+
run_offset += "\xFF" * (8 - run_offset_size)
157159
else
158160
run_offset += "\x00" * (8 - run_offset_size)
159161
end
160-
run_offset = run_offset.unpack("<q")[0]
162+
run_offset = run_offset.unpack("q<")[0]
161163

162164
size_wanted = [run_length * @bytes_per_cluster, size_max - attribut.length].min
163165

@@ -187,31 +189,31 @@ def cluster_from_attribute_non_resident(attribute, cluster_num = 0, size_max = (
187189
def mft_record_attribute(mft_record)
188190
attribute_list_offset = mft_record[20, 2].unpack("C")[0]
189191
curs = attribute_list_offset
190-
attribute_identifier = mft_record[curs, 4].unpack("I")[0]
192+
attribute_identifier = mft_record[curs, 4].unpack("V")[0]
191193
res = {}
192194
while attribute_identifier != 0xFFFFFFFF
193-
# attribute_size=mft_record[curs + 4, 4].unpack("I")[0]
195+
# attribute_size=mft_record[curs + 4, 4].unpack("V")[0]
194196
# should be on 4 bytes but doesnt work
195-
attribute_size = mft_record[curs + 4, 2].unpack("S")[0]
197+
attribute_size = mft_record[curs + 4, 2].unpack("v")[0]
196198
#print_debug("attribute_size: #{attribute_size}, attribute_identifier: #{attribute_identifier}")
197199
# resident
198200
if mft_record[curs + 8] == "\x00"
199-
content_size = mft_record[curs + 16, 4].unpack("<I")[0]
200-
content_offset = mft_record[curs + 20, 2].unpack("S")[0]
201+
content_size = mft_record[curs + 16, 4].unpack("V")[0]
202+
content_offset = mft_record[curs + 20, 2].unpack("v")[0]
201203
res[attribute_identifier] = mft_record[curs + content_offset, content_size]
202204
else
203205
# non resident
204-
if attribute_identifier == 128
206+
if attribute_identifier == data_attribute
205207
res[attribute_identifier] = mft_record[curs, attribute_size]
206208
else
207209
res[attribute_identifier] = cluster_from_attribute_non_resident(mft_record[curs, attribute_size])
208210
end
209211
end
210-
if attribute_identifier == 128
212+
if attribute_identifier == data_attribute
211213
res[attribute_identifier] = { "data" => res[attribute_identifier], "resident" => mft_record[curs + 8] == "\x00" }
212214
end
213215
curs += attribute_size
214-
attribute_identifier = mft_record[curs, 4].unpack("I")[0]
216+
attribute_identifier = mft_record[curs, 4].unpack("V")[0]
215217
end
216218
res
217219
end

0 commit comments

Comments
 (0)