Add generic and PE hooks.

0.96
Török Edvin 16 years ago
parent 41423d3836
commit ab63657088
  1. 52
      libclamav/bytecode.c
  2. 5
      libclamav/bytecode.h
  3. 16
      libclamav/bytecode_api.h
  4. 3
      libclamav/bytecode_hooks.h
  5. 3
      libclamav/others.h
  6. 27
      libclamav/pe.c
  7. 10
      libclamav/pe.h
  8. 39
      libclamav/readdb.c

@ -26,6 +26,7 @@
#include "clamav.h"
#include "others.h"
#include "pe.h"
#include "bytecode.h"
#include "bytecode_priv.h"
#include "readdb.h"
@ -45,6 +46,7 @@ struct cli_bc_ctx *cli_bytecode_context_alloc(void)
ctx->fd = -1;
ctx->off = 0;
ctx->hooks.match_counts = nomatch;
/* TODO: init all hooks with safe values */
ctx->virname = NULL;
return ctx;
}
@ -55,11 +57,18 @@ void cli_bytecode_context_destroy(struct cli_bc_ctx *ctx)
free(ctx);
}
int cli_bytecode_context_clear(struct cli_bc_ctx *ctx)
/* resets bytecode state, so you can run another bytecode with same ctx */
int cli_bytecode_context_reset(struct cli_bc_ctx *ctx)
{
free(ctx->opsizes);
free(ctx->values);
free(ctx->operands);
return CL_SUCCESS;
}
int cli_bytecode_context_clear(struct cli_bc_ctx *ctx)
{
cli_bytecode_context_reset(ctx);
memset(ctx, 0, sizeof(ctx));
return CL_SUCCESS;
}
@ -1435,7 +1444,46 @@ int cli_bytecode_runlsig(const struct cli_all_bc *bcs, const struct cli_bc *bc,
return CL_VIRUS;
}
ret = cli_bytecode_context_getresult_int(&ctx);
cli_dbgmsg("Bytecode returned code: %u\n", ret);
cli_dbgmsg("Bytecode %u returned code: %u\n", bc->id, ret);
cli_bytecode_context_clear(&ctx);
return CL_SUCCESS;
}
int cli_bytecode_runhook(const struct cl_engine *engine, struct cli_bc_ctx *ctx,
unsigned id, int fd, const char **virname)
{
const unsigned *hooks = engine->hooks[id - _BC_START_HOOKS];
unsigned i, hooks_cnt = engine->hooks_cnt[id - _BC_START_HOOKS];
int ret;
cli_bytecode_context_setfile(ctx, fd);
cli_dbgmsg("Bytecode executing hook id %u (%u hooks)\n", id, hooks_cnt);
for (i=0;i < hooks_cnt;i++) {
const struct cli_bc *bc = &engine->bcs.all_bcs[hooks[i]];
cli_bytecode_context_setfuncid(ctx, bc, 0);
ret = cli_bytecode_run(&engine->bcs, bc, ctx);
if (ret != CL_SUCCESS) {
cli_warnmsg("Bytecode failed to run: %s\n", cl_strerror(ret));
return CL_SUCCESS;
}
if (ctx->virname) {
cli_dbgmsg("Bytecode found virus: %s\n", ctx->virname);
if (virname)
*virname = ctx->virname;
cli_bytecode_context_clear(ctx);
return CL_VIRUS;
}
ret = cli_bytecode_context_getresult_int(ctx);
/* TODO: use prefix here */
cli_dbgmsg("Bytecode %u returned %u\n", bc->id, ret);
cli_bytecode_context_reset(ctx);
}
return CL_CLEAN;
}
int cli_bytecode_context_setpe(struct cli_bc_ctx *ctx, const struct cli_pe_hook_data *data)
{
ctx->hooks.exeinfo = &data->exe_info;
ctx->hooks.pedata = data;
return 0;
}

