~ubuntu-branches/ubuntu/feisty/clamav/feisty

« back to all changes in this revision

Viewing changes to libclamav/matcher.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2007-02-20 10:33:44 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20070220103344-zgcu2psnx9d98fpa
Tags: upstream-0.90
ImportĀ upstreamĀ versionĀ 0.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 *  Copyright (C) 2007-2009 Sourcefire, Inc.
3
 
 *
4
 
 *  Authors: Tomasz Kojm
 
2
 *  Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net>
5
3
 *
6
4
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License version 2 as
8
 
 *  published by the Free Software Foundation.
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License, or
 
7
 *  (at your option) any later version.
9
8
 *
10
9
 *  This program is distributed in the hope that it will be useful,
11
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
35
34
#include "matcher-ac.h"
36
35
#include "matcher-bm.h"
37
36
#include "md5.h"
38
 
#include "sha1.h"
39
 
#include "sha256.h"
40
37
#include "filetypes.h"
41
38
#include "matcher.h"
42
39
#include "pe.h"
43
40
#include "elf.h"
44
41
#include "execs.h"
45
42
#include "special.h"
46
 
#include "scanners.h"
47
43
#include "str.h"
48
 
#include "cltypes.h"
49
 
#include "default.h"
50
 
#include "macho.h"
51
 
#include "fmap.h"
52
 
#include "pe_icons.h"
53
 
#include "regex/regex.h"
54
 
#include "filtering.h"
55
 
#include "perflogging.h"
56
 
#include "bytecode_priv.h"
57
 
#include "bytecode_api_impl.h"
58
 
#include "sha256.h"
59
 
#include "sha1.h"
60
 
 
61
 
#ifdef CLI_PERF_LOGGING
62
 
 
63
 
static inline void PERF_LOG_FILTER(int32_t pos, int32_t length, int8_t trie)
64
 
{
65
 
    cli_perf_log_add(RAW_BYTES_SCANNED, length);
66
 
    cli_perf_log_add(FILTER_BYTES_SCANNED, length - pos);
67
 
    cli_perf_log_count2(TRIE_SCANNED, trie, length - pos);
68
 
}
69
 
 
70
 
static inline int PERF_LOG_TRIES(int8_t acmode, int8_t bm_called, int32_t length)
71
 
{
72
 
    if (bm_called)
73
 
        cli_perf_log_add(BM_SCANNED, length);
74
 
    if (acmode)
75
 
        cli_perf_log_add(AC_SCANNED, length);
76
 
    return 0;
77
 
}
78
 
 
79
 
#else
80
 
static inline void PERF_LOG_FILTER(int32_t pos, uint32_t length, int8_t trie) {}
81
 
static inline int PERF_LOG_TRIES(int8_t acmode, int8_t bm_called, int32_t length) { return 0; }
 
44
 
 
45
#ifdef HAVE_NCORE
 
46
#include "matcher-ncore.h"
82
47
#endif
83
48
 
84
 
static inline int matcher_run(const struct cli_matcher *root,
85
 
                              const unsigned char *buffer, uint32_t length,
86
 
                              const char **virname, struct cli_ac_data *mdata,
87
 
                              uint32_t offset,
88
 
                              const struct cli_target_info *tinfo,
89
 
                              cli_file_t ftype,
90
 
                              struct cli_matched_type **ftoffset,
91
 
                              unsigned int acmode,
92
 
                              struct cli_ac_result **acres,
93
 
                              fmap_t *map,
94
 
                              struct cli_bm_off *offdata)
95
 
{
96
 
    int ret;
97
 
    int32_t pos = 0;
98
 
    struct filter_match_info info;
99
 
    uint32_t orig_length, orig_offset;
100
 
    const unsigned char* orig_buffer;
101
 
 
102
 
    if (root->filter) {
103
 
        if(filter_search_ext(root->filter, buffer, length, &info) == -1) {
104
 
            /*  for safety always scan last maxpatlen bytes */
105
 
            pos = length - root->maxpatlen - 1;
106
 
            if (pos < 0) pos = 0;
107
 
            PERF_LOG_FILTER(pos, length, root->type);
108
 
        } else {
109
 
            /* must not cut buffer for 64[4-4]6161, because we must be able to check
110
 
             * 64! */
111
 
            pos = info.first_match - root->maxpatlen - 1;
112
 
            if (pos < 0) pos = 0;
113
 
            PERF_LOG_FILTER(pos, length, root->type);
114
 
        }
115
 
    } else {
116
 
        PERF_LOG_FILTER(0, length, root->type);
117
 
    }
118
 
 
119
 
    orig_length = length;
120
 
    orig_buffer = buffer;
121
 
    orig_offset = offset;
122
 
    length -= pos;
123
 
    buffer += pos;
124
 
    offset += pos;
125
 
    if (!root->ac_only) {
126
 
        PERF_LOG_TRIES(0, 1, length);
127
 
        if (root->bm_offmode) {
128
 
            /* Don't use prefiltering for BM offset mode, since BM keeps tracks
129
 
             * of offsets itself, and doesn't work if we skip chunks of input
130
 
             * data */
131
 
            ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata);
132
 
        } else {
133
 
            ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata);
134
 
        }
135
 
        if (ret == CL_VIRUS)
136
 
            return ret;
137
 
    }
138
 
    PERF_LOG_TRIES(acmode, 0, length);
139
 
    ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, NULL);
140
 
    return ret;
141
 
}
142
 
 
143
 
int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata)
144
 
