17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# File 'lib/fileshunter/Decoders/CAB.rb', line 17
def decode(offset)
cabinet_size = BinData::Uint32le.read(@data[offset+8..offset+11])
invalid_data("@#{offset} - Invalid CAB header.") if (BinData::Uint32le.read(@data[offset+12..offset+15]) != 0)
invalid_data("@#{offset} - Invalid CAB header.") if (BinData::Uint32le.read(@data[offset+20..offset+23]) != 0)
minor_version = @data[offset+24].ord
major_version = @data[offset+25].ord
nbr_cf_folders = BinData::Uint16le.read(@data[offset+26..offset+27])
nbr_cf_files = BinData::Uint16le.read(@data[offset+28..offset+29])
flags = BinData::Uint16le.read(@data[offset+30..offset+31])
flag_prev_cabinet = ((flags & 0b00000000_00000001) != 0)
flag_next_cabinet = ((flags & 0b00000000_00000010) != 0)
flag_reserve_present = ((flags & 0b00000000_00000100) != 0)
set_id = BinData::Uint16le.read(@data[offset+32..offset+33])
idx_cabinet = BinData::Uint16le.read(@data[offset+34..offset+35])
cursor = offset + 36
reserve_field_size_in_folder = 0
reserve_field_size_in_data = 0
if flag_reserve_present
= BinData::Uint16le.read(@data[offset+36..offset+37])
invalid_data("@#{offset} - Invalid reserve_field_size_in_header (#{})") if ( > 60000)
reserve_field_size_in_folder = @data[offset+38].ord
reserve_field_size_in_data = @data[offset+39].ord
cursor += 4 +
end
if flag_prev_cabinet
idx_terminator = @data.index(END_STRING_TERMINATOR, cursor)
invalid_data("@#{cursor} - Unable to read previous cabinet name") if (idx_terminator == nil)
cursor = idx_terminator + 1
idx_terminator = @data.index(END_STRING_TERMINATOR, cursor)
invalid_data("@#{cursor} - Unable to read previous disk name") if (idx_terminator == nil)
cursor = idx_terminator + 1
end
if flag_next_cabinet
idx_terminator = @data.index(END_STRING_TERMINATOR, cursor)
invalid_data("@#{cursor} - Unable to read next cabinet name") if (idx_terminator == nil)
cursor = idx_terminator + 1
idx_terminator = @data.index(END_STRING_TERMINATOR, cursor)
invalid_data("@#{cursor} - Unable to read next disk name") if (idx_terminator == nil)
cursor = idx_terminator + 1
end
progress(cursor)
found_relevant_data([:cab, :msu, :mzz])
metadata(
:cabinet_size => cabinet_size,
:minor_version => minor_version,
:major_version => major_version,
:nbr_cf_folders => nbr_cf_folders,
:nbr_cf_files => nbr_cf_files,
:set_id => set_id,
:idx_cabinet => idx_cabinet,
:flag_prev_cabinet => flag_prev_cabinet,
:flag_next_cabinet => flag_next_cabinet,
:flag_reserve_present => flag_reserve_present
)
data_blocks = []
log_debug "@#{cursor} - Beginning of #{nbr_cf_folders} CFFOLDER structures"
nbr_cf_folders.times do |idx_cf_folder|
first_data_offset = BinData::Uint32le.read(@data[cursor..cursor+3])
nbr_data_blocks = BinData::Uint16le.read(@data[cursor+4..cursor+5])
data_blocks << [ first_data_offset, nbr_data_blocks ]
cursor += 8 + reserve_field_size_in_folder
progress(cursor)
end
log_debug "@#{cursor} - Beginning of #{nbr_cf_files} CFFILE structures"
nbr_cf_files.times do |idx_cf_file|
cursor += 16
idx_terminator = @data.index(END_STRING_TERMINATOR, cursor)
invalid_data("@#{cursor} - Unable to read file name") if (idx_terminator == nil)
cursor = idx_terminator + 1
progress(cursor)
end
log_debug "@#{cursor} - Beginning of CFDATA"
while (!data_blocks.empty?)
first_datablock_offset, nbr_datablocks = data_blocks.shift
invalid_data("@#{cursor} - We should be on the next data block offset (#{offset+first_datablock_offset})") if (cursor-offset != first_datablock_offset)
nbr_datablocks.times do |idx_datablock|
nbr_compressed_bytes = BinData::Uint16le.read(@data[cursor+4..cursor+5])
cursor += 8 + reserve_field_size_in_data + nbr_compressed_bytes
progress(cursor)
end
end
invalid_data("@#{cursor} - We should be on at the end of the CAB file (#{offset+cabinet_size})") if (cursor-offset != cabinet_size)
if ((cursor+4 < @end_offset) and
(@data[cursor..cursor+1] == AUTHENTICODE_ID))
authenticode_size = BinData::Uint16be.read(@data[cursor+2..cursor+3])
log_debug "@#{cursor} - Found authenticode data of size #{authenticode_size}"
cursor += 4 + authenticode_size
while ((cursor < @end_offset) and
(@data[cursor] == "\x00"))
cursor += 1
end
end
return cursor
end
|