@ -32,6 +32,7 @@ struct cli_bc_inst;
struct cli_bc_type;
struct cli_bc_engine;
struct bitset_tag;
struct cl_engine;
enum bc_state {
bc_skip,
@ -65,11 +66,13 @@ struct cli_all_bc {
struct cli_bcengine *engine;
};
struct cli_pe_hook_data;
struct cli_bc_ctx *cli_bytecode_context_alloc(void);
int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, const struct cli_bc *bc, unsigned funcid);
int cli_bytecode_context_setparam_int(struct cli_bc_ctx *ctx, unsigned i, uint64_t c);
int cli_bytecode_context_setparam_ptr(struct cli_bc_ctx *ctx, unsigned i, void *data, unsigned datalen);
int cli_bytecode_context_setfile(struct cli_bc_ctx *ctx, int fd);
int cli_bytecode_context_setpe(struct cli_bc_ctx *ctx, const struct cli_pe_hook_data *data);
int cli_bytecode_context_clear(struct cli_bc_ctx *ctx);
uint64_t cli_bytecode_context_getresult_int(struct cli_bc_ctx *ctx);
void cli_bytecode_context_destroy(struct cli_bc_ctx *ctx);
@ -83,7 +86,9 @@ void cli_bytecode_destroy(struct cli_bc *bc);
int cli_bytecode_done(struct cli_all_bc *allbc);
/* Hooks */
struct cli_exe_info;
int cli_bytecode_runlsig(const struct cli_all_bc *bcs, const struct cli_bc* bc, const char **virname, const uint32_t* lsigcnt, int fd);
int cli_bytecode_runhook(const struct cl_engine *engine, struct cli_bc_ctx *ctx, unsigned id, int fd, const char **virname);
#ifdef __cplusplus
extern "C" {

@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#ifndef BYTECODE_API_H
#define BYTECODE_API_H
#ifdef __CLAMBC__
#include "bytecode_execs.h"
@ -32,16 +34,19 @@ struct foo {
struct foo *nxt;
};
enum BytecodeKind {
BC_GENERIC=0,/* generic bytecode, not tied to a specific hook */
_BC_START_HOOKS=256,
BC_LOGICAL=256,/* triggered by a logical signature */
BC_PE_UNPACKER,/* a PE unpacker */
_BC_LAST_HOOK
};
#ifdef __CLAMBC__
extern const uint32_t __clambc_match_counts[64];
extern const struct cli_exe_info __clambc_exeinfo;
enum BytecodeKind {
BC_GENERIC=0,/* generic bytecode, not tied to a specific hook */
BC_LOGICAL,/* triggered by a logical signature */
BC_PE_UNPACKER,/* a PE unpacker */
};
const uint8_t __clambc_kind;
uint32_t test0(struct foo*, uint32_t);
@ -68,3 +73,4 @@ uint32_t debug_print_uint(uint32_t a, uint32_t b);
//const char *LogicalSignature;
#endif
#endif

@ -24,7 +24,8 @@
struct cli_bc_hooks {
const uint32_t* match_counts;
const struct cli_exe_info exeinfo;
const struct cli_exe_info *exeinfo;
const struct cli_pe_hook_data *pedata;
const uint8_t kind;
};
#endif

@ -41,6 +41,7 @@
#include "libclamunrar_iface/unrar_iface.h"
#include "regex/regex.h"
#include "bytecode.h"
#include "bytecode_api.h"
/*
* CL_FLEVEL is the signature f-level specific to the current code and
@ -181,6 +182,8 @@ struct cl_engine {
/* Used for bytecode */
struct cli_all_bc bcs;
unsigned *hooks[_BC_LAST_HOOK - _BC_START_HOOKS];
unsigned hooks_cnt[_BC_LAST_HOOK - _BC_START_HOOKS];
};
struct cl_settings {

@ -439,18 +439,20 @@ int cli_scanpe(int desc, cli_ctx *ctx)
char *src = NULL, *dest = NULL;
int ndesc, ret = CL_CLEAN, upack = 0, native=0;
size_t fsize;
uint32_t valign, falign, hdr_size, j;
uint32_t valign, falign, hdr_size, j, offset;
struct cli_exe_section *exe_sections;
struct cli_matcher *md5_sect;
char timestr[32];
struct pe_image_data_dir *dirs;
struct cli_bc_ctx *bc_ctx;
struct cli_pe_hook_data pedata;
if(!ctx) {
cli_errmsg("cli_scanpe: ctx == NULL\n");
return CL_ENULLARG;
}
offset = lseek(desc, 0, SEEK_CUR);
if(cli_readn(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) {
cli_dbgmsg("Can't read DOS signature\n");
return CL_CLEAN;
@ -2252,6 +2254,27 @@ int cli_scanpe(int desc, cli_ctx *ctx)
/* to be continued ... */
/* Bytecode */
bc_ctx = cli_bytecode_context_alloc();
if (!bc_ctx) {
cli_errmsg("cli_scanpe: can't allocate memory for bc_ctx\n");
return CL_EMEM;
}
pedata.exe_info.section = exe_sections;
pedata.exe_info.nsections = nsections;
pedata.exe_info.ep = ep;
pedata.exe_info.offset = offset;
pedata.file_hdr = &file_hdr;
pedata.opt32 = &pe_opt.opt32;
pedata.opt64 = &pe_opt.opt64;
pedata.dirs = dirs;
pedata.overlays = overlays;
pedata.overlays_sz = fsize - overlays;
cli_bytecode_context_setpe(bc_ctx, &pedata);
if (cli_bytecode_runhook(ctx->engine, bc_ctx, BC_PE_UNPACKER, desc, ctx->virname) == CL_VIRUS)
return CL_VIRUS;
cli_bytecode_context_destroy(bc_ctx);
free(exe_sections);
return CL_CLEAN;
}

@ -128,6 +128,16 @@ struct pe_image_section_hdr {
uint32_t Characteristics;
};
struct cli_pe_hook_data {
struct cli_exe_info exe_info;
struct pe_image_file_hdr *file_hdr;
struct pe_image_optional_hdr32 *opt32;
struct pe_image_optional_hdr64 *opt64;
struct pe_image_data_dir *dirs;
uint32_t overlays;
int32_t overlays_sz;
};
int cli_scanpe(int desc, cli_ctx *ctx);
int cli_peheader(int desc, struct cli_exe_info *peinfo);

@ -70,6 +70,7 @@
#include "mpool.h"
#include "bytecode.h"
#include "bytecode_api.h"
#include "bytecode_priv.h"
#ifdef CL_THREAD_SAFE
# include <pthread.h>
@ -1044,6 +1045,7 @@ static int cli_loadcbc(FILE *fs, struct cl_engine *engine, unsigned int *signo,
struct cli_bc *bc;
unsigned sigs = 0;
/* TODO: virusname have a common prefix, and whitelist by that */
if((rc = cli_initroots(engine, options)))
return rc;
@ -1059,18 +1061,42 @@ static int cli_loadcbc(FILE *fs, struct cl_engine *engine, unsigned int *signo,
bc = &bcs->all_bcs[bcs->count-1];
rc = cli_bytecode_load(bc, fs, dbio);
if (rc != CL_SUCCESS) {
fprintf(stderr,"Unable to load %s bytecode: %s\n", dbname, cl_strerror(rc));
cli_errmsg("Unable to load %s bytecode: %s\n", dbname, cl_strerror(rc));
return rc;
}
sigs += 2;/* the bytecode itself and the logical sig */
if (bc->lsig) {
if (bc->kind == BC_LOGICAL) {
if (!bc->lsig) {
cli_errmsg("Bytecode %s has logical kind, but missing logical signature!\n", dbname);
return CL_EMALFDB;
}
cli_dbgmsg("Bytecode %s has logical signature: %s\n", dbname, bc->lsig);
rc = load_oneldb(bc->lsig, 0, 0, engine, options, dbname, 0, &sigs, bc, NULL);
if (rc != CL_SUCCESS) {
fprintf(stderr,"Problem parsing logical signature %s for bytecode %s: %s\n",
bc->lsig, dbname, cl_strerror(rc));
cli_errmsg("Problem parsing logical signature %s for bytecode %s: %s\n",
bc->lsig, dbname, cl_strerror(rc));
return rc;
}
} else {
if (bc->lsig) {
cli_errmsg("Bytecode %s has logical signature but is not logical kind!\n", dbname);
return CL_EMALFDB;
}
if (bc->kind >= _BC_START_HOOKS && bc->kind < _BC_LAST_HOOK) {
unsigned hook = bc->kind - _BC_START_HOOKS;
unsigned cnt = ++engine->hooks_cnt[hook];
engine->hooks[hook] = cli_realloc2(engine->hooks[hook],
sizeof(*engine->hooks[0])*cnt);
if (!engine->hooks[hook]) {
cli_errmsg("Out of memory allocating memory for hook %u", hook);
return CL_EMEM;
}
engine->hooks[hook][cnt-1] = bcs->count-1;
} else switch (bc->kind) {
default:
cli_errmsg("Bytecode: unhandled bytecode kind %u\n", bc->kind);
return CL_EMALFDB;
}
}
if (signo)
*signo += sigs;
@ -2199,6 +2225,9 @@ int cl_engine_free(struct cl_engine *engine)
cli_bytecode_destroy(&engine->bcs.all_bcs[i]);
cli_bytecode_done(&engine->bcs);
free(engine->bcs.all_bcs);
for (i=0;i<_BC_LAST_HOOK - _BC_START_HOOKS;i++) {
free (engine->hooks[i]);
}
}
if(engine->dconf->phishing & PHISHING_CONF_ENGINE)
phishing_done(engine);
@ -2286,7 +2315,7 @@ int cl_engine_compile(struct cl_engine *engine)
/* Compile bytecode */
if((ret = cli_bytecode_prepare(&engine->bcs))) {
fprintf(stderr,"Unable to compile/load bytecode: %s\n", cl_strerror(ret));
cli_errmsg("Unable to compile/load bytecode: %s\n", cl_strerror(ret));
return ret;
}

Loading…
Cancel
Save