Logical signature hook for bytecode.

0.96
Török Edvin 16 years ago
parent 459b13ed89
commit d38d6dadef
  1. 36
      libclamav/bytecode.c
  2. 3
      libclamav/bytecode.h
  3. 8
      libclamav/bytecode_api.c
  4. 3
      libclamav/bytecode_api.h
  5. 5
      libclamav/bytecode_api_decl.c
  6. 3
      libclamav/bytecode_api_impl.h
  7. 1
      libclamav/bytecode_priv.h
  8. 2
      libclamav/c++/Makefile.am
  9. 2
      libclamav/c++/Makefile.in
  10. 18
      libclamav/c++/bytecode2llvm.cpp
  11. 30
      libclamav/matcher.c
  12. 12
      libclamav/readdb.c
  13. 16
      unit_tests/input/lsig.cbc

@ -31,6 +31,9 @@
#include "readdb.h"
#include <string.h>
/* TODO: we should make sure lsigcnt is never NULL, and has at least as many
* elements as the bytecode needs */
static const uint32_t nomatch[64];
struct cli_bc_ctx *cli_bytecode_context_alloc(void)
{
struct cli_bc_ctx *ctx = cli_malloc(sizeof(*ctx));
@ -41,6 +44,8 @@ struct cli_bc_ctx *cli_bytecode_context_alloc(void)
ctx->opsizes = NULL;
ctx->fd = -1;
ctx->off = 0;
ctx->lsigcnt = nomatch;
ctx->virname = NULL;
return ctx;
}
@ -967,6 +972,8 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
default:
numOp = operand_counts[inst.opcode];
switch (numOp) {
case 0:
break;
case 1:
inst.u.unaryop = readOperand(bcfunc, buffer, &offset, len, &ok);
break;
@ -980,7 +987,7 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
inst.u.three[2] = readOperand(bcfunc, buffer, &offset, len, &ok);
break;
default:
cli_errmsg("Opcode with too many operands: %u?\n", numOp);
cli_errmsg("Opcode %u with too many operands: %u?\n", inst.opcode, numOp);
ok = 0;
break;
}
@ -1398,3 +1405,30 @@ int cli_bytecode_context_setfile(struct cli_bc_ctx *ctx, int fd)
return 0;
}
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 ret;
struct cli_bc_ctx ctx;
memset(&ctx, 0, sizeof(ctx));
cli_bytecode_context_setfuncid(&ctx, bc, 0);
ctx.lsigcnt = lsigcnt;
cli_bytecode_context_setfile(&ctx, fd);
cli_dbgmsg("Running bytecode for logical signature match\n");
ret = cli_bytecode_run(bcs, bc, &ctx);
if (ret != CL_SUCCESS) {
cli_warnmsg("Bytcode 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);
cli_dbgmsg("Bytecode returned code: %u\n", ret);
cli_bytecode_context_clear(&ctx);
return CL_SUCCESS;
}

@ -81,6 +81,9 @@ int cli_bytecode_run(const struct cli_all_bc *bcs, const struct cli_bc *bc, stru
void cli_bytecode_destroy(struct cli_bc *bc);
int cli_bytecode_done(struct cli_all_bc *allbc);
/* Hooks */
int cli_bytecode_runlsig(const struct cli_all_bc *bcs, const struct cli_bc* bc, const char **virname, const uint32_t* lsigcnt, int fd);
#ifdef __cplusplus
extern "C" {
#endif

@ -80,3 +80,11 @@ uint32_t cli_bcapi_debug_print_uint(struct cli_bc_ctx *ctx, uint32_t a, uint32_t
{
cli_dbgmsg("bytecode debug: %u\n", a);
}
/*TODO: compiler should make sure that only constants are passed here, and not
* pointers to arbitrary locations that may not be valid when bytecode finishes
* executing */
uint32_t cli_bcapi_setvirusname(struct cli_bc_ctx* ctx, const uint8_t *name, uint32_t len)
{
ctx->virname = name;
}

@ -48,6 +48,9 @@ enum {
* start of file */
int32_t seek(int32_t pos, uint32_t whence);
/* Set the name of the virus we have found */
uint32_t setvirusname(const uint8_t *name, uint32_t len);
uint32_t debug_print_str(const uint8_t *str, uint32_t len);
uint32_t debug_print_uint(uint32_t a, uint32_t b);
//const char *LogicalSignature;

@ -28,6 +28,7 @@ uint32_t cli_bcapi_test0(struct cli_bc_ctx *ctx, struct foo*, uint32_t);
uint32_t cli_bcapi_test1(struct cli_bc_ctx *ctx, uint32_t, uint32_t);
int32_t cli_bcapi_read(struct cli_bc_ctx *ctx, uint8_t*, int32_t);
int32_t cli_bcapi_seek(struct cli_bc_ctx *ctx, int32_t, uint32_t);
uint32_t cli_bcapi_setvirusname(struct cli_bc_ctx *ctx, const const uint8_t*, uint32_t);
uint32_t cli_bcapi_debug_print_str(struct cli_bc_ctx *ctx, const const uint8_t*, uint32_t);
uint32_t cli_bcapi_debug_print_uint(struct cli_bc_ctx *ctx, uint32_t, uint32_t);
@ -52,7 +53,8 @@ const struct cli_apicall cli_apicalls[]={
{"test1", 3, 0, 0},
{"read", 4, 1, 1},
{"seek", 3, 1, 0},
{"debug_print_str", 4, 2, 1},
{"setvirusname", 4, 2, 1},
{"debug_print_str", 4, 3, 1},
{"debug_print_uint", 3, 2, 0}
/* Bytecode APIcalls END */
};
@ -64,6 +66,7 @@ const cli_apicall_int2 cli_apicalls0[] = {
const cli_apicall_pointer cli_apicalls1[] = {
(cli_apicall_pointer)cli_bcapi_test0,
(cli_apicall_pointer)cli_bcapi_read,
(cli_apicall_pointer)cli_bcapi_setvirusname,
(cli_apicall_pointer)cli_bcapi_debug_print_str
};
const unsigned cli_apicall_maxapi = sizeof(cli_apicalls)/sizeof(cli_apicalls[0]);

@ -25,5 +25,8 @@ uint32_t cli_bcapi_test1(struct cli_bc_ctx *, uint32_t, uint32_t);
int32_t cli_bcapi_read(struct cli_bc_ctx*, uint8_t *data, int32_t size);
int32_t cli_bcapi_seek(struct cli_bc_ctx*, int32_t pos, uint32_t whence);
uint32_t cli_bcapi_setvirusname(struct cli_bc_ctx*, const uint8_t *name, uint32_t len);
uint32_t cli_bcapi_debug_print_str(struct cli_bc_ctx *ctx, const uint8_t*, uint32_t);
uint32_t cli_bcapi_debug_print_uint(struct cli_bc_ctx *ctx, uint32_t, uint32_t);

@ -99,6 +99,7 @@ struct cli_bc_ctx {
off_t off;
int fd;
const uint32_t *lsigcnt;
const char *virname;
};
struct cli_all_bc;
int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst);

@ -13,7 +13,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
AM_CPPFLAGS = -I$(top_srcdir)/../.. -I$(top_srcdir)/..
AM_CPPFLAGS = -I$(top_srcdir)/../.. -I$(top_srcdir)/.. -I$(top_builddir)/../../
ACLOCAL_AMFLAGS=-I m4
if DEBUG_BUILD
LLVM_CONFIG=llvm/Debug/bin/llvm-config

@ -933,7 +933,7 @@ target_vendor = @target_vendor@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = -I$(top_srcdir)/../.. -I$(top_srcdir)/..
AM_CPPFLAGS = -I$(top_srcdir)/../.. -I$(top_srcdir)/.. -I$(top_builddir)/../../
ACLOCAL_AMFLAGS = -I m4
@DEBUG_BUILD_FALSE@LLVM_CONFIG = llvm/Release/bin/llvm-config
@DEBUG_BUILD_TRUE@LLVM_CONFIG = llvm/Debug/bin/llvm-config

@ -57,6 +57,15 @@
#ifndef LLVM_MULTITHREADED
#error "Multithreading support must be available to LLVM!"
#endif
#ifdef HAVE_CONFIG_H
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#include "clamav-config.h"
#endif
#include "clamav.h"
#include "clambc.h"
#include "bytecode_priv.h"
@ -344,7 +353,6 @@ public:
{}
bool generate() {
PrettyStackTraceString Trace(BytecodeID.str().c_str());
TypeMap = new LLVMTypeMapper(Context, bc->types + 4, bc->num_types - 5);
FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context),
@ -602,6 +610,9 @@ public:
case OP_BC_RET:
Builder.CreateRet(Op0);
break;
case OP_BC_RET_VOID:
Builder.CreateRetVoid();
break;
case OP_BC_ICMP_EQ:
Store(inst->dest, Builder.CreateICmpEQ(Op0, Op1));
break;
@ -651,7 +662,8 @@ public:
}
CallInst *CI = Builder.CreateCall(DestF, args.begin(), args.end());
CI->setCallingConv(CallingConv::Fast);
Store(inst->dest, CI);
if (CI->getType()->getTypeID() != Type::VoidTyID)
Store(inst->dest, CI);
break;
}
case OP_BC_CALL_API:
@ -904,6 +916,8 @@ int bytecode_init(void)
llvm_install_error_handler(llvm_error_handler);
#ifdef CL_DEBUG
sys::PrintStackTraceOnErrorSignal();
#else
llvm::DisablePrettyStackTrace = true;
#endif
atexit(do_shutdown);

@ -318,7 +318,7 @@ int cli_checkfp(int fd, cli_ctx *ctx)
int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode)
{
unsigned char *buffer, *buff, *endbl, *upt;
unsigned char *buffer, *buff, *endbl, *upt;
int ret = CL_CLEAN, type = CL_CLEAN, bytes;
unsigned int i, evalcnt;
uint32_t buffersize, length, maxpatlen, shift = 0, offset = 0;
@ -459,10 +459,16 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
evalcnt = 0;
evalids = 0;
if(cli_ac_chklsig(troot->ac_lsigtable[i]->logic, troot->ac_lsigtable[i]->logic + strlen(troot->ac_lsigtable[i]->logic), tdata.lsigcnt[i], &evalcnt, &evalids, 0) == 1) {
if(ctx->virname)
*ctx->virname = troot->ac_lsigtable[i]->virname;
ret = CL_VIRUS;
break;
if (!troot->ac_lsigtable[i]->bc) {
if(ctx->virname)
*ctx->virname = troot->ac_lsigtable[i]->virname;
ret = CL_VIRUS;
break;
}
if (cli_bytecode_runlsig(&ctx->engine->bcs, troot->ac_lsigtable[i]->bc, ctx->virname, tdata.lsigcnt[i], desc) == CL_VIRUS) {
ret = CL_VIRUS;
break;
}
}
}
cli_ac_freedata(&tdata);
@ -473,10 +479,16 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
evalcnt = 0;
evalids = 0;
if(cli_ac_chklsig(groot->ac_lsigtable[i]->logic, groot->ac_lsigtable[i]->logic + strlen(groot->ac_lsigtable[i]->logic), gdata.lsigcnt[i], &evalcnt, &evalids, 0) == 1) {
if(ctx->virname)
*ctx->virname = groot->ac_lsigtable[i]->virname;
ret = CL_VIRUS;
break;
if (!groot->ac_lsigtable[i]->bc) {
if(ctx->virname)
*ctx->virname = groot->ac_lsigtable[i]->virname;
ret = CL_VIRUS;
break;
}
if (cli_bytecode_runlsig(&ctx->engine->bcs, groot->ac_lsigtable[i]->bc, ctx->virname, gdata.lsigcnt[i], desc) == CL_VIRUS) {
ret = CL_VIRUS;
break;
}
}
}
cli_ac_freedata(&gdata);

@ -882,6 +882,16 @@ static int load_oneldb(char *buffer, int chkpua, int chkign, struct cl_engine *e
cli_errmsg("cli_loadldb: Broken logical expression or too many subsignatures\n");
return CL_EMALFDB;
}
if (!line) {
/* This is a logical signature from the bytecode, we need all
* subsignatures, even if not referenced from the logical expression */
if (subsigs > tokens_count-3) {
cli_errmsg("load_oneldb: Too many subsignatures: %u (max %u)\n",
subsigs, tokens_count-3);
return CL_EMALFDB;
}
subsigs = tokens_count-3;
}
/* TDB */
memset(&tdb, 0, sizeof(tdb));
@ -937,7 +947,7 @@ static int load_oneldb(char *buffer, int chkpua, int chkign, struct cl_engine *e
root->ac_lsigtable = newtable;
for(i = 0; i < subsigs; i++) {
if(i >= tokens_count) {
if(i+3 >= tokens_count) {
cli_errmsg("cli_loadldb: Missing subsignature id %u\n", i);
return CL_EMALFDB;
}

@ -1,7 +1,11 @@
ClamBCaa`|`````|`aoaap`clamcoincidencejb
ClamBCaa`|`````|`bbaabp`clamcoincidencejb
L;Target:0;((0|1|2)=42,2);aabb;ffffffff;aaccee;f00d
Tedebndebmdebldebkdebadebcddadb`bdagahdaiahdaeah
E``
GalbndBafBafBbfBbf@`bmdBffBffBffBffBffBffBffBff@`bndBffB`cB`cBdf@`bldBafBafBcfBcfBefBef@`bad@@`bad@Aa`bad@Ab`bad@Ac`bcdAcD```h`bcdAbD```h`bcd@D```h`bcdAaD```h`
A`b`bLacb`baab`bFadaa
Bb`b`gbAh`aaaaeab`b`Abdb`bab`aaaTcab`babE
Tedebaeeb`eebodebndebmdebadebcdacb`bbadb`bdadb`bdakahdagahdaiahdaeah
Eaeaaaebld|amcgefdgfgifbgegcgnfafmfef``
GanbaeBafBafBbfBbf@`b`eBffBffBffBffBffBffBffBff@`baeBffB`cB`cBdf@`bodBafBafBcfBcfBefBef@`bndBdeBbgBofBjfBafBnfBnbBfdBodBod@`bad@@`bad@Aa`bad@Ab`bad@Ac`bad@Ad`bcdAcD```h`bcdAbD```h`bcd@D```h`bcdAaD```h`
A`b`bLacb`baa`Fafac
Bb`b`gbAj`aaaaeab`b`AbdTaaaaaaab
B```b`abTcab`b@d
BTcab`b@dE
A``Laab`bFabaa
Bb`b`abbaeAi`@dTdaE

Loading…
Cancel
Save