... | ... |
@@ -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 |
... | ... |
@@ -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 |
|