/src/wireshark/epan/dissectors/file-zip.c
Line | Count | Source |
1 | | /* file-zip.c |
2 | | * |
3 | | * Routines for ZIP File dissection |
4 | | * Copyright 2026, John Thacker <johnthacker@gmail.com>. |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT |
11 | | * https://libzip.org/specifications/ |
12 | | * |
13 | | * Most ZIP tools scan from the end of the file to find the central directory |
14 | | * listing, and indeed the specification only truly makes sense considering |
15 | | * this possibility. It also makes sense in the context of spanning archives |
16 | | * across multiple removable floppy disks or splitting them into files (where |
17 | | * the last disk would be the one inserted first for dearchiving, or the last |
18 | | * file would have the .zip extension), adding or removing files to an archive |
19 | | * without rewriting everything (which leaves gaps; cf. tar, where gaps are |
20 | | * not allowed and deletion is more work), etc. |
21 | | * |
22 | | * This streams from the beginning (see Mark Adler's sunzip for the approach), |
23 | | * which probably will fail on some files that other tools will handle, |
24 | | * although it has the advantage of inherently not falling prey to zip bombs |
25 | | * that use overlapping files: |
26 | | * https://www.usenix.org/system/files/woot19-paper_fifield_0.pdf |
27 | | * https://github.com/madler/sunzip |
28 | | * |
29 | | * ISO/IEC 21320-1:2015 specifies a restricted subset of ZIP files, with |
30 | | * annotations specifically disallowing the spanning/splitting, encryption, |
31 | | * digital signatures, and patched data features, allowing only compression |
32 | | * methods 0 ("stored") and 8 ("deflated"), and recommending setting the |
33 | | * UTF-8 bit. |
34 | | * |
35 | | * SPDX-License-Identifier: GPL-2.0-or-later |
36 | | */ |
37 | | |
38 | | #include "config.h" |
39 | | #include <epan/packet.h> |
40 | | #include <epan/expert.h> |
41 | | #include <epan/crc32-tvb.h> |
42 | | #include <epan/export_object.h> |
43 | | #include <epan/tfs.h> |
44 | | #include <epan/unit_strings.h> |
45 | | #include <wsutil/array.h> |
46 | | |
47 | | #include "packet-smb.h" |
48 | | |
49 | | void proto_reg_handoff_zip(void); |
50 | | void proto_register_zip(void); |
51 | | |
52 | | static int proto_zip; |
53 | | |
54 | | static dissector_handle_t zip_handle; |
55 | | |
56 | | static dissector_table_t zip_record_dissector_table; |
57 | | static dissector_table_t zip_extra_dissector_table; |
58 | | |
59 | | static int zip_eo_tap; |
60 | | |
61 | | // Header fields |
62 | | static int hf_zip_file; |
63 | | static int hf_zip_directory; |
64 | | static int hf_zip_end_of_directory; |
65 | | static int hf_zip64_end_of_directory; |
66 | | static int hf_zip64_end_of_directory_locator; |
67 | | static int hf_zip_record_signature; |
68 | | static int hf_zip_made_by; |
69 | | static int hf_zip_version_made_by; |
70 | | static int hf_zip_host_made_by; |
71 | | static int hf_zip_version_to_extract; |
72 | | |
73 | | static int hf_zip_flags; |
74 | | static int hf_zip_flag_encryption; |
75 | | static int hf_zip_flag_deflate_opts; |
76 | | static int hf_zip_flag_lzma_eos; |
77 | | static int hf_zip_flag_data_descriptor; |
78 | | static int hf_zip_flag_patched_data; |
79 | | static int hf_zip_flag_strong_encryption; |
80 | | static int hf_zip_flag_language_encoding; |
81 | | static int hf_zip_flag_central_dir_encryption; |
82 | | |
83 | | static int hf_zip_compression_method; |
84 | | static int hf_zip_last_mod_file_date_time; |
85 | | static int hf_zip_last_mod_file_time; |
86 | | static int hf_zip_last_mod_file_date; |
87 | | static int hf_zip_crc32; |
88 | | static int hf_zip_crc32_status; |
89 | | static int hf_zip_file_compressed_size; |
90 | | static int hf_zip_file_uncompressed_size; |
91 | | static int hf_zip_file_name_length; |
92 | | static int hf_zip_extra_fields_length; |
93 | | static int hf_zip_file_name; |
94 | | |
95 | | static int hf_zip_extra_fields; |
96 | | static int hf_zip_extra_field; |
97 | | static int hf_zip_extra_id; |
98 | | static int hf_zip_extra_data_size; |
99 | | static int hf_zip_extra_data; |
100 | | static int hf_zip_extra_version; |
101 | | |
102 | | static int hf_zip_extra_ntfs_tag; |
103 | | |
104 | | static int hf_zip_extra_ut_flags; |
105 | | static int hf_zip_extra_ut_flag_mtime; |
106 | | static int hf_zip_extra_ut_flag_atime; |
107 | | static int hf_zip_extra_ut_flag_ctime; |
108 | | static int hf_zip_extra_ut_mtime; |
109 | | static int hf_zip_extra_ut_atime; |
110 | | static int hf_zip_extra_ut_ctime; |
111 | | |
112 | | static int hf_zip_extra_unix_uid_size; |
113 | | static int hf_zip_extra_unix_uid; |
114 | | static int hf_zip_extra_unix_gid_size; |
115 | | static int hf_zip_extra_unix_gid; |
116 | | |
117 | | static int hf_zip_encryption_header; |
118 | | static int hf_zip_encrypted_file_data; |
119 | | static int hf_zip_compressed_file_data; |
120 | | static int hf_zip_file_data; |
121 | | |
122 | | static int hf_zip_file_comment_length; |
123 | | static int hf_zip_disk_start_number; |
124 | | static int hf_zip_internal_file_attr; |
125 | | static int hf_zip_external_file_attr; |
126 | | static int hf_zip_local_header_offset; |
127 | | static int hf_zip_file_comment; |
128 | | |
129 | | static int hf_zip_disk_number; |
130 | | static int hf_zip_directory_disk_start_number; |
131 | | static int hf_zip_directory_entries_disk; |
132 | | static int hf_zip_directory_entries; |
133 | | static int hf_zip_directory_size; |
134 | | static int hf_zip_directory_offset; |
135 | | static int hf_zip_directory_end_size; |
136 | | static int hf_zip_archive_comment; |
137 | | static int hf_zip_extensible_data_sector; |
138 | | static int hf_zip_zip64_directory_end_disk_start_number; |
139 | | static int hf_zip_zip64_directory_end_offset; |
140 | | static int hf_zip_total_disks; |
141 | | |
142 | | static int ett_zip; |
143 | | static int ett_zip_record; |
144 | | static int ett_zip_made_by; |
145 | | static int ett_zip_flags; |
146 | | static int ett_zip_extras; |
147 | | static int ett_zip_extra; |
148 | | static int ett_zip_extra_ut_flags; |
149 | | |
150 | | static expert_field ei_zip_crc32; |
151 | | static expert_field ei_zip_overflow; |
152 | | static expert_field ei_zip_underflow; |
153 | | static expert_field ei_zip_unsupported; |
154 | | |
155 | | // "PK" for Phil Katz; Big Endian for tvb_find_uint16_remaining |
156 | 0 | #define ZIP_MAGIC_UINT 0x504b |
157 | | |
158 | | /* Officially, the header signatures are Little-Endian like everything |
159 | | * in the format, though they make more sense to read Big-Endian. */ |
160 | 16 | #define ZIP_DIRECTORY_RECORD 0x02014b50 |
161 | 16 | #define ZIP_FILE_RECORD 0x04034b50 |
162 | | #define ZIP_DIGITAL_SIGNATURE_RECORD 0x05054b50 |
163 | 16 | #define ZIP_END_OF_DIRECTORY_RECORD 0x06054b50 |
164 | 16 | #define ZIP64_END_OF_DIRECTORY_RECORD 0x06064b50 |
165 | 16 | #define ZIP64_END_OF_DIRECTORY_LOCATOR_RECORD 0x07064b50 |
166 | | #define ZIP_DATA_DESCRIPTOR_RECORD 0x08074b50 |
167 | | |
168 | | static const value_string zip_record_vals[] = { |
169 | | { ZIP_DIRECTORY_RECORD, "Central Directory"}, |
170 | | { ZIP_FILE_RECORD, "File"}, |
171 | | { ZIP_DIGITAL_SIGNATURE_RECORD, "Digital Signature"}, |
172 | | { ZIP_END_OF_DIRECTORY_RECORD, "End of Central Directory"}, |
173 | | { ZIP64_END_OF_DIRECTORY_RECORD, "Zip64 End of Central Directory"}, |
174 | | { ZIP64_END_OF_DIRECTORY_LOCATOR_RECORD, "Zip64 End of Central Directory Locator"}, |
175 | | { ZIP_DATA_DESCRIPTOR_RECORD, "Data Descriptor"}, |
176 | | { 0, NULL} |
177 | | }; |
178 | | |
179 | 16 | #define ZIP_FLAG_ENCRYPTION 0x0001 |
180 | 16 | #define ZIP_FLAG_LZMA_OPTS 0x0002 |
181 | 16 | #define ZIP_FLAG_DEFLATE_OPTS 0x0006 |
182 | 16 | #define ZIP_FLAG_DATA_DESCRIPTOR 0x0008 |
183 | 16 | #define ZIP_FLAG_PATCHED_DATA 0x0020 |
184 | 16 | #define ZIP_FLAG_STRONG_ENCRYPTION 0x0040 |
185 | 16 | #define ZIP_FLAG_LANGUAGE_ENCODING 0x0800 |
186 | 16 | #define ZIP_FLAG_CENTRAL_DIR_CRYPT 0x2000 |
187 | | |
188 | | static const value_string zip_host_vals[] = { |
189 | | { 0, "MS-DOS and OS/2 (FAT/VFAT/FAT32)" }, |
190 | | { 1, "Amiga" }, |
191 | | { 2, "OpenVMS" }, |
192 | | { 3, "UNIX" }, |
193 | | { 4, "VM/CMS" }, |
194 | | { 5, "Atari ST" }, |
195 | | { 6, "OS/2 HPFS" }, |
196 | | { 7, "Macintosh" }, |
197 | | { 8, "Z-System" }, |
198 | | { 9, "CP/M" }, |
199 | | {10, "Windows NTFS" }, |
200 | | {11, "MVS (OS/390 - Z/OS)" }, |
201 | | {12, "VSE" }, |
202 | | {13, "Acorn Risc" }, |
203 | | {14, "VFAT" }, |
204 | | {15, "Alternate MVS" }, |
205 | | {16, "BeOS" }, |
206 | | {17, "Tandem" }, |
207 | | {18, "OS/400" }, |
208 | | {19, "OS X (Darwin)" }, |
209 | | { 0, NULL } |
210 | | }; |
211 | | |
212 | | static const value_string zip_deflate_opts_vals[] = { |
213 | | { 0, "Normal (-en)"} , |
214 | | { 1, "Maximum (-exx/-ex)"} , |
215 | | { 2, "Fast (-ef)"} , |
216 | | { 3, "Super Fast (-es)"} , |
217 | | { 0, NULL} |
218 | | }; |
219 | | |
220 | | static const value_string zip_method_vals[] = { |
221 | | { 0, "Store (no compression)" }, |
222 | | { 1, "Shrink" }, |
223 | | { 2, "Reduce (compression factor 1}" }, |
224 | | { 3, "Reduce (compression factor 2}" }, |
225 | | { 4, "Reduce (compression factor 3}" }, |
226 | | { 5, "Reduce (compression factor 4}" }, |
227 | | { 6, "Implode" }, |
228 | | { 7, "Tokenize (reserved)" }, |
229 | | { 8, "Deflate" }, |
230 | | { 9, "Enhanced Deflating using Deflate64(tm)" }, |
231 | | {10, "PKWARE Data Compression Library Imploding (old IBM TERSE)" }, |
232 | | {11, "Reserved by PKWARE" }, |
233 | | {12, "BZIP2" }, |
234 | | {13, "Reserved by PKWARE" }, |
235 | | {14, "LZMA" }, |
236 | | {15, "Reserved by PKWARE" }, |
237 | | {16, "IBM z/OS CMPSC" }, |
238 | | {17, "Reserved by PKWARE" }, |
239 | | {18, "IBM TERSE (new)" }, |
240 | | {19, "IBM LZ77 z Architecture" }, |
241 | | {20, "Deprecated (use 93 for zstd)" }, |
242 | | {93, "Zstandard (zstd)" }, |
243 | | {94, "MP3" }, |
244 | | {95, "XZ" }, |
245 | | {96, "JPEG variant" }, |
246 | | {97, "WavPack" }, |
247 | | {98, "PPMd version I, Rev 1" }, |
248 | | {99, "AE-x encryption marker" }, |
249 | | { 0, NULL } |
250 | | }; |
251 | | |
252 | 16 | #define ZIP_EXTRA_ZIP64 0x0001 |
253 | 16 | #define ZIP_EXTRA_NTFS 0x000a |
254 | 32 | #define ZIP_EXTRA_UT 0x5455 |
255 | 16 | #define ZIP_EXTRA_UCOM 0x6375 |
256 | 16 | #define ZIP_EXTRA_UPATH 0x7075 |
257 | 16 | #define ZIP_EXTRA_UNIX2 0x7855 |
258 | 16 | #define ZIP_EXTRA_UNIX3 0x7875 |
259 | | |
260 | | static const value_string zip_extra_id_vals[] = { |
261 | | { ZIP_EXTRA_ZIP64, "Zip64"}, |
262 | | { ZIP_EXTRA_NTFS, "NTFS"}, |
263 | | { ZIP_EXTRA_UT, "Unix Time"}, |
264 | | { ZIP_EXTRA_UCOM, "UTF-8 Comment"}, |
265 | | { ZIP_EXTRA_UPATH, "UTF-8 Path"}, |
266 | | { ZIP_EXTRA_UNIX2, "Unix (type 2)"}, |
267 | | { ZIP_EXTRA_UNIX3, "Unix (type 3)"}, |
268 | | { 0, NULL } |
269 | | }; |
270 | | |
271 | 0 | #define ZIP_EXTRA_NTFS_FILETIMES 0x0001 |
272 | | |
273 | | static const value_string zip_extra_ntfs_tag_vals[] = { |
274 | | { ZIP_EXTRA_NTFS_FILETIMES, "File Times" }, |
275 | | { 0, NULL }, |
276 | | }; |
277 | | |
278 | | static void |
279 | | decode_zip_version(char *s, uint16_t value) |
280 | 0 | { |
281 | 0 | snprintf(s, ITEM_LABEL_LENGTH, "%u.%u", value / 10, value % 10); |
282 | 0 | } |
283 | | |
284 | | static int* const * |
285 | 0 | zip_get_flags_fields(uint16_t method) { |
286 | 0 | static int* const generic_fields[] = { &hf_zip_flag_encryption, |
287 | 0 | &hf_zip_flag_data_descriptor, |
288 | 0 | &hf_zip_flag_patched_data, |
289 | 0 | &hf_zip_flag_strong_encryption, |
290 | 0 | &hf_zip_flag_language_encoding, |
291 | 0 | &hf_zip_flag_central_dir_encryption, |
292 | 0 | NULL }; |
293 | |
|
294 | 0 | static int* const deflate_fields[] = { &hf_zip_flag_encryption, |
295 | 0 | &hf_zip_flag_deflate_opts, |
296 | 0 | &hf_zip_flag_data_descriptor, |
297 | 0 | &hf_zip_flag_patched_data, |
298 | 0 | &hf_zip_flag_strong_encryption, |
299 | 0 | &hf_zip_flag_language_encoding, |
300 | 0 | &hf_zip_flag_central_dir_encryption, |
301 | 0 | NULL }; |
302 | |
|
303 | 0 | static int* const lzma_fields[] = { &hf_zip_flag_encryption, |
304 | 0 | &hf_zip_flag_lzma_eos, |
305 | 0 | &hf_zip_flag_data_descriptor, |
306 | 0 | &hf_zip_flag_patched_data, |
307 | 0 | &hf_zip_flag_strong_encryption, |
308 | 0 | &hf_zip_flag_language_encoding, |
309 | 0 | &hf_zip_flag_central_dir_encryption, |
310 | 0 | NULL }; |
311 | 0 | switch (method) { |
312 | 0 | case 8: |
313 | 0 | case 9: |
314 | 0 | return deflate_fields; |
315 | 0 | case 14: |
316 | 0 | return lzma_fields; |
317 | 0 | default: |
318 | 0 | return generic_fields; |
319 | 0 | } |
320 | 0 | } |
321 | | |
322 | | static int* const made_by_fields[] = { &hf_zip_version_made_by, |
323 | | &hf_zip_host_made_by, |
324 | | NULL }; |
325 | | |
326 | | typedef struct _zip_eo_t { |
327 | | const char *filename; |
328 | | tvbuff_t *payload; |
329 | | } zip_eo_t; |
330 | | |
331 | | static tap_packet_status |
332 | | zip_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data, tap_flags_t flags _U_) |
333 | 0 | { |
334 | 0 | export_object_list_t *object_list = (export_object_list_t *)tapdata; |
335 | 0 | const zip_eo_t *eo_info = (const zip_eo_t *)data; |
336 | 0 | export_object_entry_t *entry; |
337 | |
|
338 | 0 | if(eo_info) { /* We have data waiting for us */ |
339 | | /* These values will be freed when the Export Object window |
340 | | * is closed. */ |
341 | 0 | entry = g_new0(export_object_entry_t, 1); |
342 | |
|
343 | 0 | entry->pkt_num = pinfo->num; |
344 | | |
345 | | /* We could try to preserve the directory structure (the |
346 | | * E.O. code percent encodes various directory structures) |
347 | | * and expect the user to clean it up, rather than flattening |
348 | | * the directory structure. */ |
349 | 0 | entry->filename = eo_info->filename ? g_path_get_basename(eo_info->filename) : NULL; |
350 | 0 | entry->payload_len = tvb_captured_length(eo_info->payload); |
351 | 0 | entry->payload_data = (uint8_t *)tvb_memdup(NULL, eo_info->payload, 0, entry->payload_len); |
352 | |
|
353 | 0 | object_list->add_entry(object_list->gui_data, entry); |
354 | |
|
355 | 0 | return TAP_PACKET_REDRAW; /* State changed - window should be redrawn */ |
356 | 0 | } else { |
357 | 0 | return TAP_PACKET_DONT_REDRAW; /* State unchanged - no window updates needed */ |
358 | 0 | } |
359 | 0 | } |
360 | | |
361 | | typedef struct _zip_info_t { |
362 | | tvbuff_t *filename_tvb; |
363 | | tvbuff_t *comment_tvb; |
364 | | const uint8_t *filename; |
365 | | uint64_t uncompressed_size; |
366 | | uint64_t compressed_size; |
367 | | uint64_t local_header_offset; |
368 | | uint32_t disk_start_number; |
369 | | bool central_directory; |
370 | | } zip_info_t; |
371 | | |
372 | | static int |
373 | | dissect_zip_extra_zip64(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data) |
374 | 0 | { |
375 | 0 | zip_info_t *extra_info = (zip_info_t*)data; |
376 | |
|
377 | 0 | unsigned offset = 0; |
378 | 0 | if (extra_info->uncompressed_size == UINT32_MAX) { |
379 | 0 | proto_tree_add_item(tree, hf_zip_file_uncompressed_size, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
380 | 0 | offset += 8; |
381 | 0 | } |
382 | 0 | if (extra_info->compressed_size == UINT32_MAX) { |
383 | 0 | proto_tree_add_item_ret_uint64(tree, hf_zip_file_compressed_size, tvb, offset, 8, ENC_LITTLE_ENDIAN, &extra_info->compressed_size); |
384 | 0 | offset += 8; |
385 | 0 | } |
386 | 0 | if (extra_info->local_header_offset == UINT32_MAX) { |
387 | 0 | proto_tree_add_item(tree, hf_zip_local_header_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
388 | 0 | offset += 8; |
389 | 0 | } |
390 | 0 | if (extra_info->disk_start_number == UINT16_MAX) { |
391 | 0 | proto_tree_add_item(tree, hf_zip_disk_start_number, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
392 | 0 | offset += 4; |
393 | 0 | } |
394 | |
|
395 | 0 | return offset; |
396 | 0 | } |
397 | | |
398 | | static int |
399 | | dissect_zip_extra_ntfs(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) |
400 | 0 | { |
401 | 0 | unsigned offset = 0; |
402 | 0 | uint16_t tag, size; |
403 | |
|
404 | 0 | offset += 4; |
405 | 0 | while (tvb_reported_length_remaining(tvb, offset)) { |
406 | 0 | proto_tree_add_item_ret_uint16(tree, hf_zip_extra_ntfs_tag, tvb, offset, 2, ENC_LITTLE_ENDIAN, &tag); |
407 | 0 | offset += 2; |
408 | 0 | proto_tree_add_item_ret_uint16(tree, hf_zip_extra_data_size, tvb, offset, 2, ENC_LITTLE_ENDIAN, &size); |
409 | 0 | offset += 2; |
410 | 0 | if (tag == ZIP_EXTRA_NTFS_FILETIMES) { |
411 | 0 | proto_tree_add_item(tree, hf_zip_extra_ut_mtime, tvb, offset, 8, ENC_TIME_WINDOWS|ENC_LITTLE_ENDIAN); |
412 | 0 | proto_tree_add_item(tree, hf_zip_extra_ut_atime, tvb, offset + 8, 8, ENC_TIME_WINDOWS|ENC_LITTLE_ENDIAN); |
413 | 0 | proto_tree_add_item(tree, hf_zip_extra_ut_ctime, tvb, offset + 16, 8, ENC_TIME_WINDOWS|ENC_LITTLE_ENDIAN); |
414 | 0 | } |
415 | 0 | offset += size; |
416 | 0 | } |
417 | |
|
418 | 0 | return offset; |
419 | 0 | } |
420 | | |
421 | | static int |
422 | | dissect_zip_extra_utf8_comment(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data) |
423 | 0 | { |
424 | 0 | _U_ zip_info_t *extra_info = (zip_info_t*)data; |
425 | |
|
426 | 0 | unsigned offset = 0; |
427 | 0 | uint8_t version; |
428 | |
|
429 | 0 | proto_tree_add_item_ret_uint8(tree, hf_zip_extra_version, tvb, offset, 1, ENC_NA, &version); |
430 | 0 | offset += 1; |
431 | 0 | if (version != 1) { |
432 | 0 | return offset; |
433 | 0 | } |
434 | | |
435 | 0 | uint32_t computed_crc32 = crc32_ccitt_tvb(extra_info->comment_tvb, tvb_reported_length(extra_info->comment_tvb)); |
436 | 0 | proto_tree_add_checksum(tree, tvb, offset, hf_zip_crc32, hf_zip_crc32_status, &ei_zip_crc32, pinfo, computed_crc32, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY); |
437 | 0 | offset += 4; |
438 | 0 | proto_tree_add_item(tree, hf_zip_file_comment, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_UTF_8); |
439 | |
|
440 | 0 | return offset; |
441 | 0 | } |
442 | | |
443 | | static int |
444 | | dissect_zip_extra_utf8_path(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data) |
445 | 0 | { |
446 | 0 | zip_info_t *extra_info = (zip_info_t*)data; |
447 | |
|
448 | 0 | unsigned offset = 0; |
449 | 0 | uint32_t crc32; |
450 | 0 | uint8_t version; |
451 | |
|
452 | 0 | proto_tree_add_item_ret_uint8(tree, hf_zip_extra_version, tvb, offset, 1, ENC_NA, &version); |
453 | 0 | offset += 1; |
454 | 0 | if (version != 1) { |
455 | 0 | return offset; |
456 | 0 | } |
457 | | |
458 | 0 | uint32_t computed_crc32 = crc32_ccitt_tvb(extra_info->filename_tvb, tvb_reported_length(extra_info->filename_tvb)); |
459 | 0 | proto_tree_add_checksum(tree, tvb, offset, hf_zip_crc32, hf_zip_crc32_status, &ei_zip_crc32, pinfo, computed_crc32, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY); |
460 | 0 | crc32 = tvb_get_letohl(tvb, offset); |
461 | 0 | offset += 4; |
462 | 0 | if (crc32 != computed_crc32) { |
463 | 0 | proto_tree_add_item(tree, hf_zip_file_name, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_UTF_8); |
464 | 0 | } else { |
465 | 0 | proto_tree_add_item_ret_string(tree, hf_zip_file_name, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_UTF_8, pinfo->pool, &extra_info->filename); |
466 | 0 | } |
467 | |
|
468 | 0 | return offset; |
469 | 0 | } |
470 | | |
471 | | static int |
472 | | dissect_zip_extra_unix_time(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data) |
473 | 0 | { |
474 | 0 | static int* const ut_flags_fields[] = { &hf_zip_extra_ut_flag_mtime, |
475 | 0 | &hf_zip_extra_ut_flag_atime, |
476 | 0 | &hf_zip_extra_ut_flag_ctime, |
477 | 0 | NULL }; |
478 | |
|
479 | 0 | uint64_t flags; |
480 | 0 | zip_info_t *extra_info = (zip_info_t*)data; |
481 | |
|
482 | 0 | unsigned offset = 0; |
483 | 0 | proto_tree_add_bitmask_ret_uint64(tree, tvb, offset, hf_zip_extra_ut_flags, ett_zip_extra_ut_flags, ut_flags_fields, ENC_NA, &flags); |
484 | 0 | if (extra_info->central_directory) { |
485 | 0 | flags &= 0x1; |
486 | 0 | } |
487 | 0 | offset += 1; |
488 | 0 | if (flags & 1) { |
489 | 0 | proto_tree_add_item(tree, hf_zip_extra_ut_mtime, tvb, offset, 4, ENC_TIME_SECS|ENC_LITTLE_ENDIAN); |
490 | 0 | offset += 4; |
491 | 0 | } |
492 | 0 | if (flags & 2) { |
493 | 0 | proto_tree_add_item(tree, hf_zip_extra_ut_atime, tvb, offset, 4, ENC_TIME_SECS|ENC_LITTLE_ENDIAN); |
494 | 0 | offset += 4; |
495 | 0 | } |
496 | 0 | if (flags & 4) { |
497 | 0 | proto_tree_add_item(tree, hf_zip_extra_ut_ctime, tvb, offset, 4, ENC_TIME_SECS|ENC_LITTLE_ENDIAN); |
498 | 0 | offset += 4; |
499 | 0 | } |
500 | |
|
501 | 0 | return offset; |
502 | 0 | } |
503 | | |
504 | | static int |
505 | | dissect_zip_extra_unix2(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data) |
506 | 0 | { |
507 | 0 | zip_info_t *extra_info = (zip_info_t*)data; |
508 | 0 | unsigned offset = 0; |
509 | |
|
510 | 0 | if (extra_info->central_directory) { |
511 | 0 | return offset; |
512 | 0 | } |
513 | | |
514 | 0 | proto_tree_add_item(tree, hf_zip_extra_unix_uid, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
515 | 0 | offset += 2; |
516 | 0 | proto_tree_add_item(tree, hf_zip_extra_unix_gid, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
517 | 0 | offset += 2; |
518 | |
|
519 | 0 | return offset; |
520 | 0 | } |
521 | | |
522 | | static int |
523 | | dissect_zip_extra_unix3(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) |
524 | 0 | { |
525 | 0 | unsigned offset = 0; |
526 | 0 | uint8_t version, size; |
527 | |
|
528 | 0 | proto_tree_add_item_ret_uint8(tree, hf_zip_extra_version, tvb, offset, 1, ENC_NA, &version); |
529 | 0 | offset += 1; |
530 | 0 | if (version != 1) { |
531 | 0 | return offset; |
532 | 0 | } |
533 | 0 | proto_tree_add_item_ret_uint8(tree, hf_zip_extra_unix_uid_size, tvb, offset, 1, ENC_NA, &size); |
534 | 0 | offset += 1; |
535 | 0 | proto_tree_add_item(tree, hf_zip_extra_unix_uid, tvb, offset, size, ENC_LITTLE_ENDIAN); |
536 | 0 | offset += size; |
537 | 0 | proto_tree_add_item_ret_uint8(tree, hf_zip_extra_unix_gid_size, tvb, offset, 1, ENC_NA, &size); |
538 | 0 | offset += 1; |
539 | 0 | proto_tree_add_item(tree, hf_zip_extra_unix_gid, tvb, offset, size, ENC_LITTLE_ENDIAN); |
540 | 0 | offset += size; |
541 | |
|
542 | 0 | return offset; |
543 | 0 | } |
544 | | |
545 | | static void |
546 | | dissect_zip_extra_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, zip_info_t *extra_info) |
547 | 0 | { |
548 | 0 | proto_tree *extras_tree, *extra_tree; |
549 | 0 | proto_item *ti, *extra_ti; |
550 | |
|
551 | 0 | tvbuff_t *next_tvb; |
552 | 0 | unsigned offset = 0; |
553 | 0 | uint16_t id, size; |
554 | |
|
555 | 0 | ti = proto_tree_add_item(tree, hf_zip_extra_fields, tvb, offset, tvb_reported_length(tvb), ENC_NA); |
556 | 0 | extras_tree = proto_item_add_subtree(ti, ett_zip_extras); |
557 | |
|
558 | 0 | while (tvb_reported_length_remaining(tvb, offset)) { |
559 | 0 | extra_ti = proto_tree_add_item(extras_tree, hf_zip_extra_field, tvb, offset, 4, ENC_NA); |
560 | 0 | extra_tree = proto_item_add_subtree(extra_ti, ett_zip_extra); |
561 | 0 | proto_tree_add_item_ret_uint16(extra_tree, hf_zip_extra_id, tvb, offset, 2, ENC_LITTLE_ENDIAN, &id); |
562 | 0 | proto_item_append_text(extra_ti, ": %s", val_to_str_const(id, zip_extra_id_vals, "Unknown")); |
563 | 0 | offset += 2; |
564 | 0 | proto_tree_add_item_ret_uint16(extra_tree, hf_zip_extra_data_size, tvb, offset, 2, ENC_LITTLE_ENDIAN, &size); |
565 | 0 | offset += 2; |
566 | 0 | if (size) { |
567 | 0 | next_tvb = tvb_new_subset_length(tvb, offset, size); |
568 | 0 | if (!dissector_try_uint_with_data(zip_extra_dissector_table, id, next_tvb, pinfo, extra_tree, false, extra_info)) { |
569 | 0 | proto_tree_add_item(extra_tree, hf_zip_extra_data, tvb, offset, size, ENC_NA); |
570 | 0 | } |
571 | 0 | offset += size; |
572 | 0 | } |
573 | 0 | proto_item_set_end(extra_ti, tvb, offset); |
574 | 0 | } |
575 | 0 | } |
576 | | |
577 | | static int |
578 | | dissect_zip_file(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
579 | 0 | { |
580 | 0 | proto_tree *record_tree; |
581 | 0 | proto_item *ti, *crc_ti, *crc_status_ti, *size_ti, *flags_ti; |
582 | |
|
583 | 0 | uint64_t flags; |
584 | 0 | uint32_t crc32; |
585 | 0 | uint16_t file_name_length, extra_fields_length; |
586 | 0 | uint16_t method; |
587 | 0 | unsigned offset = 0; |
588 | 0 | int encoding; |
589 | 0 | bool encrypted = false; |
590 | 0 | zip_info_t extra_info = {0}; |
591 | |
|
592 | 0 | ti = proto_tree_add_item(tree, hf_zip_file, tvb, offset, 50, ENC_NA); |
593 | 0 | record_tree = proto_item_add_subtree(ti, ett_zip_record); |
594 | |
|
595 | 0 | proto_tree_add_item(record_tree, hf_zip_record_signature, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
596 | 0 | offset += 4; |
597 | 0 | proto_tree_add_item(record_tree, hf_zip_version_to_extract, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
598 | 0 | offset += 2; |
599 | | /* The meaning of the flags depends on the compression method. */ |
600 | 0 | method = tvb_get_letohs(tvb, offset + 2); |
601 | 0 | int* const *flags_fields = zip_get_flags_fields(method); |
602 | 0 | flags_ti = proto_tree_add_bitmask_ret_uint64(record_tree, tvb, offset, hf_zip_flags, ett_zip_flags, flags_fields, ENC_LITTLE_ENDIAN, &flags); |
603 | 0 | if (flags & ZIP_FLAG_LANGUAGE_ENCODING) { |
604 | 0 | encoding = ENC_UTF_8; |
605 | 0 | } else { |
606 | | /* According to the specification, if this bit is not set, the encoding |
607 | | * shall be ENC_CP437. In practice, it's more like the SSID element in |
608 | | * 802.11, viz., if the bit is absent the filename and comment are |
609 | | * opaque byte strings and the encoding is whatever was used by |
610 | | * the tool that made the archive. In such case, some tools will |
611 | | * include appropriate extra fields that are UTF-8 translations of |
612 | | * the filename and comment, at least if they contain octets which |
613 | | * are not in the ASCII/ISO/IEC 646 invariant set. So we could have |
614 | | * a pref here for default encoding. */ |
615 | 0 | encoding = ENC_CP437; |
616 | 0 | } |
617 | 0 | offset += 2; |
618 | 0 | proto_tree_add_item(record_tree, hf_zip_compression_method, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
619 | 0 | offset += 2; |
620 | 0 | offset = dissect_smb_datetime(tvb, record_tree, offset, hf_zip_last_mod_file_date_time, hf_zip_last_mod_file_date, hf_zip_last_mod_file_time, true); |
621 | 0 | crc_ti = proto_tree_add_item_ret_uint(record_tree, hf_zip_crc32, tvb, offset, 4, ENC_LITTLE_ENDIAN, &crc32); |
622 | 0 | offset += 4; |
623 | 0 | size_ti = proto_tree_add_item_ret_uint64(record_tree, hf_zip_file_compressed_size, tvb, offset, 4, ENC_LITTLE_ENDIAN, &extra_info.compressed_size); |
624 | 0 | offset += 4; |
625 | 0 | proto_tree_add_item_ret_uint64(record_tree, hf_zip_file_uncompressed_size, tvb, offset, 4, ENC_LITTLE_ENDIAN, &extra_info.uncompressed_size); |
626 | 0 | offset += 4; |
627 | 0 | proto_tree_add_item_ret_uint16(record_tree, hf_zip_file_name_length, tvb, offset, 2, ENC_LITTLE_ENDIAN, &file_name_length); |
628 | 0 | offset += 2; |
629 | 0 | proto_tree_add_item_ret_uint16(record_tree, hf_zip_extra_fields_length, tvb, offset, 2, ENC_LITTLE_ENDIAN, &extra_fields_length); |
630 | 0 | offset += 2; |
631 | 0 | proto_tree_add_item_ret_string(record_tree, hf_zip_file_name, tvb, offset, file_name_length, encoding, pinfo->pool, &extra_info.filename); |
632 | 0 | extra_info.filename_tvb = tvb_new_subset_length(tvb, offset, file_name_length); |
633 | 0 | offset += file_name_length; |
634 | 0 | if (extra_fields_length) { |
635 | 0 | dissect_zip_extra_fields(tvb_new_subset_length(tvb, offset, extra_fields_length), pinfo, record_tree, &extra_info); |
636 | 0 | offset += extra_fields_length; |
637 | 0 | } |
638 | 0 | proto_item_append_text(ti, ": %s", extra_info.filename); |
639 | | /* The Zip64 extra info has the real size if the compressed size is |
640 | | * UINT32_MAX. For various reasons to do with streaming or writing to |
641 | | * pipes, it's possible that the Zip64 header is used but the size is |
642 | | * not larger than UINT32_MAX, so we check. */ |
643 | 0 | if (extra_info.compressed_size > UINT32_MAX) { |
644 | 0 | expert_add_info_format(pinfo, size_ti, &ei_zip_overflow, "Compressed size unsupported (%" PRIu64 " bytes is too large)", extra_info.compressed_size); |
645 | 0 | return tvb_reported_length(tvb); |
646 | 0 | } |
647 | 0 | if (flags & ZIP_FLAG_DATA_DESCRIPTOR) { |
648 | | /* Right now we don't handle the data descriptor. The standard way |
649 | | * many programs handle them is to read the central directory |
650 | | * listing first. If the file is not encrypted, and it's compressed |
651 | | * with deflate, then we could just throw everything that's left |
652 | | * in the tvb at zlib, and if that returned a success (Z_END_STREAM) |
653 | | * check how many total bytes were consumed. We'll need a version |
654 | | * of tvb_child_uncompress_zlib that returns how many bytes were |
655 | | * consumed (and possibly the return value, to distinguish between |
656 | | * end of stream and unexpected end) to do that. |
657 | | */ |
658 | 0 | expert_add_info_format(pinfo, flags_ti, &ei_zip_unsupported, "%s", "Data descriptors are not supported yet"); |
659 | 0 | return offset; |
660 | 0 | } |
661 | 0 | if (flags & ZIP_FLAG_ENCRYPTION) { |
662 | 0 | if (!(flags & ZIP_FLAG_STRONG_ENCRYPTION)) { |
663 | 0 | proto_tree_add_item(record_tree, hf_zip_encryption_header, tvb, offset, 12, ENC_NA); |
664 | 0 | offset += 12; |
665 | 0 | if (ckd_sub(&extra_info.compressed_size, extra_info.compressed_size, 12)) { |
666 | 0 | expert_add_info_format(pinfo, size_ti, &ei_zip_underflow, "Compressed size is too small to include the indicated encryption header"); |
667 | 0 | return offset; |
668 | 0 | } |
669 | 0 | } |
670 | 0 | proto_tree_add_item(record_tree, hf_zip_encrypted_file_data, tvb, offset, (uint32_t)extra_info.compressed_size, ENC_NA); |
671 | 0 | encrypted = true; |
672 | 0 | } |
673 | | |
674 | 0 | tvbuff_t *decompr_tvb = NULL; |
675 | 0 | if (!encrypted) { |
676 | 0 | switch (method) { |
677 | 0 | case 0: |
678 | 0 | decompr_tvb = tvb_new_subset_length(tvb, offset, (uint32_t)extra_info.compressed_size); |
679 | 0 | break; |
680 | 0 | case 8: |
681 | 0 | proto_tree_add_item(record_tree, hf_zip_compressed_file_data, tvb, offset, (uint32_t)extra_info.compressed_size, ENC_NA); |
682 | 0 | if (flags & ZIP_FLAG_DATA_DESCRIPTOR) { |
683 | 0 | decompr_tvb = tvb_child_uncompress_zlib(tvb, tvb, offset, tvb_captured_length_remaining(tvb, offset)); |
684 | 0 | } else { |
685 | 0 | decompr_tvb = tvb_child_uncompress_zlib(tvb, tvb, offset, (uint32_t)extra_info.compressed_size); |
686 | 0 | } |
687 | 0 | break; |
688 | 0 | } |
689 | 0 | } |
690 | | /* We reconstruct what proto_tree_add_checksum does down here because the |
691 | | * checksum comes much earlier, and also the check is after the DOS date |
692 | | * and time in the tree, and the SMB function to compute that doesn't |
693 | | * return the proto_item, so it's harder to use proto_tree_move_item. */ |
694 | 0 | if (decompr_tvb) { |
695 | 0 | add_new_data_source(pinfo, decompr_tvb, "Decompressed file"); |
696 | 0 | proto_tree_add_item(record_tree, hf_zip_file_data, decompr_tvb, 0, tvb_reported_length(decompr_tvb), ENC_NA); |
697 | 0 | uint32_t computed_crc32 = crc32_ccitt_tvb(decompr_tvb, tvb_reported_length(decompr_tvb)); |
698 | 0 | if (crc32 == computed_crc32) { |
699 | 0 | proto_item_append_text(crc_ti, " [correct]"); |
700 | 0 | crc_status_ti = proto_tree_add_uint(record_tree, hf_zip_crc32_status, tvb, 0, 0, PROTO_CHECKSUM_E_GOOD); |
701 | 0 | } else { |
702 | 0 | proto_item_append_text(crc_ti, " incorrect, should be 0x%08x", computed_crc32); |
703 | 0 | crc_status_ti = proto_tree_add_uint(record_tree, hf_zip_crc32_status, tvb, 0, 0, PROTO_CHECKSUM_E_BAD); |
704 | 0 | expert_add_info_format(pinfo, crc_ti, &ei_zip_crc32, "%s [should be 0x%08x]", expert_get_summary(&ei_zip_crc32), computed_crc32); |
705 | 0 | } |
706 | | /* We could wait to actually tap until the central directory listing, |
707 | | * e.g. if we wanted to use the file comment if present as the |
708 | | * Export Objects "hostname" field. */ |
709 | 0 | if (have_tap_listener(zip_eo_tap)) { |
710 | 0 | zip_eo_t *eo_info = wmem_new0(pinfo->pool, zip_eo_t); |
711 | 0 | eo_info->filename = (const char*)extra_info.filename; |
712 | 0 | eo_info->payload = decompr_tvb; |
713 | |
|
714 | 0 | tap_queue_packet(zip_eo_tap, pinfo, eo_info); |
715 | 0 | } |
716 | | /* Theoretically we could send the decompressed file data to all the |
717 | | * media type heuristic dissectors, but that's how you get ZIP bombs. */ |
718 | 0 | } else { |
719 | 0 | proto_item_append_text(crc_ti, " [unverified]"); |
720 | 0 | crc_status_ti = proto_tree_add_uint(record_tree, hf_zip_crc32_status, tvb, 0, 0, PROTO_CHECKSUM_E_UNVERIFIED); |
721 | 0 | } |
722 | 0 | proto_tree_move_item(record_tree, crc_ti, crc_status_ti); |
723 | 0 | proto_item_set_generated(crc_status_ti); |
724 | |
|
725 | 0 | if (ckd_add(&offset, offset, extra_info.compressed_size)) { |
726 | 0 | offset = tvb_reported_length(tvb); |
727 | 0 | } |
728 | 0 | proto_item_set_end(ti, tvb, offset); |
729 | |
|
730 | | #if 0 |
731 | | // TODO |
732 | | if (flags & ZIP_FLAG_DATA_DESCRIPTOR) { |
733 | | |
734 | | } |
735 | | #endif |
736 | |
|
737 | 0 | return offset; |
738 | 0 | } |
739 | | |
740 | | static int |
741 | | dissect_zip_directory(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) |
742 | 0 | { |
743 | 0 | proto_item *ti; |
744 | 0 | proto_tree *record_tree; |
745 | |
|
746 | 0 | uint64_t flags; |
747 | 0 | uint16_t file_name_length, extra_fields_length, file_comment_length; |
748 | 0 | unsigned offset = 0; |
749 | 0 | int encoding; |
750 | 0 | zip_info_t extra_info = {.central_directory = true}; |
751 | |
|
752 | 0 | ti = proto_tree_add_item(tree, hf_zip_directory, tvb, offset, 50, ENC_NA); |
753 | 0 | record_tree = proto_item_add_subtree(ti, ett_zip_record); |
754 | |
|
755 | 0 | proto_tree_add_item(record_tree, hf_zip_record_signature, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
756 | 0 | offset += 4; |
757 | 0 | proto_tree_add_bitmask(record_tree, tvb, offset, hf_zip_made_by, ett_zip_made_by, made_by_fields, ENC_LITTLE_ENDIAN); |
758 | 0 | offset += 2; |
759 | 0 | proto_tree_add_item(record_tree, hf_zip_version_to_extract, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
760 | 0 | offset += 2; |
761 | 0 | int* const *flags_fields = zip_get_flags_fields(tvb_get_letohs(tvb, offset + 2)); |
762 | 0 | proto_tree_add_bitmask_ret_uint64(record_tree, tvb, offset, hf_zip_flags, ett_zip_flags, flags_fields, ENC_LITTLE_ENDIAN, &flags); |
763 | 0 | if (flags & ZIP_FLAG_LANGUAGE_ENCODING) { |
764 | 0 | encoding = ENC_UTF_8; |
765 | 0 | } else { |
766 | 0 | encoding = ENC_CP437; |
767 | 0 | } |
768 | 0 | offset += 2; |
769 | 0 | proto_tree_add_item(record_tree, hf_zip_compression_method, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
770 | 0 | offset += 2; |
771 | 0 | offset = dissect_smb_datetime(tvb, record_tree, offset, hf_zip_last_mod_file_date_time, hf_zip_last_mod_file_date, hf_zip_last_mod_file_time, true); |
772 | 0 | proto_tree_add_item(record_tree, hf_zip_crc32, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
773 | 0 | offset += 4; |
774 | 0 | proto_tree_add_item_ret_uint64(record_tree, hf_zip_file_compressed_size, tvb, offset, 4, ENC_LITTLE_ENDIAN, &extra_info.compressed_size); |
775 | 0 | offset += 4; |
776 | 0 | proto_tree_add_item_ret_uint64(record_tree, hf_zip_file_uncompressed_size, tvb, offset, 4, ENC_LITTLE_ENDIAN, &extra_info.uncompressed_size); |
777 | 0 | offset += 4; |
778 | 0 | proto_tree_add_item_ret_uint16(record_tree, hf_zip_file_name_length, tvb, offset, 2, ENC_LITTLE_ENDIAN, &file_name_length); |
779 | 0 | offset += 2; |
780 | 0 | proto_tree_add_item_ret_uint16(record_tree, hf_zip_extra_fields_length, tvb, offset, 2, ENC_LITTLE_ENDIAN, &extra_fields_length); |
781 | 0 | offset += 2; |
782 | 0 | proto_tree_add_item_ret_uint16(record_tree, hf_zip_file_comment_length, tvb, offset, 2, ENC_LITTLE_ENDIAN, &file_comment_length); |
783 | 0 | offset += 2; |
784 | 0 | proto_tree_add_item_ret_uint(record_tree, hf_zip_disk_start_number, tvb, offset, 2, ENC_LITTLE_ENDIAN, &extra_info.disk_start_number); |
785 | 0 | offset += 2; |
786 | 0 | proto_tree_add_item(record_tree, hf_zip_internal_file_attr, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
787 | 0 | offset += 2; |
788 | 0 | proto_tree_add_item(record_tree, hf_zip_external_file_attr, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
789 | 0 | offset += 4; |
790 | 0 | proto_tree_add_item_ret_uint64(record_tree, hf_zip_local_header_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN, &extra_info.local_header_offset); |
791 | 0 | offset += 4; |
792 | 0 | proto_tree_add_item_ret_string(record_tree, hf_zip_file_name, tvb, offset, file_name_length, encoding, pinfo->pool, &extra_info.filename); |
793 | 0 | extra_info.filename_tvb = tvb_new_subset_length(tvb, offset, file_name_length); |
794 | 0 | offset += file_name_length; |
795 | 0 | if (extra_fields_length) { |
796 | 0 | dissect_zip_extra_fields(tvb_new_subset_length(tvb, offset, extra_fields_length), pinfo, record_tree, &extra_info); |
797 | 0 | offset += extra_fields_length; |
798 | 0 | } |
799 | 0 | proto_item_append_text(ti, ": %s", extra_info.filename); |
800 | 0 | if (file_comment_length) { |
801 | 0 | proto_tree_add_item(record_tree, hf_zip_file_comment, tvb, offset, file_comment_length, encoding); |
802 | 0 | offset += file_comment_length; |
803 | 0 | } |
804 | |
|
805 | 0 | proto_item_set_end(ti, tvb, offset); |
806 | |
|
807 | 0 | return offset; |
808 | 0 | } |
809 | | |
810 | | static int |
811 | | dissect_zip_end_of_directory(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) |
812 | 0 | { |
813 | 0 | proto_item *ti; |
814 | 0 | proto_tree *record_tree; |
815 | |
|
816 | 0 | unsigned offset = 0, comment_length; |
817 | |
|
818 | 0 | ti = proto_tree_add_item(tree, hf_zip_end_of_directory, tvb, offset, 50, ENC_NA); |
819 | 0 | record_tree = proto_item_add_subtree(ti, ett_zip_record); |
820 | |
|
821 | 0 | proto_tree_add_item(record_tree, hf_zip_record_signature, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
822 | 0 | offset += 4; |
823 | 0 | proto_tree_add_item(record_tree, hf_zip_disk_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
824 | 0 | offset += 2; |
825 | 0 | proto_tree_add_item(record_tree, hf_zip_directory_disk_start_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
826 | 0 | offset += 2; |
827 | 0 | proto_tree_add_item(record_tree, hf_zip_directory_entries_disk, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
828 | 0 | offset += 2; |
829 | 0 | proto_tree_add_item(record_tree, hf_zip_directory_entries, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
830 | 0 | offset += 2; |
831 | 0 | proto_tree_add_item(record_tree, hf_zip_directory_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
832 | 0 | offset += 4; |
833 | 0 | proto_tree_add_item(record_tree, hf_zip_directory_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
834 | 0 | offset += 4; |
835 | 0 | proto_tree_add_item_ret_length(record_tree, hf_zip_archive_comment, tvb, offset, 2, ENC_LITTLE_ENDIAN|ENC_CP437, &comment_length); |
836 | 0 | offset += comment_length; |
837 | 0 | proto_item_set_end(ti, tvb, offset); |
838 | |
|
839 | 0 | return offset; |
840 | 0 | } |
841 | | |
842 | | static int |
843 | | dissect_zip64_end_of_directory(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) |
844 | 0 | { |
845 | 0 | proto_item *ti, *size_ti; |
846 | 0 | proto_tree *record_tree; |
847 | |
|
848 | 0 | unsigned offset = 0, end_offset; |
849 | 0 | uint64_t size; |
850 | |
|
851 | 0 | ti = proto_tree_add_item(tree, hf_zip64_end_of_directory, tvb, offset, 50, ENC_NA); |
852 | 0 | record_tree = proto_item_add_subtree(ti, ett_zip_record); |
853 | |
|
854 | 0 | proto_tree_add_item(record_tree, hf_zip_record_signature, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
855 | 0 | offset += 4; |
856 | 0 | size_ti = proto_tree_add_item_ret_uint64(record_tree, hf_zip_directory_end_size, tvb, offset, 8, ENC_LITTLE_ENDIAN, &size); |
857 | 0 | offset += 8; |
858 | 0 | if (ckd_add(&end_offset, offset, size)) { |
859 | 0 | expert_add_info(pinfo, size_ti, &ei_zip_overflow); |
860 | 0 | return tvb_reported_length(tvb); |
861 | 0 | } |
862 | 0 | proto_tree_add_bitmask(record_tree, tvb, offset, hf_zip_made_by, ett_zip_made_by, made_by_fields, ENC_LITTLE_ENDIAN); |
863 | 0 | offset += 2; |
864 | 0 | proto_tree_add_item(record_tree, hf_zip_version_to_extract, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
865 | 0 | offset += 2; |
866 | 0 | proto_tree_add_item(record_tree, hf_zip_disk_number, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
867 | 0 | offset += 4; |
868 | 0 | proto_tree_add_item(record_tree, hf_zip_directory_disk_start_number, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
869 | 0 | offset += 4; |
870 | 0 | proto_tree_add_item(record_tree, hf_zip_directory_entries_disk, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
871 | 0 | offset += 8; |
872 | 0 | proto_tree_add_item(record_tree, hf_zip_directory_entries, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
873 | 0 | offset += 8; |
874 | 0 | proto_tree_add_item(record_tree, hf_zip_directory_size, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
875 | 0 | offset += 8; |
876 | 0 | proto_tree_add_item(record_tree, hf_zip_directory_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
877 | 0 | offset += 8; |
878 | 0 | if (offset < end_offset) { |
879 | 0 | proto_tree_add_item(record_tree, hf_zip_extensible_data_sector, tvb, offset, end_offset - offset, ENC_NA); |
880 | 0 | offset = end_offset; |
881 | 0 | } |
882 | 0 | proto_item_set_end(ti, tvb, offset); |
883 | |
|
884 | 0 | return offset; |
885 | 0 | } |
886 | | |
887 | | static int |
888 | | dissect_zip64_end_of_directory_locator(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) |
889 | 0 | { |
890 | 0 | proto_item *ti; |
891 | 0 | proto_tree *record_tree; |
892 | |
|
893 | 0 | unsigned offset = 0; |
894 | |
|
895 | 0 | ti = proto_tree_add_item(tree, hf_zip64_end_of_directory_locator, tvb, offset, 20, ENC_NA); |
896 | 0 | record_tree = proto_item_add_subtree(ti, ett_zip_record); |
897 | |
|
898 | 0 | proto_tree_add_item(record_tree, hf_zip_record_signature, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
899 | 0 | offset += 4; |
900 | 0 | proto_tree_add_item(record_tree, hf_zip_zip64_directory_end_disk_start_number, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
901 | 0 | offset += 4; |
902 | 0 | proto_tree_add_item(record_tree, hf_zip_zip64_directory_end_offset, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
903 | 0 | offset += 8; |
904 | 0 | proto_tree_add_item(record_tree, hf_zip_total_disks, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
905 | 0 | offset += 4; |
906 | |
|
907 | 0 | return offset; |
908 | 0 | } |
909 | | |
910 | | static int |
911 | 0 | dissect_zip(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) { |
912 | 0 | unsigned offset = 0; |
913 | 0 | proto_tree *zip_tree; |
914 | 0 | proto_item *ti; |
915 | |
|
916 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "ZIP_FILE"); |
917 | 0 | ti = proto_tree_add_item(tree, proto_zip, tvb, offset, -1, ENC_NA); |
918 | 0 | zip_tree = proto_item_add_subtree(ti, ett_zip); |
919 | |
|
920 | 0 | int dissected; |
921 | 0 | while (tvb_find_uint16_remaining(tvb, offset, ZIP_MAGIC_UINT, &offset) && |
922 | 0 | tvb_reported_length_remaining(tvb, offset) >= 4) { |
923 | 0 | uint32_t signature = tvb_get_letohl(tvb, offset); |
924 | 0 | tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset); |
925 | 0 | if (!(dissected = dissector_try_uint_with_data(zip_record_dissector_table, signature, next_tvb, pinfo, zip_tree, false, data))) { |
926 | 0 | proto_tree_add_item(zip_tree, hf_zip_record_signature, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
927 | 0 | break; |
928 | 0 | } |
929 | 0 | offset += dissected; |
930 | 0 | } |
931 | |
|
932 | 0 | return tvb_reported_length(tvb); |
933 | 0 | } |
934 | | |
935 | | void |
936 | | proto_register_zip(void) |
937 | 16 | { |
938 | 16 | static hf_register_info hf[] = { |
939 | 16 | { &hf_zip_file, |
940 | 16 | { "Local File", "zipfile.file", |
941 | 16 | FT_NONE, BASE_NONE, NULL, |
942 | 16 | 0x0, NULL, HFILL } |
943 | 16 | }, |
944 | 16 | { &hf_zip_directory, |
945 | 16 | { "Central Directory", "zipfile.directory", |
946 | 16 | FT_NONE, BASE_NONE, NULL, |
947 | 16 | 0x0, NULL, HFILL } |
948 | 16 | }, |
949 | 16 | { &hf_zip_end_of_directory, |
950 | 16 | { "End of Central Directory", "zipfile.directory.end", |
951 | 16 | FT_NONE, BASE_NONE, NULL, |
952 | 16 | 0x0, NULL, HFILL } |
953 | 16 | }, |
954 | 16 | { &hf_zip64_end_of_directory, |
955 | 16 | { "Zip64 End of Central Directory", "zipfile.directory.end.zip64", |
956 | 16 | FT_NONE, BASE_NONE, NULL, |
957 | 16 | 0x0, NULL, HFILL } |
958 | 16 | }, |
959 | 16 | { &hf_zip64_end_of_directory_locator, |
960 | 16 | { "Zip64 End of Central Directory Locator", "zipfile.directory.end.zip64.locator", |
961 | 16 | FT_NONE, BASE_NONE, NULL, |
962 | 16 | 0x0, NULL, HFILL } |
963 | 16 | }, |
964 | 16 | { &hf_zip_record_signature, |
965 | 16 | { "Signature", "zipfile.signature", |
966 | 16 | FT_UINT32, BASE_HEX, VALS(zip_record_vals), |
967 | 16 | 0x0, NULL, HFILL } |
968 | 16 | }, |
969 | 16 | { &hf_zip_made_by, |
970 | 16 | { "Made By", "zipfile.made_by", |
971 | 16 | FT_UINT16, BASE_HEX, NULL, |
972 | 16 | 0x0, NULL, HFILL } |
973 | 16 | }, |
974 | 16 | { &hf_zip_version_made_by, |
975 | 16 | { "Version", "zipfile.made_by.version", |
976 | 16 | FT_UINT16, BASE_CUSTOM, CF_FUNC(decode_zip_version), |
977 | 16 | 0x00FF, "Supposedly the ZIP specification version supported by the creating software, but often the software's own version", HFILL } |
978 | 16 | }, |
979 | 16 | { &hf_zip_host_made_by, |
980 | 16 | { "Host System", "zipfile.made_by.host", |
981 | 16 | FT_UINT16, BASE_DEC, VALS(zip_host_vals), |
982 | 16 | 0xFF00, "Indicates compatibility of external file attributes", HFILL } |
983 | 16 | }, |
984 | 16 | { &hf_zip_version_to_extract, |
985 | 16 | { "Version to Extract", "zipfile.version_to_extract", |
986 | 16 | FT_UINT16, BASE_CUSTOM, CF_FUNC(decode_zip_version), |
987 | 16 | 0x0, "Minimum supported ZIP specification version needed to extract", HFILL } |
988 | 16 | }, |
989 | 16 | { &hf_zip_flags, |
990 | 16 | { "Flags", "zipfile.flags", |
991 | 16 | FT_UINT16, BASE_DEC, NULL, |
992 | 16 | 0x0, NULL, HFILL } |
993 | 16 | }, |
994 | 16 | { &hf_zip_flag_encryption, |
995 | 16 | { "Encryption", "zipfile.flag.encryption", |
996 | 16 | FT_BOOLEAN, 16, TFS(&tfs_used_notused), |
997 | 16 | ZIP_FLAG_ENCRYPTION, NULL, HFILL } |
998 | 16 | }, |
999 | 16 | { &hf_zip_flag_lzma_eos, |
1000 | 16 | { "LZMA EOS marker", "zipfile.flag.lzma.eos", |
1001 | 16 | FT_BOOLEAN, 16, TFS(&tfs_present_absent), |
1002 | 16 | ZIP_FLAG_LZMA_OPTS, NULL, HFILL } |
1003 | 16 | }, |
1004 | 16 | { &hf_zip_flag_deflate_opts, |
1005 | 16 | { "DEFLATE options", "zipfile.flag.deflate_opts", |
1006 | 16 | FT_UINT16, BASE_HEX, VALS(zip_deflate_opts_vals), |
1007 | 16 | ZIP_FLAG_DEFLATE_OPTS, NULL, HFILL } |
1008 | 16 | }, |
1009 | 16 | { &hf_zip_flag_data_descriptor, |
1010 | 16 | { "Data Descriptor", "zipfile.flag.data_descriptor", |
1011 | 16 | FT_BOOLEAN, 16, TFS(&tfs_present_absent), |
1012 | 16 | ZIP_FLAG_DATA_DESCRIPTOR, |
1013 | 16 | "Seeking was not possible when producing file; CRC-32 and sizes are zero in header", HFILL } |
1014 | 16 | }, |
1015 | 16 | { &hf_zip_flag_patched_data, |
1016 | 16 | { "Patched Data", "zipfile.flag.patched_data", |
1017 | 16 | FT_BOOLEAN, 16, TFS(&tfs_set_notset), |
1018 | 16 | ZIP_FLAG_PATCHED_DATA, NULL, HFILL } |
1019 | 16 | }, |
1020 | 16 | { &hf_zip_flag_strong_encryption, |
1021 | 16 | { "Strong Encryption", "zipfile.flag.encrypted.strong", |
1022 | 16 | FT_BOOLEAN, 16, TFS(&tfs_used_notused), |
1023 | 16 | ZIP_FLAG_STRONG_ENCRYPTION, NULL, HFILL } |
1024 | 16 | }, |
1025 | 16 | { &hf_zip_flag_language_encoding, |
1026 | 16 | { "UTF-8", "zipfile.flag.language_encoding", |
1027 | 16 | FT_BOOLEAN, 16, TFS(&tfs_used_notused), |
1028 | 16 | ZIP_FLAG_LANGUAGE_ENCODING, |
1029 | 16 | "Filename and comment fields for this file are in UTF-8", HFILL } |
1030 | 16 | }, |
1031 | 16 | { &hf_zip_flag_central_dir_encryption, |
1032 | 16 | { "Central Directory Encryption", "zipfile.flag.encrypted.central_directory", |
1033 | 16 | FT_BOOLEAN, 16, TFS(&tfs_used_notused), |
1034 | 16 | ZIP_FLAG_CENTRAL_DIR_CRYPT, NULL, HFILL } |
1035 | 16 | }, |
1036 | 16 | { &hf_zip_compression_method, |
1037 | 16 | { "Compression Method", "zipfile.file.compression_method", |
1038 | 16 | FT_UINT16, BASE_DEC, VALS(zip_method_vals), |
1039 | 16 | 0x0, NULL, HFILL } |
1040 | 16 | }, |
1041 | 16 | { &hf_zip_last_mod_file_date_time, |
1042 | 16 | { "Last Mod File Date and Time", "zipfile.file.last_mod_file_date_time", |
1043 | 16 | FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, |
1044 | 16 | 0x0, NULL, HFILL } |
1045 | 16 | }, |
1046 | 16 | { &hf_zip_last_mod_file_time, |
1047 | 16 | { "Last Mod File Time", "zipfile.file.last_mod_file_time", |
1048 | 16 | FT_UINT16, BASE_HEX, NULL, |
1049 | 16 | 0x0, NULL, HFILL } |
1050 | 16 | }, |
1051 | 16 | { &hf_zip_last_mod_file_date, |
1052 | 16 | { "Last Mod File Date", "zipfile.file.last_mod_file_date", |
1053 | 16 | FT_UINT16, BASE_HEX, NULL, |
1054 | 16 | 0x0, NULL, HFILL } |
1055 | 16 | }, |
1056 | 16 | { &hf_zip_crc32, |
1057 | 16 | { "CRC", "zipfile.file.crc32", |
1058 | 16 | FT_UINT32, BASE_HEX, NULL, |
1059 | 16 | 0x0, NULL, HFILL } |
1060 | 16 | }, |
1061 | 16 | { &hf_zip_crc32_status, |
1062 | 16 | { "CRC Status", "zipfile.file.crc32.status", |
1063 | 16 | FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), |
1064 | 16 | 0x0, NULL, HFILL } |
1065 | 16 | }, |
1066 | 16 | { &hf_zip_file_compressed_size, |
1067 | 16 | { "File Compressed Size", "zipfile.file.size", |
1068 | 16 | FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), |
1069 | 16 | 0x0, NULL, HFILL } |
1070 | 16 | }, |
1071 | 16 | { &hf_zip_file_uncompressed_size, |
1072 | 16 | { "File Uncompressed Size", "zipfile.file.size.uncompressed", |
1073 | 16 | FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), |
1074 | 16 | 0x0, NULL, HFILL } |
1075 | 16 | }, |
1076 | 16 | { &hf_zip_file_name_length, |
1077 | 16 | { "File Name Length", "zipfile.file.name.length", |
1078 | 16 | FT_UINT16, BASE_DEC, NULL, |
1079 | 16 | 0x0, NULL, HFILL } |
1080 | 16 | }, |
1081 | 16 | { &hf_zip_extra_fields_length, |
1082 | 16 | { "Extra Fields Length", "zipfile.extras.length", |
1083 | 16 | FT_UINT16, BASE_DEC, NULL, |
1084 | 16 | 0x0, NULL, HFILL } |
1085 | 16 | }, |
1086 | 16 | { &hf_zip_extra_fields, |
1087 | 16 | { "Extra Fields", "zipfile.extras", |
1088 | 16 | FT_NONE, BASE_NONE, NULL, |
1089 | 16 | 0x0, NULL, HFILL } |
1090 | 16 | }, |
1091 | 16 | { &hf_zip_extra_field, |
1092 | 16 | { "Extra Field", "zipfile.extra", |
1093 | 16 | FT_NONE, BASE_NONE, NULL, |
1094 | 16 | 0x0, NULL, HFILL } |
1095 | 16 | }, |
1096 | 16 | { &hf_zip_extra_id, |
1097 | 16 | { "ID", "zipfile.extra.id", |
1098 | 16 | FT_UINT16, BASE_HEX, VALS(zip_extra_id_vals), |
1099 | 16 | 0x0, NULL, HFILL } |
1100 | 16 | }, |
1101 | 16 | { &hf_zip_extra_data_size, |
1102 | 16 | { "Data Size", "zipfile.extra.data.size", |
1103 | 16 | FT_UINT16, BASE_DEC, NULL, |
1104 | 16 | 0x0, NULL, HFILL } |
1105 | 16 | }, |
1106 | 16 | { &hf_zip_extra_data, |
1107 | 16 | { "Data", "zipfile.extra.data", |
1108 | 16 | FT_BYTES, BASE_NONE, NULL, |
1109 | 16 | 0x0, NULL, HFILL } |
1110 | 16 | }, |
1111 | 16 | { &hf_zip_extra_version, |
1112 | 16 | { "Version", "zipfile.extra.version", |
1113 | 16 | FT_UINT8, BASE_DEC, NULL, |
1114 | 16 | 0x0, NULL, HFILL }, |
1115 | 16 | }, |
1116 | | |
1117 | 16 | { &hf_zip_extra_ntfs_tag, |
1118 | 16 | { "Tag", "zipfile.extra.ntfs.tag", |
1119 | 16 | FT_UINT16, BASE_HEX, VALS(zip_extra_ntfs_tag_vals), |
1120 | 16 | 0x0, NULL, HFILL }, |
1121 | 16 | }, |
1122 | | |
1123 | 16 | { &hf_zip_extra_ut_flags, |
1124 | 16 | { "Flags", "zipfile.extra.ut.flags", |
1125 | 16 | FT_UINT8, BASE_HEX, NULL, |
1126 | 16 | 0x0, NULL, HFILL }, |
1127 | 16 | }, |
1128 | 16 | { &hf_zip_extra_ut_flag_mtime, |
1129 | 16 | { "Modification Time", "zipfile.extra.ut.flag.mtime", |
1130 | 16 | FT_BOOLEAN, 8, TFS(&tfs_present_absent), |
1131 | 16 | 0x1, NULL, HFILL }, |
1132 | 16 | }, |
1133 | 16 | { &hf_zip_extra_ut_flag_atime, |
1134 | 16 | { "Access Time", "zipfile.extra.ut.flag.atime", |
1135 | 16 | FT_BOOLEAN, 8, TFS(&tfs_present_absent), |
1136 | 16 | 0x2, NULL, HFILL }, |
1137 | 16 | }, |
1138 | 16 | { &hf_zip_extra_ut_flag_ctime, |
1139 | 16 | { "Creation Time", "zipfile.extra.ut.flag.ctime", |
1140 | 16 | FT_BOOLEAN, 8, TFS(&tfs_present_absent), |
1141 | 16 | 0x4, NULL, HFILL }, |
1142 | 16 | }, |
1143 | 16 | { &hf_zip_extra_ut_mtime, |
1144 | 16 | { "Modification Time", "zipfile.extra.ut.mtime", |
1145 | 16 | FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, |
1146 | 16 | 0x0, NULL, HFILL }, |
1147 | 16 | }, |
1148 | 16 | { &hf_zip_extra_ut_atime, |
1149 | 16 | { "Access Time", "zipfile.extra.ut.atime", |
1150 | 16 | FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, |
1151 | 16 | 0x0, NULL, HFILL }, |
1152 | 16 | }, |
1153 | 16 | { &hf_zip_extra_ut_ctime, |
1154 | 16 | { "Creation Time", "zipfile.extra.ut.ctime", |
1155 | 16 | FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, |
1156 | 16 | 0x0, NULL, HFILL }, |
1157 | 16 | }, |
1158 | 16 | { &hf_zip_extra_unix_uid_size, |
1159 | 16 | { "User ID size", "zipfile.extra.unix.uid_size", |
1160 | 16 | FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), |
1161 | 16 | 0x0, NULL, HFILL }, |
1162 | 16 | }, |
1163 | 16 | { &hf_zip_extra_unix_uid, |
1164 | 16 | { "User ID", "zipfile.extra.unix.uid", |
1165 | 16 | FT_UINT16, BASE_DEC, NULL, |
1166 | 16 | 0x0, NULL, HFILL }, |
1167 | 16 | }, |
1168 | 16 | { &hf_zip_extra_unix_gid_size, |
1169 | 16 | { "Group ID size", "zipfile.extra.unix.gid_size", |
1170 | 16 | FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), |
1171 | 16 | 0x0, NULL, HFILL }, |
1172 | 16 | }, |
1173 | 16 | { &hf_zip_extra_unix_gid, |
1174 | 16 | { "Group ID", "zipfile.extra.unix.gid", |
1175 | 16 | FT_UINT16, BASE_DEC, NULL, |
1176 | 16 | 0x0, NULL, HFILL }, |
1177 | 16 | }, |
1178 | | |
1179 | 16 | { &hf_zip_file_comment_length, |
1180 | 16 | { "File Comment Length", "zipfile.file.file_comment.length", |
1181 | 16 | FT_UINT16, BASE_DEC, NULL, |
1182 | 16 | 0x0, NULL, HFILL } |
1183 | 16 | }, |
1184 | 16 | { &hf_zip_disk_start_number, |
1185 | 16 | { "Disk Number Start", "zipfile.file.disk_start_number", |
1186 | 16 | FT_UINT32, BASE_DEC, NULL, |
1187 | 16 | 0x0, NULL, HFILL } |
1188 | 16 | }, |
1189 | 16 | { &hf_zip_internal_file_attr, |
1190 | 16 | { "Internal File Attributes", "zipfile.file.internal_file_attr", |
1191 | 16 | FT_UINT16, BASE_HEX, NULL, |
1192 | 16 | 0x0, NULL, HFILL } |
1193 | 16 | }, |
1194 | 16 | { &hf_zip_external_file_attr, |
1195 | 16 | { "External File Attributes", "zipfile.file.external_file_attr", |
1196 | 16 | FT_UINT32, BASE_HEX, NULL, |
1197 | 16 | 0x0, NULL, HFILL } |
1198 | 16 | }, |
1199 | 16 | { &hf_zip_local_header_offset, |
1200 | 16 | { "Local Header Offset", "zipfile.file.local_header_offset", |
1201 | 16 | FT_UINT64, BASE_DEC_HEX, NULL, |
1202 | 16 | 0x0, NULL, HFILL } |
1203 | 16 | }, |
1204 | 16 | { &hf_zip_file_name, |
1205 | 16 | { "File Name", "zipfile.file.name", |
1206 | 16 | FT_STRING, BASE_NONE, NULL, |
1207 | 16 | 0x0, NULL, HFILL } |
1208 | 16 | }, |
1209 | 16 | { &hf_zip_file_comment, |
1210 | 16 | { "File Comment", "zipfile.file.comment", |
1211 | 16 | FT_STRING, BASE_NONE, NULL, |
1212 | 16 | 0x0, NULL, HFILL } |
1213 | 16 | }, |
1214 | 16 | { &hf_zip_encryption_header, |
1215 | 16 | { "Encryption Header", "zipfile.file.encryption_header", |
1216 | 16 | FT_BYTES, BASE_NONE, NULL, |
1217 | 16 | 0x0, NULL, HFILL } |
1218 | 16 | }, |
1219 | 16 | { &hf_zip_encrypted_file_data, |
1220 | 16 | { "Encrypted File Data", "zipfile.file.data.encrypted", |
1221 | 16 | FT_BYTES, BASE_NONE, NULL, |
1222 | 16 | 0x0, NULL, HFILL } |
1223 | 16 | }, |
1224 | 16 | { &hf_zip_compressed_file_data, |
1225 | 16 | { "Compressed File Data", "zipfile.file.data.compressed", |
1226 | 16 | FT_BYTES, BASE_NONE, NULL, |
1227 | 16 | 0x0, NULL, HFILL } |
1228 | 16 | }, |
1229 | 16 | { &hf_zip_file_data, |
1230 | 16 | { "File Data", "zipfile.file.data", |
1231 | 16 | FT_BYTES, BASE_NONE, NULL, |
1232 | 16 | 0x0, NULL, HFILL } |
1233 | 16 | }, |
1234 | 16 | { &hf_zip_disk_number, |
1235 | 16 | { "Disk Number", "zipfile.directory.disk_number", |
1236 | 16 | FT_UINT32, BASE_DEC, NULL, |
1237 | 16 | 0x0, NULL, HFILL } |
1238 | 16 | }, |
1239 | 16 | { &hf_zip_directory_disk_start_number, |
1240 | 16 | { "Start of Central Directory Disk Number", "zipfile.directory.disk_start_number", |
1241 | 16 | FT_UINT32, BASE_DEC, NULL, |
1242 | 16 | 0x0, NULL, HFILL } |
1243 | 16 | }, |
1244 | 16 | { &hf_zip_directory_entries_disk, |
1245 | 16 | { "Total Number of Entries on This Disk", "zipfile.directory.disk_entries", |
1246 | 16 | FT_UINT64, BASE_DEC, NULL, |
1247 | 16 | 0x0, NULL, HFILL } |
1248 | 16 | }, |
1249 | 16 | { &hf_zip_directory_entries, |
1250 | 16 | { "Total Number of Entries", "zipfile.directory.entries", |
1251 | 16 | FT_UINT64, BASE_DEC, NULL, |
1252 | 16 | 0x0, NULL, HFILL } |
1253 | 16 | }, |
1254 | 16 | { &hf_zip_directory_size, |
1255 | 16 | { "Central Directory Size", "zipfile.directory.size", |
1256 | 16 | FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), |
1257 | 16 | 0x0, NULL, HFILL } |
1258 | 16 | }, |
1259 | 16 | { &hf_zip_directory_offset, |
1260 | 16 | { "Central Directory Offset", "zipfile.directory.offset", |
1261 | 16 | FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), |
1262 | 16 | 0x0, "Offset with respect to starting disk/file for spanned/split archives", HFILL } |
1263 | 16 | }, |
1264 | 16 | { &hf_zip_directory_end_size, |
1265 | 16 | { "Zip64 End of Central Directory Size", "zipfile.zip64.directory.end.size", |
1266 | 16 | FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), |
1267 | 16 | 0x0, NULL, HFILL } |
1268 | 16 | }, |
1269 | 16 | { &hf_zip_archive_comment, |
1270 | 16 | { "ZIP Archive Comment", "zipfile.archive_comment", |
1271 | 16 | FT_UINT_STRING, BASE_NONE, NULL, |
1272 | 16 | 0x0, NULL, HFILL } |
1273 | 16 | }, |
1274 | 16 | { &hf_zip_extensible_data_sector, |
1275 | 16 | { "Extensible Data Sector", "zipfile.zip64.directory.end.extensible_data_sector", |
1276 | 16 | FT_BYTES, BASE_NONE, NULL, |
1277 | 16 | 0x0, NULL, HFILL } |
1278 | 16 | }, |
1279 | 16 | { &hf_zip_zip64_directory_end_disk_start_number, |
1280 | 16 | { "Start of Zip64 End of Central Directory Disk Number", "zipfile.zip64.directory.end.disk_start_number", |
1281 | 16 | FT_UINT32, BASE_DEC, NULL, |
1282 | 16 | 0x0, NULL, HFILL } |
1283 | 16 | }, |
1284 | 16 | { &hf_zip_zip64_directory_end_offset, |
1285 | 16 | { "Zip64 End of Central Directory Offset", "zipfile.zip64.directory.end.offset", |
1286 | 16 | FT_UINT64, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), |
1287 | 16 | 0x0, "Offset with respect to starting disk/file for spanned/split archives", HFILL } |
1288 | 16 | }, |
1289 | 16 | { &hf_zip_total_disks, |
1290 | 16 | { "Total Number of Disks", "zipfile.total_disks", |
1291 | 16 | FT_UINT32, BASE_DEC, NULL, |
1292 | 16 | 0x0, NULL, HFILL } |
1293 | 16 | }, |
1294 | 16 | }; |
1295 | | |
1296 | 16 | static int *ett[] = { |
1297 | 16 | &ett_zip, |
1298 | 16 | &ett_zip_record, |
1299 | 16 | &ett_zip_made_by, |
1300 | 16 | &ett_zip_flags, |
1301 | 16 | &ett_zip_extras, |
1302 | 16 | &ett_zip_extra, |
1303 | 16 | &ett_zip_extra_ut_flags, |
1304 | 16 | }; |
1305 | | |
1306 | 16 | proto_zip = proto_register_protocol("ZIP File Format", "ZIP_FILE", "zipfile"); |
1307 | | |
1308 | 16 | zip_handle = register_dissector("zipfile", dissect_zip, proto_zip); |
1309 | 16 | proto_register_field_array(proto_zip, hf, array_length(hf)); |
1310 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
1311 | | |
1312 | 16 | static ei_register_info ei[] = { |
1313 | 16 | { &ei_zip_crc32, { "zipfile.file.crc32.bad", PI_CHECKSUM, PI_WARN, "Bad CRC32", EXPFILL }}, |
1314 | 16 | { &ei_zip_unsupported, { "zipfile.unsupported", PI_UNDECODED, PI_WARN, "Unsupported feature", EXPFILL }}, |
1315 | 16 | { &ei_zip_overflow, { "zipfile.overflow", PI_UNDECODED, PI_WARN, "Too large values are unsupported", EXPFILL }}, |
1316 | 16 | { &ei_zip_underflow, { "zipfile.underflow", PI_MALFORMED, PI_ERROR, "Too small value is bogus", EXPFILL }}, |
1317 | 16 | }; |
1318 | | |
1319 | 16 | expert_module_t *expert_zip = expert_register_protocol(proto_zip); |
1320 | 16 | expert_register_field_array(expert_zip, ei, array_length(ei)); |
1321 | | |
1322 | 16 | zip_record_dissector_table = register_dissector_table("zip.record", |
1323 | 16 | "ZIP Record", proto_zip, FT_UINT32, BASE_HEX); |
1324 | 16 | zip_extra_dissector_table = register_dissector_table("zip.extra", |
1325 | 16 | "ZIP Extra Field", proto_zip, FT_UINT16, BASE_HEX); |
1326 | | |
1327 | 16 | zip_eo_tap = register_export_object(proto_zip, zip_eo_packet, NULL); |
1328 | 16 | } |
1329 | | |
1330 | | static bool |
1331 | | dissect_zip_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
1332 | 0 | { |
1333 | | // Reject if we don't have enough room for the heuristics |
1334 | 0 | if (tvb_captured_length(tvb) < 4) { |
1335 | 0 | return false; |
1336 | 0 | } |
1337 | | |
1338 | | // For heuristics, we're not going to try to handle self-extracting |
1339 | | // archives with executable code at the beginning (or anything else |
1340 | | // at the start); let some other Fileshark dissector take those. |
1341 | 0 | switch (tvb_get_letohl(tvb, 0)) { |
1342 | 0 | case ZIP_FILE_RECORD: |
1343 | 0 | case ZIP_END_OF_DIRECTORY_RECORD: // Degenerate empty case |
1344 | 0 | break; |
1345 | 0 | default: |
1346 | 0 | return false; |
1347 | 0 | } |
1348 | | |
1349 | 0 | return dissect_zip(tvb, pinfo, tree, data) > 0; |
1350 | 0 | } |
1351 | | |
1352 | | void |
1353 | | proto_reg_handoff_zip(void) |
1354 | 16 | { |
1355 | 16 | dissector_add_uint("zip.record", ZIP_FILE_RECORD, create_dissector_handle(dissect_zip_file, proto_zip)); |
1356 | 16 | dissector_add_uint("zip.record", ZIP_DIRECTORY_RECORD, create_dissector_handle(dissect_zip_directory, proto_zip)); |
1357 | 16 | dissector_add_uint("zip.record", ZIP_END_OF_DIRECTORY_RECORD, create_dissector_handle(dissect_zip_end_of_directory, proto_zip)); |
1358 | 16 | dissector_add_uint("zip.record", ZIP64_END_OF_DIRECTORY_RECORD, create_dissector_handle(dissect_zip64_end_of_directory, proto_zip)); |
1359 | 16 | dissector_add_uint("zip.record", ZIP64_END_OF_DIRECTORY_LOCATOR_RECORD, create_dissector_handle(dissect_zip64_end_of_directory_locator, proto_zip)); |
1360 | | |
1361 | 16 | dissector_add_uint("zip.extra", ZIP_EXTRA_ZIP64, create_dissector_handle(dissect_zip_extra_zip64, proto_zip)); |
1362 | 16 | dissector_add_uint("zip.extra", ZIP_EXTRA_NTFS, create_dissector_handle(dissect_zip_extra_ntfs, proto_zip)); |
1363 | 16 | dissector_add_uint("zip.extra", ZIP_EXTRA_UT, create_dissector_handle(dissect_zip_extra_unix_time, proto_zip)); |
1364 | 16 | dissector_add_uint("zip.extra", ZIP_EXTRA_UCOM, create_dissector_handle(dissect_zip_extra_utf8_comment, proto_zip)); |
1365 | 16 | dissector_add_uint("zip.extra", ZIP_EXTRA_UPATH, create_dissector_handle(dissect_zip_extra_utf8_path, proto_zip)); |
1366 | 16 | dissector_add_uint("zip.extra", ZIP_EXTRA_UT, create_dissector_handle(dissect_zip_extra_unix_time, proto_zip)); |
1367 | 16 | dissector_add_uint("zip.extra", ZIP_EXTRA_UNIX2, create_dissector_handle(dissect_zip_extra_unix2, proto_zip)); |
1368 | 16 | dissector_add_uint("zip.extra", ZIP_EXTRA_UNIX3, create_dissector_handle(dissect_zip_extra_unix3, proto_zip)); |
1369 | | |
1370 | | // Register some media types to handle in a generic way |
1371 | 16 | dissector_add_string("media_type", "application/zip", zip_handle); |
1372 | 16 | dissector_add_string("media_type", "application/java-archive", zip_handle); // Unofficial types abound |
1373 | | |
1374 | 16 | dissector_add_string("media_type.suffix", "zip", zip_handle); |
1375 | | |
1376 | | // Register the ZIP heuristic dissector |
1377 | 16 | heur_dissector_add("wtap_file", dissect_zip_heur, "ZIP file", "zip_wtap", proto_zip, HEURISTIC_ENABLE); |
1378 | 16 | } |