Browse code

Add generic and PE hooks.

Török Edvin authored on 2009/10/02 23:33:11
Showing 8 changed files
... ...
@@ -26,6 +26,7 @@
26 26
 
27 27
 #include "clamav.h"
28 28
 #include "others.h"
29
+#include "pe.h"
29 30
 #include "bytecode.h"
30 31
 #include "bytecode_priv.h"
31 32
 #include "readdb.h"
... ...
@@ -45,6 +46,7 @@ struct cli_bc_ctx *cli_bytecode_context_alloc(void)
45 45
     ctx->fd = -1;
46 46
     ctx->off = 0;
47 47
     ctx->hooks.match_counts = nomatch;
48
+    /* TODO: init all hooks with safe values */
48 49
     ctx->virname = NULL;
49 50
     return ctx;
50 51
 }
... ...
@@ -55,11 +57,18 @@ void cli_bytecode_context_destroy(struct cli_bc_ctx *ctx)
55 55
    free(ctx);
56 56
 }
57 57
 
58
-int cli_bytecode_context_clear(struct cli_bc_ctx *ctx)
58
+/* resets bytecode state, so you can run another bytecode with same ctx */
59
+int cli_bytecode_context_reset(struct cli_bc_ctx *ctx)
59 60
 {
60 61
     free(ctx->opsizes);
61 62
     free(ctx->values);
62 63
     free(ctx->operands);
64
+    return CL_SUCCESS;
65
+}
66
+
67
+int cli_bytecode_context_clear(struct cli_bc_ctx *ctx)
68
+{
69
+    cli_bytecode_context_reset(ctx);
63 70
     memset(ctx, 0, sizeof(ctx));
64 71
     return CL_SUCCESS;
65 72
 }
... ...
@@ -1435,7 +1444,46 @@ int cli_bytecode_runlsig(const struct cli_all_bc *bcs, const struct cli_bc *bc,
1435 1435
 	return CL_VIRUS;
1436 1436
     }
1437 1437
     ret = cli_bytecode_context_getresult_int(&ctx);
1438
-    cli_dbgmsg("Bytecode returned code: %u\n", ret);
1438
+    cli_dbgmsg("Bytecode %u returned code: %u\n", bc->id, ret);
1439 1439
     cli_bytecode_context_clear(&ctx);
1440 1440
     return CL_SUCCESS;
1441 1441
 }
1442
+
1443
+int cli_bytecode_runhook(const struct cl_engine *engine, struct cli_bc_ctx *ctx,
1444
+			 unsigned id, int fd, const char **virname)
1445
+{
1446
+    const unsigned *hooks = engine->hooks[id - _BC_START_HOOKS];
1447
+    unsigned i, hooks_cnt = engine->hooks_cnt[id - _BC_START_HOOKS];
1448
+    int ret;
1449
+
1450
+    cli_bytecode_context_setfile(ctx, fd);
1451
+    cli_dbgmsg("Bytecode executing hook id %u (%u hooks)\n", id, hooks_cnt);
1452
+    for (i=0;i < hooks_cnt;i++) {
1453
+	const struct cli_bc *bc = &engine->bcs.all_bcs[hooks[i]];
1454
+	cli_bytecode_context_setfuncid(ctx, bc, 0);
1455
+	ret = cli_bytecode_run(&engine->bcs, bc, ctx);
1456
+	if (ret != CL_SUCCESS) {
1457
+	    cli_warnmsg("Bytecode failed to run: %s\n", cl_strerror(ret));
1458
+	    return CL_SUCCESS;
1459
+	}
1460
+	if (ctx->virname) {
1461
+	    cli_dbgmsg("Bytecode found virus: %s\n", ctx->virname);
1462
+	    if (virname)
1463
+		*virname = ctx->virname;
1464
+	    cli_bytecode_context_clear(ctx);
1465
+	    return CL_VIRUS;
1466
+	}
1467
+	ret = cli_bytecode_context_getresult_int(ctx);
1468
+	/* TODO: use prefix here */
1469
+	cli_dbgmsg("Bytecode %u returned %u\n", bc->id, ret);
1470
+	cli_bytecode_context_reset(ctx);
1471
+    }
1472
+    return CL_CLEAN;
1473
+}
1474
+
1475
+int cli_bytecode_context_setpe(struct cli_bc_ctx *ctx, const struct cli_pe_hook_data *data)
1476
+{
1477
+    ctx->hooks.exeinfo = &data->exe_info;
1478
+    ctx->hooks.pedata = data;
1479
+    return 0;
1480
+}
... ...
@@ -32,6 +32,7 @@ struct cli_bc_inst;
32 32
 struct cli_bc_type;