{
145
 
        int ret = CL_CLEAN;
146
 
        unsigned int i;
 
49
static cli_file_t targettab[CL_TARGET_TABLE_SIZE] = { 0, CL_TYPE_MSEXE, CL_TYPE_MSOLE2, CL_TYPE_HTML, CL_TYPE_MAIL, CL_TYPE_GRAPHICS, CL_TYPE_ELF };
 
50
 
 
51
extern short cli_debug_flag;
 
52
 
 
53
int cli_scanbuff(const unsigned char *buffer, unsigned int length, const char **virname, const struct cl_engine *engine, cli_file_t ftype)
 
54
{
 
55
        int ret = CL_CLEAN, i;
147
56
        struct cli_ac_data mdata;
148
57
        struct cli_matcher *groot, *troot = NULL;
149
 
        const char **virname=ctx->virname;
150
 
        const struct cl_engine *engine=ctx->engine;
 
58
 
151
59
 
152
60
    if(!engine) {
153
61
        cli_errmsg("cli_scanbuff: engine == NULL\n");
154
62
        return CL_ENULLARG;
155
63
    }
156
64
 
 
65
#ifdef HAVE_NCORE
 
66
    if(engine->ncore)
 
67
        return cli_ncore_scanbuff(buffer, length, virname, engine, ftype, targettab);
 
68
#endif
 
69
 
157
70
    groot = engine->root[0]; /* generic signatures */
158
71
 
159
72
    if(ftype) {
160
 
        for(i = 1; i < CLI_MTARGETS; i++) {
161
 
            if(cli_mtargets[i].target == ftype) {
 
73
        for(i = 1; i < CL_TARGET_TABLE_SIZE; i++) {
 
74
            if(targettab[i] == ftype) {
162
75
                troot = engine->root[i];
163
76
                break;
164
77
            }
167
80
 
168
81
    if(troot) {
169
82
 
170
 
        if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
171
 
            return ret;
172
 
 
173
 
        ret = matcher_run(troot, buffer, length, virname, acdata ? (acdata[0]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
174
 
 
175
 
        if(!acdata)
176
 
            cli_ac_freedata(&mdata);
177
 
 
178
 
        if(ret == CL_VIRUS || ret == CL_EMEM)
179
 
            return ret;
180
 
    }
181
 
 
182
 
    if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
183
 
        return ret;
184
 
 
185
 
    ret = matcher_run(groot, buffer, length, virname, acdata ? (acdata[1]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
186
 
 
187
 
    if(!acdata)
 
83
        if((ret = cli_ac_initdata(&mdata, troot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
 
84
            return ret;
 
85
 
 
86
        if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, troot, 0, ftype, -1)) != CL_VIRUS)
 
87
            ret = cli_ac_scanbuff(buffer, length, virname, troot, &mdata, 0, 0, ftype, -1, NULL);
 
88
 
188
89
        cli_ac_freedata(&mdata);
189
90
 
 
91
        if(ret == CL_VIRUS)
 
92
            return ret;
 
93
    }
 
94
 
 
95
    if((ret = cli_ac_initdata(&mdata, groot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
 
96
        return ret;
 
97
 
 
98
    if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, groot, 0, ftype, -1)) != CL_VIRUS)
 
99
        ret = cli_ac_scanbuff(buffer, length, virname, groot, &mdata, 0, 0, ftype, -1, NULL);
 
100
 
 
101
    cli_ac_freedata(&mdata);
 
102
 
190
103
    return ret;
191
104
}
192
105
 
193
 
/*
194
 
 * offdata[0]: type
195
 
 * offdata[1]: offset value
196
 
 * offdata[2]: max shift
197
 
 * offdata[3]: section number
198
 
 */
199
 
int cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max)
200
 
{
201
 
        char offcpy[65];
 
106
struct cli_md5_node *cli_vermd5(const unsigned char *md5, const struct cl_engine *engine)
 
107
{
 
108
        struct cli_md5_node *pt;
 
109
 
 
110
 
 
111
    if(!(pt = engine->md5_hlist[md5[0] & 0xff]))
 
112
        return NULL;
 
113
 
 
114
    while(pt) {
 
115
        if(!memcmp(pt->md5, md5, 16))
 
116
            return pt;
 
117
 
 
118
        pt = pt->next;
 
119
    }
 
120
 
 
121
    return NULL;
 
122
}
 
123
 
 
124
off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd, cli_file_t ftype, int *ret)
 
125
{
 
126
        int (*einfo)(int, struct cli_exe_info *) = NULL;
202
127
        unsigned int n, val;
203
 
        char *pt;
204
 
 
205
 
    if(!info) { /* decode offset string */
206
 
        if(!offstr) {
207
 
            cli_errmsg("cli_caloff: offstr == NULL\n");
208
 
            return CL_ENULLARG;
209
 
        }
210
 
 
211
 
        if(!strcmp(offstr, "*")) {
212
 
            offdata[0] = *offset_max = *offset_min = CLI_OFF_ANY;
213
 
            return CL_SUCCESS;
214
 
        }
215
 
 
216
 
        if(strlen(offstr) > 64) {
217
 
            cli_errmsg("cli_caloff: Offset string too long\n");
218
 
            return CL_EMALFDB;
219
 
        }
220
 
        strcpy(offcpy, offstr);
221
 
 
222
 
        if((pt = strchr(offcpy, ','))) {
223
 
            if(!cli_isnumber(pt + 1)) {
224
 
                cli_errmsg("cli_caloff: Invalid offset shift value\n");
225
 
                return CL_EMALFDB;
226
 
            }
227
 
            offdata[2] = atoi(pt + 1);
228
 
            *pt = 0;
229
 
        } else {
230
 
            offdata[2] = 0;
231
 
        }
232
 
 
233
 
        *offset_max = *offset_min = CLI_OFF_NONE;
234
 
 
235
 
        if(!strncmp(offcpy, "EP+", 3) || !strncmp(offcpy, "EP-", 3)) {
236
 
            if(offcpy[2] == '+')
237
 
                offdata[0] = CLI_OFF_EP_PLUS;
238
 
            else
239
 
                offdata[0] = CLI_OFF_EP_MINUS;
240
 
 
241
 
            if(!cli_isnumber(&offcpy[3])) {
242
 
                cli_errmsg("cli_caloff: Invalid offset value\n");
243
 
                return CL_EMALFDB;
244
 
            }
245
 
            offdata[1] = atoi(&offcpy[3]);
246
 
 
247
 
        } else if(offcpy[0] == 'S') {
248
 
            if(!strncmp(offstr, "SL+", 3)) {
249
 
                offdata[0] = CLI_OFF_SL_PLUS;
250
 
                if(!cli_isnumber(&offcpy[3])) {
251
 
                    cli_errmsg("cli_caloff: Invalid offset value\n");
252
 
                    return CL_EMALFDB;
253
 
                }
254
 
                offdata[1] = atoi(&offcpy[3]);
255
 
 
256
 
            } else if(sscanf(offcpy, "S%u+%u", &n, &val) == 2) {
257
 
                offdata[0] = CLI_OFF_SX_PLUS;
258
 
                offdata[1] = val;
259
 
                offdata[3] = n;
260
 
            } else {
261
 
                cli_errmsg("cli_caloff: Invalid offset string\n");
262
 
                return CL_EMALFDB;
263
 
            }
264
 
 
265
 
        } else if(!strncmp(offcpy, "EOF-", 4)) {
266
 
            offdata[0] = CLI_OFF_EOF_MINUS;
267
 
            if(!cli_isnumber(&offcpy[4])) {
268
 
                cli_errmsg("cli_caloff: Invalid offset value\n");
269
 
                return CL_EMALFDB;
270
 
            }
271
 
            offdata[1] = atoi(&offcpy[4]);
272
 
        } else if(!strncmp(offcpy, "VI", 2)) {
273
 
            /* versioninfo */
274
 
            offdata[0] = CLI_OFF_VERSION;
275
 
        } else if (strchr(offcpy, '$')) {
276
 
            if (sscanf(offcpy, "$%u$", &n) != 1) {
277
 
                cli_errmsg("cli_caloff: Invalid macro($) in offset: %s\n", offcpy);
278
 
                return CL_EMALFDB;
279
 
            }
280
 
            if (n >= 32) {
281
 
                cli_errmsg("cli_caloff: at most 32 macro groups supported\n");
282
 
                return CL_EMALFDB;
283
 
            }
284
 
            offdata[0] = CLI_OFF_MACRO;
285
 
            offdata[1] = n;
286
 
        } else {
287
 
            offdata[0] = CLI_OFF_ABSOLUTE;
288
 
            if(!cli_isnumber(offcpy)) {
289
 
                cli_errmsg("cli_caloff: Invalid offset value\n");
290
 
                return CL_EMALFDB;
291
 
            }
292
 
            *offset_min = offdata[1] = atoi(offcpy);
293
 
            *offset_max = *offset_min + offdata[2];
294
 
        }
295
 
 
296
 
        if(offdata[0] != CLI_OFF_ANY && offdata[0] != CLI_OFF_ABSOLUTE &&
297
 
           offdata[0] != CLI_OFF_EOF_MINUS && offdata[0] != CLI_OFF_MACRO) {
298
 
            if(target != 1 && target != 6 && target != 9) {
299
 
                cli_errmsg("cli_caloff: Invalid offset type for target %u\n", target);
300
 
                return CL_EMALFDB;
301
 
            }
302
 
        }
303
 
 
304
 
    } else {
305
 
        /* calculate relative offsets */
 
128
        off_t pos, offset;
 
129
 
 
130
 
 
131
    *ret = 0;
 
132
 
 
133
    if(!strncmp(offstr, "EP", 2) || offstr[0] == 'S') {
 
134
 
306
135
        if(info->status == -1) {
307
 
            *offset_min = CLI_OFF_NONE;
308
 
            if(offset_max)
309
 
                *offset_max = CLI_OFF_NONE;
310
 
            return CL_SUCCESS;
311
 
        }
312
 
 
313
 
        switch(offdata[0]) {
314
 
            case CLI_OFF_EOF_MINUS:
315
 
                *offset_min = info->fsize - offdata[1];
316
 
                break;
317
 
 
318
 
            case CLI_OFF_EP_PLUS:
319
 
                *offset_min = info->exeinfo.ep + offdata[1];
320
 
                break;
321
 
 
322
 
            case CLI_OFF_EP_MINUS:
323
 
                *offset_min = info->exeinfo.ep - offdata[1];
324
 
                break;
325
 
 
326
 
            case CLI_OFF_SL_PLUS:
327
 
                *offset_min = info->exeinfo.section[info->exeinfo.nsections - 1].raw + offdata[1];
328
 
                break;
329
 
 
330
 
            case CLI_OFF_SX_PLUS:
331
 
                if(offdata[3] >= info->exeinfo.nsections)
332
 
                    *offset_min = CLI_OFF_NONE;
333
 
                else
334
 
                    *offset_min = info->exeinfo.section[offdata[3]].raw + offdata[1];
335
 
                break;
336
 
            case CLI_OFF_VERSION:
337
 
                *offset_min = *offset_max = CLI_OFF_ANY;
338
 
                break;
339
 
            default:
340
 
                cli_errmsg("cli_caloff: Not a relative offset (type: %u)\n", offdata[0]);
341
 
                return CL_EARG;
342
 
        }
343
 
 
344
 
        if(offset_max) {
345
 
            if(*offset_min != CLI_OFF_NONE)
346
 
                *offset_max = *offset_min + offdata[2];
347
 
            else
348
 
                *offset_max = CLI_OFF_NONE;
349
 
        }
350
 
    }
351
 
 
352
 
    return CL_SUCCESS;
353
 
}
354
 
 
355
 
static void targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map)
356
 
{
357
 
        int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;
358
 
 
359
 
 
360
 
    memset(info, 0, sizeof(struct cli_target_info));
361
 
    info->fsize = map->len;
362
 
    cli_hashset_init_noalloc(&info->exeinfo.vinfo);
363
 
 
364
 
    if(target == 1)
365
 
        einfo = cli_peheader;
366
 
    else if(target == 6)
367
 
        einfo = cli_elfheader;
368
 
    else if(target == 9)
369
 
        einfo = cli_machoheader;
370
 
    else return;
371
 
 
372
 
    if(einfo(map, &info->exeinfo))
373
 
        info->status = -1;
374
 
    else
375
 
        info->status = 1;
376
 
}
377
 
 
378
 
int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx)
379
 
{
380
 
        char md5[33];
381
 
        unsigned int i;
382
 
        const char *virname;
383
 
        SHA1Context sha1;
384
 
        SHA256_CTX sha256;
385
 
        fmap_t *map;
386
 
        char *ptr;
387
 
        uint8_t shash1[SHA1_HASH_SIZE*2+1];
388
 
        uint8_t shash256[SHA256_HASH_SIZE*2+1];
389
 
        int have_sha1, have_sha256;
390
 
 
391
 
    if(cli_hm_scan(digest, size, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
392
 
        cli_dbgmsg("cli_checkfp(md5): Found false positive detection (fp sig: %s)\n", virname);
393
 
        return CL_CLEAN;
394
 
    }
395
 
 
396
 
    for(i = 0; i < 16; i++)
397
 
        sprintf(md5 + i * 2, "%02x", digest[i]);
398
 
    md5[32] = 0;
399
 
    cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int) size, *ctx->virname ? *ctx->virname : "Name");
400
 
 
401
 
    map = *ctx->fmap;
402
 
    have_sha1 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, size);
403
 
    have_sha256 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA256, size);
404
 
    if(have_sha1 || have_sha256) {
405
 
        if((ptr = fmap_need_off_once(map, 0, size))) {
406
 
            if(have_sha1) {
407
 
                SHA1Init(&sha1);
408
 
                SHA1Update(&sha1, ptr, size);
409
 
                SHA1Final(&sha1, &shash1[SHA1_HASH_SIZE]);
410
 
                if(cli_hm_scan(&shash1[SHA1_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS){
411
 
                    cli_dbgmsg("cli_checkfp(sha1): Found false positive detection (fp sig: %s)\n", virname);
412
 
                    return CL_CLEAN;
413
 
                }
414
 
            }
415
 
            if(have_sha256) {
416
 
                sha256_init(&sha256);
417
 
                sha256_update(&sha256, ptr, size);
418
 
                sha256_final(&sha256, &shash256[SHA256_HASH_SIZE]);
419
 
                if(cli_hm_scan(&shash256[SHA256_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS){
420
 
                    cli_dbgmsg("cli_checkfp(sha256): Found false positive detection (fp sig: %s)\n", virname);
421
 
                    return CL_CLEAN;
422
 
                }
423
 
            }
424
 
        }
425
 
    }
426
 
#ifdef HAVE__INTERNAL__SHA_COLLECT
427
 
    if((ctx->options & CL_SCAN_INTERNAL_COLLECT_SHA) && ctx->sha_collect>0) {
428
 
        if((ptr = fmap_need_off_once(map, 0, size))) {
429
 
            if(!have_sha256) {
430
 
                sha256_init(&sha256);
431
 
                sha256_update(&sha256, ptr, size);
432
 
                sha256_final(&sha256, &shash256[SHA256_HASH_SIZE]);
433
 
            }
434
 
            for(i=0; i<SHA256_HASH_SIZE; i++)
435
 
                sprintf((char *)shash256+i*2, "%02x", shash256[SHA256_HASH_SIZE+i]);
436
 
 
437
 
            if(!have_sha1) {
438
 
                SHA1Init(&sha1);
439
 
                SHA1Update(&sha1, ptr, size);
440
 
                SHA1Final(&sha1, &shash1[SHA1_HASH_SIZE]);
441
 
            }
442
 
            for(i=0; i<SHA1_HASH_SIZE; i++)
443
 
                sprintf((char *)shash1+i*2, "%02x", shash1[SHA1_HASH_SIZE+i]);
444
 
 
445
 
            cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, *ctx->virname, ctx->entry_filename);
446
 
        } else
447
 
            cli_errmsg("can't compute sha\n!");
448
 
        ctx->sha_collect = -1;
449
 
    }
450
 
#endif
451
 
 
452
 
    if (ctx->engine->cb_hash)
453
 
        ctx->engine->cb_hash(ctx->fmap[0]->fd, size, md5, ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx);
454
 
 
455
 
    return CL_VIRUS;
456
 
}
457
 
 
458
 
static int matchicon(cli_ctx *ctx, struct cli_exe_info *exeinfo, const char *grp1, const char *grp2)
459
 
{
460
 
        icon_groupset iconset;
461
 
 
462
 
    if(!ctx ||
463
 
       !ctx->engine ||
464
 
       !ctx->engine->iconcheck ||
465
 
       !ctx->engine->iconcheck->group_counts[0] ||
466
 
       !ctx->engine->iconcheck->group_counts[1] ||
467
 
       !exeinfo->res_addr
468
 
    ) return CL_CLEAN;
469
 
 
470
 
    cli_icongroupset_init(&iconset);
471
 
    cli_icongroupset_add(grp1 ? grp1 : "*", &iconset, 0, ctx);
472
 
    cli_icongroupset_add(grp2 ? grp2 : "*", &iconset, 1, ctx);
473
 
    return cli_scanicon(&iconset, exeinfo->res_addr, ctx, exeinfo->section, exeinfo->nsections, exeinfo->hdr_size);
474
 
}
475
 
 
476
 
int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx , const uint8_t* grp1, int32_t grp1len,
477
 
                            const uint8_t* grp2, int32_t grp2len)
478
 
{
479
 
    int ret;
480
 
    char group1[128], group2[128];
481
 
    const char **oldvirname;
482
 
    struct cli_exe_info info;
483
 
 
484
 
    if (!ctx->hooks.pedata->ep) {
485
 
        cli_dbgmsg("bytecode: matchicon only works with PE files\n");
486
 
        return -1;
487
 
    }
488
 
    if ((size_t) grp1len > sizeof(group1)-1 ||
489
 
        (size_t) grp2len > sizeof(group2)-1)
490
 
        return -1;
491
 
    oldvirname = ((cli_ctx*)ctx->ctx)->virname;
492
 
    ((cli_ctx*)ctx->ctx)->virname = NULL;
493
 
    memcpy(group1, grp1, grp1len);
494
 
    memcpy(group2, grp2, grp2len);
495
 
    group1[grp1len] = 0;
496
 
    group2[grp2len] = 0;
497
 
    memset(&info, 0, sizeof(info));
498
 
    if (ctx->bc->kind == BC_PE_UNPACKER || ctx->bc->kind == BC_PE_ALL) {
499
 
        if(le16_to_host(ctx->hooks.pedata->file_hdr.Characteristics) & 0x2000 ||
500
 
           !ctx->hooks.pedata->dirs[2].Size)
501
 
            info.res_addr = 0;
 
136
            *ret = -1;
 
137
            return 0;
 
138
 
 
139
        } else if(!info->status) {
 
140
 
 
141
            if(ftype == CL_TYPE_MSEXE)
 
142
                einfo = cli_peheader;
 
143
            else if(ftype == CL_TYPE_ELF)
 
144
                einfo = cli_elfheader;
 
145
 
 
146
            if(einfo) {
 
147
                if((pos = lseek(fd, 0, SEEK_CUR)) == -1) {
 
148
                    cli_dbgmsg("Invalid descriptor\n");
 
149
                    info->status = *ret = -1;
 
150
                    return 0;
 
151
                }
 
152
 
 
153
                lseek(fd, 0, SEEK_SET);
 
154
                if(einfo(fd, &info->exeinfo)) {
 
155
                    lseek(fd, pos, SEEK_SET);
 
156
                    info->status = *ret = -1;
 
157
                    return 0;
 
158
                }
 
159
                lseek(fd, pos, SEEK_SET);
 
160
                info->status = 1;
 
161
            }
 
162
        }
 
163
    }
 
164
 
 
165
    if(isdigit(offstr[0])) {
 
166
        return atoi(offstr);
 
167
 
 
168
    } else if(info->status == 1 && (!strncmp(offstr, "EP+", 3) || !strncmp(offstr, "EP-", 3))) {
 
169
 
 
170
        if(offstr[2] == '+')
 
171
            return info->exeinfo.ep + atoi(offstr + 3);
502
172
        else
503
 
            info.res_addr = le32_to_host(ctx->hooks.pedata->dirs[2].VirtualAddress);
504
 
    } else
505
 
        info.res_addr = ctx->resaddr; /* from target_info */
506
 
    info.section = (struct cli_exe_section*)ctx->sections;
507
 
    info.nsections = ctx->hooks.pedata->nsections;
508
 
    info.hdr_size = ctx->hooks.pedata->hdr_size;
509
 
    cli_dbgmsg("bytecode matchicon %s %s\n", group1, group2);
510
 
    ret = matchicon(ctx->ctx, &info, group1[0] ? group1 : NULL,
511
 
                    group2[0] ? group2 : NULL);
512
 
    ((cli_ctx*)ctx->ctx)->virname = oldvirname;
513
 
    return ret;
514
 
}
515
 
 
516
 
 
517
 
int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres)
518
 
{
519
 
    int ret = CL_EMEM, empty;
520
 
    fmap_t *map = *ctx->fmap;
521
 
 
522
 
    if((*ctx->fmap = fmap_check_empty(desc, 0, 0, &empty))) {
523
 
        ret = cli_fmap_scandesc(ctx, ftype, ftonly, ftoffset, acmode, acres, NULL);
524
 
        map->dont_cache_flag = (*ctx->fmap)->dont_cache_flag;
525
 
        funmap(*ctx->fmap);
526
 
    }
527
 
    *ctx->fmap = map;
528
 
    if(empty)
529
 
        return CL_CLEAN;
530
 
    return ret;
531
 
}
532
 
 
533
 
int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash)
534
 
{
535
 
        unsigned int i, evalcnt;
536
 
        uint64_t evalids;
537
 
        fmap_t *map = *ctx->fmap;
538
 
 
539
 
    for(i = 0; i < root->ac_lsigs; i++) {
540
 
        evalcnt = 0;
541
 
        evalids = 0;
542
 
        cli_ac_chkmacro(root, acdata, i);
543
 
        if(cli_ac_chklsig(root->ac_lsigtable[i]->logic, root->ac_lsigtable[i]->logic + strlen(root->ac_lsigtable[i]->logic), acdata->lsigcnt[i], &evalcnt, &evalids, 0) == 1) {
544
 
            if(root->ac_lsigtable[i]->tdb.container && root->ac_lsigtable[i]->tdb.container[0] != ctx->container_type)
545
 
                continue;
546
 
            if(root->ac_lsigtable[i]->tdb.filesize && (root->ac_lsigtable[i]->tdb.filesize[0] > map->len || root->ac_lsigtable[i]->tdb.filesize[1] < map->len))
547
 
                continue;
548
 
 
549
 
            if(root->ac_lsigtable[i]->tdb.ep || root->ac_lsigtable[i]->tdb.nos) {
550
 
                if(!target_info || target_info->status != 1)
551
 
                    continue;
552
 
                if(root->ac_lsigtable[i]->tdb.ep && (root->ac_lsigtable[i]->tdb.ep[0] > target_info->exeinfo.ep || root->ac_lsigtable[i]->tdb.ep[1] < target_info->exeinfo.ep))
553
 
                    continue;
554
 
                if(root->ac_lsigtable[i]->tdb.nos && (root->ac_lsigtable[i]->tdb.nos[0] > target_info->exeinfo.nsections || root->ac_lsigtable[i]->tdb.nos[1] < target_info->exeinfo.nsections))
555
 
                    continue;
556
 
            }
557
 
 
558
 
            if(hash && root->ac_lsigtable[i]->tdb.handlertype) {
559
 
                if(memcmp(ctx->handlertype_hash, hash, 16)) {
560
 
                    ctx->recursion++;
561
 
                    memcpy(ctx->handlertype_hash, hash, 16);
562
 
                    if(cli_magic_scandesc_type(map->fd, ctx, root->ac_lsigtable[i]->tdb.handlertype[0]) == CL_VIRUS) {
563
 
                        ctx->recursion--;
564
 
                        return CL_VIRUS;
565
 
                    }
566
 
                    ctx->recursion--;
567
 
                    continue;
568
 
                }
569
 
            }
570
 
 
571
 
            if(root->ac_lsigtable[i]->tdb.icongrp1 || root->ac_lsigtable[i]->tdb.icongrp2) {
572
 
                if(!target_info || target_info->status != 1)
573
 
                    continue;
574
 
                if(matchicon(ctx, &target_info->exeinfo, root->ac_lsigtable[i]->tdb.icongrp1, root->ac_lsigtable[i]->tdb.icongrp2) == CL_VIRUS) {
575
 
                    if(!root->ac_lsigtable[i]->bc_idx) {
576
 
                        if(ctx->virname)
577
 
                            *ctx->virname = root->ac_lsigtable[i]->virname;
578
 
                        return CL_VIRUS;
579
 
                    } else if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
580
 
                        return CL_VIRUS;
581
 
                    }
582
 
                }
583
 
                continue;
584
 
            }
585
 
            if(!root->ac_lsigtable[i]->bc_idx) {
586
 
                if(ctx->virname)
587
 
                    *ctx->virname = root->ac_lsigtable[i]->virname;
588
 
                return CL_VIRUS;
589
 
            }
590
 
            if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
591
 
                return CL_VIRUS;
592
 
            }
593
 
        }
594
 
    }
595
 
    return CL_CLEAN;
596
 
}
597
 
 
598
 
