Browse code

Linux bytecode unpackers

Jonas Zaddach authored on 2019/03/19 23:28:49
Showing 6 changed files
... ...
@@ -2983,6 +2983,9 @@ void cli_bytecode_describe(const struct cli_bc *bc)
2983 2983
         case BC_PRECLASS:
2984 2984
             puts("preclass hook");
2985 2985
             break;
2986
+        case BC_ELF_UNPACKER:
2987
+            puts("ELF unpacker hook");
2988
+            break;
2986 2989
         default:
2987 2990
             printf("Unknown (type %u)", bc->kind);
2988 2991
             break;
... ...
@@ -3024,6 +3027,12 @@ void cli_bytecode_describe(const struct cli_bc *bc)
3024 3024
             else
3025 3025
                 puts("all PRECLASS files!");
3026 3026
             break;
3027
+        case BC_ELF_UNPACKER:
3028
+            if (bc->lsig)
3029
+                puts("ELF files matching logical signature (unpacked)");
3030
+            else
3031
+                puts("all ELF files! (unpacked)");
3032
+            break;
3027 3033
         default:
3028 3034
             puts("N/A (unknown type)\n");
3029 3035
             break;
... ...
@@ -70,6 +70,8 @@ enum BytecodeKind {
70 70
     /** specifies a PRECLASS hook, executes at the end of file property collection and
71 71
       * operates on the original file targeted for property collection */
72 72
     BC_PRECLASS,
73
+    /** specifies an ELF unpacker, executed on ELF files on a logical trigger */
74
+    BC_ELF_UNPACKER,
73 75
     _BC_LAST_HOOK
74 76
 };
75 77
 
... ...
@@ -42,11 +42,21 @@
42 42
 #include "clamav.h"
43 43
 #include "execs.h"
44 44
 #include "matcher.h"
45
+#include "scanners.h"
45 46
 
46 47
 #define EC16(v, conv) (conv ? cbswap16(v) : v)
47 48
 #define EC32(v, conv) (conv ? cbswap32(v) : v)
48 49
 #define EC64(v, conv) (conv ? cbswap64(v) : v)
49 50
 
51
+
52
+#define CLI_TMPUNLK()               \
53
+    if (!ctx->engine->keeptmp) {    \
54
+        if (cli_unlink(tempfile)) { \
55
+            free(tempfile);         \
56
+            return CL_EUNLINK;      \
57
+        }                           \
58
+    }
59
+
50 60
 static void cli_elf_sectionlog(uint32_t sh_type, uint32_t sh_flags);
51 61
 
52 62
 static uint32_t cli_rawaddr32(uint32_t vaddr, struct elf_program_hdr32 *ph, uint16_t phnum, uint8_t conv, uint8_t *err)
... ...
@@ -834,3 +844,60 @@ int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo)
834 834
 
835 835
     return 0;
836 836
 }
837
+
838
+/*
839
+ * ELF file unpacking.
840
+ */
841
+int cli_unpackelf(cli_ctx *ctx)
842
+{
843
+    char *tempfile;
844
+    int ndesc;
845
+    struct cli_bc_ctx *bc_ctx;
846
+    int ret;
847
+    fmap_t *map = *ctx->fmap;
848
+
849
+    /* Bytecode BC_ELF_UNPACKER hook */
850
+    bc_ctx = cli_bytecode_context_alloc();
851
+    if (!bc_ctx) {
852
+        cli_errmsg("cli_scanelf: can't allocate memory for bc_ctx\n");
853
+        return CL_EMEM;
854
+    }
855
+
856
+    cli_bytecode_context_setctx(bc_ctx, ctx);
857
+
858
+    cli_dbgmsg("Running bytecode hook\n");
859
+    ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_ELF_UNPACKER, map);
860
+    cli_dbgmsg("Finished running bytecode hook\n");
861
+    switch (ret) {
862
+        case CL_VIRUS:
863
+            cli_bytecode_context_destroy(bc_ctx);
864
+            return CL_VIRUS;
865
+        case CL_SUCCESS:
866
+            ndesc = cli_bytecode_context_getresult_file(bc_ctx, &tempfile);
867
+            cli_bytecode_context_destroy(bc_ctx);
868
+            if (ndesc != -1 && tempfile) {
869
+                if (ctx->engine->keeptmp) 
870
+                    cli_dbgmsg("cli_scanelf: Unpacked and rebuilt executable saved in %s\n", tempfile);
871
+                else
872
+                    cli_dbgmsg("cli_scanelf: Unpacked and rebuilt executable\n");
873
+                lseek(ndesc, 0, SEEK_SET);
874
+                cli_dbgmsg("***** Scanning rebuilt ELF file *****\n");
875
+                if (cli_magic_scandesc(ndesc, tempfile, ctx) == CL_VIRUS) {
876
+                    close(ndesc);
877
+                    CLI_TMPUNLK();
878
+                    free(tempfile);
879
+                    return CL_VIRUS;
880
+                } 
881
+                close(ndesc);
882
+                CLI_TMPUNLK();
883
+                free(tempfile);
884
+                return CL_CLEAN;
885
+            }
886
+            break;
887
+        default:
888
+            cli_bytecode_context_destroy(bc_ctx);
889
+    }
890
+
891
+    return CL_CLEAN;
892
+}
893
+
... ...
@@ -147,4 +147,6 @@ int cli_scanelf(cli_ctx *ctx);
147 147
 
148 148
 int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo);
149 149
 
150
+int cli_unpackelf(cli_ctx *ctx);
151
+
150 152
 #endif
... ...
@@ -119,6 +119,7 @@ enum perfev {
119 119
     PERFT_BYTECODE,
120 120
     PERFT_KTIME,
121 121
     PERFT_UTIME,
122
+    PERFT_ELF,
122 123
     PERFT_LAST
123 124
 };
124 125
 
... ...
@@ -3520,6 +3520,11 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3520 3520
             }
3521 3521
             perf_nested_stop(ctx, PERFT_PE, PERFT_SCAN);
3522 3522
             break;
3523
+        case CL_TYPE_ELF:
3524
+            perf_nested_start(ctx, PERFT_ELF, PERFT_SCAN);
3525
+            ret = cli_unpackelf(ctx);
3526
+            perf_nested_stop(ctx, PERFT_ELF, PERFT_SCAN);
3527
+            break;
3523 3528
         case CL_TYPE_BINARY_DATA:
3524 3529
             ret = cli_fmap_scandesc(ctx, CL_TYPE_OTHER, 0, NULL, AC_SCAN_VIR, NULL, NULL);
3525 3530
             break;