33 33
 struct cli_bc_engine;
34 34
 struct bitset_tag;
35
+struct cl_engine;
35 36
 
36 37
 enum bc_state {
37 38
     bc_skip,
... ...
@@ -65,11 +66,13 @@ struct cli_all_bc {
65 65
     struct cli_bcengine *engine;
66 66
 };
67 67
 
68
+struct cli_pe_hook_data;
68 69
 struct cli_bc_ctx *cli_bytecode_context_alloc(void);
69 70
 int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, const struct cli_bc *bc, unsigned funcid);
70 71
 int cli_bytecode_context_setparam_int(struct cli_bc_ctx *ctx, unsigned i, uint64_t c);
71 72
 int cli_bytecode_context_setparam_ptr(struct cli_bc_ctx *ctx, unsigned i, void *data, unsigned datalen);
72 73
 int cli_bytecode_context_setfile(struct cli_bc_ctx *ctx, int fd);
74
+int cli_bytecode_context_setpe(struct cli_bc_ctx *ctx, const struct cli_pe_hook_data *data);
73 75
 int cli_bytecode_context_clear(struct cli_bc_ctx *ctx);
74 76
 uint64_t cli_bytecode_context_getresult_int(struct cli_bc_ctx *ctx);
75 77
 void cli_bytecode_context_destroy(struct cli_bc_ctx *ctx);
... ...
@@ -83,7 +86,9 @@ void cli_bytecode_destroy(struct cli_bc *bc);
83 83
 int cli_bytecode_done(struct cli_all_bc *allbc);
84 84
 
85 85
 /* Hooks */
86
+struct cli_exe_info;
86 87
 int cli_bytecode_runlsig(const struct cli_all_bc *bcs, const struct cli_bc* bc, const char **virname, const uint32_t* lsigcnt, int fd);
88
+int cli_bytecode_runhook(const struct cl_engine *engine, struct cli_bc_ctx *ctx, unsigned id, int fd, const char **virname);
87 89
 
88 90
 #ifdef __cplusplus
89 91
 extern "C" {
... ...
@@ -19,6 +19,8 @@
19 19
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 20
  *  MA 02110-1301, USA.
21 21
  */
22
+#ifndef BYTECODE_API_H
23
+#define BYTECODE_API_H
22 24
 
23 25
 #ifdef __CLAMBC__
24 26
 #include "bytecode_execs.h"
... ...
@@ -32,16 +34,19 @@ struct foo {
32 32
     struct foo *nxt;
33 33
 };
34 34
 
35
+enum BytecodeKind {
36
+    BC_GENERIC=0,/* generic bytecode, not tied to a specific hook */
37
+    _BC_START_HOOKS=256,
38
+    BC_LOGICAL=256,/* triggered by a logical signature */
39
+    BC_PE_UNPACKER,/* a PE unpacker */
40
+    _BC_LAST_HOOK
41
+};
42
+
35 43
 #ifdef __CLAMBC__
36 44
 
37 45
 extern const uint32_t __clambc_match_counts[64];
38 46
 extern const struct cli_exe_info __clambc_exeinfo;
39 47
 
40
-enum BytecodeKind {
41
-    BC_GENERIC=0,/* generic bytecode, not tied to a specific hook */
42
-    BC_LOGICAL,/* triggered by a logical signature */
43
-    BC_PE_UNPACKER,/* a PE unpacker */
44
-};
45 48
 const uint8_t __clambc_kind;
46 49
 
47 50
 uint32_t test0(struct foo*, uint32_t);
... ...
@@ -68,3 +73,4 @@ uint32_t debug_print_uint(uint32_t a, uint32_t b);
68 68
 //const char *LogicalSignature;
69 69
 
70 70
 #endif
71
+#endif
... ...
@@ -24,7 +24,8 @@
24 24
 
25 25
 struct cli_bc_hooks {
26 26
 	 const uint32_t* match_counts;
27
-	 const struct cli_exe_info exeinfo;
27
+	 const struct cli_exe_info *exeinfo;
28
+	 const struct cli_pe_hook_data *pedata;
28 29
 	 const uint8_t kind;
29 30
 };
30 31
 #endif
... ...
@@ -41,6 +41,7 @@
41 41
 #include "libclamunrar_iface/unrar_iface.h"
42 42
 #include "regex/regex.h"
43 43
 #include "bytecode.h"
44
+#include "bytecode_api.h"
44 45
 
45 46
 /*
46 47
  * CL_FLEVEL is the signature f-level specific to the current code and
... ...
@@ -181,6 +182,8 @@ struct cl_engine {
181 181
 
182 182
     /* Used for bytecode */
183 183
     struct cli_all_bc bcs;
184
+    unsigned *hooks[_BC_LAST_HOOK - _BC_START_HOOKS];
185
+    unsigned hooks_cnt[_BC_LAST_HOOK - _BC_START_HOOKS];
184 186
 };
