Blame


1 5391aec5 2021-08-21 op /*
2 5391aec5 2021-08-21 op * This is free and unencumbered software released into the public domain.
3 5391aec5 2021-08-21 op */
4 5391aec5 2021-08-21 op
5 5391aec5 2021-08-21 op #include <sys/mman.h>
6 5391aec5 2021-08-21 op
7 5391aec5 2021-08-21 op #include <endian.h>
8 5391aec5 2021-08-21 op #include <err.h>
9 5391aec5 2021-08-21 op #include <fcntl.h>
10 5391aec5 2021-08-21 op #include <limits.h>
11 5391aec5 2021-08-21 op #include <stdint.h>
12 5391aec5 2021-08-21 op #include <stdio.h>
13 5391aec5 2021-08-21 op #include <string.h>
14 5391aec5 2021-08-21 op #include <unistd.h>
15 5391aec5 2021-08-21 op #include <zlib.h>
16 5391aec5 2021-08-21 op
17 5391aec5 2021-08-21 op #define MIN(a, b) ((a) < (b) ? (a) : (b))
18 5391aec5 2021-08-21 op
19 5391aec5 2021-08-21 op void *
20 5391aec5 2021-08-21 op find_central_directory(uint8_t *addr, size_t len)
21 5391aec5 2021-08-21 op {
22 5391aec5 2021-08-21 op uint32_t offset;
23 5391aec5 2021-08-21 op uint16_t clen;
24 5391aec5 2021-08-21 op uint8_t *p, *end;
25 5391aec5 2021-08-21 op
26 5391aec5 2021-08-21 op /*
27 5391aec5 2021-08-21 op * At -22 bytes from the end there is the end of the central
28 5391aec5 2021-08-21 op * directory assuming an empty comment. It's a sensible place
29 5391aec5 2021-08-21 op * from which start.
30 5391aec5 2021-08-21 op */
31 5391aec5 2021-08-21 op if (len < 22)
32 5391aec5 2021-08-21 op return NULL;
33 5391aec5 2021-08-21 op end = addr + len;
34 5391aec5 2021-08-21 op p = end - 22;
35 5391aec5 2021-08-21 op
36 5391aec5 2021-08-21 op again:
37 5391aec5 2021-08-21 op for (; p > addr; --p)
38 5391aec5 2021-08-21 op if (memcmp(p, "\x50\x4b\x05\x06", 4) == 0)
39 5391aec5 2021-08-21 op break;
40 5391aec5 2021-08-21 op
41 5391aec5 2021-08-21 op if (p == addr)
42 5391aec5 2021-08-21 op return NULL;
43 5391aec5 2021-08-21 op
44 5391aec5 2021-08-21 op /* read comment length */
45 5391aec5 2021-08-21 op memcpy(&clen, p + 20, sizeof(clen));
46 5391aec5 2021-08-21 op clen = le16toh(clen);
47 5391aec5 2021-08-21 op
48 5391aec5 2021-08-21 op /* false signature inside a comment? */
49 5391aec5 2021-08-21 op if (clen + 22 != end - p) {
50 5391aec5 2021-08-21 op p--;
51 5391aec5 2021-08-21 op goto again;
52 5391aec5 2021-08-21 op }
53 5391aec5 2021-08-21 op
54 5391aec5 2021-08-21 op /* read the offset for the central directory */
55 5391aec5 2021-08-21 op memcpy(&offset, p + 16, sizeof(offset));
56 5391aec5 2021-08-21 op offset = le32toh(offset);
57 5391aec5 2021-08-21 op
58 5391aec5 2021-08-21 op if (addr + offset > p)
59 5391aec5 2021-08-21 op return NULL;
60 5391aec5 2021-08-21 op
61 5391aec5 2021-08-21 op return addr + offset;
62 5391aec5 2021-08-21 op }
63 5391aec5 2021-08-21 op
64 5391aec5 2021-08-21 op void
65 5391aec5 2021-08-21 op ls(uint8_t *zip, size_t len, uint8_t *cd)
66 5391aec5 2021-08-21 op {
67 5391aec5 2021-08-21 op uint16_t flen, xlen, clen;
68 5391aec5 2021-08-21 op uint8_t *end;
69 5391aec5 2021-08-21 op char filename[PATH_MAX];
70 5391aec5 2021-08-21 op
71 5391aec5 2021-08-21 op end = zip + len;
72 5391aec5 2021-08-21 op while (cd < end - 46 && memcmp(cd, "\x50\x4b\x01\x02", 4) == 0) {
73 5391aec5 2021-08-21 op memcpy(&flen, cd + 28, sizeof(flen));
74 5391aec5 2021-08-21 op memcpy(&xlen, cd + 28 + 2, sizeof(xlen));
75 5391aec5 2021-08-21 op memcpy(&clen, cd + 28 + 2 + 2, sizeof(clen));
76 5391aec5 2021-08-21 op
77 5391aec5 2021-08-21 op flen = le16toh(flen);
78 5391aec5 2021-08-21 op xlen = le16toh(xlen);
79 5391aec5 2021-08-21 op clen = le16toh(clen);
80 5391aec5 2021-08-21 op
81 5391aec5 2021-08-21 op memset(filename, 0, sizeof(filename));
82 5391aec5 2021-08-21 op memcpy(filename, cd + 46, MIN(sizeof(filename)-1, flen));
83 5391aec5 2021-08-21 op
84 5391aec5 2021-08-21 op printf("%s\n", filename);
85 5391aec5 2021-08-21 op
86 5391aec5 2021-08-21 op cd += 46 + flen + xlen + clen;
87 5391aec5 2021-08-21 op }
88 5391aec5 2021-08-21 op }
89 5391aec5 2021-08-21 op
90 5391aec5 2021-08-21 op void *
91 5391aec5 2021-08-21 op map_file(int fd, size_t *len)
92 5391aec5 2021-08-21 op {
93 5391aec5 2021-08-21 op off_t jump;
94 5391aec5 2021-08-21 op void *addr;
95 5391aec5 2021-08-21 op
96 5391aec5 2021-08-21 op if ((jump = lseek(fd, 0, SEEK_END)) == -1)
97 5391aec5 2021-08-21 op err(1, "lseek");
98 5391aec5 2021-08-21 op
99 5391aec5 2021-08-21 op if (lseek(fd, 0, SEEK_SET) == -1)
100 5391aec5 2021-08-21 op err(1, "lseek");
101 5391aec5 2021-08-21 op
102 5391aec5 2021-08-21 op if ((addr = mmap(NULL, jump, PROT_READ, MAP_PRIVATE, fd, 0))
103 5391aec5 2021-08-21 op == MAP_FAILED)
104 5391aec5 2021-08-21 op err(1, "mmap");
105 5391aec5 2021-08-21 op
106 5391aec5 2021-08-21 op *len = jump;
107 5391aec5 2021-08-21 op return addr;
108 5391aec5 2021-08-21 op }
109 5391aec5 2021-08-21 op
110 5391aec5 2021-08-21 op int
111 5391aec5 2021-08-21 op main(int argc, char **argv)
112 5391aec5 2021-08-21 op {
113 5391aec5 2021-08-21 op int fd;
114 5391aec5 2021-08-21 op void *zip, *cd;
115 5391aec5 2021-08-21 op size_t len;
116 5391aec5 2021-08-21 op
117 5391aec5 2021-08-21 op if (argc != 2)
118 5391aec5 2021-08-21 op errx(1, "missing file to inspect");
119 5391aec5 2021-08-21 op
120 5391aec5 2021-08-21 op if ((fd = open(argv[1], O_RDONLY)) == -1)
121 5391aec5 2021-08-21 op err(1, "can't open %s", argv[1]);
122 5391aec5 2021-08-21 op
123 5391aec5 2021-08-21 op zip = map_file(fd, &len);
124 5391aec5 2021-08-21 op if ((cd = find_central_directory(zip, len)) == NULL)
125 5391aec5 2021-08-21 op errx(1, "can't find the central directory");
126 5391aec5 2021-08-21 op
127 5391aec5 2021-08-21 op ls(zip, len, cd);
128 5391aec5 2021-08-21 op
129 5391aec5 2021-08-21 op munmap(zip, len);
130 5391aec5 2021-08-21 op close(fd);
131 5391aec5 2021-08-21 op
132 5391aec5 2021-08-21 op return 0;
133 5391aec5 2021-08-21 op }