From 4747786752d5448359a001f0400e43b7a202599b Mon Sep 17 00:00:00 2001 From: Andy Ragusa Date: Thu, 2 Mar 2023 17:23:46 -0800 Subject: [PATCH] Sigtool: Add vba macro support for OOXML files Add a new cl_engine_set_clcb_vba() function to set a cb_vba callback function and add clcb_generic_data handler prototype to the clamav.h public API. The cb_vba callback function will be run whenever VBA is extracted from office documents. The provided data will be a normalized copy of the original VBA. This callback is added to support Sigtool so it can use the same VBA extraction logic as when scanning documents. Change the Sigtool temp directory creation for any commands that use temp directories so that you can select a custom temp directory with the `--tempdir=PATH` option, and can retain the temp files with the `--leave-temps` option. Added `--tempdir` and `--leave-temps` to the Sigtool `--help` output. Added `--tempdir` and `--leave-temps` to the Sigtool manpage. --- common/optparser.c | 2 +- docs/man/sigtool.1.in | 6 + libclamav/clamav.h | 21 +++ libclamav/libclamav.map | 1 + libclamav/others.c | 5 + libclamav/others.h | 1 + libclamav/vba_extract.c | 10 ++ sigtool/sigtool.c | 370 +++++++++++++++++++++++++--------------- sigtool/vba.c | 307 +-------------------------------- sigtool/vba.h | 4 +- 10 files changed, 285 insertions(+), 442 deletions(-) diff --git a/common/optparser.c b/common/optparser.c index 10398cb0f5..c13d56ed0e 100644 --- a/common/optparser.c +++ b/common/optparser.c @@ -118,7 +118,7 @@ const struct clam_option __clam_options[] = { {NULL, "verbose", 'v', CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM | OPT_CLAMSCAN | OPT_CLAMDSCAN | OPT_SIGTOOL | OPT_CLAMONACC, "", ""}, {NULL, "dumpcerts", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "Dump authenticode certificate chain.", ""}, {NULL, "quiet", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM | OPT_CLAMSCAN | OPT_CLAMDSCAN | OPT_SIGTOOL | OPT_CLAMONACC, "", ""}, - {NULL, "leave-temps", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", ""}, + {NULL, "leave-temps", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_SIGTOOL, "", ""}, {NULL, "no-warnings", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM, "", ""}, {NULL, "show-progress", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM, "", ""}, {NULL, "stdout", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM | OPT_CLAMSCAN | OPT_CLAMDSCAN | OPT_SIGTOOL | OPT_CLAMONACC, "", ""}, diff --git a/docs/man/sigtool.1.in b/docs/man/sigtool.1.in index 1bc5acdfc3..990349393d 100644 --- a/docs/man/sigtool.1.in +++ b/docs/man/sigtool.1.in @@ -114,6 +114,12 @@ Test all signatures from DATABASE against TARGET_FILE. This option will only giv .TP \fB\-\-print\-certs=FILE\fR Print Authenticode details from a PE file. +.TP +\fB\-\-tempdir=DIRECTORY\fR +Create temporary files in DIRECTORY. Directory must be writable for the user running sigtool. +.TP +\fB\-\-leave\-temps\fR +Do not remove temporary files. .SH "ENVIRONMENT VARIABLES" .LP diff --git a/libclamav/clamav.h b/libclamav/clamav.h index d0e707ed9f..a3b187ebbe 100644 --- a/libclamav/clamav.h +++ b/libclamav/clamav.h @@ -814,6 +814,27 @@ typedef int (*clcb_file_props)(const char *j_propstr, int rc, void *cbdata); */ extern void cl_engine_set_clcb_file_props(struct cl_engine *engine, clcb_file_props callback); +/** + * @brief generic data callback function. + * + * Callback handler prototype for callbacks passing back data and application context. + * + * @param data A pointer to some data. Should be treated as read-only and may be freed after callback. + * @param data_len The length of data. + * @param cbdata Opaque application provided data. + */ +typedef int (*clcb_generic_data)(const unsigned char *const data, const size_t data_len, void *cbdata); + +/** + * @brief Set a custom VBA macro callback function. + * + * Caution: changing options for an engine that is in-use is not thread-safe! + * + * @param engine The initialized scanning engine. + * @param callback The callback function pointer. + */ +extern void cl_engine_set_clcb_vba(struct cl_engine *engine, clcb_generic_data callback); + /* ---------------------------------------------------------------------------- * Statistics/telemetry gathering callbacks. * diff --git a/libclamav/libclamav.map b/libclamav/libclamav.map index e6d5b07d22..6fe8ce253c 100644 --- a/libclamav/libclamav.map +++ b/libclamav/libclamav.map @@ -74,6 +74,7 @@ CLAMAV_1.0.0 { CLAMAV_1.1.0 { global: cl_cvdgetage; + cl_engine_set_clcb_vba; } CLAMAV_1.0.0; CLAMAV_PRIVATE { global: diff --git a/libclamav/others.c b/libclamav/others.c index f14d633613..5eeba0a074 100644 --- a/libclamav/others.c +++ b/libclamav/others.c @@ -1927,6 +1927,11 @@ void cl_engine_set_clcb_file_props(struct cl_engine *engine, clcb_file_props cal engine->cb_file_props = callback; } +void cl_engine_set_clcb_vba(struct cl_engine *engine, clcb_generic_data callback) +{ + engine->cb_vba = callback; +} + uint8_t cli_get_debug_flag() { return cli_debug_flag; diff --git a/libclamav/others.h b/libclamav/others.h index d75e37dcd3..1dbe67329d 100644 --- a/libclamav/others.h +++ b/libclamav/others.h @@ -416,6 +416,7 @@ struct cl_engine { void *cb_sigload_ctx; clcb_hash cb_hash; clcb_meta cb_meta; + clcb_generic_data cb_vba; clcb_file_props cb_file_props; clcb_progress cb_sigload_progress; void *cb_sigload_progress_ctx; diff --git a/libclamav/vba_extract.c b/libclamav/vba_extract.c index 910d9a486b..5c35dd3090 100644 --- a/libclamav/vba_extract.c +++ b/libclamav/vba_extract.c @@ -1259,10 +1259,20 @@ cl_error_t cli_vba_readdir_new(cli_ctx *ctx, const char *dir, struct uniq *U, co module_data_utf8_size = vba_normalize(module_data_utf8, module_data_utf8_size); CLI_WRITEN(module_data_utf8, module_data_utf8_size); + + if (NULL != ctx->engine->cb_vba) { + ctx->engine->cb_vba(module_data_utf8, module_data_utf8_size, ctx->cb_ctx); + } + module_stream_found = 1; free(module_data_utf8); module_data_utf8 = NULL; } else { + /*If normalization didn't work, fall back to the pre-normalized data.*/ + if (NULL != ctx->engine->cb_vba) { + ctx->engine->cb_vba(module_data, module_data_size, ctx->cb_ctx); + } + CLI_WRITEN("\n\n", 30); cli_dbgmsg("cli_vba_readdir_new: Failed to decode VBA module content from codepage %" PRIu16 " to UTF8\n", codepage); } diff --git a/sigtool/sigtool.c b/sigtool/sigtool.c index 6f5ef8c1d1..1aa6400ae8 100644 --- a/sigtool/sigtool.c +++ b/sigtool/sigtool.c @@ -39,6 +39,10 @@ #include #include +#ifndef _WIN32 +#include +#endif + // libclamav #include "clamav.h" #include "matcher.h" @@ -433,7 +437,6 @@ static int fuzzy_img(const struct optstruct *opts) static int htmlnorm(const struct optstruct *opts) { int fd; - fmap_t *map; cli_ctx *ctx = NULL; if ((fd = open(optget(opts, "html-normalise")->strarg, O_RDONLY | O_BINARY)) == -1) { @@ -443,7 +446,7 @@ static int htmlnorm(const struct optstruct *opts) if (NULL != (ctx = convenience_ctx(fd))) { html_normalise_map(ctx, ctx->fmap, ".", NULL, NULL); - funmap(map); + funmap(ctx->fmap); } else mprintf(LOGG_ERROR, "fmap failed\n"); @@ -698,13 +701,21 @@ static int writeinfo(const char *dbname, const char *builder, const char *header } static int diffdirs(const char *old, const char *new, const char *patch); -static int verifydiff(const char *diff, const char *cvd, const char *incdir); +static int verifydiff(const struct optstruct *opts, const char *diff, const char *cvd, const char *incdir); static int qcompare(const void *a, const void *b) { return strcmp(*(char *const *)a, *(char *const *)b); } +char *createTempDir(const struct optstruct *opts); +void removeTempDir(const struct optstruct *opts, char *dir) +{ + if (!optget(opts, "leave-temps")->enabled) { + cli_rmdirs(dir); + } +} + static int build(const struct optstruct *opts) { int ret, bc = 0, hy = 0; @@ -1088,22 +1099,13 @@ static int build(const struct optstruct *opts) } /* generate patch */ - if (!(pt = cli_gentemp(NULL))) { - mprintf(LOGG_ERROR, "build: Can't generate temporary name\n"); - unlink(newcvd); - return -1; - } - - if (mkdir(pt, 0700)) { - mprintf(LOGG_ERROR, "build: Can't create temporary directory %s\n", pt); - free(pt); - unlink(newcvd); + if (!(pt = createTempDir(opts))) { return -1; } if (CL_SUCCESS != cl_cvdunpack(olddb, pt, true)) { mprintf(LOGG_ERROR, "build: Can't unpack CVD file %s\n", olddb); - cli_rmdirs(pt); + removeTempDir(opts, pt); free(pt); unlink(newcvd); return -1; @@ -1112,24 +1114,13 @@ static int build(const struct optstruct *opts) olddb[sizeof(olddb) - 1] = '\0'; free(pt); - if (!(pt = cli_gentemp(NULL))) { - mprintf(LOGG_ERROR, "build: Can't generate temporary name\n"); - cli_rmdirs(olddb); - unlink(newcvd); - return -1; - } - - if (mkdir(pt, 0700)) { - mprintf(LOGG_ERROR, "build: Can't create temporary directory %s\n", pt); - free(pt); - cli_rmdirs(olddb); - unlink(newcvd); + if (!(pt = createTempDir(opts))) { return -1; } if (CL_SUCCESS != cl_cvdunpack(newcvd, pt, true)) { mprintf(LOGG_ERROR, "build: Can't unpack CVD file %s\n", newcvd); - cli_rmdirs(pt); + removeTempDir(opts, pt); free(pt); cli_rmdirs(olddb); unlink(newcvd); @@ -1138,8 +1129,7 @@ static int build(const struct optstruct *opts) snprintf(patch, sizeof(patch), "%s-%u.script", dbname, version); ret = diffdirs(olddb, pt, patch); - - cli_rmdirs(pt); + removeTempDir(opts, pt); free(pt); if (ret == -1) { @@ -1148,7 +1138,7 @@ static int build(const struct optstruct *opts) return -1; } - ret = verifydiff(patch, NULL, olddb); + ret = verifydiff(opts, patch, NULL, olddb); cli_rmdirs(olddb); if (ret == -1) { @@ -1251,9 +1241,9 @@ static int cvdinfo(const struct optstruct *opts) return 0; } -static int listdb(const char *filename, const regex_t *regex); +static int listdb(const struct optstruct *opts, const char *filename, const regex_t *regex); -static int listdir(const char *dirname, const regex_t *regex) +static int listdir(const struct optstruct *opts, const char *dirname, const regex_t *regex) { DIR *dd; struct dirent *dent; @@ -1298,7 +1288,7 @@ static int listdir(const char *dirname, const regex_t *regex) } sprintf(dbfile, "%s" PATHSEP "%s", dirname, dent->d_name); - if (listdb(dbfile, regex) == -1) { + if (listdb(opts, dbfile, regex) == -1) { mprintf(LOGG_ERROR, "listdb: Error listing database %s\n", dbfile); free(dbfile); closedir(dd); @@ -1313,7 +1303,7 @@ static int listdir(const char *dirname, const regex_t *regex) return 0; } -static int listdb(const char *filename, const regex_t *regex) +static int listdb(const struct optstruct *opts, const char *filename, const regex_t *regex) { FILE *fh; char *buffer, *pt, *start, *dir; @@ -1344,33 +1334,26 @@ static int listdb(const char *filename, const regex_t *regex) free(buffer); fclose(fh); - if (!(dir = cli_gentemp(NULL))) { - mprintf(LOGG_ERROR, "listdb: Can't generate temporary name\n"); - return -1; - } - - if (mkdir(dir, 0700)) { - mprintf(LOGG_ERROR, "listdb: Can't create temporary directory %s\n", dir); - free(dir); + if (!(dir = createTempDir(opts))) { return -1; } if (CL_SUCCESS != cl_cvdunpack(filename, dir, true)) { mprintf(LOGG_ERROR, "listdb: Can't unpack CVD file %s\n", filename); - cli_rmdirs(dir); + removeTempDir(opts, dir); free(dir); return -1; } /* list extracted directory */ - if (listdir(dir, regex) == -1) { + if (listdir(opts, dir, regex) == -1) { mprintf(LOGG_ERROR, "listdb: Can't list directory %s\n", filename); - cli_rmdirs(dir); + removeTempDir(opts, dir); free(dir); return -1; } - cli_rmdirs(dir); + removeTempDir(opts, dir); free(dir); return 0; @@ -1542,13 +1525,13 @@ static int listsigs(const struct optstruct *opts, int mode) if (S_ISDIR(sb.st_mode)) { if (!strcmp(name, DATADIR)) { dbdir = freshdbdir(); - ret = listdir(localdbdir ? localdbdir : dbdir, NULL); + ret = listdir(opts, localdbdir ? localdbdir : dbdir, NULL); free(dbdir); } else { - ret = listdir(name, NULL); + ret = listdir(opts, name, NULL); } } else { - ret = listdb(name, NULL); + ret = listdb(opts, name, NULL); } } else { @@ -1558,7 +1541,7 @@ static int listsigs(const struct optstruct *opts, int mode) } mprintf_stdout = 1; dbdir = freshdbdir(); - ret = listdir(localdbdir ? localdbdir : dbdir, ®); + ret = listdir(opts, localdbdir ? localdbdir : dbdir, ®); free(dbdir); cli_regfree(®); } @@ -1566,62 +1549,199 @@ static int listsigs(const struct optstruct *opts, int mode) return ret; } -static int vbadump(const struct optstruct *opts) +char *createTempDir(const struct optstruct *opts) { - int fd, hex_output; - char *dir; - const char *pt; - struct uniq *files = NULL; - cli_ctx *ctx; - int has_vba = 0, has_xlm = 0; - - if (optget(opts, "vba-hex")->enabled) { - hex_output = 1; - pt = optget(opts, "vba-hex")->strarg; + const struct optstruct *opt; + const char *tempdir = NULL; + char *ret = NULL; + + if (opts && ((opt = optget(opts, "tempdir"))->enabled)) { + tempdir = opt->strarg; } else { - hex_output = 0; - pt = optget(opts, "vba")->strarg; + tempdir = cli_gettmpdir(); } - if ((fd = open(pt, O_RDONLY | O_BINARY)) == -1) { - mprintf(LOGG_ERROR, "vbadump: Can't open file %s\n", pt); - return -1; + ret = (char *)cli_gentemp_with_prefix(tempdir, "sigtool"); + if (NULL == ret) { + logg(LOGG_ERROR, "Can't create temporary directory name.\n"); + goto done; } - /* generate the temporary directory */ - if (!(dir = cli_gentemp(NULL))) { - mprintf(LOGG_ERROR, "vbadump: Can't generate temporary name\n"); - close(fd); - return -1; + if (mkdir(ret, 0700)) { + logg(LOGG_ERROR, "Can't create temporary directory for scan: %s.\n", tempdir); + free((char *)ret); + ret = NULL; } - if (mkdir(dir, 0700)) { - mprintf(LOGG_ERROR, "vbadump: Can't create temporary directory %s\n", dir); - free(dir); - close(fd); - return -1; +done: + + return ret; +} + +static bool setTempDir(struct cl_engine *engine, const struct optstruct *opts) +{ + bool bRet = false; + int ret = -1; + const char *tempdir = createTempDir(opts); + if (NULL == tempdir) { + goto done; } - if (!(ctx = convenience_ctx(fd))) { - close(fd); - free(dir); - return -1; + + if ((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, tempdir))) { + logg(LOGG_ERROR, "cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret)); + goto done; } - if (cli_ole2_extract(dir, ctx, &files, &has_vba, &has_xlm, NULL)) { - destroy_ctx(ctx); - cli_rmdirs(dir); - free(dir); - close(fd); + + bRet = true; +done: + if (tempdir) { + free((char *)tempdir); + } + return bRet; +} + +static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options) +{ + cl_error_t ret = CL_SUCCESS; + int fd = -1; + const char *virname = NULL; + char *real_filename = NULL; + unsigned long int blocks = 0; + + if (NULL == filename || NULL == engine || NULL == opts || NULL == options) { + logg(LOGG_INFO, "scanfile: Invalid args.\n"); + ret = CL_EARG; + goto done; + } + + ret = cli_realpath((const char *)filename, &real_filename); + if (CL_SUCCESS != ret) { + logg(LOGG_DEBUG, "Failed to determine real filename of %s.\n", filename); + logg(LOGG_DEBUG, "Quarantine of the file may fail if file path contains symlinks.\n"); + } else { + filename = real_filename; + } + + if ((fd = safe_open(filename, O_RDONLY | O_BINARY)) == -1) { + logg(LOGG_WARNING, "Can't open file %s: %s\n", filename, strerror(errno)); + goto done; + } + + if (CL_CLEAN != cl_scandesc_callback(fd, filename, &virname, &blocks, engine, options, NULL)) { + logg(LOGG_ERROR, "Error parsing '%s'\n", filename); + goto done; + } + +done: + if (NULL != real_filename) { + free(real_filename); + } + return; +} + +static int vba_callback(const unsigned char *const metaString, const size_t metaStringLen, void *context) +{ + + size_t i = 0; + + UNUSEDPARAM(context); + + if (NULL == metaString) { return -1; } - destroy_ctx(ctx); - if (has_vba && files) - sigtool_vba_scandir(dir, hex_output, files); - cli_rmdirs(dir); - free(dir); - close(fd); + + for (i = 0; i < metaStringLen; i++) { +#ifndef _WIN32 + if ('\r' == metaString[i]) { + continue; + } +#endif + printf("%c", metaString[i]); + } + printf("\n"); + return 0; } +static int vbadump(const struct optstruct *opts) +{ + int ret = -1; + + struct cl_scan_options options; + struct cl_engine *engine = NULL; + +#ifndef _WIN32 + struct rlimit rlim; +#endif + + const char *filename = NULL; + + /* Initalize scan options struct */ + memset(&options, 0, sizeof(struct cl_scan_options)); + + if ((ret = cl_init(CL_INIT_DEFAULT))) { + logg(LOGG_ERROR, "Can't initialize libclamav: %s\n", cl_strerror(ret)); + ret = 2; + goto done; + } + + if (!(engine = cl_engine_new())) { + logg(LOGG_ERROR, "Can't initialize antivirus engine\n"); + ret = 2; + goto done; + } + + cl_engine_set_clcb_vba(engine, vba_callback); + + if (!setTempDir(engine, opts)) { + ret = 2; + goto done; + } + + if ((ret = cl_engine_compile(engine)) != 0) { + logg(LOGG_ERROR, "Database initialization error: %s\n", cl_strerror(ret)); + ret = 2; + goto done; + } + +#ifndef _WIN32 + if (getrlimit(RLIMIT_FSIZE, &rlim) == 0) { + if (rlim.rlim_cur < (rlim_t)cl_engine_get_num(engine, CL_ENGINE_MAX_FILESIZE, NULL)) + logg(LOGG_WARNING, "System limit for file size is lower than engine->maxfilesize\n"); + if (rlim.rlim_cur < (rlim_t)cl_engine_get_num(engine, CL_ENGINE_MAX_SCANSIZE, NULL)) + logg(LOGG_WARNING, "System limit for file size is lower than engine->maxscansize\n"); + } else { + logg(LOGG_WARNING, "Cannot obtain resource limits for file size\n"); + } +#endif + + options.general |= CL_SCAN_GENERAL_COLLECT_METADATA; + + /*Have the engine unpack everything so that we don't miss anything. We'll clean it up later.*/ + options.parse = ~0; + + /*Need to explicitly set this to always keep temps, since we are scanning extracted ooxml/ole2 files + * from our scan directory to print all the vba content. Remove it later if leave-temps was not + * specified */ + cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1); + + filename = optget(opts, "vba")->strarg; + if (NULL == filename) { + filename = optget(opts, "vba-hex")->strarg; + } + scanfile(filename, engine, opts, &options); + + removeTempDir(opts, engine->tmpdir); + + ret = 0; +done: + + /* free the engine */ + cl_engine_free(engine); + + return ret; +} + static int comparesha(const char *diff) { char info[32], buff[FILEBUFF], *sha, *pt, *name; @@ -1960,7 +2080,7 @@ static int dircopy(const char *src, const char *dest) return 0; } -static int verifydiff(const char *diff, const char *cvd, const char *incdir) +static int verifydiff(const struct optstruct *opts, const char *diff, const char *cvd, const char *incdir) { char *tempdir, cwd[512]; int ret = 0, fd; @@ -1975,29 +2095,21 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir) return -1; } - tempdir = cli_gentemp(NULL); - if (!tempdir) { - mprintf(LOGG_ERROR, "verifydiff: Can't generate temporary name for tempdir\n"); - return -1; - } - - if (mkdir(tempdir, 0700) == -1) { - mprintf(LOGG_ERROR, "verifydiff: Can't create directory %s\n", tempdir); - free(tempdir); + if (!(tempdir = createTempDir(opts))) { return -1; } if (cvd) { if (CL_SUCCESS != cl_cvdunpack(cvd, tempdir, true)) { mprintf(LOGG_ERROR, "verifydiff: Can't unpack CVD file %s\n", cvd); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); return -1; } } else { if (dircopy(incdir, tempdir) == -1) { mprintf(LOGG_ERROR, "verifydiff: Can't copy dir %s to %s\n", incdir, tempdir); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); return -1; } @@ -2005,21 +2117,21 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir) if (!getcwd(cwd, sizeof(cwd))) { mprintf(LOGG_ERROR, "verifydiff: getcwd() failed\n"); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); return -1; } if ((fd = open(diff, O_RDONLY | O_BINARY)) == -1) { mprintf(LOGG_ERROR, "verifydiff: Can't open diff file %s\n", diff); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); return -1; } if (chdir(tempdir) == -1) { mprintf(LOGG_ERROR, "verifydiff: Can't chdir to %s\n", tempdir); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); close(fd); return -1; @@ -2029,7 +2141,7 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir) mprintf(LOGG_ERROR, "verifydiff: Can't apply %s\n", diff); if (chdir(cwd) == -1) mprintf(LOGG_WARNING, "verifydiff: Can't chdir to %s\n", cwd); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); close(fd); return -1; @@ -2040,7 +2152,7 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir) if (chdir(cwd) == -1) mprintf(LOGG_WARNING, "verifydiff: Can't chdir to %s\n", cwd); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); if (!ret) { @@ -3197,45 +3309,25 @@ static int makediff(const struct optstruct *opts) return -1; } - odir = cli_gentemp(NULL); - if (!odir) { - mprintf(LOGG_ERROR, "makediff: Can't generate temporary name for odir\n"); - return -1; - } - - if (mkdir(odir, 0700) == -1) { - mprintf(LOGG_ERROR, "makediff: Can't create directory %s\n", odir); - free(odir); + if (!(odir = createTempDir(opts))) { return -1; } if (CL_SUCCESS != cl_cvdunpack(optget(opts, "diff")->strarg, odir, true)) { mprintf(LOGG_ERROR, "makediff: Can't unpack CVD file %s\n", optget(opts, "diff")->strarg); - cli_rmdirs(odir); - free(odir); - return -1; - } - - ndir = cli_gentemp(NULL); - if (!ndir) { - mprintf(LOGG_ERROR, "makediff: Can't generate temporary name for ndir\n"); - cli_rmdirs(odir); + removeTempDir(opts, odir); free(odir); return -1; } - if (mkdir(ndir, 0700) == -1) { - mprintf(LOGG_ERROR, "makediff: Can't create directory %s\n", ndir); - free(ndir); - cli_rmdirs(odir); - free(odir); + if (!(ndir = createTempDir(opts))) { return -1; } if (CL_SUCCESS != cl_cvdunpack(opts->filename[0], ndir, true)) { mprintf(LOGG_ERROR, "makediff: Can't unpack CVD file %s\n", opts->filename[0]); - cli_rmdirs(odir); - cli_rmdirs(ndir); + removeTempDir(opts, odir); + removeTempDir(opts, ndir); free(odir); free(ndir); return -1; @@ -3244,15 +3336,15 @@ static int makediff(const struct optstruct *opts) snprintf(name, sizeof(name), "%s-%u.script", getdbname(opts->filename[0], dbname, sizeof(dbname)), newver); ret = diffdirs(odir, ndir, name); - cli_rmdirs(odir); - cli_rmdirs(ndir); + removeTempDir(opts, odir); + removeTempDir(opts, ndir); free(odir); free(ndir); if (ret == -1) return -1; - if (verifydiff(name, optget(opts, "diff")->strarg, NULL) == -1) { + if (verifydiff(opts, name, optget(opts, "diff")->strarg, NULL) == -1) { snprintf(broken, sizeof(broken), "%s.broken", name); if (rename(name, broken)) { unlink(name); @@ -3456,6 +3548,8 @@ static void help(void) mprintf(LOGG_INFO, " cdiff format\n"); mprintf(LOGG_INFO, " --run-cdiff=FILE -r FILE Execute update script FILE in cwd\n"); mprintf(LOGG_INFO, " --verify-cdiff=DIFF CVD/CLD Verify DIFF against CVD/CLD\n"); + mprintf(LOGG_INFO, " --tempdir=DIRECTORY Create temporary files in DIRECTORY\n"); + mprintf(LOGG_INFO, " --leave-temps[=yes/no(*)] Do not remove temporary files\n"); mprintf(LOGG_INFO, "\n"); return; @@ -3559,9 +3653,9 @@ int main(int argc, char **argv) ret = -1; } else { if (S_ISDIR(sb.st_mode)) - ret = verifydiff(optget(opts, "verify-cdiff")->strarg, NULL, opts->filename[0]); + ret = verifydiff(opts, optget(opts, "verify-cdiff")->strarg, NULL, opts->filename[0]); else - ret = verifydiff(optget(opts, "verify-cdiff")->strarg, opts->filename[0], NULL); + ret = verifydiff(opts, optget(opts, "verify-cdiff")->strarg, opts->filename[0], NULL); } } } else diff --git a/sigtool/vba.c b/sigtool/vba.c index e9852a7a5d..54304e9fe1 100644 --- a/sigtool/vba.c +++ b/sigtool/vba.c @@ -154,47 +154,7 @@ cli_ctx *convenience_ctx(int fd) return ctx; } -void destroy_ctx(cli_ctx *ctx) -{ - if (NULL != ctx) { - if (NULL != ctx->recursion_stack) { - /* Clean up any fmaps */ - while (ctx->recursion_level > 0) { - if (NULL != ctx->recursion_stack[ctx->recursion_level].fmap) { - funmap(ctx->recursion_stack[ctx->recursion_level].fmap); - ctx->recursion_stack[ctx->recursion_level].fmap = NULL; - } - ctx->recursion_level -= 1; - } - if (NULL != ctx->recursion_stack[0].fmap) { - funmap(ctx->recursion_stack[0].fmap); - ctx->recursion_stack[0].fmap = NULL; - } - - free(ctx->recursion_stack); - ctx->recursion_stack = NULL; - } - - if (NULL != ctx->engine) { - cl_engine_free((struct cl_engine *)ctx->engine); - ctx->engine = NULL; - } - - if (NULL != ctx->options) { - free(ctx->options); - ctx->options = NULL; - } - - if (NULL != ctx->evidence) { - evidence_free(ctx->evidence); - } - - free(ctx); - } -} - -int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U); - +/*only called by wm_decode_macro*/ static char *get_unicode_name(char *name, int size) { int i, j; @@ -224,6 +184,7 @@ static char *get_unicode_name(char *name, int size) return newname; } +/*only called by wm_decode_macro*/ static void output_token(unsigned char token) { int i; @@ -320,6 +281,7 @@ static void output_token(unsigned char token) return; } +/*only called by wm_decode_macro*/ static void output_token67(uint16_t token) { int i; @@ -670,6 +632,7 @@ static void output_token67(uint16_t token) return; } +/*only called by wm_decode_macro*/ static void output_token73(uint16_t token) { int i; @@ -921,6 +884,7 @@ static void output_token73(uint16_t token) return; } +/*only called by wm_decode_macro*/ static void print_hex_buff(unsigned char *start, unsigned char *end, int hex_output) { if (!hex_output) { @@ -1099,264 +1063,3 @@ static void wm_decode_macro(unsigned char *buff, uint32_t len, int hex_output) } print_hex_buff(line_start, buff + i, hex_output); } - -static int sigtool_scandir(const char *dirname, int hex_output) -{ - int status = -1; - DIR *dd = NULL; - struct dirent *dent; - STATBUF statbuf; - const char *tmpdir; - char *fname = NULL; - char *dir = NULL; - cl_error_t ret = CL_CLEAN; - int desc = -1; - cli_ctx *ctx = NULL; - int has_vba = 0, has_xlm = 0; - - if ((dd = opendir(dirname)) != NULL) { - while ((dent = readdir(dd))) { - if (dent->d_ino) { - if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) { - /* build the full name */ - fname = (char *)cli_calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char)); - if (!fname) { - status = -1; - goto done; - } - - sprintf(fname, "%s" PATHSEP "%s", dirname, dent->d_name); - - /* stat the file */ - if (LSTAT(fname, &statbuf) != -1) { - if (S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) { - if (sigtool_scandir(fname, hex_output)) { - status = CL_VIRUS; - goto done; - } - } else { - if (S_ISREG(statbuf.st_mode)) { - struct uniq *files = NULL; - tmpdir = cli_gettmpdir(); - - /* generate the temporary directory */ - dir = cli_gentemp(tmpdir); - if (!dir) { - printf("cli_gentemp() failed\n"); - status = -1; - goto done; - } - - if (mkdir(dir, 0700)) { - printf("Can't create temporary directory %s\n", dir); - status = CL_ETMPDIR; - goto done; - } - - if ((desc = open(fname, O_RDONLY | O_BINARY)) == -1) { - printf("Can't open file %s\n", fname); - status = 1; - goto done; - } - - if (!(ctx = convenience_ctx(desc))) { - status = 1; - goto done; - } - if ((ret = cli_ole2_extract(dir, ctx, &files, &has_vba, &has_xlm, NULL))) { - printf("ERROR %s\n", cl_strerror(ret)); - - status = ret; - goto done; - } - - if (has_vba && files) - sigtool_vba_scandir(dir, hex_output, files); - - // Cleanup - if (desc >= 0) { - close(desc); - desc = -1; - } - - destroy_ctx(ctx); - ctx = NULL; - - cli_rmdirs(dir); - free(dir); - dir = NULL; - } - } - } - - // Cleanup - free(fname); - fname = NULL; - } - } - } - } else { - logg(LOGG_ERROR, "Can't open directory %s.\n", dirname); - return CL_EOPEN; - } - - status = 0; - -done: - if (desc >= 0) { - close(desc); - } - if (NULL != dd) { - closedir(dd); - } - if (NULL != ctx) { - destroy_ctx(ctx); - } - if (NULL != dir) { - cli_rmdirs(dir); - free(dir); - } - if (NULL != fname) { - free(fname); - } - - return status; -} - -int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U) -{ - cl_error_t status = CL_CLEAN; - cl_error_t ret; - int i, fd; - size_t data_len; - vba_project_t *vba_project = NULL; - DIR *dd; - struct dirent *dent; - STATBUF statbuf; - char *fullname, vbaname[1024], *hash; - unsigned char *data; - uint32_t hashcnt; - unsigned int j; - - if (CL_SUCCESS != (ret = uniq_get(U, "_vba_project", 12, NULL, &hashcnt))) { - logg(LOGG_ERROR, "ScanDir -> uniq_get('_vba_project') failed.\n"); - return ret; - } - - while (hashcnt) { - if (!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) { - hashcnt--; - continue; - } - - for (i = 0; i < vba_project->count; i++) { - for (j = 0; j < vba_project->colls[i]; j++) { - snprintf(vbaname, 1024, "%s" PATHSEP "%s_%u", vba_project->dir, vba_project->name[i], j); - vbaname[sizeof(vbaname) - 1] = '\0'; - - fd = open(vbaname, O_RDONLY | O_BINARY); - if (fd == -1) continue; - data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len); - close(fd); - - if (data) { - data = (unsigned char *)realloc(data, data_len + 1); - data[data_len] = '\0'; - printf("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data); - free(data); - } - } - } - - cli_free_vba_project(vba_project); - vba_project = NULL; - - hashcnt--; - } - - if (CL_SUCCESS != (ret = uniq_get(U, "powerpoint document", 19, &hash, &hashcnt))) { - logg(LOGG_ERROR, "ScanDir -> uniq_get('powerpoint document') failed.\n"); - return ret; - } - - while (hashcnt) { - snprintf(vbaname, 1024, "%s" PATHSEP "%s_%u", dirname, hash, hashcnt); - vbaname[sizeof(vbaname) - 1] = '\0'; - - fd = open(vbaname, O_RDONLY | O_BINARY); - if (fd == -1) { - hashcnt--; - continue; - } - if ((fullname = cli_ppt_vba_read(fd, NULL))) { - sigtool_scandir(fullname, hex_output); - cli_rmdirs(fullname); - free(fullname); - } - close(fd); - hashcnt--; - } - - if (CL_SUCCESS != (ret = uniq_get(U, "worddocument", 12, &hash, &hashcnt))) { - logg(LOGG_ERROR, "ScanDir -> uniq_get('worddocument') failed.\n"); - return ret; - } - - while (hashcnt) { - snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt); - vbaname[sizeof(vbaname) - 1] = '\0'; - - fd = open(vbaname, O_RDONLY | O_BINARY); - if (fd == -1) { - hashcnt--; - continue; - } - - if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) { - close(fd); - hashcnt--; - continue; - } - - for (i = 0; i < vba_project->count; i++) { - data_len = vba_project->length[i]; - data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], (uint32_t)data_len, vba_project->key[i]); - if (data) { - data = (unsigned char *)realloc(data, data_len + 1); - data[data_len] = '\0'; - printf("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data); - free(data); - } - } - - close(fd); - cli_free_vba_project(vba_project); - vba_project = NULL; - hashcnt--; - } - - if ((dd = opendir(dirname)) != NULL) { - while ((dent = readdir(dd))) { - if (dent->d_ino) { - if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) { - /* build the full name */ - fullname = calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char)); - sprintf(fullname, "%s" PATHSEP "%s", dirname, dent->d_name); - - /* stat the file */ - if (LSTAT(fullname, &statbuf) != -1) { - if (S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) - sigtool_vba_scandir(fullname, hex_output, U); - } - free(fullname); - } - } - } - } else { - logg(LOGG_ERROR, "ScanDir -> Can't open directory %s.\n", dirname); - return CL_EOPEN; - } - - closedir(dd); - return status; -} diff --git a/sigtool/vba.h b/sigtool/vba.h index 032e94cd72..410fd9cd87 100644 --- a/sigtool/vba.h +++ b/sigtool/vba.h @@ -24,7 +24,9 @@ #include "uniq.h" #include "others.h" -int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U); +struct optstruct; +int sigtool_vba_scandir(const struct optstruct *opts, const char *dirname, int hex_output, struct uniq *U); + cli_ctx *convenience_ctx(int fd); void destroy_ctx(cli_ctx *ctx);