... | ... |
@@ -303,8 +303,9 @@ am__libclamav_la_SOURCES_DIST = matcher-ac.c matcher-ac.h matcher-bm.c \ |
303 | 303 |
msdoc.h matcher-pcre.c matcher-pcre.h regex_pcre.c \ |
304 | 304 |
regex_pcre.h msxml.c msxml.h msxml_parser.c msxml_parser.h \ |
305 | 305 |
tiff.c tiff.h hwp.c hwp.h lzw/lzwdec.c lzw/lzwdec.h \ |
306 |
- yara_arena.c yara_arena.h yara_compiler.c yara_compiler.h \ |
|
307 |
- yara_exec.c yara_exec.h yara_hash.c yara_hash.h yara_grammar.y \ |
|
306 |
+ matcher-byte-comp.c matcher-byte-comp.h yara_arena.c \ |
|
307 |
+ yara_arena.h yara_compiler.c yara_compiler.h yara_exec.c \ |
|
308 |
+ yara_exec.h yara_hash.c yara_hash.h yara_grammar.y \ |
|
308 | 309 |
yara_lexer.l yara_lexer.h yara_parser.c yara_parser.h \ |
309 | 310 |
yara_clam.h bignum.h bignum_fast.h \ |
310 | 311 |
tomsfastmath/addsub/fp_add.c tomsfastmath/addsub/fp_add_d.c \ |
... | ... |
@@ -445,7 +446,8 @@ am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \ |
445 | 445 |
libclamav_la-msdoc.lo libclamav_la-matcher-pcre.lo \ |
446 | 446 |
libclamav_la-regex_pcre.lo libclamav_la-msxml.lo \ |
447 | 447 |
libclamav_la-msxml_parser.lo libclamav_la-tiff.lo \ |
448 |
- libclamav_la-hwp.lo libclamav_la-lzwdec.lo $(am__objects_1) \ |
|
448 |
+ libclamav_la-hwp.lo libclamav_la-lzwdec.lo \ |
|
449 |
+ libclamav_la-matcher-byte-comp.lo $(am__objects_1) \ |
|
449 | 450 |
libclamav_la-fp_add.lo libclamav_la-fp_add_d.lo \ |
450 | 451 |
libclamav_la-fp_addmod.lo libclamav_la-fp_cmp.lo \ |
451 | 452 |
libclamav_la-fp_cmp_d.lo libclamav_la-fp_cmp_mag.lo \ |
... | ... |
@@ -1341,7 +1343,8 @@ libclamav_la_SOURCES = matcher-ac.c matcher-ac.h matcher-bm.c \ |
1341 | 1341 |
openioc.h msdoc.c msdoc.h matcher-pcre.c matcher-pcre.h \ |
1342 | 1342 |
regex_pcre.c regex_pcre.h msxml.c msxml.h msxml_parser.c \ |
1343 | 1343 |
msxml_parser.h tiff.c tiff.h hwp.c hwp.h lzw/lzwdec.c \ |
1344 |
- lzw/lzwdec.h $(am__append_9) bignum.h bignum_fast.h \ |
|
1344 |
+ lzw/lzwdec.h matcher-byte-comp.c matcher-byte-comp.h \ |
|
1345 |
+ $(am__append_9) bignum.h bignum_fast.h \ |
|
1345 | 1346 |
tomsfastmath/addsub/fp_add.c tomsfastmath/addsub/fp_add_d.c \ |
1346 | 1347 |
tomsfastmath/addsub/fp_addmod.c tomsfastmath/addsub/fp_cmp.c \ |
1347 | 1348 |
tomsfastmath/addsub/fp_cmp_d.c \ |
... | ... |
@@ -1702,6 +1705,7 @@ distclean-compile: |
1702 | 1702 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-macho.Plo@am__quote@ |
1703 | 1703 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher-ac.Plo@am__quote@ |
1704 | 1704 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher-bm.Plo@am__quote@ |
1705 |
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher-byte-comp.Plo@am__quote@ |
|
1705 | 1706 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher-hash.Plo@am__quote@ |
1706 | 1707 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher-pcre.Plo@am__quote@ |
1707 | 1708 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-matcher.Plo@am__quote@ |
... | ... |
@@ -2882,6 +2886,13 @@ libclamav_la-lzwdec.lo: lzw/lzwdec.c |
2882 | 2882 |
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
2883 | 2883 |
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(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-lzwdec.lo `test -f 'lzw/lzwdec.c' || echo '$(srcdir)/'`lzw/lzwdec.c |
2884 | 2884 |
|
2885 |
+libclamav_la-matcher-byte-comp.lo: matcher-byte-comp.c |
|
2886 |
+@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-matcher-byte-comp.lo -MD -MP -MF $(DEPDIR)/libclamav_la-matcher-byte-comp.Tpo -c -o libclamav_la-matcher-byte-comp.lo `test -f 'matcher-byte-comp.c' || echo '$(srcdir)/'`matcher-byte-comp.c |
|
2887 |
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-matcher-byte-comp.Tpo $(DEPDIR)/libclamav_la-matcher-byte-comp.Plo |
|
2888 |
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='matcher-byte-comp.c' object='libclamav_la-matcher-byte-comp.lo' libtool=yes @AMDEPBACKSLASH@ |
|
2889 |
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
2890 |
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(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-matcher-byte-comp.lo `test -f 'matcher-byte-comp.c' || echo '$(srcdir)/'`matcher-byte-comp.c |
|
2891 |
+ |
|
2885 | 2892 |
libclamav_la-yara_arena.lo: yara_arena.c |
2886 | 2893 |
@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-yara_arena.lo -MD -MP -MF $(DEPDIR)/libclamav_la-yara_arena.Tpo -c -o libclamav_la-yara_arena.lo `test -f 'yara_arena.c' || echo '$(srcdir)/'`yara_arena.c |
2887 | 2894 |
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-yara_arena.Tpo $(DEPDIR)/libclamav_la-yara_arena.Plo |
2888 | 2895 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,524 @@ |
0 |
+/* |
|
1 |
+ * Byte comparison matcher support functions |
|
2 |
+ * |
|
3 |
+ * Copyright (C) 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
4 |
+ * All Rights Reserved. |
|
5 |
+ * |
|
6 |
+ * Authors: Mickey Sola |
|
7 |
+ * |
|
8 |
+ * This program is free software; you can redistribute it and/or modify |
|
9 |
+ * it under the terms of the GNU General Public License version 2 as |
|
10 |
+ * published by the Free Software Foundation. |
|
11 |
+ * |
|
12 |
+ * This program is distributed in the hope that it will be useful, |
|
13 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
15 |
+ * GNU General Public License for more details. |
|
16 |
+ * |
|
17 |
+ * You should have received a copy of the GNU General Public License |
|
18 |
+ * along with this program; if not, write to the Free Software |
|
19 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
20 |
+ * MA 02110-1301, USA. |
|
21 |
+ */ |
|
22 |
+ |
|
23 |
+#if HAVE_CONFIG_H |
|
24 |
+#include "clamav-config.h" |
|
25 |
+#endif |
|
26 |
+ |
|
27 |
+#include "clamav.h" |
|
28 |
+#include "cltypes.h" |
|
29 |
+#include "others.h" |
|
30 |
+#include "matcher.h" |
|
31 |
+#include "matcher-ac.h" |
|
32 |
+#include "matcher-byte-comp.h" |
|
33 |
+#include "mpool.h" |
|
34 |
+#include "readdb.h" |
|
35 |
+#include "str.h" |
|
36 |
+ |
|
37 |
+/* DEBUGGING */ |
|
38 |
+//#define MATCHER_BCOMP_DEBUG |
|
39 |
+#ifdef MATCHER_BCOMP_DEBUG |
|
40 |
+# define bcm_dbgmsg(...) cli_dbgmsg( __VA_ARGS__) |
|
41 |
+#else |
|
42 |
+# define bcm_dbgmsg(...) |
|
43 |
+#endif |
|
44 |
+#undef MATCHER_BCOMP_DEBUG |
|
45 |
+ |
|
46 |
+/* BCOMP MATCHER FUNCTIONS */ |
|
47 |
+ |
|
48 |
+ |
|
49 |
+/** |
|
50 |
+ * @brief function to add the byte compare subsig into the matcher root struct |
|
51 |
+ * |
|
52 |
+ * @param root the matcher root struct in question, houses all relevant lsig and subsig info |
|
53 |
+ * @param virname virusname as given by the signature |
|
54 |
+ * @param hexsig the raw sub signature buffer itself which we will be checking/parsing |
|
55 |
+ * @param lsigid the numeric internal reference number which can be used to access this lsig in the root struct |
|
56 |
+ * @param options additional options for pattern matching, stored as a bitmask |
|
57 |
+ * |
|
58 |
+ */ |
|
59 |
+int cli_bcomp_addpatt(struct cli_matcher *root, const char *virname, const char *hexsig, const char *offset, const uint32_t *lsigid, unsigned int options) { |
|
60 |
+ |
|
61 |
+ if (!hexsig || !(*hexsig) || !root) |
|
62 |
+ return CL_ENULLARG; |
|
63 |
+ |
|
64 |
+ size_t len = 0; |
|
65 |
+ const char *buf_start = NULL; |
|
66 |
+ const char *buf_end = NULL; |
|
67 |
+ char *buf = NULL; |
|
68 |
+ const char *tokens[3]; |
|
69 |
+ size_t toks = 0; |
|
70 |
+ int16_t ref_subsigid = -1; |
|
71 |
+ int64_t offset_param = 0; |
|
72 |
+ size_t byte_length = 0; |
|
73 |
+ uint32_t comp_val = 0; |
|
74 |
+ char *hexcpy = NULL; |
|
75 |
+ |
|
76 |
+ /* we'll be using these to help the root matcher struct keep track of each loaded byte compare pattern */ |
|
77 |
+ struct cli_bcomp_meta **newmetatable; |
|
78 |
+ uint32_t bcomp_count = 0; |
|
79 |
+ |
|
80 |
+ /* zero out our byte compare data struct and tie it to the root struct's mempool instance */ |
|
81 |
+ struct cli_bcomp_meta *bcomp; |
|
82 |
+ bcomp = (struct cli_bcomp_meta *) mpool_calloc(root->mempool, 1, sizeof(*bcomp)); |
|
83 |
+ if (!bcomp) { |
|
84 |
+ cli_errmsg("cli_bcomp_addpatt: Unable to allocate memory for new byte compare meta\n"); |
|
85 |
+ return CL_EMEM; |
|
86 |
+ } |
|
87 |
+ |
|
88 |
+ /* allocate virname space with the root structure's mempool instance */ |
|
89 |
+ bcomp->virname = (char *) cli_mpool_virname(root->mempool, virname, options & CL_DB_OFFICIAL); |
|
90 |
+ if(!bcomp->virname) { |
|
91 |
+ cli_errmsg("cli_bcomp_addpatt: Unable to allocate memory for virname or NULL virname\n"); |
|
92 |
+ cli_bcomp_freemeta(root, bcomp); |
|
93 |
+ return CL_EMEM; |
|
94 |
+ } |
|
95 |
+ |
|
96 |
+ /* bring along the standard lsigid vector, first param marks validity of vector, 2nd is lsigid, 3rd is subsigid */ |
|
97 |
+ if (lsigid) { |
|
98 |
+ root->ac_lsigtable[lsigid[0]]->virname = bcomp->virname; |
|
99 |
+ |
|
100 |
+ bcomp->lsigid[0] = 1; |
|
101 |
+ bcomp->lsigid[1] = lsigid[0]; |
|
102 |
+ bcomp->lsigid[2] = lsigid[1]; |
|
103 |
+ } |
|
104 |
+ else { |
|
105 |
+ /* sigtool */ |
|
106 |
+ bcomp->lsigid[0] = 0; |
|
107 |
+ } |
|
108 |
+ |
|
109 |
+ /* first need to grab the subsig reference, we'll use this later to determine our offset */ |
|
110 |
+ buf_start = hexsig; |
|
111 |
+ buf_end = hexsig; |
|
112 |
+ |
|
113 |
+ ref_subsigid = strtol(buf_start, (char**) &buf_end, 10); |
|
114 |
+ if (buf_end && buf_end[0] != '(') { |
|
115 |
+ cli_errmsg("cli_bcomp_addpatt: while byte compare subsig parsing, reference subsig id was invalid or included non-decimal character\n"); |
|
116 |
+ cli_bcomp_freemeta(root, bcomp); |
|
117 |
+ return CL_EMALFDB; |
|
118 |
+ } |
|
119 |
+ |
|
120 |
+ bcomp->ref_subsigid = ref_subsigid; |
|
121 |
+ |
|
122 |
+ /* use the passed hexsig buffer to find the start and ending parens and store the param length (minus starting paren) */ |
|
123 |
+ buf_start = buf_end; |
|
124 |
+ if (buf_start[0] == '(') { |
|
125 |
+ if (buf_end = strchr(buf_start, ')')) { |
|
126 |
+ len = (size_t) (buf_end - ++buf_start); |
|
127 |
+ } |
|
128 |
+ else { |
|
129 |
+ cli_errmsg("cli_bcomp_addpatt: ending paren not found\n"); |
|
130 |
+ cli_bcomp_freemeta(root, bcomp); |
|
131 |
+ return CL_EMALFDB; |
|
132 |
+ } |
|
133 |
+ } |
|
134 |
+ else { |
|
135 |
+ cli_errmsg("cli_bcomp_addpatt: opening paren not found\n"); |
|
136 |
+ cli_bcomp_freemeta(root, bcomp); |
|
137 |
+ return CL_EMALFDB; |
|
138 |
+ } |
|
139 |
+ |
|
140 |
+ /* make a working copy of the param buffer */ |
|
141 |
+ buf = cli_strndup(buf_start, len); |
|
142 |
+ |
|
143 |
+ /* break up the new param buffer into its component strings and verify we have exactly 3 */ |
|
144 |
+ toks = cli_strtokenize(buf, '#', 3+1, tokens); |
|
145 |
+ if (3 != toks) { |
|
146 |
+ cli_errmsg("cli_bcomp_addpatt: %zu (or more) params provided, 3 expected\n", toks); |
|
147 |
+ free(buf); |
|
148 |
+ cli_bcomp_freemeta(root, bcomp); |
|
149 |
+ return CL_EMALFDB; |
|
150 |
+ } |
|
151 |
+ |
|
152 |
+ /* since null termination is super guaranteed thanks to strndup and cli_strokenize, we can use strtol to grab the |
|
153 |
+ * offset params. this has the added benefit of letting us parse hex values too */ |
|
154 |
+ buf_end = NULL; |
|
155 |
+ buf_start = tokens[0]; |
|
156 |
+ switch (buf_start[0]) { |
|
157 |
+ case '<': |
|
158 |
+ if ((++buf_start)[0] == '<') { |
|
159 |
+ offset_param = strtol(++buf_start, (char**) &buf_end, 0); |
|
160 |
+ if (buf_end && buf_end+1 != tokens[1]) { |
|
161 |
+ cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), offset parameter included invalid characters\n", tokens[0], tokens[1], tokens[2]); |
|
162 |
+ free(buf); |
|
163 |
+ cli_bcomp_freemeta(root, bcomp); |
|
164 |
+ return CL_EMALFDB; |
|
165 |
+ } |
|
166 |
+ /* two's-complement for negative value */ |
|
167 |
+ offset_param = (~offset_param) + 1; |
|
168 |
+ |
|
169 |
+ } else { |
|
170 |
+ cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), shift operator not valid\n", tokens[0], tokens[1], tokens[2]); |
|
171 |
+ free(buf); |
|
172 |
+ cli_bcomp_freemeta(root, bcomp); |
|
173 |
+ return CL_EMALFDB; |
|
174 |
+ } |
|
175 |
+ break; |
|
176 |
+ |
|
177 |
+ case '>': |
|
178 |
+ if ((++buf_start)[0] == '>') { |
|
179 |
+ offset_param = strtol(buf_start, (char**) &buf_end, 0); |
|
180 |
+ if (buf_end && buf_end+1 != tokens[1]) { |
|
181 |
+ cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), offset parameter included invalid characters\n", tokens[0], tokens[1], tokens[2]); |
|
182 |
+ free(buf); |
|
183 |
+ cli_bcomp_freemeta(root, bcomp); |
|
184 |
+ return CL_EMALFDB; |
|
185 |
+ } |
|
186 |
+ break; |
|
187 |
+ } else { |
|
188 |
+ cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), shift operator and/or offset not valid\n", tokens[0], tokens[1], tokens[2]); |
|
189 |
+ free(buf); |
|
190 |
+ cli_bcomp_freemeta(root, bcomp); |
|
191 |
+ return CL_EMALFDB; |
|
192 |
+ } |
|
193 |
+ case '0': |
|
194 |
+ case '\0': |
|
195 |
+ offset_param = 0; |
|
196 |
+ break; |
|
197 |
+ |
|
198 |
+ default: |
|
199 |
+ cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), shift operator included invalid characters\n", tokens[0], tokens[1], tokens[2]); |
|
200 |
+ free(buf); |
|
201 |
+ cli_bcomp_freemeta(root, bcomp); |
|
202 |
+ return CL_EMALFDB; |
|
203 |
+ } |
|
204 |
+ |
|
205 |
+ bcomp->offset = offset_param; |
|
206 |
+ |
|
207 |
+ /* the byte length indicator options are stored in a bitmask--by design each option gets its own nibble */ |
|
208 |
+ buf_start = tokens[1]; |
|
209 |
+ |
|
210 |
+ switch (*buf_start) { |
|
211 |
+ case 'h': bcomp->options |= CLI_BCOMP_HEX; break; |
|
212 |
+ case 'd': bcomp->options |= CLI_BCOMP_DEC; break; |
|
213 |
+ |
|
214 |
+ default: |
|
215 |
+ cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), hex/decimal byte length indicator was found invalid\n", tokens[0], tokens[1], tokens[2]); |
|
216 |
+ free(buf); |
|
217 |
+ cli_bcomp_freemeta(root, bcomp); |
|
218 |
+ return CL_EMALFDB; |
|
219 |
+ } |
|
220 |
+ |
|
221 |
+ buf_start++; |
|
222 |
+ switch (*buf_start) { |
|
223 |
+ case 'l': bcomp->options |= CLI_BCOMP_LE; break; |
|
224 |
+ case 'b': bcomp->options |= CLI_BCOMP_BE; break; |
|
225 |
+ |
|
226 |
+ default: |
|
227 |
+ cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), little/big endian byte length indicator was invalid\n", tokens[0], tokens[1], tokens[2]); |
|
228 |
+ free(buf); |
|
229 |
+ cli_bcomp_freemeta(root, bcomp); |
|
230 |
+ return CL_EMALFDB; |
|
231 |
+ } |
|
232 |
+ |
|
233 |
+ /* parse out the byte length parameter */ |
|
234 |
+ buf_start++; |
|
235 |
+ buf_end = NULL; |
|
236 |
+ byte_length = strtol(buf_start, (char **) &buf_end, 0); |
|
237 |
+ if (buf_end && buf_end+1 != tokens[2]) { |
|
238 |
+ cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), byte length parameter included invalid characters\n", tokens[0], tokens[1], tokens[3]); |
|
239 |
+ free(buf); |
|
240 |
+ cli_bcomp_freemeta(root, bcomp); |
|
241 |
+ return CL_EMALFDB; |
|
242 |
+ } |
|
243 |
+ |
|
244 |
+ bcomp->byte_len = byte_length; |
|
245 |
+ |
|
246 |
+ /* currectly only >, <, and = are supported comparison symbols--this makes parsing very simple */ |
|
247 |
+ buf_start = tokens[2]; |
|
248 |
+ switch (*buf_start) { |
|
249 |
+ case '<': |
|
250 |
+ case '>': |
|
251 |
+ case '=': |
|
252 |
+ bcomp->comp_symbol = *buf_start; break; |
|
253 |
+ |
|
254 |
+ default: |
|
255 |
+ cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), byte comparison symbol was invalid (>, <, = are supported operators)\n", tokens[0], tokens[1], tokens[2]); |
|
256 |
+ free(buf); |
|
257 |
+ cli_bcomp_freemeta(root, bcomp); |
|
258 |
+ return CL_EMALFDB; |
|
259 |
+ } |
|
260 |
+ |
|
261 |
+ |
|
262 |
+ /* no more tokens after this, so we take advantage of strtol and check if the buf_end is null terminated or not */ |
|
263 |
+ buf_start++; |
|
264 |
+ buf_end = NULL; |
|
265 |
+ comp_val = strtol(buf_start, (char **) &buf_end, 0); |
|
266 |
+ if (*buf_end) { |
|
267 |
+ cli_errmsg("cli_bcomp_addpatt: while parsing (%s#%s#%s), comparison value contained invalid input\n", tokens[0], tokens[1], tokens[2]); |
|
268 |
+ free(buf); |
|
269 |
+ cli_bcomp_freemeta(root, bcomp); |
|
270 |
+ return CL_EMALFDB; |
|
271 |
+ } |
|
272 |
+ |
|
273 |
+ bcomp->comp_value = comp_val; |
|
274 |
+ |
|
275 |
+ /* manually verify successful pattern parsing */ |
|
276 |
+ bcm_dbgmsg("Matcher Byte Compare: (%s%ld#%c%c%zu#%c%d)\n", |
|
277 |
+ bcomp->offset == 0 ? "" : |
|
278 |
+ (bcomp->offset < 0 ? "<<" : ">>"), |
|
279 |
+ bcomp->offset, |
|
280 |
+ bcomp->options & CLI_BCOMP_HEX ? 'h' : 'd', |
|
281 |
+ bcomp->options & CLI_BCOMP_LE ? 'l' : 'b', |
|
282 |
+ bcomp->byte_len, |
|
283 |
+ bcomp->comp_symbol, |
|
284 |
+ bcomp->comp_value); |
|
285 |
+ |
|
286 |
+ /* add byte compare info to the root after reallocation */ |
|
287 |
+ bcomp_count = root->bcomp_metas+1; |
|
288 |
+ |
|
289 |
+ /* allocate space for new meta table to store in root structure and increment number of byte compare patterns added */ |
|
290 |
+ newmetatable = (struct cli_bcomp_meta **) mpool_realloc(root->mempool, root->bcomp_metatable, bcomp_count * sizeof(struct cli_bcomp_meta *)); |
|
291 |
+ if(!newmetatable) { |
|
292 |
+ cli_errmsg("cli_bcomp_addpatt: Unable to allocate memory for new bcomp meta table\n"); |
|
293 |
+ cli_bcomp_freemeta(root, bcomp); |
|
294 |
+ return CL_EMEM; |
|
295 |
+ } |
|
296 |
+ |
|
297 |
+ newmetatable[bcomp_count-1] = bcomp; |
|
298 |
+ root->bcomp_metatable = newmetatable; |
|
299 |
+ |
|
300 |
+ root->bcomp_metas = bcomp_count; |
|
301 |
+ |
|
302 |
+ /* if everything went well bcomp has been totally populated, which means we can cleanup and exit */ |
|
303 |
+ free(buf); |
|
304 |
+ return CL_SUCCESS; |
|
305 |
+} |
|
306 |
+ |
|
307 |
+/** |
|
308 |
+ * @brief function to perform all byte compare matching on the file buffer |
|
309 |
+ * |
|
310 |
+ * @param map the file map to perform logical byte comparison upon |
|
311 |
+ * @param res the result structure, primarily used by sigtool |
|
312 |
+ * @param root the root structure in which all byte compare lsig and subsig information is stored |
|
313 |
+ * @param mdata the ac data struct which contains offset information from recent subsig matches |
|
314 |
+ * @param ctx the clamav context struct |
|
315 |
+ * |
|
316 |
+ */ |
|
317 |
+int cli_bcomp_scanbuf(fmap_t *map, const char **virname, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, cli_ctx *ctx) { |
|
318 |
+ |
|
319 |
+ int64_t i = 0, rc = 0, ret = CL_SUCCESS; |
|
320 |
+ uint32_t lsigid, ref_subsigid; |
|
321 |
+ uint32_t offset = 0; |
|
322 |
+ uint8_t viruses_found = 0; |
|
323 |
+ struct cli_bcomp_meta *bcomp = NULL; |
|
324 |
+ |
|
325 |
+ if (!(root) || !(root->bcomp_metas) || !(root->bcomp_metatable) || !(mdata) || !(mdata->offmatrix) || !(ctx)) { |
|
326 |
+ return CL_SUCCESS; |
|
327 |
+ } |
|
328 |
+ |
|
329 |
+ for(i = 0; i < root->bcomp_metas; i++) { |
|
330 |
+ |
|
331 |
+ bcomp = root->bcomp_metatable[i]; |
|
332 |
+ lsigid = bcomp->lsigid[1]; |
|
333 |
+ ref_subsigid = bcomp->ref_subsigid; |
|
334 |
+ |
|
335 |
+ /* ensures the referenced subsig matches as expected, and also ensures mdata has the needed offset */ |
|
336 |
+ if (ret = lsig_sub_matched(root, mdata, lsigid, ref_subsigid, CLI_OFF_NONE, 0)) { |
|
337 |
+ continue; |
|
338 |
+ } |
|
339 |
+ |
|
340 |
+ /* grab the needed offset using from the last matched subsig offset matrix, i.e. the match performed above */ |
|
341 |
+ if (mdata->lsigsuboff_last[lsigid]) { |
|
342 |
+ offset = mdata->lsigsuboff_last[lsigid][ref_subsigid]; |
|
343 |
+ } else { |
|
344 |
+ ret = CL_SUCCESS; |
|
345 |
+ continue; |
|
346 |
+ } |
|
347 |
+ |
|
348 |
+ /* now we have all the pieces of the puzzle, so lets do our byte compare check */ |
|
349 |
+ ret = cli_bcmp_compare_check(map, offset, bcomp); |
|
350 |
+ |
|
351 |
+ /* set and append our lsig's virus name if the comparison came back positive */ |
|
352 |
+ if (CL_VIRUS == ret) { |
|
353 |
+ viruses_found = 1; |
|
354 |
+ |
|
355 |
+ if (virname) { |
|
356 |
+ *virname = bcomp->virname; |
|
357 |
+ } |
|
358 |
+ /* if we aren't scanning all, let's just exit here */ |
|
359 |
+ if (!SCAN_ALL) { |
|
360 |
+ break; |
|
361 |
+ } else { |
|
362 |
+ ret = cli_append_virus(ctx, (const char *)bcomp->virname); |
|
363 |
+ } |
|
364 |
+ } |
|
365 |
+ } |
|
366 |
+ |
|
367 |
+ if (ret == CL_SUCCESS && viruses_found) { |
|
368 |
+ return CL_VIRUS; |
|
369 |
+ } |
|
370 |
+ return ret; |
|
371 |
+} |
|
372 |
+ |
|
373 |
+/** |
|
374 |
+ * @brief does a numerical, logical byte comparison on a particular offset given a filemapping and the offset |
|
375 |
+ * |
|
376 |
+ * @param map the file buffer we'll be accessing to do our comparison check |
|
377 |
+ * @param offset the offset of the referenced subsig match from the start of the file buffer |
|
378 |
+ * @param bm the byte comparison meta data struct, contains all the other info needed to do the comparison |
|
379 |
+ * |
|
380 |
+ */ |
|
381 |
+int cli_bcmp_compare_check(fmap_t *map, int offset, struct cli_bcomp_meta *bm) |
|
382 |
+{ |
|
383 |
+ if (!map || !bm) { |
|
384 |
+ bcm_dbgmsg("bcmp_compare_check: a param is null\n"); |
|
385 |
+ return CL_ENULLARG; |
|
386 |
+ } |
|
387 |
+ |
|
388 |
+ const uint32_t byte_len = bm->byte_len; |
|
389 |
+ uint32_t length = map->len; |
|
390 |
+ const unsigned char *buffer = NULL; |
|
391 |
+ unsigned char *conversion_buf = NULL; |
|
392 |
+ char opt = (char) bm->options; |
|
393 |
+ uint32_t value = 0; |
|
394 |
+ const unsigned char* end_buf = NULL; |
|
395 |
+ |
|
396 |
+ /* ensure we won't run off the end of the file buffer */ |
|
397 |
+ if (bm->offset > 0) { |
|
398 |
+ if (!((offset + bm->offset + byte_len <= length))) { |
|
399 |
+ bcm_dbgmsg("bcmp_compare_check: %u bytes requested at offset %zu would go past file buffer of %u\n", byte_len, (offset + bm->offset), length); |
|
400 |
+ return CL_CLEAN; |
|
401 |
+ } |
|
402 |
+ } else { |
|
403 |
+ if (!(offset + bm->offset > 0)) { |
|
404 |
+ bcm_dbgmsg("bcmp_compare_check: negative offset would underflow buffer\n"); |
|
405 |
+ return CL_CLEAN; |
|
406 |
+ } |
|
407 |
+ } |
|
408 |
+ |
|
409 |
+ /* jump to byte compare offset, then store off specified bytes into a null terminated buffer */ |
|
410 |
+ offset += bm->offset; |
|
411 |
+ buffer = fmap_need_off_once(map, offset, byte_len); |
|
412 |
+ bcm_dbgmsg("bcmp_compare_check: literal extracted bytes before comparison (%s)\n", buffer); |
|
413 |
+ |
|
414 |
+ /* handle byte length options to convert the string appropriately */ |
|
415 |
+ switch(opt) { |
|
416 |
+ /*hl*/ |
|
417 |
+ case CLI_BCOMP_HEX | CLI_BCOMP_LE: |
|
418 |
+ value = cli_strntoul(buffer, byte_len, (char**) &end_buf, 16); |
|
419 |
+ if (value < 0 || NULL == end_buf || buffer+byte_len != end_buf) { |
|
420 |
+ bcm_dbgmsg("bcmp_compare_check: little endian hex conversion unsuccessful\n"); |
|
421 |
+ return CL_CLEAN; |
|
422 |
+ } |
|
423 |
+ |
|
424 |
+ value = le32_to_host(value); |
|
425 |
+ break; |
|
426 |
+ |
|
427 |
+ /*hb*/ |
|
428 |
+ case CLI_BCOMP_HEX | CLI_BCOMP_BE: |
|
429 |
+ value = cli_strntoul(buffer, byte_len, (char**) &end_buf, 16); |
|
430 |
+ if (value < 0 || NULL == end_buf || buffer+byte_len != end_buf) { |
|
431 |
+ |
|
432 |
+ bcm_dbgmsg("bcmp_compare_check: big endian hex conversion unsuccessful\n"); |
|
433 |
+ return CL_CLEAN; |
|
434 |
+ } |
|
435 |
+ |
|
436 |
+ value = be32_to_host(value); |
|
437 |
+ break; |
|
438 |
+ |
|
439 |
+ /*dl*/ |
|
440 |
+ case CLI_BCOMP_DEC | CLI_BCOMP_LE: |
|
441 |
+ value = cli_strntoul(buffer, byte_len, (char**) &end_buf, 10); |
|
442 |
+ if (value < 0 || NULL == end_buf || buffer+byte_len != end_buf) { |
|
443 |
+ |
|
444 |
+ bcm_dbgmsg("bcmp_compare_check: little endian decimal conversion unsuccessful\n"); |
|
445 |
+ return CL_CLEAN; |
|
446 |
+ } |
|
447 |
+ |
|
448 |
+ value = le32_to_host(value); |
|
449 |
+ break; |
|
450 |
+ |
|
451 |
+ /*db*/ |
|
452 |
+ case CLI_BCOMP_DEC | CLI_BCOMP_BE: |
|
453 |
+ value = cli_strntoul(buffer, byte_len, (char**) &end_buf, 10); |
|
454 |
+ if (value < 0 || NULL == end_buf || buffer+byte_len != end_buf) { |
|
455 |
+ |
|
456 |
+ bcm_dbgmsg("bcmp_compare_check: big endian decimal conversion unsuccessful\n"); |
|
457 |
+ return CL_CLEAN; |
|
458 |
+ } |
|
459 |
+ |
|
460 |
+ value = be32_to_host(value); |
|
461 |
+ break; |
|
462 |
+ |
|
463 |
+ default: |
|
464 |
+ return CL_ENULLARG; |
|
465 |
+ } |
|
466 |
+ |
|
467 |
+ /* do the actual comparison */ |
|
468 |
+ switch (bm->comp_symbol) { |
|
469 |
+ |
|
470 |
+ case '>': |
|
471 |
+ if (value > bm->comp_value) { |
|
472 |
+ bcm_dbgmsg("bcmp_compare_check: extracted value (%u) greater than comparison value (%u)\n", value, bm->comp_value); |
|
473 |
+ return CL_VIRUS; |
|
474 |
+ } |
|
475 |
+ break; |
|
476 |
+ |
|
477 |
+ case '<': |
|
478 |
+ if (value < bm->comp_value) { |
|
479 |
+ bcm_dbgmsg("bcmp_compare_check: extracted value (%u) less than comparison value (%u)\n", value, bm->comp_value); |
|
480 |
+ return CL_VIRUS; |
|
481 |
+ } |
|
482 |
+ break; |
|
483 |
+ |
|
484 |
+ case '=': |
|
485 |
+ if (value == bm->comp_value) { |
|
486 |
+ bcm_dbgmsg("bcmp_compare_check: extracted value (%u) equal to comparison value (%u)\n", value, bm->comp_value); |
|
487 |
+ return CL_VIRUS; |
|
488 |
+ } |
|
489 |
+ break; |
|
490 |
+ |
|
491 |
+ default: |
|
492 |
+ bcm_dbgmsg("bcmp_compare_check: comparison symbol (%c) invalid\n", bm->comp_symbol); |
|
493 |
+ return CL_ENULLARG; |
|
494 |
+ } |
|
495 |
+ |
|
496 |
+ /* comparison was not successful */ |
|
497 |
+ bcm_dbgmsg("bcmp_compare_check: extracted value was not %c %u\n", bm->comp_symbol, bm->comp_value); |
|
498 |
+ return CL_CLEAN; |
|
499 |
+} |
|
500 |
+ |
|
501 |
+/** |
|
502 |
+ * @brief cleans up the byte compare data struct |
|
503 |
+ * |
|
504 |
+ * @param root the root matcher struct whose mempool instance the bcomp struct has been allocated with |
|
505 |
+ * @param bm the bcomp struct to be freed |
|
506 |
+ * |
|
507 |
+ */ |
|
508 |
+void cli_bcomp_freemeta(struct cli_matcher *root, struct cli_bcomp_meta *bm) { |
|
509 |
+ |
|
510 |
+ if(!bm) { |
|
511 |
+ return; |
|
512 |
+ } |
|
513 |
+ |
|
514 |
+ if (bm->virname) { |
|
515 |
+ mpool_free(root->mempool, bm->virname); |
|
516 |
+ bm->virname = NULL; |
|
517 |
+ } |
|
518 |
+ |
|
519 |
+ mpool_free(root->mempool, bm); |
|
520 |
+ bm = NULL; |
|
521 |
+ |
|
522 |
+ return; |
|
523 |
+} |
0 | 524 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,58 @@ |
0 |
+/* |
|
1 |
+ * Support for matcher using byte compare |
|
2 |
+ * |
|
3 |
+ * Copyright (C) 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
4 |
+ * All Rights Reserved. |
|
5 |
+ * |
|
6 |
+ * Authors: Mickey Sola |
|
7 |
+ * |
|
8 |
+ * This program is free software; you can redistribute it and/or modify |
|
9 |
+ * it under the terms of the GNU General Public License version 2 as |
|
10 |
+ * published by the Free Software Foundation. |
|
11 |
+ * |
|
12 |
+ * This program is distributed in the hope that it will be useful, |
|
13 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
15 |
+ * GNU General Public License for more details. |
|
16 |
+ * |
|
17 |
+ * You should have received a copy of the GNU General Public License |
|
18 |
+ * along with this program; if not, write to the Free Software |
|
19 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
20 |
+ * MA 02110-1301, USA. |
|
21 |
+ */ |
|
22 |
+ |
|
23 |
+#ifndef __MATCHER_BCOMP_H |
|
24 |
+#define __MATCHER_BCOMP_H |
|
25 |
+ |
|
26 |
+#if HAVE_CONFIG_H |
|
27 |
+#include "clamav-config.h" |
|
28 |
+#endif |
|
29 |
+ |
|
30 |
+#include <sys/types.h> |
|
31 |
+ |
|
32 |
+#include "cltypes.h" |
|
33 |
+#include "dconf.h" |
|
34 |
+#include "mpool.h" |
|
35 |
+ |
|
36 |
+#define CLI_BCOMP_HEX 0x0001 |
|
37 |
+#define CLI_BCOMP_DEC 0x0002 |
|
38 |
+#define CLI_BCOMP_LE 0x0010 |
|
39 |
+#define CLI_BCOMP_BE 0x0020 |
|
40 |
+ |
|
41 |
+struct cli_bcomp_meta { |
|
42 |
+ char *virname; |
|
43 |
+ uint16_t ref_subsigid; /* identifies the dependent subsig from which we will do comparisons from */ |
|
44 |
+ uint32_t lsigid[3]; |
|
45 |
+ ssize_t offset; /* offset from the referenced subsig, handled at match-time */ |
|
46 |
+ uint16_t options; /* bitmask */ |
|
47 |
+ size_t byte_len; |
|
48 |
+ char comp_symbol; /* <, >, = are supported */ |
|
49 |
+ uint32_t comp_value; |
|
50 |
+}; |
|
51 |
+ |
|
52 |
+int cli_bcomp_addpatt(struct cli_matcher *root, const char *virname, const char* hexsig, const char *offset, const uint32_t *lsigid, unsigned int options); |
|
53 |
+int cli_pcre_bcmp_compare_check(fmap_t *map, int offset, struct cli_bcomp_meta *bm); |
|
54 |
+void cli_bcomp_freemeta(struct cli_matcher *root, struct cli_bcomp_meta *bm); |
|
55 |
+int cli_bcomp_scanbuf(fmap_t *map, const char **virname, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, cli_ctx *ctx); |
|
56 |
+ |
|
57 |
+#endif |
... | ... |
@@ -321,15 +321,11 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const char * |
321 | 321 |
|
322 | 322 |
/* cli_pcre_addoptions handles pcre specific options */ |
323 | 323 |
while (cli_pcre_addoptions(&(pm->pdata), &opt, 0) != CL_SUCCESS) { |
324 |
- /* handle matcher specific options here */ |
|
324 |
+ /* it will return here to handle any matcher specific options */ |
|
325 | 325 |
switch (*opt) { |
326 | 326 |
case 'g': pm->flags |= CLI_PCRE_GLOBAL; break; |
327 | 327 |
case 'r': pm->flags |= CLI_PCRE_ROLLING; break; |
328 | 328 |
case 'e': pm->flags |= CLI_PCRE_ENCOMPASS; break; |
329 |
- case 'z': if(CL_SUCCESS == cli_pcre_bcmp_add_opts(&opt, &pm->bcmp_data)) { |
|
330 |
- pm->flags |= CLI_PCRE_BCOMP; |
|
331 |
- break; |
|
332 |
- } |
|
333 | 329 |
default: |
334 | 330 |
cli_errmsg("cli_pcre_addpatt: unknown/extra pcre option encountered %c\n", *opt); |
335 | 331 |
cli_pcre_freemeta(root, pm); |
... | ... |
@@ -348,18 +344,6 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const char * |
348 | 348 |
else |
349 | 349 |
pm_dbgmsg("Matcher: NONE\n"); |
350 | 350 |
|
351 |
- if (pm->flags && pm->flags & CLI_PCRE_BCOMP) { |
|
352 |
- pm_dbgmsg("Matcher Byte Compare: (%zu#%c%c%zu#%c%d)\n", |
|
353 |
- pm->bcmp_data.offset, |
|
354 |
- pm->bcmp_data.options & CLI_PCRE_BCOMP_HEX ? 'h' : 'd', |
|
355 |
- pm->bcmp_data.options & CLI_PCRE_BCOMP_LE ? 'l' : 'b', |
|
356 |
- pm->bcmp_data.byte_len, |
|
357 |
- pm->bcmp_data.comp_symbol, |
|
358 |
- pm->bcmp_data.comp_value); |
|
359 |
- } |
|
360 |
- else |
|
361 |
- pm_dbgmsg("Matcher Byte Compare: NONE\n"); |
|
362 |
- |
|
363 | 351 |
if (pm->pdata.options) { |
364 | 352 |
#if USING_PCRE2 |
365 | 353 |
pm_dbgmsg("Compiler: %s%s%s%s%s%s%s\n", |
... | ... |
@@ -410,125 +394,6 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const char * |
410 | 410 |
return CL_SUCCESS; |
411 | 411 |
} |
412 | 412 |
|
413 |
-int cli_pcre_bcmp_add_opts(const char **opt, struct cli_pcre_bcomp *bcomp) { |
|
414 |
- |
|
415 |
- if (!opt || !(*opt) || !bcomp) |
|
416 |
- return CL_ENULLARG; |
|
417 |
- |
|
418 |
- size_t len = 0; |
|
419 |
- const char *buf_start = ++(*opt); |
|
420 |
- const char *buf_end = NULL; |
|
421 |
- char *buf = NULL; |
|
422 |
- const char *tokens[3]; |
|
423 |
- size_t toks = 0; |
|
424 |
- uint64_t offset_param = 0; |
|
425 |
- size_t byte_length = 0; |
|
426 |
- uint32_t comp_val = 0; |
|
427 |
- |
|
428 |
- memset(bcomp, 0, sizeof(struct cli_pcre_bcomp)); |
|
429 |
- |
|
430 |
- |
|
431 |
- |
|
432 |
- if (**opt == '(') { |
|
433 |
- if (buf_end = strchr(buf_start, ')')) { |
|
434 |
- len = (size_t) (buf_end - ++buf_start); |
|
435 |
- } |
|
436 |
- else { |
|
437 |
- cli_errmsg("cli_pcre_addbytecomp: ending paren not found\n"); |
|
438 |
- return CL_EMALFDB; |
|
439 |
- } |
|
440 |
- } |
|
441 |
- else { |
|
442 |
- cli_errmsg("cli_pcre_addbytecomp: opening paren not found\n"); |
|
443 |
- return CL_EMALFDB; |
|
444 |
- } |
|
445 |
- |
|
446 |
- buf = cli_strndup(buf_start, len); |
|
447 |
- pm_dbgmsg("buf: %s\n", buf); |
|
448 |
- *opt += len+1; |
|
449 |
- pm_dbgmsg("opt_pos: %c\n", **opt); |
|
450 |
- |
|
451 |
- toks = cli_strtokenize(buf, '#', 3+1, tokens); |
|
452 |
- if (3 != toks) { |
|
453 |
- cli_errmsg("cli_pcre_addbytecomp: %zu params provided, 3 expected\n", toks); |
|
454 |
- free(buf); |
|
455 |
- return CL_EMALFDB; |
|
456 |
- } |
|
457 |
- |
|
458 |
- buf_end = NULL; |
|
459 |
- offset_param = strtol(tokens[0], (char**) &buf_end, 0); |
|
460 |
- if (buf_end && buf_end+1 != tokens[1]) { |
|
461 |
- cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), offset parameter included invalid characters\n", tokens[0], tokens[1], tokens[2]); |
|
462 |
- free(buf); |
|
463 |
- return CL_EMALFDB; |
|
464 |
- } |
|
465 |
- |
|
466 |
- bcomp->offset = offset_param; |
|
467 |
- |
|
468 |
- buf_start = tokens[1]; |
|
469 |
- |
|
470 |
- switch (*buf_start) { |
|
471 |
- case 'h': bcomp->options |= CLI_PCRE_BCOMP_HEX; break; |
|
472 |
- case 'd': bcomp->options |= CLI_PCRE_BCOMP_DEC; break; |
|
473 |
- |
|
474 |
- default: |
|
475 |
- cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), hex/decimal byte length indicator was found invalid\n", tokens[0], tokens[1], tokens[2]); |
|
476 |
- free(buf); |
|
477 |
- return CL_EMALFDB; |
|
478 |
- } |
|
479 |
- |
|
480 |
- |
|
481 |
- buf_start++; |
|
482 |
- switch (*buf_start) { |
|
483 |
- case 'l': bcomp->options |= CLI_PCRE_BCOMP_LE; break; |
|
484 |
- case 'b': bcomp->options |= CLI_PCRE_BCOMP_BE; break; |
|
485 |
- |
|
486 |
- default: |
|
487 |
- cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), little/big endian byte length indicator was invalid\n", tokens[0], tokens[1], tokens[2]); |
|
488 |
- free(buf); |
|
489 |
- return CL_EMALFDB; |
|
490 |
- } |
|
491 |
- |
|
492 |
- buf_start++; |
|
493 |
- buf_end = NULL; |
|
494 |
- byte_length = strtol(buf_start, (char **) &buf_end, 0); |
|
495 |
- if (buf_end && buf_end+1 != tokens[2]) { |
|
496 |
- cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), byte length parameter included invalid characters\n", tokens[0], tokens[1], tokens[3]); |
|
497 |
- free(buf); |
|
498 |
- return CL_EMALFDB; |
|
499 |
- } |
|
500 |
- |
|
501 |
- bcomp->byte_len = byte_length; |
|
502 |
- |
|
503 |
- buf_start = tokens[2]; |
|
504 |
- pm_dbgmsg("tokens2: %c\n", *tokens[2]); |
|
505 |
- switch (*buf_start) { |
|
506 |
- case '<': |
|
507 |
- case '>': |
|
508 |
- case '=': |
|
509 |
- bcomp->comp_symbol = *buf_start; break; |
|
510 |
- |
|
511 |
- default: |
|
512 |
- cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), byte comparison symbol was invalid (>, <, = are supported operators)\n", tokens[0], tokens[1], tokens[2]); |
|
513 |
- free(buf); |
|
514 |
- return CL_EMALFDB; |
|
515 |
- } |
|
516 |
- |
|
517 |
- buf_start++; |
|
518 |
- buf_end = NULL; |
|
519 |
- comp_val = strtol(buf_start, (char **) &buf_end, 0); |
|
520 |
- if (*buf_end) { |
|
521 |
- cli_errmsg("cli_pcre_addbytecomp: while parsing (%s#%s#%s), comparison value contained invalid input\n", tokens[0], tokens[1], tokens[2]); |
|
522 |
- free(buf); |
|
523 |
- return CL_EMALFDB; |
|
524 |
- } |
|
525 |
- |
|
526 |
- bcomp->comp_value = comp_val; |
|
527 |
- |
|
528 |
- free(buf); |
|
529 |
- return CL_SUCCESS; |
|
530 |
-} |
|
531 |
- |
|
532 | 413 |
int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, long long unsigned recmatch_limit, const struct cli_dconf *dconf) |
533 | 414 |
{ |
534 | 415 |
unsigned int i; |
... | ... |
@@ -738,6 +603,7 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char ** |
738 | 738 |
memset(&p_res, 0, sizeof(p_res)); |
739 | 739 |
|
740 | 740 |
for (i = 0; i < root->pcre_metas; ++i) { |
741 |
+ |
|
741 | 742 |
pm = root->pcre_metatable[i]; |
742 | 743 |
pd = &(pm->pdata); |
743 | 744 |
|
... | ... |
@@ -852,13 +718,15 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char ** |
852 | 852 |
cli_event_count(p_sigevents, pm->sigmatch_id); |
853 | 853 |
|
854 | 854 |
/* for logical signature evaluation */ |
855 |
+ |
|
855 | 856 |
if (pm->lsigid[0]) { |
856 | 857 |
pm_dbgmsg("cli_pcre_scanbuf: assigning lsigcnt[%d][%d], located @ %d\n", |
857 | 858 |
pm->lsigid[1], pm->lsigid[2], adjbuffer+p_res.match[0]); |
858 | 859 |
|
859 | 860 |
ret = lsig_sub_matched(root, mdata, pm->lsigid[1], pm->lsigid[2], adjbuffer+p_res.match[0], 0); |
860 |
- if (ret != CL_SUCCESS) |
|
861 |
- break; |
|
861 |
+ if (ret != CL_SUCCESS) { |
|
862 |
+ break; |
|
863 |
+ } |
|
862 | 864 |
} else { |
863 | 865 |
/* for raw match data - sigtool only */ |
864 | 866 |
if(res) { |
... | ... |
@@ -890,23 +758,18 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char ** |
890 | 890 |
/* move off to the end of the match for next match; offset is relative to adjbuffer |
891 | 891 |
* NOTE: misses matches starting within the last match; TODO: start from start of last match? */ |
892 | 892 |
offset = p_res.match[1]; |
893 |
- |
|
894 |
- if(pm->flags & CLI_PCRE_BCOMP) { |
|
895 |
- ret = cli_pcre_bcmp_compare_check(buffer, length, offset, pm); |
|
896 |
- if (ret != CL_SUCCESS) { |
|
897 |
- break; |
|
898 |
- } |
|
899 |
- } |
|
900 | 893 |
|
901 | 894 |
} while (global && rc > 0 && offset < adjlength); |
902 | 895 |
|
903 | 896 |
/* handle error code */ |
904 |
- if (rc < 0 && p_res.err != CL_SUCCESS) |
|
897 |
+ if (rc < 0 && p_res.err != CL_SUCCESS) { |
|
905 | 898 |
ret = p_res.err; |
899 |
+ } |
|
906 | 900 |
|
907 | 901 |
/* jumps out of main loop from 'global' loop */ |
908 |
- if (ret != CL_SUCCESS) |
|
902 |
+ if (ret != CL_SUCCESS) { |
|
909 | 903 |
break; |
904 |
+ } |
|
910 | 905 |
} |
911 | 906 |
|
912 | 907 |
/* free match results */ |
... | ... |
@@ -917,97 +780,6 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char ** |
917 | 917 |
return ret; |
918 | 918 |
} |
919 | 919 |
|
920 |
-int cli_pcre_bcmp_compare_check(const unsigned char *buffer, uint32_t length, int offset, struct cli_pcre_meta *pm) |
|
921 |
-{ |
|
922 |
- if (!buffer || !pm) { |
|
923 |
- return CL_ENULLARG; |
|
924 |
- } |
|
925 |
- |
|
926 |
- const uint32_t byte_len = pm->bcmp_data.byte_len; |
|
927 |
- unsigned char* conversion_buf[byte_len+1]; |
|
928 |
- char opt = (char) pm->bcmp_data.options; |
|
929 |
- uint32_t value = 0; |
|
930 |
- const unsigned char* end_buf = NULL; |
|
931 |
- |
|
932 |
- if (!(pm->flags & CLI_PCRE_BCOMP) || !(offset + pm->bcmp_data.offset + pm->bcmp_data.byte_len < length)) { |
|
933 |
- return CL_SUCCESS; |
|
934 |
- |
|
935 |
- } |
|
936 |
- |
|
937 |
- offset += pm->bcmp_data.offset; |
|
938 |
- memcpy(conversion_buf, buffer+offset, byte_len); |
|
939 |
- conversion_buf[byte_len] = '\0'; |
|
940 |
- |
|
941 |
- switch(opt) { |
|
942 |
- /*hb*/ |
|
943 |
- case CLI_PCRE_BCOMP_HEX | CLI_PCRE_BCOMP_LE: |
|
944 |
- value = cli_strntoul(buffer+offset, byte_len, &end_buf, 16); |
|
945 |
- if (value < 0 || NULL == end_buf || buffer+offset+byte_len != end_buf) { |
|
946 |
- return CL_SUCCESS; |
|
947 |
- } |
|
948 |
- |
|
949 |
- value = le32_to_host(value); |
|
950 |
- break; |
|
951 |
- |
|
952 |
- /*hl*/ |
|
953 |
- case CLI_PCRE_BCOMP_HEX | CLI_PCRE_BCOMP_BE: |
|
954 |
- value = cli_strntoul(buffer+offset, byte_len, &end_buf, 16); |
|
955 |
- if (value < 0 || NULL == end_buf || buffer+offset+byte_len != end_buf) { |
|
956 |
- return CL_SUCCESS; |
|
957 |
- } |
|
958 |
- |
|
959 |
- value = be32_to_host(value); |
|
960 |
- break; |
|
961 |
- |
|
962 |
- /*dl*/ |
|
963 |
- case CLI_PCRE_BCOMP_DEC | CLI_PCRE_BCOMP_LE: |
|
964 |
- value = cli_strntoul(buffer+offset, byte_len, &end_buf, 10); |
|
965 |
- if (value < 0 || NULL == end_buf || buffer+offset+byte_len != end_buf) { |
|
966 |
- return CL_SUCCESS; |
|
967 |
- } |
|
968 |
- |
|
969 |
- value = le32_to_host(value); |
|
970 |
- break; |
|
971 |
- |
|
972 |
- /*db*/ |
|
973 |
- case CLI_PCRE_BCOMP_DEC | CLI_PCRE_BCOMP_BE: |
|
974 |
- value = cli_strntoul(buffer+offset, byte_len, &end_buf, 10); |
|
975 |
- if (value < 0 || NULL == end_buf || buffer+offset+byte_len != end_buf) { |
|
976 |
- return CL_SUCCESS; |
|
977 |
- } |
|
978 |
- |
|
979 |
- value = be32_to_host(value); |
|
980 |
- break; |
|
981 |
- |
|
982 |
- default: |
|
983 |
- return CL_ENULLARG; |
|
984 |
- } |
|
985 |
- |
|
986 |
- switch (pm->bcmp_data.comp_symbol) { |
|
987 |
- |
|
988 |
- case '>': |
|
989 |
- if (value > pm->bcmp_data.comp_value) { |
|
990 |
- return CL_VIRUS; |
|
991 |
- } |
|
992 |
- |
|
993 |
- case '<': |
|
994 |
- if (value < pm->bcmp_data.comp_value) { |
|
995 |
- return CL_VIRUS; |
|
996 |
- } |
|
997 |
- |
|
998 |
- case '=': |
|
999 |
- if (value == pm->bcmp_data.comp_value) { |
|
1000 |
- return CL_VIRUS; |
|
1001 |
- } |
|
1002 |
- |
|
1003 |
- default: |
|
1004 |
- return CL_ENULLARG; |
|
1005 |
- } |
|
1006 |
- |
|
1007 |
- return CL_SUCCESS; |
|
1008 |
-} |
|
1009 |
- |
|
1010 |
- |
|
1011 | 920 |
void cli_pcre_freemeta(struct cli_matcher *root, struct cli_pcre_meta *pm) |
1012 | 921 |
{ |
1013 | 922 |
if (!pm) |
... | ... |
@@ -54,25 +54,11 @@ struct cli_pcre_off { |
54 | 54 |
|
55 | 55 |
#define CLI_PCRE_DISABLED 0x80000000 /* used for dconf or fail to build */ |
56 | 56 |
|
57 |
-#define CLI_PCRE_BCOMP_HEX 0x10 |
|
58 |
-#define CLI_PCRE_BCOMP_DEC 0x20 |
|
59 |
-#define CLI_PCRE_BCOMP_LE 0x01 |
|
60 |
-#define CLI_PCRE_BCOMP_BE 0x02 |
|
61 |
- |
|
62 |
-struct cli_pcre_bcomp { |
|
63 |
- size_t offset; |
|
64 |
- uint32_t options; |
|
65 |
- size_t byte_len; |
|
66 |
- char comp_symbol; |
|
67 |
- uint32_t comp_value; |
|
68 |
-}; |
|
69 |
- |
|
70 | 57 |
struct cli_pcre_meta { |
71 | 58 |
char *trigger; |
72 | 59 |
char *virname; |
73 | 60 |
uint32_t lsigid[3]; /* 0=valid, 1=lsigid, 2=subsigid */ |
74 | 61 |
struct cli_pcre_data pdata; |
75 |
- struct cli_pcre_bcomp bcmp_data; |
|
76 | 62 |
/* clamav offset data */ |
77 | 63 |
uint32_t offdata[4]; |
78 | 64 |
uint32_t offset_min, offset_max; |
... | ... |
@@ -96,8 +82,6 @@ void cli_pcre_freeoff(struct cli_pcre_off *data); |
96 | 96 |
int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char **virname, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, const struct cli_pcre_off *data, cli_ctx *ctx); |
97 | 97 |
void cli_pcre_freemeta(struct cli_matcher *root, struct cli_pcre_meta *pm); |
98 | 98 |
void cli_pcre_freetable(struct cli_matcher *root); |
99 |
-int cli_pcre_bcmp_compare_check(const unsigned char *buffer, uint32_t length, int offset, struct cli_pcre_meta *pm); |
|
100 |
-int cli_pcre_bcmp_add_opts(const char **opt, struct cli_pcre_bcomp *bcomp); |
|
101 | 99 |
#else |
102 | 100 |
/* NO-PCRE DECLARATIONS - defined because encasing everything in '#if' is a pain and because dynamic library mappings are weird */ |
103 | 101 |
#define PCRE_BYPASS "" |
... | ... |
@@ -180,6 +180,24 @@ static inline int matcher_run(const struct cli_matcher *root, |
180 | 180 |
return ret; |
181 | 181 |
} |
182 | 182 |
|
183 |
+ if (root->bcomp_metas) { |
|
184 |
+ ret = cli_bcomp_scanbuf(map, virname, acres, root, mdata, ctx); |
|
185 |
+ if (ret != CL_CLEAN) { |
|
186 |
+ if (ret == CL_VIRUS) { |
|
187 |
+ if (SCAN_ALL) |
|
188 |
+ viruses_found = 1; |
|
189 |
+ else { |
|
190 |
+ ret = cli_append_virus(ctx, *virname); |
|
191 |
+ if (ret != CL_CLEAN) |
|
192 |
+ return ret; |
|
193 |
+ } |
|
194 |
+ } else if (ret > CL_TYPENO && acmode & AC_SCAN_VIR) |
|
195 |
+ saved_ret = ret; |
|
196 |
+ else |
|
197 |
+ return ret; |
|
198 |
+ } |
|
199 |
+ } |
|
200 |
+ |
|
183 | 201 |
/* due to logical triggered, pcres cannot be evaluated until after full subsig matching */ |
184 | 202 |
/* cannot save pcre execution state without possible evasion; must scan entire buffer */ |
185 | 203 |
/* however, scanning the whole buffer may require the whole buffer being loaded into memory */ |
... | ... |
@@ -228,13 +246,16 @@ static inline int matcher_run(const struct cli_matcher *root, |
228 | 228 |
#endif /* HAVE_PCRE */ |
229 | 229 |
/* end experimental fragment */ |
230 | 230 |
|
231 |
- if (ctx && !SCAN_ALLMATCHES && ret == CL_VIRUS) |
|
231 |
+ if (ctx && !SCAN_ALLMATCHES && ret == CL_VIRUS) { |
|
232 | 232 |
return cli_append_virus(ctx, *virname); |
233 |
- if (ctx && SCAN_ALLMATCHES && viruses_found) |
|
233 |
+ } |
|
234 |
+ if (ctx && SCAN_ALLMATCHES && viruses_found) { |
|
234 | 235 |
return CL_VIRUS; |
235 |
- |
|
236 |
- if (saved_ret && ret == CL_CLEAN) |
|
236 |
+ } |
|
237 |
+ if (saved_ret && ret == CL_CLEAN) { |
|
237 | 238 |
return saved_ret; |
239 |
+ } |
|
240 |
+ |
|
238 | 241 |
return ret; |
239 | 242 |
} |
240 | 243 |
|
... | ... |
@@ -1217,6 +1238,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
1217 | 1217 |
if(bm_offmode) |
1218 | 1218 |
cli_bm_freeoff(&toff); |
1219 | 1219 |
cli_pcre_freeoff(&tpoff); |
1220 |
+ |
|
1220 | 1221 |
} |
1221 | 1222 |
|
1222 | 1223 |
if(groot) { |
... | ... |
@@ -1231,10 +1253,16 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
1231 | 1231 |
|
1232 | 1232 |
cli_hashset_destroy(&info.exeinfo.vinfo); |
1233 | 1233 |
|
1234 |
+<<<<<<< HEAD |
|
1234 | 1235 |
if (SCAN_ALLMATCHES && viruses_found) |
1236 |
+======= |
|
1237 |
+ if (SCAN_ALL && viruses_found) { |
|
1238 |
+>>>>>>> refactoring byte compare functionality as a subsig; adding loader and matchers for bytecompare subsig |
|
1235 | 1239 |
return CL_VIRUS; |
1236 |
- if(ret == CL_VIRUS) |
|
1240 |
+ } |
|
1241 |
+ if(ret == CL_VIRUS) { |
|
1237 | 1242 |
return CL_VIRUS; |
1243 |
+ } |
|
1238 | 1244 |
|
1239 | 1245 |
return (acmode & AC_SCAN_FT) ? type : CL_CLEAN; |
1240 | 1246 |
} |
... | ... |
@@ -49,6 +49,7 @@ |
49 | 49 |
#include "matcher-ac.h" |
50 | 50 |
#include "matcher-bm.h" |
51 | 51 |
#include "matcher-pcre.h" |
52 |
+#include "matcher-byte-comp.h" |
|
52 | 53 |
#include "matcher-hash.h" |
53 | 54 |
#include "matcher.h" |
54 | 55 |
#include "others.h" |
... | ... |
@@ -125,7 +126,7 @@ char *cli_virname(const char *virname, unsigned int official) |
125 | 125 |
|
126 | 126 |
int cli_sigopts_handler(struct cli_matcher *root, const char *virname, const char *hexsig, uint8_t sigopts, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options) |
127 | 127 |
{ |
128 |
- char *hexcpy, *start, *end; |
|
128 |
+ char *hexcpy, *start, *end, *mid; |
|
129 | 129 |
unsigned int i; |
130 | 130 |
int ret = CL_SUCCESS; |
131 | 131 |
|
... | ... |
@@ -192,6 +193,19 @@ int cli_sigopts_handler(struct cli_matcher *root, const char *virname, const cha |
192 | 192 |
return ret; |
193 | 193 |
} |
194 | 194 |
|
195 |
+ /* BCOMP sigopt handling */ |
|
196 |
+ start = strchr(hexcpy, '#'); |
|
197 |
+ end = strrchr(hexcpy, '#'); |
|
198 |
+ mid = strchr(hexcpy, '('); |
|
199 |
+ |
|
200 |
+ if (start != end && mid && (*(++mid) == '#' || !strncmp(mid, ">>", 2) || |
|
201 |
+ !strncmp(mid, "<<", 2) || !strncmp(mid, "0#", 2))) { |
|
202 |
+ /* TODO byte compare currently does not have support for sigopts, pass through */ |
|
203 |
+ ret = cli_parse_add(root, virname, hexcpy, sigopts, rtype, type, offset, target, lsigid, options); |
|
204 |
+ free(hexcpy); |
|
205 |
+ return ret; |
|
206 |
+ } |
|
207 |
+ |
|
195 | 208 |
/* NORMAL HEXSIG sigopt handling */ |
196 | 209 |
/* FULLWORD sigopt handling - only happens once */ |
197 | 210 |
if (sigopts & ACPATT_OPTION_FULLWORD) { |
... | ... |
@@ -299,7 +313,7 @@ int cli_sigopts_handler(struct cli_matcher *root, const char *virname, const cha |
299 | 299 |
int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, uint8_t sigopts, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options) |
300 | 300 |
{ |
301 | 301 |
struct cli_bm_patt *bm_new; |
302 |
- char *pt, *hexcpy, *start, *n, l, r; |
|
302 |
+ char *pt, *hexcpy, *start = NULL, *mid = NULL, *end = NULL, *n, l, r; |
|
303 | 303 |
const char *wild; |
304 | 304 |
int ret, asterisk = 0, range; |
305 | 305 |
unsigned int i, j, hexlen, nest, parts = 0; |
... | ... |
@@ -582,9 +596,17 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex |
582 | 582 |
|
583 | 583 |
free(pt); |
584 | 584 |
} |
585 |
+ } else if((start = strchr(hexsig, '(')) && (mid = strchr(hexsig, '#')) && (end = strrchr(hexsig, '#')) && mid != end) { |
|
586 |
+ |
|
587 |
+ /* format seems to match byte_compare */ |
|
588 |
+ if ( ret = cli_bcomp_addpatt(root, virname, hexsig, offset, lsigid, options) ) { |
|
589 |
+ cli_errmsg("cli_parse_add(): Problem adding signature (2b).\n"); |
|
590 |
+ return ret; |
|
591 |
+ } |
|
592 |
+ |
|
585 | 593 |
} else if(root->ac_only || type || lsigid || sigopts || strpbrk(hexsig, "?([") || (root->bm_offmode && (!strcmp(offset, "*") || strchr(offset, ','))) || strstr(offset, "VI") || strchr(offset, '$')) { |
586 | 594 |
if((ret = cli_ac_addsig(root, virname, hexsig, sigopts, 0, 0, 0, rtype, type, 0, 0, offset, lsigid, options))) { |
587 |
- cli_errmsg("cli_parse_add(): Problem adding signature (3).\n"); |
|
595 |
+ cli_errmsg("cli_parse_add(): Problem adding signature (3). %s \n", hexsig); |
|
588 | 596 |
return ret; |
589 | 597 |
} |
590 | 598 |
} else { |