From c84683f2f4db68d30d297cdb97898f9dc9b8a461 Mon Sep 17 00:00:00 2001 From: Jonas Zaddach Date: Wed, 17 Apr 2019 20:30:21 +0200 Subject: [PATCH] Mach-O bytecode unpackers --- libclamav/bytecode.c | 9 ++++++ libclamav/bytecode_api.h | 2 ++ libclamav/events.h | 1 + libclamav/macho.c | 60 ++++++++++++++++++++++++++++++++++++++++ libclamav/macho.h | 1 + libclamav/scanners.c | 6 ++++ 6 files changed, 79 insertions(+) diff --git a/libclamav/bytecode.c b/libclamav/bytecode.c index bbc848cc1..9aad4a275 100644 --- a/libclamav/bytecode.c +++ b/libclamav/bytecode.c @@ -2986,6 +2986,9 @@ void cli_bytecode_describe(const struct cli_bc *bc) case BC_ELF_UNPACKER: puts("ELF unpacker hook"); break; + case BC_MACHO_UNPACKER: + puts("Mach-O unpacker hook"); + break; default: printf("Unknown (type %u)", bc->kind); break; @@ -3033,6 +3036,12 @@ void cli_bytecode_describe(const struct cli_bc *bc) else puts("all ELF files! (unpacked)"); break; + case BC_MACHO_UNPACKER: + if (bc->lsig) + puts("Mach-O files matching logical signature (unpacked)"); + else + puts("all Mach-O files! (unpacked)"); + break; default: puts("N/A (unknown type)\n"); break; diff --git a/libclamav/bytecode_api.h b/libclamav/bytecode_api.h index 3105d3337..aae8598cc 100644 --- a/libclamav/bytecode_api.h +++ b/libclamav/bytecode_api.h @@ -72,6 +72,8 @@ enum BytecodeKind { BC_PRECLASS, /** specifies an ELF unpacker, executed on ELF files on a logical trigger */ BC_ELF_UNPACKER, + /** specifies an Mach-O unpacker, executed on Mach-O files on a logical trigger */ + BC_MACHO_UNPACKER, _BC_LAST_HOOK }; diff --git a/libclamav/events.h b/libclamav/events.h index 1e5eb0c69..df84b73d1 100644 --- a/libclamav/events.h +++ b/libclamav/events.h @@ -120,6 +120,7 @@ enum perfev { PERFT_KTIME, PERFT_UTIME, PERFT_ELF, + PERFT_MACHO, PERFT_LAST }; diff --git a/libclamav/macho.c b/libclamav/macho.c index a832ee8fc..0108a39ad 100644 --- a/libclamav/macho.c +++ b/libclamav/macho.c @@ -35,6 +35,14 @@ #include "execs.h" #include "scanners.h" +#define CLI_TMPUNLK() \ + if (!ctx->engine->keeptmp) { \ + if (cli_unlink(tempfile)) { \ + free(tempfile); \ + return CL_EUNLINK; \ + } \ + } + #define EC32(v, conv) (conv ? cbswap32(v) : v) #define EC64(v, conv) (conv ? cbswap64(v) : v) @@ -556,3 +564,55 @@ int cli_scanmacho_unibin(cli_ctx *ctx) return ret; /* result from the last binary */ } + +int cli_unpackmacho(cli_ctx *ctx) +{ + char *tempfile; + int ndesc; + struct cli_bc_ctx *bc_ctx; + int ret; + fmap_t *map = *ctx->fmap; + + /* Bytecode BC_MACHO_UNPACKER hook */ + bc_ctx = cli_bytecode_context_alloc(); + if (!bc_ctx) { + cli_errmsg("cli_scanelf: can't allocate memory for bc_ctx\n"); + return CL_EMEM; + } + + cli_bytecode_context_setctx(bc_ctx, ctx); + + ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_MACHO_UNPACKER, map); + switch (ret) { + case CL_VIRUS: + cli_bytecode_context_destroy(bc_ctx); + return CL_VIRUS; + case CL_SUCCESS: + ndesc = cli_bytecode_context_getresult_file(bc_ctx, &tempfile); + cli_bytecode_context_destroy(bc_ctx); + if (ndesc != -1 && tempfile) { + if (ctx->engine->keeptmp) + cli_dbgmsg("cli_scanmacho: Unpacked and rebuilt executable saved in %s\n", tempfile); + else + cli_dbgmsg("cli_scanmacho: Unpacked and rebuilt executable\n"); + lseek(ndesc, 0, SEEK_SET); + cli_dbgmsg("***** Scanning rebuilt Mach-O file *****\n"); + if (cli_magic_scandesc(ndesc, tempfile, ctx) == CL_VIRUS) { + close(ndesc); + CLI_TMPUNLK(); + free(tempfile); + return CL_VIRUS; + } + close(ndesc); + CLI_TMPUNLK(); + free(tempfile); + return CL_SUCCESS; + } + break; + default: + cli_bytecode_context_destroy(bc_ctx); + } + + return CL_CLEAN; +} + diff --git a/libclamav/macho.h b/libclamav/macho.h index 939aec355..f58824012 100644 --- a/libclamav/macho.h +++ b/libclamav/macho.h @@ -29,5 +29,6 @@ int cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo); int cli_machoheader(fmap_t *map, struct cli_exe_info *fileinfo); int cli_scanmacho_unibin(cli_ctx *ctx); +int cli_unpackmacho(cli_ctx *ctx); #endif diff --git a/libclamav/scanners.c b/libclamav/scanners.c index ce7f00ee0..8cb49e17e 100644 --- a/libclamav/scanners.c +++ b/libclamav/scanners.c @@ -3525,6 +3525,12 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type) ret = cli_unpackelf(ctx); perf_nested_stop(ctx, PERFT_ELF, PERFT_SCAN); break; + case CL_TYPE_MACHO: + case CL_TYPE_MACHO_UNIBIN: + perf_nested_start(ctx, PERFT_MACHO, PERFT_SCAN); + ret = cli_unpackmacho(ctx); + perf_nested_stop(ctx, PERFT_MACHO, PERFT_SCAN); + break; case CL_TYPE_BINARY_DATA: ret = cli_fmap_scandesc(ctx, CL_TYPE_OTHER, 0, NULL, AC_SCAN_VIR, NULL, NULL); break;