int32_t cli_bcapi_extract_new(struct cli_bc_ctx *ctx, int32_t id) { cli_ctx *cctx; int res = -1; cli_event_count(EV, BCEV_EXTRACTED); cli_dbgmsg("previous tempfile had %u bytes\n", ctx->written); if (!ctx->written) return 0; if (ctx->ctx && cli_updatelimits(ctx->ctx, ctx->written)) return -1; ctx->written = 0; if (lseek(ctx->outfd, 0, SEEK_SET) == -1) { cli_dbgmsg("bytecode: call to lseek() has failed\n"); return CL_ESEEK; } cli_dbgmsg("bytecode: scanning extracted file %s\n", ctx->tempfile); cctx = (cli_ctx*)ctx->ctx; if (cctx) { cli_file_t current = cctx->container_type; if (ctx->containertype != CL_TYPE_ANY) cctx->container_type = ctx->containertype; cctx->recursion++; res = cli_magic_scandesc(ctx->outfd, cctx); cctx->recursion--; cctx->container_type = current; if (res == CL_VIRUS) { ctx->virname = cli_get_last_virus(cctx); ctx->found = 1; } } if ((cctx && cctx->engine->keeptmp) || (ftruncate(ctx->outfd, 0) == -1)) { close(ctx->outfd); if (!(cctx && cctx->engine->keeptmp) && ctx->tempfile) cli_unlink(ctx->tempfile); free(ctx->tempfile); ctx->tempfile = NULL; ctx->outfd = 0; } cli_dbgmsg("bytecode: extracting new file with id %u\n", id); return res; }
int32_t cli_bcapi_read(struct cli_bc_ctx* ctx, uint8_t *data, int32_t size) { int n; if (!ctx->fmap) { API_MISUSE(); return -1; } if (size < 0 || size > CLI_MAX_ALLOCATION) { cli_warnmsg("bytecode: negative read size: %d\n", size); API_MISUSE(); return -1; } n = fmap_readn(ctx->fmap, data, ctx->off, size); if (n <= 0) { cli_dbgmsg("bcapi_read: fmap_readn failed (requested %d)\n", size); cli_event_count(EV, BCEV_READ_ERR); return n; } cli_event_int(EV, BCEV_OFFSET, ctx->off); cli_event_fastdata(EV, BCEV_READ, data, size); //cli_event_data(EV, BCEV_READ, data, n); ctx->off += n; return n; }
uint32_t cli_bcapi_disasm_x86(struct cli_bc_ctx *ctx, struct DISASM_RESULT *res, uint32_t len) { int n; const unsigned char *buf; const unsigned char* next; if (!res || !ctx->fmap || ctx->off >= ctx->fmap->len) { API_MISUSE(); return -1; } /* 32 should be longest instr we support decoding. * When we'll support mmx/sse instructions this should be updated! */ n = MIN(32, ctx->fmap->len - ctx->off); buf = fmap_need_off_once(ctx->fmap, ctx->off, n); if (buf) next = cli_disasm_one(buf, n, res, 0); else next = NULL; if (!next) { cli_dbgmsg("bcapi_disasm: failed\n"); cli_event_count(EV, BCEV_DISASM_FAIL); return -1; } return ctx->off + next - buf; }
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) { struct cli_pcre_meta **metatable = root->pcre_metatable, *pm = NULL; struct cli_pcre_data *pd; struct cli_pcre_results p_res; struct cli_ac_result *newres; uint32_t adjbuffer, adjshift, adjlength; unsigned int i, evalcnt = 0; uint64_t maxfilesize, evalids = 0; uint32_t global, encompass, rolling; int rc, offset, ret = CL_SUCCESS, options=0; uint8_t viruses_found = 0; if ((root->pcre_metas == 0) || (!root->pcre_metatable) || (ctx && ctx->dconf && !(ctx->dconf->pcre & PCRE_CONF_SUPPORT))) return CL_SUCCESS; memset(&p_res, 0, sizeof(p_res)); for (i = 0; i < root->pcre_metas; ++i) { pm = root->pcre_metatable[i]; pd = &(pm->pdata); /* skip checking and running disabled pcres */ if (pm->flags & CLI_PCRE_DISABLED) { cli_dbgmsg("cli_pcre_scanbuf: skipping disabled regex /%s/\n", pd->expression); continue; } /* skip checking and running CLI_OFF_NONE pcres */ if (data && data->offset[i] == CLI_OFF_NONE) { pm_dbgmsg("cli_pcre_scanbuf: skipping CLI_OFF_NONE regex /%s/\n", pd->expression); continue; } /* evaluate trigger */ if (pm->lsigid[0]) { cli_dbgmsg("cli_pcre_scanbuf: checking %s; running regex /%s/\n", pm->trigger, pd->expression); #ifdef PCRE_BYPASS if (strcmp(pm->trigger, PCRE_BYPASS)) #endif if (cli_ac_chklsig(pm->trigger, pm->trigger + strlen(pm->trigger), mdata->lsigcnt[pm->lsigid[1]], &evalcnt, &evalids, 0) != 1) continue; } else { cli_dbgmsg("cli_pcre_scanbuf: skipping %s check due to uninitialized lsigid\n", pm->trigger); /* fall-through to unconditional execution - sigtool-only */ } global = (pm->flags & CLI_PCRE_GLOBAL); /* globally search for all matches (within bounds) */ encompass = (pm->flags & CLI_PCRE_ENCOMPASS); /* encompass search to offset->offset+maxshift */ rolling = (pm->flags & CLI_PCRE_ROLLING); /* rolling search (unanchored) */ offset = pd->search_offset; /* this is usually 0 */ cli_dbgmsg("cli_pcre_scanbuf: triggered %s; running regex /%s/%s%s\n", pm->trigger, pd->expression, global ? " (global)":"", rolling ? " (rolling)":""); /* adjust the buffer sent to cli_pcre_match for offset and maxshift */ if (!data) { if (cli_pcre_qoff(pm, length, &adjbuffer, &adjshift) != CL_SUCCESS) continue; } else { adjbuffer = data->offset[i]; adjshift = data->shift[i]; } /* check for need to anchoring */ if (!rolling && !adjshift && (adjbuffer != CLI_OFF_ANY)) #if USING_PCRE2 options |= PCRE2_ANCHORED; #else options |= PCRE_ANCHORED; #endif else options = 0; if (adjbuffer == CLI_OFF_ANY) adjbuffer = 0; /* check the offset bounds */ if (adjbuffer < length) { /* handle encompass flag */ if (encompass && adjshift != 0 && adjshift != CLI_OFF_NONE) { if (adjbuffer+adjshift > length) adjlength = length - adjbuffer; else adjlength = adjshift; } else { /* NOTE - if using non-encompass method 2, alter shift universally */ /* TODO - limitations on non-encompassed buffers? */ adjlength = length - adjbuffer; } } else { /* starting offset is outside bounds of file, skip pcre execution silently */ pm_dbgmsg("cli_pcre_scanbuf: starting offset is outside bounds of file %u >= %u\n", adjbuffer, length); continue; } pm_dbgmsg("cli_pcre_scanbuf: passed buffer adjusted to %u +%u(%u)[%u]%s\n", adjbuffer, adjlength, adjbuffer+adjlength, adjshift, encompass ? " (encompass)":""); /* if the global flag is set, loop through the scanning */ do { /* reset the match results */ if ((ret = cli_pcre_results_reset(&p_res, pd)) != CL_SUCCESS) break; /* performance metrics */ cli_event_time_start(p_sigevents, pm->sigtime_id); rc = cli_pcre_match(pd, buffer+adjbuffer, adjlength, offset, options, &p_res); cli_event_time_stop(p_sigevents, pm->sigtime_id); /* if debug, generate a match report */ if (cli_debug_flag) cli_pcre_report(pd, buffer+adjbuffer, adjlength, rc, &p_res); /* matched, rc shouldn't be >0 unless a full match occurs */ if (rc > 0) { cli_dbgmsg("cli_pcre_scanbuf: located regex match @ %d\n", adjbuffer+p_res.match[0]); /* check if we've gone over offset+shift */ if (!encompass && adjshift) { if (p_res.match[0] > adjshift) { /* ignore matched offset (outside of maxshift) */ cli_dbgmsg("cli_pcre_scanbuf: match found outside of maxshift @%u\n", adjbuffer+p_res.match[0]); break; } } /* track the detection count */ cli_event_count(p_sigevents, pm->sigmatch_id); /* for logical signature evaluation */ if (pm->lsigid[0]) { pm_dbgmsg("cli_pcre_scanbuf: assigning lsigcnt[%d][%d], located @ %d\n", pm->lsigid[1], pm->lsigid[2], adjbuffer+p_res.match[0]); ret = lsig_sub_matched(root, mdata, pm->lsigid[1], pm->lsigid[2], adjbuffer+p_res.match[0], 0); if (ret != CL_SUCCESS) break; } else { /* for raw match data - sigtool only */ if(res) { newres = (struct cli_ac_result *)cli_calloc(1, sizeof(struct cli_ac_result)); if(!newres) { cli_errmsg("cli_pcre_scanbuff: Can't allocate memory for new result\n"); ret = CL_EMEM; break; } newres->virname = pm->virname; newres->customdata = NULL; /* get value? */ newres->next = *res; newres->offset = adjbuffer+p_res.match[0]; *res = newres; } else { if (ctx && SCAN_ALL) { viruses_found = 1; cli_append_virus(ctx, (const char *)pm->virname); } if (virname) *virname = pm->virname; if (!ctx || !SCAN_ALL) { ret = CL_VIRUS; break; } } } } /* move off to the end of the match for next match; offset is relative to adjbuffer * NOTE: misses matches starting within the last match; TODO: start from start of last match? */ offset = p_res.match[1]; } while (global && rc > 0 && offset < adjlength); /* handle error code */ if (rc < 0 && p_res.err != CL_SUCCESS) ret = p_res.err; /* jumps out of main loop from 'global' loop */ if (ret != CL_SUCCESS) break; }