-
Notifications
You must be signed in to change notification settings - Fork 81
/
Copy pathsquashfs.py
235 lines (197 loc) · 7.17 KB
/
squashfs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
from typing import Optional
from structlog import get_logger
from unblob.extractors import Command
from ...file_utils import get_endian, round_up
from ...models import File, HexString, StructHandler, ValidChunk
logger = get_logger()
PAD_SIZES = [4_096, 1_024]
class _SquashFSBase(StructHandler):
BIG_ENDIAN_MAGIC = 0x73_71_73_68
EXTRACTOR = Command(
"sasquatch", "-no-exit-code", "-f", "-d", "{outdir}", "{inpath}"
)
def calculate_chunk(self, file: File, start_offset: int) -> Optional[ValidChunk]:
file.seek(start_offset)
endian = get_endian(file, self.BIG_ENDIAN_MAGIC)
header = self.parse_header(file, endian)
end_of_data_offset = start_offset + header.bytes_used
file.seek(end_of_data_offset)
padding = file.read(
round_up(header.bytes_used, max(PAD_SIZES)) - header.bytes_used
)
for pad_size in sorted(PAD_SIZES, reverse=True):
size = round_up(header.bytes_used, pad_size)
padding_length = size - header.bytes_used
if padding.startswith(b"\00" * padding_length):
end_offset = start_offset + size
return ValidChunk(start_offset=start_offset, end_offset=end_offset)
return ValidChunk(
start_offset=start_offset, end_offset=start_offset + header.bytes_used
)
class SquashFSv3Handler(_SquashFSBase):
NAME = "squashfs_v3"
PATTERNS = [
HexString(
"""
// 00000000 73 71 73 68 00 00 00 03 00 00 00 00 00 00 00 00 |sqsh............|
// 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 |................|
// squashfs_v3_magic_be
73 71 73 68 [24] 00 03
"""
),
HexString(
"""
// 00000000 68 73 71 73 03 00 00 00 00 00 00 00 00 00 00 00 |hsqs............|
// 00000010 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 |................|
// squashfs_v3_magic_le
68 73 71 73 [24] 03 00
"""
),
]
C_DEFINITIONS = r"""
typedef struct squashfs3_super_block
{
char s_magic[4];
uint32 inodes;
uint32 bytes_used_2;
uint32 uid_start_2;
uint32 guid_start_2;
uint32 inode_table_start_2;
uint32 directory_table_start_2;
uint16 s_major;
uint16 s_minor;
uint16 block_size_1;
uint16 block_log;
uint8 flags;
uint8 no_uids;
uint8 no_guids;
uint32 mkfs_time /* time of filesystem creation */;
uint64 root_inode;
uint32 block_size;
uint32 fragments;
uint32 fragment_table_start_2;
uint64 bytes_used;
uint64 uid_start;
uint64 guid_start;
uint64 inode_table_start;
uint64 directory_table_start;
uint64 fragment_table_start;
uint64 lookup_table_start;
} squashfs3_super_block_t;
"""
HEADER_STRUCT = "squashfs3_super_block_t"
class SquashFSv3DDWRTHandler(SquashFSv3Handler):
NAME = "squashfs_v3_ddwrt"
BIG_ENDIAN_MAGIC = 0x74_71_73_68
PATTERNS = [
HexString(
"""
// 00000000 68 73 71 74 21 02 00 00 00 00 00 00 00 00 00 00 |hsqt!...........|
// 00000010 00 00 00 00 00 00 00 00 50 02 00 00 03 00 00 00 |........P.......|
// squashfs_v3_magic_ddwrt_le
68 73 71 74 [24] 03 00
"""
),
HexString(
"""
// 00000000 74 71 73 68 21 02 00 00 00 00 00 00 00 00 00 00 |tqsh!...........|
// 00000010 00 00 00 00 00 00 00 00 50 02 00 03 00 00 00 00 |........P.......|
// squashfs_v3_magic_ddwrt_be
68 73 71 74 [24] 00 03
"""
),
]
class SquashFSv3BroadcomHandler(SquashFSv3Handler):
NAME = "squashfs_v3_broadcom"
BIG_ENDIAN_MAGIC = 0x71_73_68_73
PATTERNS = [
HexString(
"""
// 00000000 73 68 73 71 0f 05 00 00 c8 a9 00 01 00 00 00 bc |shsq............|
// 00000010 1f 2d 00 a2 d0 2b 00 bf 79 2e 00 65 03 00 00 00 |.-...+..y..e....|
// squashfs_v3_magic_broadcom_le
73 68 73 71 [24] 03 00
"""
),
HexString(
"""
// 00000000 71 73 68 73 0f 05 00 00 c8 a9 00 01 00 00 00 bc |qshs............|
// 00000010 1f 2d 00 a2 d0 2b 00 bf 79 2e 00 65 00 03 00 00 |.-...+..y..e....|
// squashfs_v3_magic_broadcom_be
71 73 68 73 [24] 00 03
"""
),
]
class SquashFSv3NSHandler(SquashFSv3Handler):
NAME = "squashfs_v3_nonstandard"
BIG_ENDIAN_MAGIC = 0x73_71_6C_7A
PATTERNS = [
HexString(
"""
// 00000000 7a 6c 71 73 00 00 04 df 57 00 17 95 46 00 19 ed |zlqs....W...F...|
// 00000010 20 08 04 8e 02 40 01 06 c9 02 16 00 00 03 00 01 | ....@..........|
// squashfs_v3_magic_nonstandard_le
7A 6c 71 73 [24] 03 00
"""
),
HexString(
"""
// 00000000 73 71 6c 7a 00 00 04 df 57 00 17 95 46 00 19 ed |sqlz....W...F...|
// 00000010 20 08 04 8e 02 40 01 06 c9 02 16 00 00 03 00 01 | ....@..........|
// squashfs_v3_magic_nonstandard_be
73 71 6c 7A [24] 00 03
"""
),
]
class SquashFSv4LEHandler(_SquashFSBase):
NAME = "squashfs_v4_le"
PATTERNS = [
HexString(
"""
// 00000000 68 73 71 73 03 00 00 00 00 c1 9c 61 00 00 02 00 |hsqs.......a....|
// 00000010 01 00 00 00 01 00 11 00 c0 00 01 00 04 00 00 00 |................|
// squashfs_v4_magic_le
68 73 71 73 [24] 04 00
"""
),
]
C_DEFINITIONS = r"""
typedef struct squashfs4_super_block
{
char s_magic[4];
uint32 inodes;
uint32 mkfs_time /* time of filesystem creation */;
uint32 block_size;
uint32 fragments;
uint16 compression;
uint16 block_log;
uint16 flags;
uint16 no_ids;
uint16 s_major;
uint16 s_minor;
uint64 root_inode;
uint64 bytes_used;
uint64 id_table_start;
uint64 xattr_id_table_start;
uint64 inode_table_start;
uint64 directory_table_start;
uint64 fragment_table_start;
uint64 lookup_table_start;
} squashfs4_super_block_t;
"""
HEADER_STRUCT = "squashfs4_super_block_t"
class SquashFSv4BEHandler(SquashFSv4LEHandler):
NAME = "squashfs_v4_be"
PATTERNS = [
HexString(
"""
// 00000000 73 71 73 68 03 00 00 00 00 c1 9c 61 00 00 02 00 |sqsh.......a....|
// 00000010 01 00 00 00 01 00 11 00 c0 00 01 00 04 00 00 00 |................|
// squashfs_v4_magic_be
73 71 73 68 [24] 00 04
"""
)
]
EXTRACTOR = Command(
"sasquatch-v4be", "-be", "-no-exit-code", "-f", "-d", "{outdir}", "{inpath}"
)