int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash)
599
 
{
600
 
        unsigned char *buff;
601
 
        int ret = CL_CLEAN, type = CL_CLEAN, bytes, compute_hash[CLI_HASH_AVAIL_TYPES];
602
 
        unsigned int i = 0, bm_offmode = 0;
603
 
        uint32_t maxpatlen, offset = 0;
 
173
            return info->exeinfo.ep - atoi(offstr + 3);
 
174
 
 
175
    } else if(info->status == 1 && offstr[0] == 'S') {
 
176
 
 
177
        if(!strncmp(offstr, "SL", 2) && info->exeinfo.section[info->exeinfo.nsections - 1].rsz) {
 
178
 
 
179
            if(sscanf(offstr, "SL+%u", &val) != 1) {
 
180
                *ret = -1;
 
181
                return 0;
 
182
            }
 
183
 
 
184
            offset = val + info->exeinfo.section[info->exeinfo.nsections - 1].raw;
 
185
 
 
186
        } else {
 
187
 
 
188
            if(sscanf(offstr, "S%u+%u", &n, &val) != 2) {
 
189
                *ret = -1;
 
190
                return 0;
 
191
            }
 
192
 
 
193
            if(n >= info->exeinfo.nsections || !info->exeinfo.section[n].rsz) {
 
194
                *ret = -1;
 
195
                return 0;
 
196
            }
 
197
 
 
198
            offset = val + info->exeinfo.section[n].raw;
 
199
        }
 
200
 
 
201
        return offset;
 
202
 
 
203
    } else if(!strncmp(offstr, "EOF-", 4)) {
 
204
            struct stat sb;
 
205
 
 
206
        if(!info->fsize) {
 
207
            if(fstat(fd, &sb) == -1) {
 
208
                info->status = *ret = -1;
 
209
                return 0;
 
210
            }
 
211
            info->fsize = sb.st_size;
 
212
        }
 
213
 
 
214
        return info->fsize - atoi(offstr + 4);
 
215
    }
 
