Finally, due to the multiple possible ways to interpret the content
of a cd/dvd, I cannot guarantee that we scan the "right" files.
... | ... |
@@ -1,3 +1,7 @@ |
1 |
+Mon Nov 14 21:22:26 CET 2011 (acab) |
|
2 |
+----------------------------------- |
|
3 |
+ * libclamav: add preliminary support for iso9660 image files |
|
4 |
+ |
|
1 | 5 |
Fri Nov 4 00:52:21 CET 2011 (acab) |
2 | 6 |
----------------------------------- |
3 | 7 |
* libclamav/pe.c: parse vinfo where varfileinfo occours before stringfileinfo |
... | ... |
@@ -158,8 +158,8 @@ am__libclamav_la_SOURCES_DIST = clamav.h matcher-ac.c matcher-ac.h \ |
158 | 158 |
bytecode_api_decl.c bytecode_api.h bytecode_api_impl.h \ |
159 | 159 |
bytecode_hooks.h cache.c cache.h bytecode_detect.c \ |
160 | 160 |
bytecode_detect.h builtin_bytecodes.h events.c events.h swf.c \ |
161 |
- swf.h jpeg.c jpeg.h png.c png.h arc4.c arc4.h bignum.c \ |
|
162 |
- bignum_class.h |
|
161 |
+ swf.h jpeg.c jpeg.h png.c png.h iso9660.c iso9660.h arc4.c \ |
|
162 |
+ arc4.h bignum.c bignum_class.h |
|
163 | 163 |
@LINK_TOMMATH_FALSE@am__objects_1 = libclamav_la-bignum.lo |
164 | 164 |
am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \ |
165 | 165 |
libclamav_la-matcher-bm.lo libclamav_la-matcher-hash.lo \ |
... | ... |
@@ -212,7 +212,7 @@ am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \ |
212 | 212 |
libclamav_la-bytecode_api_decl.lo libclamav_la-cache.lo \ |
213 | 213 |
libclamav_la-bytecode_detect.lo libclamav_la-events.lo \ |
214 | 214 |
libclamav_la-swf.lo libclamav_la-jpeg.lo libclamav_la-png.lo \ |
215 |
- libclamav_la-arc4.lo $(am__objects_1) |
|
215 |
+ libclamav_la-iso9660.lo libclamav_la-arc4.lo $(am__objects_1) |
|
216 | 216 |
libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS) |
217 | 217 |
AM_V_lt = $(am__v_lt_$(V)) |
218 | 218 |
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) |
... | ... |
@@ -671,7 +671,8 @@ libclamav_la_SOURCES = clamav.h matcher-ac.c matcher-ac.h matcher-bm.c \ |
671 | 671 |
bytecode_api_decl.c bytecode_api.h bytecode_api_impl.h \ |
672 | 672 |
bytecode_hooks.h cache.c cache.h bytecode_detect.c \ |
673 | 673 |
bytecode_detect.h builtin_bytecodes.h events.c events.h swf.c \ |
674 |
- swf.h jpeg.c jpeg.h png.c png.h arc4.c arc4.h $(am__append_7) |
|
674 |
+ swf.h jpeg.c jpeg.h png.c png.h iso9660.c iso9660.h arc4.c \ |
|
675 |
+ arc4.h $(am__append_7) |
|
675 | 676 |
noinst_LTLIBRARIES = libclamav_internal_utils.la libclamav_internal_utils_nothreads.la libclamav_nocxx.la |
676 | 677 |
COMMON_CLEANFILES = version.h version.h.tmp *.gcda *.gcno |
677 | 678 |
@MAINTAINER_MODE_TRUE@BUILT_SOURCES = jsparse/generated/operators.h jsparse/generated/keywords.h jsparse-keywords.gperf |
... | ... |
@@ -840,6 +841,7 @@ distclean-compile: |
840 | 840 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-inflate64.Plo@am__quote@ |
841 | 841 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-is_tar.Plo@am__quote@ |
842 | 842 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-ishield.Plo@am__quote@ |
843 |
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-iso9660.Plo@am__quote@ |
|
843 | 844 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-jpeg.Plo@am__quote@ |
844 | 845 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-js-norm.Plo@am__quote@ |
845 | 846 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-line.Plo@am__quote@ |
... | ... |
@@ -1763,6 +1765,14 @@ libclamav_la-png.lo: png.c |
1763 | 1763 |
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
1764 | 1764 |
@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-png.lo `test -f 'png.c' || echo '$(srcdir)/'`png.c |
1765 | 1765 |
|
1766 |
+libclamav_la-iso9660.lo: iso9660.c |
|
1767 |
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-iso9660.lo -MD -MP -MF $(DEPDIR)/libclamav_la-iso9660.Tpo -c -o libclamav_la-iso9660.lo `test -f 'iso9660.c' || echo '$(srcdir)/'`iso9660.c |
|
1768 |
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-iso9660.Tpo $(DEPDIR)/libclamav_la-iso9660.Plo |
|
1769 |
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ |
|
1770 |
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='iso9660.c' object='libclamav_la-iso9660.lo' libtool=yes @AMDEPBACKSLASH@ |
|
1771 |
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
1772 |
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-iso9660.lo `test -f 'iso9660.c' || echo '$(srcdir)/'`iso9660.c |
|
1773 |
+ |
|
1766 | 1774 |
libclamav_la-arc4.lo: arc4.c |
1767 | 1775 |
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-arc4.lo -MD -MP -MF $(DEPDIR)/libclamav_la-arc4.Tpo -c -o libclamav_la-arc4.lo `test -f 'arc4.c' || echo '$(srcdir)/'`arc4.c |
1768 | 1776 |
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-arc4.Tpo $(DEPDIR)/libclamav_la-arc4.Plo |
... | ... |
@@ -92,6 +92,7 @@ static struct dconf_module modules[] = { |
92 | 92 |
{ "ARCHIVE", "AUTOIT", ARCH_CONF_AUTOIT, 1 }, |
93 | 93 |
{ "ARCHIVE", "ISHIELD", ARCH_CONF_ISHIELD, 1 }, |
94 | 94 |
{ "ARCHIVE", "7zip", ARCH_CONF_7Z, 1 }, |
95 |
+ { "ARCHIVE", "ISO9660", ARCH_CONF_ISO9660, 1 }, |
|
95 | 96 |
|
96 | 97 |
{ "DOCUMENT", "HTML", DOC_CONF_HTML, 1 }, |
97 | 98 |
{ "DOCUMENT", "RTF", DOC_CONF_RTF, 1 }, |
... | ... |
@@ -165,6 +165,7 @@ static const char *ftypes_int[] = { |
165 | 165 |
"0:0:53514c69746520666f726d6174203300:SQLite database:CL_TYPE_ANY:CL_TYPE_IGNORED", |
166 | 166 |
"0:0:d9d505f920a163d7:SQLite journal:CL_TYPE_ANY:CL_TYPE_IGNORED", |
167 | 167 |
"0:0:ffd9ffd8:JPEG (bad header):CL_TYPE_ANY:CL_TYPE_GRAPHICS:70", |
168 |
+ "1:*:014344303031{2043-2443}4344303031:ISO9660:CL_TYPE_ANY:CL_TYPE_ISO9660:71", |
|
168 | 169 |
NULL |
169 | 170 |
}; |
170 | 171 |
|
171 | 172 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,319 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2011 Sourcefire, Inc. |
|
2 |
+ * |
|
3 |
+ * Authors: aCaB <acab@clamav.net> |
|
4 |
+ * |
|
5 |
+ * This program is free software; you can redistribute it and/or modify |
|
6 |
+ * it under the terms of the GNU General Public License version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#include <string.h> |
|
21 |
+#include "scanners.h" |
|
22 |
+#include "iso9660.h" |
|
23 |
+#include "fmap.h" |
|
24 |
+#include "str.h" |
|
25 |
+#include "hashtab.h" |
|
26 |
+ |
|
27 |
+typedef struct { |
|
28 |
+ cli_ctx *ctx; |
|
29 |
+ size_t base_offset; |
|
30 |
+ unsigned int blocksz; |
|
31 |
+ unsigned int sectsz; |
|
32 |
+ unsigned int fileno; |
|
33 |
+ unsigned int joliet; |
|
34 |
+ char buf[260]; |
|
35 |
+ struct cli_hashset dir_blocks; |
|
36 |
+} iso9660_t; |
|
37 |
+ |
|
38 |
+ |
|
39 |
+static void *needblock(const iso9660_t *iso, unsigned int block, int temp) { |
|
40 |
+ cli_ctx *ctx = iso->ctx; |
|
41 |
+ size_t loff; |
|
42 |
+ unsigned int blocks_per_sect = (2048 / iso->blocksz); |
|
43 |
+ if(block > (((*ctx->fmap)->len - iso->base_offset) / iso->sectsz) * blocks_per_sect) |
|
44 |
+ return NULL; /* Block is out of file */ |
|
45 |
+ loff = (block / blocks_per_sect) * iso->sectsz; /* logical sector */ |
|
46 |
+ loff += (block % blocks_per_sect) * iso->blocksz; /* logical block within the secotor */ |
|
47 |
+ if(temp) |
|
48 |
+ return fmap_need_off_once(*ctx->fmap, iso->base_offset + loff, iso->blocksz); |
|
49 |
+ return fmap_need_off(*ctx->fmap, iso->base_offset + loff, iso->blocksz); |
|
50 |
+} |
|
51 |
+ |
|
52 |
+ |
|
53 |
+static int iso_scan_file(const iso9660_t *iso, unsigned int block, unsigned int len) { |
|
54 |
+ char *tmpf; |
|
55 |
+ int fd, ret; |
|
56 |
+ if(cli_gentempfd(NULL, &tmpf, &fd) != CL_SUCCESS) |
|
57 |
+ return CL_ETMPFILE; |
|
58 |
+ |
|
59 |
+ cli_dbgmsg("iso_scan_file: dumping to %s\n", tmpf); |
|
60 |
+ while(len) { |
|
61 |
+ void *buf = needblock(iso, block, 1); |
|
62 |
+ if(cli_writen(fd, buf, iso->blocksz) != iso->blocksz) { |
|
63 |
+ close(fd); |
|
64 |
+ ret = cli_unlink(tmpf); |
|
65 |
+ free(tmpf); |
|
66 |
+ if(ret) |
|
67 |
+ return CL_EUNLINK; |
|
68 |
+ return CL_EWRITE; |
|
69 |
+ } |
|
70 |
+ len -= MIN(len, iso->blocksz); |
|
71 |
+ block++; |
|
72 |
+ } |
|
73 |
+ |
|
74 |
+ ret = cli_magic_scandesc(fd, iso->ctx); |
|
75 |
+ |
|
76 |
+ close(fd); |
|
77 |
+ |
|
78 |
+ if(!iso->ctx->engine->keeptmp) { |
|
79 |
+ if(cli_unlink(tmpf)) { |
|
80 |
+ free(tmpf); |
|
81 |
+ return CL_EUNLINK; |
|
82 |
+ } |
|
83 |
+ } |
|
84 |
+ |
|
85 |
+ free(tmpf); |
|
86 |
+ return ret; |
|
87 |
+} |
|
88 |
+ |
|
89 |
+static char *iso_string(iso9660_t *iso, void *src, unsigned int len) { |
|
90 |
+ if(iso->joliet) { |
|
91 |
+ char *utf8; |
|
92 |
+ if(len > sizeof(iso->buf)) |
|
93 |
+ len = sizeof(iso->buf) - 2; |
|
94 |
+ memcpy(iso->buf, src, len); |
|
95 |
+ iso->buf[len] = '\0'; |
|
96 |
+ iso->buf[len+1] = '\0'; |
|
97 |
+ utf8 = cli_utf16_to_utf8(iso->buf, len, UTF16_BE); |
|
98 |
+ if(!utf8) |
|
99 |
+ utf8 = ""; |
|
100 |
+ strncpy(iso->buf, utf8, sizeof(iso->buf)); |
|
101 |
+ iso->buf[sizeof(iso->buf)-1] = '\0'; |
|
102 |
+ free(utf8); |
|
103 |
+ } else { |
|
104 |
+ memcpy(iso->buf, src, len); |
|
105 |
+ iso->buf[len] = '\0'; |
|
106 |
+ } |
|
107 |
+ return iso->buf; |
|
108 |
+} |
|
109 |
+ |
|
110 |
+ |
|
111 |
+static int iso_parse_dir(iso9660_t *iso, unsigned int block, unsigned int len) { |
|
112 |
+ cli_ctx *ctx = iso->ctx; |
|
113 |
+ int ret = CL_CLEAN; |
|
114 |
+ |
|
115 |
+ if(len < 34) { |
|
116 |
+ cli_dbgmsg("iso_parse_dir: Directory too small, skipping\n"); |
|
117 |
+ return CL_CLEAN; |
|
118 |
+ } |
|
119 |
+ |
|
120 |
+ for(; len && ret == CL_CLEAN; block++, len -= MIN(len, iso->blocksz)) { |
|
121 |
+ uint8_t *dir, *dir_orig; |
|
122 |
+ unsigned int dirsz; |
|
123 |
+ |
|
124 |
+ if(iso->dir_blocks.count > 1024) { |
|
125 |
+ cli_dbgmsg("iso_parse_dir: Breaking out due to too many dir records\n"); |
|
126 |
+ return CL_BREAK; |
|
127 |
+ } |
|
128 |
+ |
|
129 |
+ if(cli_hashset_contains(&iso->dir_blocks, block)) |
|
130 |
+ continue; |
|
131 |
+ |
|
132 |
+ if((ret = cli_hashset_addkey(&iso->dir_blocks, block)) != CL_CLEAN) |
|
133 |
+ return ret; |
|
134 |
+ |
|
135 |
+ dir = dir_orig = needblock(iso, block, 0); |
|
136 |
+ if(!dir) |
|
137 |
+ return CL_CLEAN; |
|
138 |
+ |
|
139 |
+ for(dirsz = MIN(iso->blocksz, len);;) { |
|
140 |
+ unsigned int entrysz = *dir, fileoff, filesz; |
|
141 |
+ char *sep; |
|
142 |
+ |
|
143 |
+ if(!dirsz || !entrysz) /* continuing on next block, if any */ |
|
144 |
+ break; |
|
145 |
+ if(entrysz > dirsz) { /* record size overlaps onto the next sector, no point in looking in there */ |
|
146 |
+ cli_dbgmsg("iso_parse_dir: Directory entry overflow, breaking out %u %u\n", entrysz, dirsz); |
|
147 |
+ len = 0; |
|
148 |
+ break; |
|
149 |
+ } |
|
150 |
+ if(entrysz < 34) { /* this shouldn't happen really*/ |
|
151 |
+ cli_dbgmsg("iso_parse_dir: Too short directory entry, attempting to skip\n"); |
|
152 |
+ dirsz -= entrysz; |
|
153 |
+ dir += entrysz; |
|
154 |
+ continue; |
|
155 |
+ } |
|
156 |
+ filesz = dir[32]; |
|
157 |
+ if(filesz == 1 && (dir[33] == 0 || dir[33] == 1)) { /* skip "." and ".." */ |
|
158 |
+ dirsz -= entrysz; |
|
159 |
+ dir += entrysz; |
|
160 |
+ continue; |
|
161 |
+ } |
|
162 |
+ |
|
163 |
+ if(filesz + 33 > dirsz) { |
|
164 |
+ cli_dbgmsg("iso_parse_dir: Directory entry name overflow, clamping\n"); |
|
165 |
+ filesz = dirsz - 33; |
|
166 |
+ } |
|
167 |
+ iso_string(iso, &dir[33], filesz); |
|
168 |
+ sep = memchr(iso->buf, ';', filesz); |
|
169 |
+ if(sep) |
|
170 |
+ *sep = '\0'; |
|
171 |
+ else |
|
172 |
+ iso->buf[filesz] = '\0'; |
|
173 |
+ fileoff = cli_readint32(dir+2); |
|
174 |
+ fileoff += dir[1]; |
|
175 |
+ filesz = cli_readint32(dir+10); |
|
176 |
+ |
|
177 |
+ cli_dbgmsg("iso_parse_dir: %s '%s': off %x - size %x - flags %x - unit size %x - gap size %x - volume %u\n", (dir[25] & 2) ? "Directory" : "File", iso->buf, fileoff, filesz, dir[25], dir[26], dir[27], cli_readint32(&dir[28]) & 0xffff); |
|
178 |
+ if(cli_matchmeta(ctx, iso->buf, filesz, filesz, 0, 0, 0, NULL) == CL_VIRUS) { |
|
179 |
+ ret = CL_VIRUS; |
|
180 |
+ break; |
|
181 |
+ } |
|
182 |
+ |
|
183 |
+ if(dir[26] || dir[27]) |
|
184 |
+ cli_dbgmsg("iso_parse_dir: Skipping interleaved file\n"); |
|
185 |
+ else { |
|
186 |
+ /* TODO Handle multi-extent ? */ |
|
187 |
+ if(dir[25] & 2) { |
|
188 |
+ ret = iso_parse_dir(iso, fileoff, filesz); |
|
189 |
+ } else { |
|
190 |
+ if(cli_checklimits("ISO9660", ctx, filesz, 0, 0) != CL_SUCCESS) |
|
191 |
+ cli_dbgmsg("iso_parse_dir: Skipping overlimit file\n"); |
|
192 |
+ else |
|
193 |
+ ret = iso_scan_file(iso, fileoff, filesz); |
|
194 |
+ } |
|
195 |
+ } |
|
196 |
+ dirsz -= entrysz; |
|
197 |
+ dir += entrysz; |
|
198 |
+ } |
|
199 |
+ |
|
200 |
+ fmap_unneed_ptr(*ctx->fmap, dir_orig, iso->blocksz); |
|
201 |
+ } |
|
202 |
+ return ret; |
|
203 |
+} |
|
204 |
+ |
|
205 |
+int cli_scaniso(cli_ctx *ctx, size_t offset) { |
|
206 |
+ uint8_t *privol, *next; |
|
207 |
+ iso9660_t iso; |
|
208 |
+ int i; |
|
209 |
+ |
|
210 |
+ if(offset < 32768) |
|
211 |
+ return CL_CLEAN; /* Need 16 sectors at least 2048 bytes long */ |
|
212 |
+ |
|
213 |
+ privol = fmap_need_off(*ctx->fmap, offset, 2448 + 6); |
|
214 |
+ if(!privol) |
|
215 |
+ return CL_CLEAN; |
|
216 |
+ |
|
217 |
+ next = (uint8_t *)cli_memstr((char *)privol + 2049, 2448 + 6 - 2049, "CD001", 5); |
|
218 |
+ if(!next) |
|
219 |
+ return CL_CLEAN; /* Find next volume descriptor */ |
|
220 |
+ |
|
221 |
+ iso.sectsz = (next - privol) - 1; |
|
222 |
+ if(iso.sectsz * 16 > offset) |
|
223 |
+ return CL_CLEAN; /* Need room for 16 system sectors */ |
|
224 |
+ |
|
225 |
+ iso.blocksz = cli_readint32(privol+128) & 0xffff; |
|
226 |
+ if(iso.blocksz != 512 && iso.blocksz != 1024 && iso.blocksz != 2048) |
|
227 |
+ return CL_CLEAN; /* Likely not a cdrom image */ |
|
228 |
+ |
|
229 |
+ iso.base_offset = offset - iso.sectsz * 16; |
|
230 |
+ iso.joliet = 0; |
|
231 |
+ |
|
232 |
+ for(i=16; i<32 ;i++) { /* scan for a joliet secondary volume descriptor */ |
|
233 |
+ next = fmap_need_off_once(*ctx->fmap, iso.base_offset + i * iso.sectsz, 2048); |
|
234 |
+ if(!next) |
|
235 |
+ break; /* Out of disk */ |
|
236 |
+ if(*next == 0xff || memcmp(next+1, "CD001", 5)) |
|
237 |
+ break; /* Not a volume descriptor */ |
|
238 |
+ if(*next != 2) |
|
239 |
+ continue; /* Not a secondary volume descriptor */ |
|
240 |
+ if(next[88] != 0x25 || next[89] != 0x2f) |
|
241 |
+ continue; /* Not a joliet descriptor */ |
|
242 |
+ if(next[156+26] || next[156+27]) |
|
243 |
+ continue; /* Root is interleaved so we fallback to the primary descriptor */ |
|
244 |
+ switch(next[90]) { |
|
245 |
+ case 0x40: /* Level 1 */ |
|
246 |
+ iso.joliet = 1; |
|
247 |
+ break; |
|
248 |
+ case 0x43: /* Level 2 */ |
|
249 |
+ iso.joliet = 2; |
|
250 |
+ break; |
|
251 |
+ case 0x45: /* Level 3 */ |
|
252 |
+ iso.joliet = 3; |
|
253 |
+ break; |
|
254 |
+ default: /* Not Joliet */ |
|
255 |
+ continue; |
|
256 |
+ } |
|
257 |
+ break; |
|
258 |
+ } |
|
259 |
+ |
|
260 |
+ /* TODO rr, el torito, udf ? */ |
|
261 |
+ |
|
262 |
+ /* NOTE: freeing sector now. it is still safe to access as we don't alloc anymore */ |
|
263 |
+ fmap_unneed_off(*ctx->fmap, offset, 2448); |
|
264 |
+ if(iso.joliet) |
|
265 |
+ privol = next; |
|
266 |
+ |
|
267 |
+ cli_dbgmsg("in cli_scaniso\n"); |
|
268 |
+ if(cli_debug_flag) { |
|
269 |
+ cli_dbgmsg("cli_scaniso: Raw sector size: %u\n", iso.sectsz); |
|
270 |
+ cli_dbgmsg("cli_scaniso: Block size: %u\n", iso.blocksz); |
|
271 |
+ |
|
272 |
+ cli_dbgmsg("cli_scaniso: Volume descriptor version: %u\n", privol[6]); |
|
273 |
+ |
|
274 |
+#define ISOSTRING(src, len) iso_string(&iso, (src), (len)) |
|
275 |
+ cli_dbgmsg("cli_scaniso: System: %s\n", ISOSTRING(privol + 8, 32)); |
|
276 |
+ cli_dbgmsg("cli_scaniso: Volume: %s\n", ISOSTRING(privol + 40, 32)); |
|
277 |
+ |
|
278 |
+ cli_dbgmsg("cli_scaniso: Volume space size: 0x%x blocks\n", cli_readint32(&privol[80])); |
|
279 |
+ cli_dbgmsg("cli_scaniso: Volume %u of %u\n", cli_readint32(privol+124) & 0xffff, cli_readint32(privol+120) & 0xffff); |
|
280 |
+ |
|
281 |
+ cli_dbgmsg("cli_scaniso: Volume Set: %s\n", ISOSTRING(privol + 190, 128)); |
|
282 |
+ cli_dbgmsg("cli_scaniso: Publisher: %s\n", ISOSTRING(privol + 318, 128)); |
|
283 |
+ cli_dbgmsg("cli_scaniso: Data Preparer: %s\n", ISOSTRING(privol + 446, 128)); |
|
284 |
+ cli_dbgmsg("cli_scaniso: Application: %s\n", ISOSTRING(privol + 574, 128)); |
|
285 |
+ |
|
286 |
+#define ISOTIME(s,n) cli_dbgmsg("cli_scaniso: "s": %c%c%c%c-%c%c-%c%c %c%c:%c%c:%c%c\n", privol[n],privol[n+1],privol[n+2],privol[n+3], privol[n+4],privol[n+5], privol[n+6],privol[n+7], privol[n+8],privol[n+9], privol[n+10],privol[n+11], privol[n+12],privol[n+13]) |
|
287 |
+ ISOTIME("Volume creation time",813); |
|
288 |
+ ISOTIME("Volume modification time",830); |
|
289 |
+ ISOTIME("Volume expiration time",847); |
|
290 |
+ ISOTIME("Volume effective time",864); |
|
291 |
+ |
|
292 |
+ cli_dbgmsg("cli_scaniso: Path table size: 0x%x\n", cli_readint32(privol+132) & 0xffff); |
|
293 |
+ cli_dbgmsg("cli_scaniso: LSB Path Table: 0x%x\n", cli_readint32(privol+140)); |
|
294 |
+ cli_dbgmsg("cli_scaniso: Opt LSB Path Table: 0x%x\n", cli_readint32(privol+144)); |
|
295 |
+ cli_dbgmsg("cli_scaniso: MSB Path Table: 0x%x\n", cbswap32(cli_readint32(privol+148))); |
|
296 |
+ cli_dbgmsg("cli_scaniso: Opt MSB Path Table: 0x%x\n", cbswap32(cli_readint32(privol+152))); |
|
297 |
+ cli_dbgmsg("cli_scaniso: File Structure Version: %u\n", privol[881]); |
|
298 |
+ |
|
299 |
+ if(iso.joliet) |
|
300 |
+ cli_dbgmsg("cli_scaniso: Joliet level %u\n", iso.joliet); |
|
301 |
+ } |
|
302 |
+ |
|
303 |
+ if(privol[156+26] || privol[156+27]) { |
|
304 |
+ cli_dbgmsg("cli_scaniso: Interleaved root directory is not supported\n"); |
|
305 |
+ return CL_CLEAN; |
|
306 |
+ } |
|
307 |
+ |
|
308 |
+ iso.ctx = ctx; |
|
309 |
+ i = cli_hashset_init(&iso.dir_blocks, 1024, 80); |
|
310 |
+ if(i != CL_SUCCESS) |
|
311 |
+ return i; |
|
312 |
+ i = iso_parse_dir(&iso, cli_readint32(privol+156+2) + privol[156+1], cli_readint32(privol+156+10)); |
|
313 |
+ cli_hashset_destroy(&iso.dir_blocks); |
|
314 |
+ if(i == CL_BREAK) |
|
315 |
+ return CL_CLEAN; |
|
316 |
+ return i; |
|
317 |
+} |
|
318 |
+ |
0 | 319 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,28 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2011 Sourcefire, Inc. |
|
2 |
+ * |
|
3 |
+ * Authors: aCaB <acab@clamav.net> |
|
4 |
+ * |
|
5 |
+ * This program is free software; you can redistribute it and/or modify |
|
6 |
+ * it under the terms of the GNU General Public License version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#ifndef __ISO9660_H |
|
21 |
+#define __ISO9660_H |
|
22 |
+ |
|
23 |
+#include "others.h" |
|
24 |
+ |
|
25 |
+int cli_scaniso(cli_ctx *ctx, size_t offset); |
|
26 |
+ |
|
27 |
+#endif |
... | ... |
@@ -93,6 +93,7 @@ |
93 | 93 |
#include "swf.h" |
94 | 94 |
#include "jpeg.h" |
95 | 95 |
#include "png.h" |
96 |
+#include "iso9660.h" |
|
96 | 97 |
|
97 | 98 |
#ifdef HAVE_BZLIB_H |
98 | 99 |
#include <bzlib.h> |
... | ... |
@@ -1879,7 +1880,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_ |
1879 | 1879 |
{ |
1880 | 1880 |
int ret = CL_CLEAN, nret = CL_CLEAN; |
1881 | 1881 |
struct cli_matched_type *ftoffset = NULL, *fpt; |
1882 |
- uint32_t lastzip, lastrar; |
|
1882 |
+ uint32_t lastrar; |
|
1883 | 1883 |
struct cli_exe_info peinfo; |
1884 | 1884 |
unsigned int acmode = AC_SCAN_VIR, break_loop = 0; |
1885 | 1885 |
fmap_t *map = *ctx->fmap; |
... | ... |
@@ -1901,7 +1902,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_ |
1901 | 1901 |
perf_nested_start(ctx, PERFT_RAWTYPENO, PERFT_SCAN); |
1902 | 1902 |
ctx->recursion++; |
1903 | 1903 |
if(nret != CL_VIRUS) { |
1904 |
- lastzip = lastrar = 0xdeadbeef; |
|
1904 |
+ lastrar = 0xdeadbeef; |
|
1905 | 1905 |
fpt = ftoffset; |
1906 | 1906 |
while(fpt) { |
1907 | 1907 |
if(fpt->offset) switch(fpt->type) { |
... | ... |
@@ -1940,6 +1941,15 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_ |
1940 | 1940 |
} |
1941 | 1941 |
break; |
1942 | 1942 |
|
1943 |
+ case CL_TYPE_ISO9660: |
|
1944 |
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ISO9660)) { |
|
1945 |
+ ctx->container_type = CL_TYPE_ISO9660; |
|
1946 |
+ ctx->container_size = map->len - fpt->offset; /* not precise */ |
|
1947 |
+ cli_dbgmsg("ISO9660 signature found at %u\n", (unsigned int) fpt->offset); |
|
1948 |
+ nret = cli_scaniso(ctx, fpt->offset); |
|
1949 |
+ } |
|
1950 |
+ break; |
|
1951 |
+ |
|
1943 | 1952 |
case CL_TYPE_NULSFT: |
1944 | 1953 |
if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) && fpt->offset > 4) { |
1945 | 1954 |
ctx->container_type = CL_TYPE_NULSFT; |
... | ... |
@@ -592,3 +592,73 @@ int cli_hexnibbles(char *str, int len) |
592 | 592 |
} |
593 | 593 |
return 0; |
594 | 594 |
} |
595 |
+ |
|
596 |
+char *cli_utf16_to_utf8(const char *utf16, size_t length, utf16_type type) |
|
597 |
+{ |
|
598 |
+ /* utf8 - |
|
599 |
+ * 4 bytes for utf16 high+low surrogate (4 bytes input) |
|
600 |
+ * 3 bytes for utf16 otherwise (2 bytes input) */ |
|
601 |
+ size_t i, j; |
|
602 |
+ size_t needed = length * 3/2 + 2; |
|
603 |
+ char *s2; |
|
604 |
+ |
|
605 |
+ if (length < 2) |
|
606 |
+ return cli_strdup(""); |
|
607 |
+ if (length % 2) { |
|
608 |
+ cli_warnmsg("utf16 length is not multiple of two: %lu\n", (long)length); |
|
609 |
+ length--; |
|
610 |
+ } |
|
611 |
+ |
|
612 |
+ s2 = cli_malloc(needed); |
|
613 |
+ if (!s2) |
|
614 |
+ return NULL; |
|
615 |
+ |
|
616 |
+ i = 0; |
|
617 |
+ |
|
618 |
+ if((utf16[0] == '\xff' && utf16[1] == '\xfe') || (utf16[0] == '\xfe' && utf16[1] == '\xff')) { |
|
619 |
+ i += 2; |
|
620 |
+ if(type == UTF16_BOM) |
|
621 |
+ type = (utf16[0] == '\xff') ? UTF16_LE : UTF16_BE; |
|
622 |
+ } else if(type == UTF16_BOM) |
|
623 |
+ type = UTF16_BE; |
|
624 |
+ |
|
625 |
+ for (j=0;i<length && j<needed;i += 2) { |
|
626 |
+ uint16_t c = cli_readint16(&utf16[i]); |
|
627 |
+ if(type == UTF16_BE) |
|
628 |
+ c = cbswap16(c); |
|
629 |
+ if (c < 0x80) { |
|
630 |
+ s2[j++] = c; |
|
631 |
+ } else if (c < 0x800) { |
|
632 |
+ s2[j] = 0xc0 | (c >>6); |
|
633 |
+ s2[j+1] = 0x80 | (c&0x3f); |
|
634 |
+ j += 2; |
|
635 |
+ } else if (c < 0xd800 || c >= 0xe000) { |
|
636 |
+ s2[j] = 0xe0 | (c >> 12); |
|
637 |
+ s2[j+1] = 0x80 | ((c >> 6) & 0x3f); |
|
638 |
+ s2[j+2] = 0x80 | (c & 0x3f); |
|
639 |
+ j += 3; |
|
640 |
+ } else if (c < 0xdc00 && i+3 < length) { |
|
641 |
+ uint16_t c2; |
|
642 |
+ /* UTF16 high+low surrogate */ |
|
643 |
+ c = c - 0xd800 + 0x40; |
|
644 |
+ c2 = i+3 < length ? cli_readint16(&utf16[i+2]) : 0; |
|
645 |
+ c2 -= 0xdc00; |
|
646 |
+ s2[j] = 0xf0 | (c >> 8); |
|
647 |
+ s2[j+1] = 0x80 | ((c >> 2) & 0x3f); |
|
648 |
+ s2[j+2] = 0x80 | ((c&3) << 4) | (c2 >> 6); |
|
649 |
+ s2[j+3] = 0x80 | (c2 & 0x3f); |
|
650 |
+ j += 4; |
|
651 |
+ i += 2; |
|
652 |
+ } else { |
|
653 |
+ cli_dbgmsg("UTF16 surrogate encountered at wrong pos\n"); |
|
654 |
+ /* invalid char */ |
|
655 |
+ s2[j++] = 0xef; |
|
656 |
+ s2[j++] = 0xbf; |
|
657 |
+ s2[j++] = 0xbd; |
|
658 |
+ } |
|
659 |
+ } |
|
660 |
+ if (j >= needed) |
|
661 |
+ j = needed-1; |
|
662 |
+ s2[j] = '\0'; |
|
663 |
+ return s2; |
|
664 |
+} |
... | ... |
@@ -51,4 +51,11 @@ struct text_buffer; |
51 | 51 |
int cli_textbuffer_append_normalize(struct text_buffer *buf, const char *str, size_t len); |
52 | 52 |
int cli_hexnibbles(char *str, int len); |
53 | 53 |
|
54 |
+typedef enum { |
|
55 |
+ UTF16_BE, /* Force big endian */ |
|
56 |
+ UTF16_LE, /* Force little endian */ |
|
57 |
+ UTF16_BOM /* Use BOM if available otherwise assume big endian */ |
|
58 |
+} utf16_type; |
|
59 |
+char *cli_utf16_to_utf8(const char *utf16, size_t length, utf16_type type); |
|
60 |
+ |
|
54 | 61 |
#endif |