185 187
 
186 188
 struct cl_settings {
... ...
@@ -439,18 +439,20 @@ int cli_scanpe(int desc, cli_ctx *ctx)
439 439
 	char *src = NULL, *dest = NULL;
440 440
 	int ndesc, ret = CL_CLEAN, upack = 0, native=0;
441 441
 	size_t fsize;
442
-	uint32_t valign, falign, hdr_size, j;
442
+	uint32_t valign, falign, hdr_size, j, offset;
443 443
 	struct cli_exe_section *exe_sections;
444 444
 	struct cli_matcher *md5_sect;
445 445
 	char timestr[32];
446 446
 	struct pe_image_data_dir *dirs;
447
+	struct cli_bc_ctx *bc_ctx;
448
+	struct cli_pe_hook_data pedata;
447 449
 
448 450
 
449 451
     if(!ctx) {
450 452
 	cli_errmsg("cli_scanpe: ctx == NULL\n");
451 453
 	return CL_ENULLARG;
452 454
     }
453
-
455
+    offset = lseek(desc, 0, SEEK_CUR);
454 456
     if(cli_readn(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) {
455 457
 	cli_dbgmsg("Can't read DOS signature\n");
456 458
 	return CL_CLEAN;
... ...
@@ -2252,6 +2254,27 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2252 2252
 
2253 2253
     /* to be continued ... */
2254 2254
 
2255
+    /* Bytecode */
2256
+    bc_ctx = cli_bytecode_context_alloc();
2257
+    if (!bc_ctx) {
2258
+	cli_errmsg("cli_scanpe: can't allocate memory for bc_ctx\n");
2259
+	return CL_EMEM;
2260
+    }
2261
+    pedata.exe_info.section = exe_sections;
2262
+    pedata.exe_info.nsections = nsections;
2263
+    pedata.exe_info.ep = ep;
2264
+    pedata.exe_info.offset = offset;
2265
+    pedata.file_hdr = &file_hdr;
2266
+    pedata.opt32 = &pe_opt.opt32;
2267
+    pedata.opt64 = &pe_opt.opt64;
2268
+    pedata.dirs = dirs;
2269
+    pedata.overlays = overlays;
2270
+    pedata.overlays_sz = fsize - overlays;
2271
+    cli_bytecode_context_setpe(bc_ctx, &pedata);
2272
+    if (cli_bytecode_runhook(ctx->engine, bc_ctx, BC_PE_UNPACKER, desc, ctx->virname) == CL_VIRUS)
2273
+	return CL_VIRUS;
2274
+    cli_bytecode_context_destroy(bc_ctx);
2275
+
2255 2276
     free(exe_sections);
2256 2277
     return CL_CLEAN;
2257 2278
 }
... ...
@@ -128,6 +128,16 @@ struct pe_image_section_hdr {
128 128
     uint32_t Characteristics;
129 129
 };
130 130
 
131
+struct cli_pe_hook_data {
132
+    struct cli_exe_info exe_info;
133
+    struct pe_image_file_hdr *file_hdr;
134
+    struct pe_image_optional_hdr32 *opt32;
135
+    struct pe_image_optional_hdr64 *opt64;
136
+    struct pe_image_data_dir *dirs;
137
+    uint32_t overlays;
138
+    int32_t overlays_sz;
139
+};
140
+
131 141
 int cli_scanpe(int desc, cli_ctx *ctx);
132 142
 
133 143
 int cli_peheader(int desc, struct cli_exe_info *peinfo);
... ...
@@ -70,6 +70,7 @@
70 70
 
71 71
 #include "mpool.h"
72 72
 #include "bytecode.h"
73
+#include "bytecode_api.h"
73 74
 #include "bytecode_priv.h"
74 75
 #ifdef CL_THREAD_SAFE
75 76
 #  include <pthread.h>
... ...
@@ -1044,6 +1045,7 @@ static int cli_loadcbc(FILE *fs, struct cl_engine *engine, unsigned int *signo,
1044 1044
     struct cli_bc *bc;
1045 1045
     unsigned sigs = 0;
1046 1046
 
1047
+    /* TODO: virusname have a common prefix, and whitelist by that */
1047 1048
     if((rc = cli_initroots(engine, options)))
1048 1049
 	return rc;
1049 1050
 
... ...
@@ -1059,18 +1061,42 @@ static int cli_loadcbc(FILE *fs, struct cl_engine *engine, unsigned int *signo,
1059 1059
     bc = &bcs->all_bcs[bcs->count-1];
1060 1060
     rc = cli_bytecode_load(bc, fs, dbio);
1061 1061
     if (rc != CL_SUCCESS) {
1062
-	fprintf(stderr,"Unable to load %s bytecode: %s\n", dbname, cl_strerror(rc));
1062
+	cli_errmsg("Unable to load %s bytecode: %s\n", dbname, cl_strerror(rc));
1063 1063
 	return rc;
1064 1064
     }
1065 1065
     sigs += 2;/* the bytecode itself and the logical sig */
1066
-    if (bc->lsig) {
1066
+    if (bc->kind == BC_LOGICAL) {
1067
+	if (!bc->lsig) {
1068
+	    cli_errmsg("Bytecode %s has logical kind, but missing logical signature!\n", dbname);
1069
+	    return CL_EMALFDB;
1070
+	}
1067 1071
 	cli_dbgmsg("Bytecode %s has logical signature: %s\n", dbname, bc->lsig);
1068 1072
 	rc = load_oneldb(bc->lsig, 0, 0, engine, options, dbname, 0, &sigs, bc, NULL);
1069 1073
 	if (rc != CL_SUCCESS) {
1070
-	    fprintf(stderr,"Problem parsing logical signature %s for bytecode %s: %s\n",
1071
-		    bc->lsig, dbname, cl_strerror(rc));
1074
+	    cli_errmsg("Problem parsing logical signature %s for bytecode %s: %s\n",
1075
+		       bc->lsig, dbname, cl_strerror(rc));
1072 1076
 	    return rc;
1073 1077
 	}
1078
+    } else {
1079
+	if (bc->lsig) {
1080
+	    cli_errmsg("Bytecode %s has logical signature but is not logical kind!\n", dbname);
1081
+	    return CL_EMALFDB;
1082
+	}
1083
+	if (bc->kind >= _BC_START_HOOKS && bc->kind < _BC_LAST_HOOK) {
1084
+	    unsigned hook = bc->kind - _BC_START_HOOKS;
1085
+	    unsigned cnt = ++engine->hooks_cnt[hook];
1086
+	    engine->hooks[hook] = cli_realloc2(engine->hooks[hook],
1087
+					       sizeof(*engine->hooks[0])*cnt);
1088
+	    if (!engine->hooks[hook]) {
1089
+		cli_errmsg("Out of memory allocating memory for hook %u", hook);
1090
+		return CL_EMEM;
1091
+	    }
1092
+	    engine->hooks[hook][cnt-1] = bcs->count-1;
1093
+	} else switch (bc->kind) {
1094
+	    default:
1095
+		cli_errmsg("Bytecode: unhandled bytecode kind %u\n", bc->kind);
1096
+		return CL_EMALFDB;
1097
+	}
1074 1098
     }
1075 1099
     if (signo)
1076 1100
 	*signo += sigs;
... ...
@@ -2199,6 +2225,9 @@ int cl_engine_free(struct cl_engine *engine)
2199 2199
 		cli_bytecode_destroy(&engine->bcs.all_bcs[i]);
2200 2200
 	cli_bytecode_done(&engine->bcs);
2201 2201
 	free(engine->bcs.all_bcs);
2202
+	for (i=0;i<_BC_LAST_HOOK - _BC_START_HOOKS;i++) {
2203
+	    free (engine->hooks[i]);
2204
+	}
2202 2205
     }
2203 2206
     if(engine->dconf->phishing & PHISHING_CONF_ENGINE)
2204 2207
 	phishing_done(engine);
... ...
@@ -2286,7 +2315,7 @@ int cl_engine_compile(struct cl_engine *engine)
2286 2286
 
2287 2287
     /* Compile bytecode */
2288 2288
     if((ret = cli_bytecode_prepare(&engine->bcs))) {
2289
-	fprintf(stderr,"Unable to compile/load bytecode: %s\n", cl_strerror(ret));
2289
+	cli_errmsg("Unable to compile/load bytecode: %s\n", cl_strerror(ret));
2290 2290
 	return ret;
2291 2291
     }
2292 2292