216
 
 
217
    *ret = -1;
 
218
    return 0;
 
219
}
 
220
 
 
221
static int cli_checkfp(int fd, const struct cl_engine *engine)
 
222
{
 
223
        struct cli_md5_node *md5_node;
 
224
        unsigned char *digest;
 
225
 
 
226
 
 
227
    if(engine->md5_hlist) {
 
228
 
 
229
        if(!(digest = cli_md5digest(fd))) {
 
230
            cli_errmsg("cli_checkfp(): Can't generate MD5 checksum\n");
 
231
            return 0;
 
232
        }
 
233
 
 
234
        if((md5_node = cli_vermd5(digest, engine)) && md5_node->fp) {
 
235
                struct stat sb;
 
236
 
 
237
            if(fstat(fd, &sb))
 
238
                return CL_EIO;
 
239
 
 
240
            if((unsigned int) sb.st_size != md5_node->size) {
 
241
                cli_warnmsg("Detected false positive MD5 match. Please report.\n");
 
242
            } else {
 
243
                cli_dbgmsg("Eliminated false positive match (fp sig: %s)\n", md5_node->virname);
 
244
                free(digest);
 
245
                return 1;
 
246
            }
 
247
        }
 
248
 
 
249
        free(digest);
 
250
    }
 
251
 
 
252
    return 0;
 
253
}
 
254
 
 
255
int cli_validatesig(cli_file_t ftype, const char *offstr, off_t fileoff, struct cli_target_info *info, int desc, const char *virname)
 
256
{
 
257
        off_t offset;
 
258
        int ret;
 
259
 
 
260
 
 
261
    if(offstr && desc != -1) {
 
262
        offset = cli_caloff(offstr, info, desc, ftype, &ret);
 
263
 
 
264
        if(ret == -1) {
 
265
            cli_dbgmsg("cli_validatesig: Can't calculate offset for signature %s\n", virname);
 
266
            return 0;
 
267
        }
 
268
 
 
269
        if(fileoff != offset) {
 
270
            cli_dbgmsg("Signature offset: %lu, expected: %lu (%s)\n", fileoff, offset, virname);
 
271
            return 0;
 
272
        }
 
273
    }
 
274
 
 
275
    return 1;
 
276
}
 
277
 
 
278
int cli_scandesc(int desc, cli_ctx *ctx, unsigned short otfrec, cli_file_t ftype, unsigned short ftonly, struct cli_matched_type **ftoffset)
 
279
{
 
280
        unsigned char *buffer, *buff, *endbl, *upt;
 
281
        int ret = CL_CLEAN, type = CL_CLEAN, i, bytes;
 
282
        unsigned int buffersize, length, maxpatlen, shift = 0;
 
283
        unsigned long int offset = 0;
604
284
        struct cli_ac_data gdata, tdata;
605
 
        struct cli_bm_off toff;
606
285
        cli_md5_ctx md5ctx;
607
 
        SHA256_CTX sha256ctx;
608
 
        SHA1Context sha1ctx;
609
 
        unsigned char digest[CLI_HASH_AVAIL_TYPES][32];
 
286
        unsigned char digest[16];
 
287
        struct cli_md5_node *md5_node;
610
288
        struct cli_matcher *groot = NULL, *troot = NULL;
611
 
        struct cli_target_info info;
612
 
        fmap_t *map = *ctx->fmap;
613
 
        struct cli_matcher *hdb, *fp;
 
289
 
614
290
 
615
291
    if(!ctx->engine) {
616
292
        cli_errmsg("cli_scandesc: engine == NULL\n");
617
293
        return CL_ENULLARG;
618
294
    }
619
295
 
 
296
#ifdef HAVE_NCORE
 
297
    if(ctx->engine->ncore) {
 
298
            int cont;
 
299
 
 
300
        ret = cli_ncore_scandesc(desc, ctx, ftype, &cont, targettab, &md5ctx);
 
301
        if(!cont)
 
302
            return ret;
 
303
    }
 
304
#endif
 
305
 
620
306
    if(!ftonly)
621
307
        groot = ctx->engine->root[0]; /* generic signatures */
622
308
 
623
309
    if(ftype) {
624
 
        for(i = 1; i < CLI_MTARGETS; i++) {
625
 
            if(cli_mtargets[i].target == ftype) {
 
310
        for(i = 1; i < CL_TARGET_TABLE_SIZE; i++) {
 
311
            if(targettab[i] == ftype) {
626
312
                troot = ctx->engine->root[i];
627
313
                break;
628
314
            }
641
327
            maxpatlen = groot->maxpatlen;
642
328
    }
643
329
 
644
 
    targetinfo(&info, i, map);
 
330
    /* prepare the buffer */
 
331
    buffersize = maxpatlen + SCANBUFF;
 
332
    if(!(buffer = (unsigned char *) cli_calloc(buffersize, sizeof(unsigned char)))) {
 
333
        cli_dbgmsg("cli_scandesc(): unable to cli_calloc(%u)\n", buffersize);
 
334
        return CL_EMEM;
 
335
    }
645
336
 
646
 
    if(!ftonly)
647
 
        if((ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(groot, &gdata, &info))) {
648
 
            if(info.exeinfo.section)
649
 
                free(info.exeinfo.section);
650
 
            cli_hashset_destroy(&info.exeinfo.vinfo);
651
 
            return ret;
652
 
        }
 
337
    if(!ftonly && (ret = cli_ac_initdata(&gdata, groot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
 
338
        return ret;
653
339
 
654
340
    if(troot) {
655
 
        if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(troot, &tdata, &info))) {
656
 
            if(!ftonly)
657
 
                cli_ac_freedata(&gdata);
658
 
            if(info.exeinfo.section)
659
 
                free(info.exeinfo.section);
660
 
            cli_hashset_destroy(&info.exeinfo.vinfo);
 
341
        if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
661
342
            return ret;
662
 
        }
663
 
        if(troot->bm_offmode) {
664
 
            if(map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
665
 
                if((ret = cli_bm_initoff(troot, &toff, &info))) {
666
 
                    if(!ftonly)
667
 
                        cli_ac_freedata(&gdata);
668
 
                    cli_ac_freedata(&tdata);
669
 
                    if(info.exeinfo.section)
670
 
                        free(info.exeinfo.section);
671
 
                    cli_hashset_destroy(&info.exeinfo.vinfo);
672
 
                    return ret;
673
 
                }
674
 
                bm_offmode = 1;
675
 
            }
676
 
        }
677
 
    }
678
 
 
679
 
    hdb = ctx->engine->hm_hdb;
680
 
    fp = ctx->engine->hm_fp;
681
 
 
682
 
    if(!ftonly && hdb) {
683
 
        if(!refhash) {
684
 
            if(cli_hm_have_size(hdb, CLI_HASH_MD5, map->len) || cli_hm_have_size(fp, CLI_HASH_MD5, map->len)) {
685
 
                cli_md5_init(&md5ctx);
686
 
                compute_hash[CLI_HASH_MD5] = 1;
687
 
            } else
688
 
                compute_hash[CLI_HASH_MD5] = 0;
689
 
        } else {
690
 
            compute_hash[CLI_HASH_MD5] = 0;
691
 
            memcpy(digest[CLI_HASH_MD5], refhash, 16);
692
 
        }
693
 
 
694
 
        if(cli_hm_have_size(hdb, CLI_HASH_SHA1, map->len) || cli_hm_have_size(fp, CLI_HASH_SHA1, map->len)) {
695
 
            SHA1Init(&sha1ctx);
696
 
            compute_hash[CLI_HASH_SHA1] = 1;
697
 
        } else
698
 
            compute_hash[CLI_HASH_SHA1] = 0;
699
 
 
700
 
        if(cli_hm_have_size(hdb, CLI_HASH_SHA256, map->len) || cli_hm_have_size(fp, CLI_HASH_SHA256, map->len)) {
701
 
            sha256_init(&sha256ctx);
702
 
            compute_hash[CLI_HASH_SHA256] = 1;
703
 
        } else
704
 
            compute_hash[CLI_HASH_SHA256] = 0;
705
 
    }
706
 
 
707
 
    while(offset < map->len) {
708
 
        bytes = MIN(map->len - offset, SCANBUFF);
709
 
        if(!(buff = fmap_need_off_once(map, offset, bytes)))
710
 
            break;
 
343
    }
 
344
 
 
345
    if(!ftonly && ctx->engine->md5_hlist)
 
346
        cli_md5_init(&md5ctx);
 
347
 
 
348
    buff = buffer;
 
349
    buff += maxpatlen; /* pointer to read data block */
 
350
    endbl = buff + SCANBUFF - maxpatlen; /* pointer to the last block
 
351
                                          * length of maxpatlen
 
352
                                          */
 
353
 
 
354
    upt = buff;
 
355
    while((bytes = cli_readn(desc, buff + shift, SCANBUFF - shift)) > 0) {
 
356
 
711
357
        if(ctx->scanned)
712
358
            *ctx->scanned += bytes / CL_COUNT_PRECISION;
713
359
 
 
360
        length = shift + bytes;
 
361
        if(upt == buffer)
 
362
            length += maxpatlen;
 
363
 
714
364
        if(troot) {
715
 
            ret = matcher_run(troot, buff, bytes, ctx->virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL);
 
365
            if(troot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, troot, offset, ftype, desc)) != CL_VIRUS)
 
366
                ret = cli_ac_scanbuff(upt, length, ctx->virname, troot, &tdata, otfrec, offset, ftype, desc, ftoffset);
716
367
 
717
 
            if(ret == CL_VIRUS || ret == CL_EMEM) {
 
368
            if(ret == CL_VIRUS) {
 
369
                free(buffer);
718
370
                if(!ftonly)
719
371
                    cli_ac_freedata(&gdata);
720
372
                cli_ac_freedata(&tdata);
721
 
                if(bm_offmode)
722
 
                    cli_bm_freeoff(&toff);
723
 
                if(info.exeinfo.section)
724
 
                    free(info.exeinfo.section);
725
 
                cli_hashset_destroy(&info.exeinfo.vinfo);
726
 
                return ret;
 
373
 
 
374
                lseek(desc, 0, SEEK_SET);
 
375
                if(cli_checkfp(desc, ctx->engine))
 
376
                    return CL_CLEAN;
 
377
                else
 
378
                    return CL_VIRUS;
727
379
            }
728
380
        }
729
381
 
730
382
        if(!ftonly) {
731
 
            ret = matcher_run(groot, buff, bytes, ctx->virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL);
 
383
            if(groot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, groot, offset, ftype, desc)) != CL_VIRUS)
 
384
                ret = cli_ac_scanbuff(upt, length, ctx->virname, groot, &gdata, otfrec, offset, ftype, desc, ftoffset);
732
385
 
733
 
            if(ret == CL_VIRUS || ret == CL_EMEM) {
 
386
            if(ret == CL_VIRUS) {
 
387
                free(buffer);
734
388
                cli_ac_freedata(&gdata);
735
 
                if(troot) {
 
389
                if(troot)
736
390
                    cli_ac_freedata(&tdata);
737
 
                    if(bm_offmode)
738
 
                        cli_bm_freeoff(&toff);
739
 
                }
740
 
                if(info.exeinfo.section)
741
 
                    free(info.exeinfo.section);
742
 
                cli_hashset_destroy(&info.exeinfo.vinfo);
743
 
                return ret;
744
 
            } else if((acmode & AC_SCAN_FT) && ret >= CL_TYPENO) {
 
391
                lseek(desc, 0, SEEK_SET);
 
392
                if(cli_checkfp(desc, ctx->engine))
 
393
                    return CL_CLEAN;
 
394
                else
 
395
                    return CL_VIRUS;
 
396
 
 
397
            } else if(otfrec && ret >= CL_TYPENO) {
745
398
                if(ret > type)
746
399
                    type = ret;
747
400
            }
748
401
 
749
 
            if(hdb) {
750
 
                void *data = buff + maxpatlen * (offset!=0);
751
 
                uint32_t data_len = bytes - maxpatlen * (offset!=0);
752
 
 
753
 
                if(compute_hash[CLI_HASH_MD5])
754
 
                    cli_md5_update(&md5ctx, data, data_len);
755
 
                if(compute_hash[CLI_HASH_SHA1])
756
 
                    SHA1Update(&sha1ctx, data, data_len);
757
 
                if(compute_hash[CLI_HASH_SHA256])
758
 
                    sha256_update(&sha256ctx, data, data_len);
759
 
            }
760
 
        }
761
 
 
762
 
        if(bytes < SCANBUFF) break;
763
 
        offset += bytes - maxpatlen;
764
 
    }
765
 
 
766
 
    if(!ftonly && hdb) {
767
 
        enum CLI_HASH_TYPE hashtype;
768
 
 
769
 
        if(compute_hash[CLI_HASH_MD5])
770
 
            cli_md5_final(digest[CLI_HASH_MD5], &md5ctx);
771
 
        if(refhash)
772
 
            compute_hash[CLI_HASH_MD5] = 1;
773
 
        if(compute_hash[CLI_HASH_SHA1])
774
 
            SHA1Final(&sha1ctx, digest[CLI_HASH_SHA1]);
775
 
        if(compute_hash[CLI_HASH_SHA256])
776
 
            sha256_final(&sha256ctx, digest[CLI_HASH_SHA256]);
777
 
 
778
 
        for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
779
 
            if(compute_hash[hashtype] && (ret = cli_hm_scan(digest[hashtype], map->len, ctx->virname, hdb, hashtype)) == CL_VIRUS)
780
 
                break;
781
 
        }
782
 
 
783
 
        if(ret == CL_VIRUS && fp) {
784
 
            for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
785
 
                if(compute_hash[hashtype] && cli_hm_scan(digest[hashtype], map->len, ctx->virname, fp, hashtype) == CL_VIRUS) {
786
 
                    ret = CL_CLEAN;
787
 
                    break;
788
 
                }
789
 
            }
790
 
        }
791
 
    }
792
 
 
793
 
    if(troot) {
794
 
        if(ret != CL_VIRUS)
795
 
            ret = cli_lsig_eval(ctx, troot, &tdata, &info, refhash);
 
402
            if(ctx->engine->md5_hlist)
 
403
                cli_md5_update(&md5ctx, buff + shift, bytes);
 
404
        }
 
405
 
 
406
        if(bytes + shift == SCANBUFF) {
 
407
            memmove(buffer, endbl, maxpatlen);
 
408
            offset += SCANBUFF;
 
409
 
 
410
            if(upt == buff) {
 
411
                upt = buffer;
 
412
                offset -= maxpatlen;
 
413
            }
 
414
 
 
415
            shift = 0;
 
416
 
 
417
        } else {
 
418
            shift += bytes;
 
419
        }
 
420
 
 
421
    }
 
422
 
 
423
    free(buffer);
 
424
    if(!ftonly)
 
425
        cli_ac_freedata(&gdata);
 
426
    if(troot)
796
427
        cli_ac_freedata(&tdata);
797
 
        if(bm_offmode)
798
 
            cli_bm_freeoff(&toff);
799
 
    }
800
 
 
801
 
    if(groot) {
802
 
        if(ret != CL_VIRUS)
803
 
            ret = cli_lsig_eval(ctx, groot, &gdata, &info, refhash);
804
 
        cli_ac_freedata(&gdata);
805
 
    }
806
 
 
807
 
    if(info.exeinfo.section)
808
 
        free(info.exeinfo.section);
809
 
    cli_hashset_destroy(&info.exeinfo.vinfo);
810
 
 
811
 
    if(ret == CL_VIRUS)
812
 
        return CL_VIRUS;
813
 
 
814
 
    return (acmode & AC_SCAN_FT) ? type : CL_CLEAN;
815
 
}
816
 
 
817
 
int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer, int encrypted, int filepos, int res1, void *res2)
818
 
{
819
 
        const struct cli_cdb *cdb;
820
 
 
821
 
    if(!(cdb = ctx->engine->cdb))
822
 
        return CL_CLEAN;
823
 
 
824
 
    do {
825
 
        if(cdb->ctype != CL_TYPE_ANY && cdb->ctype != ctx->container_type)
826
 
            continue;
827
 
 
828
 
        if(cdb->encrypted != 2 && cdb->encrypted != encrypted)
829
 
            continue;
830
 
 
831
 
        if(cdb->res1 && (cdb->ctype == CL_TYPE_ZIP || cdb->ctype == CL_TYPE_RAR) && cdb->res1 != res1)
832
 
            continue;
833
 
 
834
 
#define CDBRANGE(field, val)                                                \
835
 
        if(field[0] != CLI_OFF_ANY) {                                       \
836
 
            if(field[0] == field[1] && field[0] != val)                     \
837
 
                continue;                                                   \
838
 
            else if(field[0] != field[1] && ((field[0] && field[0] > val) ||\
839
 
              (field[1] && field[1] < val)))                                \
840
 
                continue;                                                   \
 
428
 
 
429
    if(!ftonly && ctx->engine->md5_hlist) {
 
430
        cli_md5_final(digest, &md5ctx);
 
431
 
 
432
        if((md5_node = cli_vermd5(digest, ctx->engine)) && !md5_node->fp) {
 
433
                struct stat sb;
 
434
 
 
435
            if(fstat(desc, &sb))
 
436
                return CL_EIO;
 
437
 
 
438
            if((unsigned int) sb.st_size != md5_node->size) {
 
439
                cli_warnmsg("Detected false positive MD5 match. Please report.\n");
 
440
            } else {
 
441
                if(ctx->virname)
 
442
                    *ctx->virname = md5_node->virname;
 
443
 
 
444
                return CL_VIRUS;
 
445
            }
841
446
        }
842
 
 
843
 
        CDBRANGE(cdb->csize, ctx->container_size);
844
 
        CDBRANGE(cdb->fsizec, fsizec);
845
 
        CDBRANGE(cdb->fsizer, fsizer);
846
 
        CDBRANGE(cdb->filepos, filepos);
847
 
 
848
 
        if(cdb->name.re_magic && (!fname || cli_regexec(&cdb->name, fname, 0, NULL, 0) == REG_NOMATCH))
849
 
            continue;
850
 
 
851
 
        *ctx->virname = cdb->virname;
852
 
        return CL_VIRUS;
853
 
 
854
 
    } while((cdb = cdb->next));
855
 
 
856
 
    return CL_CLEAN;
 
447
    }
 
448
 
 
449
    return otfrec ? type : CL_CLEAN;
857
450
}