Changes include:
- Fixing several memory leaks noticed when running with ASan
- Adds documentation for several functions and structs
- Simplifies the interface for using cli_targetinfo_init/destroy
and cli_exe_info_init/destroy
- A few other minor changes
... | ... |
@@ -455,7 +455,6 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
455 | 455 |
section_hdr = (struct elf_section_hdr32 *)cli_calloc(shnum, shentsize); |
456 | 456 |
if (!section_hdr) { |
457 | 457 |
cli_errmsg("ELF: Can't allocate memory for section headers\n"); |
458 |
- cli_exe_info_destroy(elfinfo); |
|
459 | 458 |
return CL_EMEM; |
460 | 459 |
} |
461 | 460 |
if (ctx) { |
... | ... |
@@ -473,7 +472,6 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
473 | 473 |
cli_dbgmsg("ELF: Possibly broken ELF file\n"); |
474 | 474 |
} |
475 | 475 |
free(section_hdr); |
476 |
- cli_exe_info_destroy(elfinfo); |
|
477 | 476 |
if (ctx && SCAN_HEURISTIC_BROKEN) { |
478 | 477 |
cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
479 | 478 |
return CL_VIRUS; |
... | ... |
@@ -558,7 +556,6 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
558 | 558 |
section_hdr = (struct elf_section_hdr64 *)cli_calloc(shnum, shentsize); |
559 | 559 |
if (!section_hdr) { |
560 | 560 |
cli_errmsg("ELF: Can't allocate memory for section headers\n"); |
561 |
- cli_exe_info_destroy(elfinfo); |
|
562 | 561 |
return CL_EMEM; |
563 | 562 |
} |
564 | 563 |
if (ctx) { |
... | ... |
@@ -576,7 +573,6 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
576 | 576 |
cli_dbgmsg("ELF: Possibly broken ELF file\n"); |
577 | 577 |
} |
578 | 578 |
free(section_hdr); |
579 |
- cli_exe_info_destroy(elfinfo); |
|
580 | 579 |
if (ctx && SCAN_HEURISTIC_BROKEN) { |
581 | 580 |
cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
582 | 581 |
return CL_VIRUS; |
... | ... |
@@ -805,6 +801,12 @@ int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo) |
805 | 805 |
|
806 | 806 |
cli_dbgmsg("in cli_elfheader\n"); |
807 | 807 |
|
808 |
+ // TODO This code assumes elfinfo->offset == 0, which might not always |
|
809 |
+ // be the case. For now just print this debug message and continue on |
|
810 |
+ if (0 != elfinfo->offset) { |
|
811 |
+ cli_dbgmsg("cli_elfheader: Assumption Violated: elfinfo->offset != 0\n"); |
|
812 |
+ } |
|
813 |
+ |
|
808 | 814 |
ret = cli_elf_fileheader(NULL, map, &file_hdr, &conv, &is64); |
809 | 815 |
if (ret != CL_CLEAN) { |
810 | 816 |
return -1; |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
/* |
2 |
- * Copyright (C) 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * Copyright (C) 2018-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 | 3 |
* |
4 | 4 |
* Authors: Andrew Williams |
5 | 5 |
* |
... | ... |
@@ -21,19 +21,50 @@ |
21 | 21 |
#include "execs.h" |
22 | 22 |
#include <string.h> |
23 | 23 |
|
24 |
+/** |
|
25 |
+ * Initialize a struct cli_exe_info so that it's ready to be populated |
|
26 |
+ * by the EXE header parsing functions (cli_peheader, cli_elfheader, and |
|
27 |
+ * cli_machoheader) and/or cli_exe_info_destroy. |
|
28 |
+ * |
|
29 |
+ * @param exeinfo a pointer to the struct cli_exe_info to initialize |
|
30 |
+ * @param offset the file offset corresponding to the start of the |
|
31 |
+ * executable that exeinfo stores information about |
|
32 |
+ */ |
|
24 | 33 |
void cli_exe_info_init(struct cli_exe_info *exeinfo, uint32_t offset) |
25 | 34 |
{ |
26 | 35 |
|
27 | 36 |
if (NULL == exeinfo) { |
28 | 37 |
return; |
29 | 38 |
} |
30 |
- // TODO the memset below might not be needed. Instead, replace with: |
|
31 |
- // exeinfo->sections = NULL; |
|
32 |
- // memset(&exeinfo->vinfo, '\0', sizeof(exeinfo->vinfo)); |
|
39 |
+ |
|
33 | 40 |
memset(exeinfo, '\0', sizeof(*exeinfo)); |
34 | 41 |
exeinfo->offset = offset; |
42 |
+ |
|
43 |
+ // TODO Replace the memset above with the following once we can make |
|
44 |
+ // certain that this is the only initialization needed (maybe run with |
|
45 |
+ // MemorySanitizer?) |
|
46 |
+ |
|
47 |
+ ///* Initialize all of the members which are actually used by the matcher |
|
48 |
+ // * and by the bytecode runtime. The rest is executable specific and |
|
49 |
+ // * we'll leave it to be populated by the exe parsing code. */ |
|
50 |
+ //exeinfo->offset = offset; |
|
51 |
+ //exeinfo->sections = NULL; |
|
52 |
+ //exeinfo->nsections = 0; |
|
53 |
+ //exeinfo->ep = 0; |
|
54 |
+ ///* NOTE: These are PE-specific to an extent, but we should still |
|
55 |
+ // * initialize them for other exe types because they are used by |
|
56 |
+ // * the matcher/bytecode runtime. */ |
|
57 |
+ //exeinfo->hdr_size = 0; |
|
58 |
+ //exeinfo->res_addr = 0; |
|
59 |
+ //cli_hashset_init_noalloc(&(exeinfo->vinfo)); |
|
35 | 60 |
} |
36 | 61 |
|
62 |
+/** |
|
63 |
+ * Free resources associated with a struct cli_exe_info initialized |
|
64 |
+ * via cli_exe_info_init |
|
65 |
+ * |
|
66 |
+ * @param exeinfo a pointer to the struct cli_exe_info to destroy |
|
67 |
+ */ |
|
37 | 68 |
void cli_exe_info_destroy(struct cli_exe_info *exeinfo) |
38 | 69 |
{ |
39 | 70 |
|
... | ... |
@@ -33,17 +33,19 @@ |
33 | 33 |
* NOTE: This is used to store PE, MachO, and ELF section information. Not |
34 | 34 |
* all members are populated by the respective parsing functions. |
35 | 35 |
* |
36 |
- * NOTE: This structure MUST stay in-sync with the ones defined within the |
|
37 |
- * clamav-bytecode-compiler source at: |
|
38 |
- * - clang/lib/Headers/bytecode_execs.h |
|
39 |
- * - llvm/tools/clang/lib/Headers/bytecode_execs.h |
|
40 |
- * We allocate space for an array of these and pass it directly to the |
|
41 |
- * bytecode sig runtime for use. |
|
36 |
+ * NOTE: This header file originates in the clamav-devel source and gets |
|
37 |
+ * copied into the clamav-bytecode-compiler source through a script |
|
38 |
+ * (sync-clamav.sh). This is done because an array of this structure is |
|
39 |
+ * allocated by libclamav and passed to the bytecode sig runtime. |
|
42 | 40 |
* |
43 |
- * TODO Next time we are making changes to the clamav-bytecode-compiler |
|
44 |
- * source, modify this structure to also include the section name (here and |
|
45 |
- * there). Then, populate this field in the PE/MachO/ELF header parsing |
|
46 |
- * functions. Choose a length that's reasonable for all platforms |
|
41 |
+ * If you need to make changes to this structure, you will need to update |
|
42 |
+ * it in both repos. Also, I'm not sure whether changing this structure |
|
43 |
+ * would require a recompile of all previous bytecode sigs. This should |
|
44 |
+ * be investigated before changes are made. |
|
45 |
+ * |
|
46 |
+ * TODO Modify this structure to also include the section name (in both |
|
47 |
+ * repos). Then, populate this field in the libclamav PE/MachO/ELF header |
|
48 |
+ * parsing functions. Choose a length that's reasonable for all platforms |
|
47 | 49 |
*/ |
48 | 50 |
struct cli_exe_section { |
49 | 51 |
uint32_t rva; /**< Relative VirtualAddress */ |
... | ... |
@@ -61,18 +63,17 @@ struct cli_exe_section { |
61 | 61 |
* NOTE: This is used to store PE, MachO, and ELF executable information, |
62 | 62 |
* but it predominantly has fields for PE info. Not all members are |
63 | 63 |
* populated by the respective parsing functions. |
64 |
- * |
|
65 |
- * TODO: Document which fields are PE only (maybe put those into a union of |
|
66 |
- * structs containing the various type-specific members) |
|
67 |
- |
|
68 |
- * NOTE: This structure is also defined in the clamav-bytecode-compiler |
|
69 |
- * source at: |
|
70 |
- * - clang/lib/Headers/bytecode_execs.h |
|
71 |
- * - llvm/tools/clang/lib/Headers/bytecode_execs.h |
|
72 |
- * Based on how we use it, though, it doesn't need to stay in-sync |
|
73 | 64 |
* |
74 |
- * TODO Next time we are making changes to the clamav-bytecode-compiler |
|
75 |
- * source, remove this structure definition there so it's not confusing |
|
65 |
+ * NOTE: This header file originates in the clamav-devel source and gets |
|
66 |
+ * copied into the clamav-bytecode-compiler source through a script |
|
67 |
+ * (sync-clamav.sh). This is done because an array of cli_exe_section |
|
68 |
+ * structs is allocated by libclamav and passed to the bytecode sig |
|
69 |
+ * runtime. |
|
70 |
+ * |
|
71 |
+ * This structure is not used by the bytecode sig runtime, so it can be |
|
72 |
+ * modified in the clamav-devel repo without requiring the changes to |
|
73 |
+ * be propagated to the clamav-bytecode-compile repo and that code rebuilt. |
|
74 |
+ * It'd be nice to keep them in sync if possible, though. |
|
76 | 75 |
*/ |
77 | 76 |
struct cli_exe_info { |
78 | 77 |
/** Information about all the sections of this file. |
... | ... |
@@ -91,15 +92,12 @@ struct cli_exe_info { |
91 | 91 |
*/ |
92 | 92 |
uint16_t nsections; |
93 | 93 |
|
94 |
- // TODO Remove - not required |
|
95 |
- void *dummy; /* for compat - preserve offset */ |
|
94 |
+ /***************** Begin PE-specific Section *****************/ |
|
96 | 95 |
|
97 |
- /** Resources RVA - PE ONLY */ |
|
98 |
- // TODO Maybe get rid of this - it looks like it's only used by the |
|
99 |
- // icon matching code (and maybe the bytecode API more broadly?) |
|
96 |
+ /** Resources RVA */ |
|
100 | 97 |
uint32_t res_addr; |
101 | 98 |
|
102 |
- /** Size of the header (aligned) - PE ONLY. This corresponds to |
|
99 |
+ /** Size of the header (aligned). This corresponds to |
|
103 | 100 |
* SizeOfHeaders in the optional header |
104 | 101 |
*/ |
105 | 102 |
uint32_t hdr_size; |
... | ... |
@@ -140,7 +138,7 @@ struct cli_exe_info { |
140 | 140 |
/* Raw data copied in from the EXE directly. |
141 | 141 |
* |
142 | 142 |
* NOTE: The data in the members below haven't been converted to host |
143 |
- * endianness, so all field accesses most account for this to ensure |
|
143 |
+ * endianness, so all field accesses must account for this to ensure |
|
144 | 144 |
* proper functionality on big endian systems (the PE header is always |
145 | 145 |
* little-endian) |
146 | 146 |
*/ |
... | ... |
@@ -159,9 +157,10 @@ struct cli_exe_info { |
159 | 159 |
* the unpopulated entries will be memset'd to zero. |
160 | 160 |
*/ |
161 | 161 |
struct pe_image_data_dir dirs[16]; |
162 |
+ |
|
163 |
+ /***************** End PE-specific Section *****************/ |
|
162 | 164 |
}; |
163 | 165 |
|
164 |
-// TODO Document |
|
165 | 166 |
void cli_exe_info_init(struct cli_exe_info *exeinfo, uint32_t offset); |
166 | 167 |
void cli_exe_info_destroy(struct cli_exe_info *exeinfo); |
167 | 168 |
|
... | ... |
@@ -204,9 +204,16 @@ int cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo) |
204 | 204 |
fmap_t *map = *ctx->fmap; |
205 | 205 |
ssize_t at; |
206 | 206 |
|
207 |
- if (fileinfo) |
|
207 |
+ if (fileinfo) { |
|
208 | 208 |
matcher = 1; |
209 | 209 |
|
210 |
+ // TODO This code assumes fileinfo->offset == 0, which might not always |
|
211 |
+ // be the case. For now just print this debug message and continue on |
|
212 |
+ if (0 != fileinfo->offset) { |
|
213 |
+ cli_dbgmsg("cli_scanmacho: Assumption Violated: fileinfo->offset != 0\n"); |
|
214 |
+ } |
|
215 |
+ } |
|
216 |
+ |
|
210 | 217 |
if (fmap_readn(map, &hdr, 0, sizeof(hdr)) != sizeof(hdr)) { |
211 | 218 |
cli_dbgmsg("cli_scanmacho: Can't read header\n"); |
212 | 219 |
return matcher ? -1 : CL_EFORMAT; |
... | ... |
@@ -504,23 +504,39 @@ int cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned |
504 | 504 |
return CL_SUCCESS; |
505 | 505 |
} |
506 | 506 |
|
507 |
+/** |
|
508 |
+ * Initialize a struct cli_target_info so that it's ready to have its exeinfo |
|
509 |
+ * populated by the call to cli_targetinfo and/or destroyed by |
|
510 |
+ * cli_targetinfo_destroy. |
|
511 |
+ * |
|
512 |
+ * @param info a pointer to the struct cli_target_info to initialize |
|
513 |
+ */ |
|
507 | 514 |
void cli_targetinfo_init(struct cli_target_info *info) |
508 | 515 |
{ |
509 | 516 |
|
510 | 517 |
if (NULL == info) { |
511 | 518 |
return; |
512 | 519 |
} |
513 |
- // Things that must be initialized here: |
|
514 |
- // - status (set to 0) |
|
515 |
- // - vinfo |
|
516 |
- // Maybe other things. |
|
517 |
- // TODO Consider replacing with just the required member assignments |
|
518 |
- // for performance |
|
519 |
- memset(info, 0, sizeof(struct cli_target_info)); |
|
520 |
- |
|
521 |
- cli_hashset_init_noalloc(&info->exeinfo.vinfo); |
|
520 |
+ info->status = 0; |
|
521 |
+ cli_exe_info_init(&(info->exeinfo), 0); |
|
522 | 522 |
} |
523 | 523 |
|
524 |
+/** Parse the executable headers and, if successful, populate exeinfo |
|
525 |
+ * |
|
526 |
+ * @param info A structure to populate with info from the exe header. This |
|
527 |
+ * MUST be initialized via cli_targetinfo_init prior to calling |
|
528 |
+ * @param target the target executable file type. Possible values are: |
|
529 |
+ * - 1 - PE32 / PE32+ |
|
530 |
+ * - 6 - ELF |
|
531 |
+ * - 9 - MachO |
|
532 |
+ * @param map The fmap_t backing the file being scanned |
|
533 |
+ * |
|
534 |
+ * @return If target refers to a supported executable file type, the exe header |
|
535 |
+ * will be parsed and, if successful, info->status will be set to 1. |
|
536 |
+ * If parsing the exe header fails, info->status will be set to -1. |
|
537 |
+ * The caller MUST destroy info via a call to cli_targetinfo_destroy |
|
538 |
+ * regardless of what info->status is set to. |
|
539 |
+ */ |
|
524 | 540 |
void cli_targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map) |
525 | 541 |
{ |
526 | 542 |
int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL; |
... | ... |
@@ -542,14 +558,21 @@ void cli_targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *m |
542 | 542 |
info->status = 1; |
543 | 543 |
} |
544 | 544 |
|
545 |
+/** |
|
546 |
+ * Free resources associated with a struct cli_target_info initialized |
|
547 |
+ * via cli_targetinfo_init |
|
548 |
+ * |
|
549 |
+ * @param info a pointer to the struct cli_target_info to destroy |
|
550 |
+ */ |
|
545 | 551 |
void cli_targetinfo_destroy(struct cli_target_info *info) |
546 | 552 |
{ |
547 | 553 |
|
548 |
- if (NULL == info || info->status != 1) { |
|
554 |
+ if (NULL == info) { |
|
549 | 555 |
return; |
550 | 556 |
} |
551 | 557 |
|
552 | 558 |
cli_exe_info_destroy(&(info->exeinfo)); |
559 |
+ info->status = 0; |
|
553 | 560 |
} |
554 | 561 |
|
555 | 562 |
int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx) |
... | ... |
@@ -701,6 +724,9 @@ int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx, const uint8_t *grp1, int32_t |
701 | 701 |
const char **oldvirname; |
702 | 702 |
struct cli_exe_info info; |
703 | 703 |
|
704 |
+ // TODO This isn't a good check, since EP will be zero for DLLs and |
|
705 |
+ // (assuming pedata->ep is populated from exeinfo->pe) non-zero for |
|
706 |
+ // some MachO and ELF executables |
|
704 | 707 |
if (!ctx->hooks.pedata->ep) { |
705 | 708 |
cli_dbgmsg("bytecode: matchicon only works with PE files\n"); |
706 | 709 |
return -1; |
... | ... |
@@ -981,7 +1007,18 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
981 | 981 |
* (which is broken for signed binaries within signed binaries). |
982 | 982 |
* |
983 | 983 |
* If we want to add support for more signature parsing in the future |
984 |
- * (Ex: MachO sigs), do that here too. */ |
|
984 |
+ * (Ex: MachO sigs), do that here too. |
|
985 |
+ * |
|
986 |
+ * One benefit of not continuing on to scan files with trusted signatures |
|
987 |
+ * is that the bytes associated with the exe won't get counted against the |
|
988 |
+ * scansize limits, which means we have an increased chance of catching |
|
989 |
+ * malware in container types (NSIS, iShield, etc.) where the file size is |
|
990 |
+ * large. A common case where this occurs is installers that embed one |
|
991 |
+ * or more of the various Microsoft Redistributable Setup packages. These |
|
992 |
+ * can easily be 5 MB or more in size, and might appear before malware |
|
993 |
+ * does in a given sample. |
|
994 |
+ */ |
|
995 |
+ |
|
985 | 996 |
if (1 == info.status && i == 1) { |
986 | 997 |
ret = cli_check_auth_header(ctx, &(info.exeinfo)); |
987 | 998 |
|
... | ... |
@@ -373,6 +373,10 @@ void findres(uint32_t by_type, uint32_t by_name, fmap_t *map, struct cli_exe_inf |
373 | 373 |
return; |
374 | 374 |
} |
375 | 375 |
|
376 |
+ if (0 != peinfo->offset) { |
|
377 |
+ cli_dbgmsg("findres: Assumption Violated: Looking for version info when peinfo->offset != 0\n"); |
|
378 |
+ } |
|
379 |
+ |
|
376 | 380 |
res_rva = EC32(peinfo->dirs[2].VirtualAddress); |
377 | 381 |
|
378 | 382 |
if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size), 16)) || err) |
... | ... |
@@ -3305,6 +3309,8 @@ int cli_scanpe(cli_ctx *ctx) |
3305 | 3305 |
uint32_t fileoffset; |
3306 | 3306 |
const char *tbuff; |
3307 | 3307 |
|
3308 |
+ // TODO shouldn't peinfo->ep be used here instead? ep is the file |
|
3309 |
+ // offset, vep is the entry point RVA |
|
3308 | 3310 |
fileoffset = (peinfo->vep + cli_readint32(epbuff + 1) + 5); |
3309 | 3311 |
while (fileoffset == 0x154 || fileoffset == 0x158) { |
3310 | 3312 |
char *src; |
... | ... |
@@ -4450,7 +4456,6 @@ int cli_pe_targetinfo(fmap_t *map, struct cli_exe_info *peinfo) |
4450 | 4450 |
* @param map The fmap_t backing the file being scanned |
4451 | 4451 |
* @param peinfo A structure to populate with info from the PE header. This |
4452 | 4452 |
* MUST be initialized via cli_exe_info_init prior to calling |
4453 |
- * being passed in. |
|
4454 | 4453 |
* @param opts A bitfield indicating various options related to PE header |
4455 | 4454 |
* parsing. The options are (prefixed with CLI_PEHEADER_OPT_): |
4456 | 4455 |
* - NONE - Do default parsing |
... | ... |
@@ -4474,9 +4479,8 @@ int cli_pe_targetinfo(fmap_t *map, struct cli_exe_info *peinfo) |
4474 | 4474 |
* is returned. If it seems like the PE is broken, |
4475 | 4475 |
* CLI_PEHEADER_RET_BROKEN_PE is returned. Otherwise, one of the |
4476 | 4476 |
* other error codes is returned. |
4477 |
- * If CLI_PEHEADER_RET_SUCCESS is returned, it is the caller's |
|
4478 |
- * responsibility to destroy peinfo. Otherwise, it's safe to do |
|
4479 |
- * so but not required. |
|
4477 |
+ * The caller MUST destroy peinfo, regardless of what this function |
|
4478 |
+ * returns. |
|
4480 | 4479 |
* |
4481 | 4480 |
* TODO What constitutes a "broken PE" seems somewhat arbitrary in places. |
4482 | 4481 |
* I think a PE should only be considered broken if it will not run on |
... | ... |
@@ -4506,7 +4510,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
4506 | 4506 |
struct pe_image_file_hdr *file_hdr; |
4507 | 4507 |
struct pe_image_optional_hdr32 *opt32; |
4508 | 4508 |
struct pe_image_optional_hdr64 *opt64; |
4509 |
- struct pe_image_section_hdr *section_hdrs; |
|
4509 |
+ struct pe_image_section_hdr *section_hdrs = NULL; |
|
4510 | 4510 |
unsigned int i, j, section_pe_idx; |
4511 | 4511 |
unsigned int err; |
4512 | 4512 |
uint32_t salign, falign; |
... | ... |
@@ -4516,6 +4520,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
4516 | 4516 |
uint32_t is_exe = 0; |
4517 | 4517 |
int native = 0; |
4518 | 4518 |
int read; |
4519 |
+ int ret = CLI_PEHEADER_RET_GENERIC_ERROR; |
|
4519 | 4520 |
#if HAVE_JSON |
4520 | 4521 |
int toval = 0; |
4521 | 4522 |
struct json_object *pe_json = NULL; |
... | ... |
@@ -4526,7 +4531,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
4526 | 4526 |
(opts & CLI_PEHEADER_OPT_COLLECT_JSON || |
4527 | 4527 |
opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO)) { |
4528 | 4528 |
cli_errmsg("cli_peheader: ctx can't be NULL for options specified\n"); |
4529 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
4529 |
+ goto done; |
|
4530 | 4530 |
} |
4531 | 4531 |
|
4532 | 4532 |
#if HAVE_JSON |
... | ... |
@@ -4538,18 +4543,19 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
4538 | 4538 |
fsize = map->len - peinfo->offset; |
4539 | 4539 |
if (fmap_readn(map, &e_magic, peinfo->offset, sizeof(e_magic)) != sizeof(e_magic)) { |
4540 | 4540 |
cli_dbgmsg("cli_peheader: Can't read DOS signature\n"); |
4541 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
4541 |
+ goto done; |
|
4542 | 4542 |
} |
4543 | 4543 |
|
4544 | 4544 |
if (EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) { |
4545 | 4545 |
cli_dbgmsg("cli_peheader: Invalid DOS signature\n"); |
4546 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
4546 |
+ goto done; |
|
4547 | 4547 |
} |
4548 | 4548 |
|
4549 | 4549 |
if (fmap_readn(map, &(peinfo->e_lfanew), peinfo->offset + 58 + sizeof(e_magic), sizeof(peinfo->e_lfanew)) != sizeof(peinfo->e_lfanew)) { |
4550 | 4550 |
/* truncated header? */ |
4551 | 4551 |
cli_dbgmsg("cli_peheader: Unable to read e_lfanew - truncated header?\n"); |
4552 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
4552 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
4553 |
+ goto done; |
|
4553 | 4554 |
} |
4554 | 4555 |
|
4555 | 4556 |
peinfo->e_lfanew = EC32(peinfo->e_lfanew); |
... | ... |
@@ -4558,20 +4564,20 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
4558 | 4558 |
} |
4559 | 4559 |
if (!peinfo->e_lfanew) { |
4560 | 4560 |
cli_dbgmsg("cli_peheader: Not a PE file - e_lfanew == 0\n"); |
4561 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
4561 |
+ goto done; |
|
4562 | 4562 |
} |
4563 | 4563 |
|
4564 | 4564 |
if (fmap_readn(map, &(peinfo->file_hdr), peinfo->offset + peinfo->e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) { |
4565 | 4565 |
/* bad information in e_lfanew - probably not a PE file */ |
4566 | 4566 |
cli_dbgmsg("cli_peheader: Can't read file header\n"); |
4567 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
4567 |
+ goto done; |
|
4568 | 4568 |
} |
4569 | 4569 |
|
4570 | 4570 |
file_hdr = &(peinfo->file_hdr); |
4571 | 4571 |
|
4572 | 4572 |
if (EC32(file_hdr->Magic) != PE_IMAGE_NT_SIGNATURE) { |
4573 | 4573 |
cli_dbgmsg("cli_peheader: Invalid PE signature (probably NE file)\n"); |
4574 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
4574 |
+ goto done; |
|
4575 | 4575 |
} |
4576 | 4576 |
|
4577 | 4577 |
if (EC16(file_hdr->Characteristics) & 0x2000) { |
... | ... |
@@ -4745,7 +4751,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
4745 | 4745 |
cli_dbgmsg("cli_peheader: Invalid NumberOfSections (>%d)\n", PE_MAXSECTIONS); |
4746 | 4746 |
} |
4747 | 4747 |
} |
4748 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
4748 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
4749 |
+ goto done; |
|
4749 | 4750 |
} |
4750 | 4751 |
|
4751 | 4752 |
timestamp = (time_t)EC32(file_hdr->TimeDateStamp); |
... | ... |
@@ -4753,13 +4760,14 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
4753 | 4753 |
|
4754 | 4754 |
if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) { |
4755 | 4755 |
cli_dbgmsg("NumberOfSections: %d\n", peinfo->nsections); |
4756 |
- cli_dbgmsg("TimeDateStamp: %s\n", cli_ctime(×tamp, timestr, sizeof(timestr))); |
|
4756 |
+ cli_dbgmsg("TimeDateStamp: %s", cli_ctime(×tamp, timestr, sizeof(timestr))); |
|
4757 | 4757 |
cli_dbgmsg("SizeOfOptionalHeader: 0x%x\n", opt_hdr_size); |
4758 | 4758 |
} |
4759 | 4759 |
|
4760 | 4760 |
#if HAVE_JSON |
4761 | 4761 |
if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
4762 | 4762 |
cli_jsonint(pe_json, "NumberOfSections", peinfo->nsections); |
4763 |
+ /* NOTE: the TimeDateStamp value will look like "Wed Dec 31 19:00:00 1969\n" */ |
|
4763 | 4764 |
cli_jsonstr(pe_json, "TimeDateStamp", cli_ctime(×tamp, timestr, sizeof(timestr))); |
4764 | 4765 |
cli_jsonint(pe_json, "SizeOfOptionalHeader", opt_hdr_size); |
4765 | 4766 |
} |
... | ... |
@@ -4776,13 +4784,15 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
4776 | 4776 |
pe_add_heuristic_property(ctx, "BadOptionalHeaderSize"); |
4777 | 4777 |
} |
4778 | 4778 |
#endif |
4779 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
4779 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
4780 |
+ goto done; |
|
4780 | 4781 |
} |
4781 | 4782 |
|
4782 | 4783 |
at = peinfo->offset + peinfo->e_lfanew + sizeof(struct pe_image_file_hdr); |
4783 | 4784 |
if (fmap_readn(map, &(peinfo->pe_opt.opt32), at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) { |
4784 | 4785 |
cli_dbgmsg("cli_peheader: Can't read optional file header\n"); |
4785 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
4786 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
4787 |
+ goto done; |
|
4786 | 4788 |
} |
4787 | 4789 |
stored_opt_hdr_size = sizeof(struct pe_image_optional_hdr32); |
4788 | 4790 |
at += stored_opt_hdr_size; |
... | ... |
@@ -4800,12 +4810,14 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
4800 | 4800 |
pe_add_heuristic_property(ctx, "BadOptionalHeaderSizePE32Plus"); |
4801 | 4801 |
} |
4802 | 4802 |
#endif |
4803 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
4803 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
4804 |
+ goto done; |
|
4804 | 4805 |
} |
4805 | 4806 |
|
4806 | 4807 |
if (fmap_readn(map, (void *)(((size_t) & (peinfo->pe_opt.opt64)) + sizeof(struct pe_image_optional_hdr32)), at, OPT_HDR_SIZE_DIFF) != OPT_HDR_SIZE_DIFF) { |
4807 | 4808 |
cli_dbgmsg("cli_peheader: Can't read additional optional file header bytes\n"); |
4808 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
4809 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
4810 |
+ goto done; |
|
4809 | 4811 |
} |
4810 | 4812 |
|
4811 | 4813 |
stored_opt_hdr_size += OPT_HDR_SIZE_DIFF; |
... | ... |
@@ -4987,14 +4999,16 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
4987 | 4987 |
if (!native && (!salign || (salign % 0x1000))) { |
4988 | 4988 |
cli_dbgmsg("cli_peheader: Bad section alignment\n"); |
4989 | 4989 |
if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) { |
4990 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
4990 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
4991 |
+ goto done; |
|
4991 | 4992 |
} |
4992 | 4993 |
} |
4993 | 4994 |
|
4994 | 4995 |
if (!native && (!falign || (falign % 0x200))) { |
4995 | 4996 |
cli_dbgmsg("cli_peheader: Bad file alignment\n"); |
4996 | 4997 |
if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) { |
4997 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
4998 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
4999 |
+ goto done; |
|
4998 | 5000 |
} |
4999 | 5001 |
} |
5000 | 5002 |
|
... | ... |
@@ -5023,13 +5037,14 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5023 | 5023 |
|
5024 | 5024 |
if (opt_hdr_size < (stored_opt_hdr_size + data_dirs_size)) { |
5025 | 5025 |
cli_dbgmsg("cli_peheader: SizeOfOptionalHeader too small (doesn't include data dir size)\n"); |
5026 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
5026 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
5027 |
+ goto done; |
|
5027 | 5028 |
} |
5028 | 5029 |
|
5029 | 5030 |
read = fmap_readn(map, peinfo->dirs, at, data_dirs_size); |
5030 | 5031 |
if (read < 0 || (uint32_t)read != data_dirs_size) { |
5031 | 5032 |
cli_dbgmsg("cli_peheader: Can't read optional file header data dirs\n"); |
5032 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5033 |
+ goto done; |
|
5033 | 5034 |
} |
5034 | 5035 |
at += data_dirs_size; |
5035 | 5036 |
|
... | ... |
@@ -5060,25 +5075,21 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5060 | 5060 |
|
5061 | 5061 |
if (!peinfo->sections) { |
5062 | 5062 |
cli_dbgmsg("cli_peheader: Can't allocate memory for section headers\n"); |
5063 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5063 |
+ goto done; |
|
5064 | 5064 |
} |
5065 | 5065 |
|
5066 | 5066 |
section_hdrs = (struct pe_image_section_hdr *)cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr)); |
5067 | 5067 |
|
5068 | 5068 |
if (!section_hdrs) { |
5069 | 5069 |
cli_dbgmsg("cli_peheader: Can't allocate memory for section headers\n"); |
5070 |
- free(peinfo->sections); |
|
5071 |
- peinfo->sections = NULL; |
|
5072 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5070 |
+ goto done; |
|
5073 | 5071 |
} |
5074 | 5072 |
|
5075 | 5073 |
read = fmap_readn(map, section_hdrs, at, peinfo->nsections * sizeof(struct pe_image_section_hdr)); |
5076 | 5074 |
if (read < 0 || (uint32_t)read != peinfo->nsections * sizeof(struct pe_image_section_hdr)) { |
5077 | 5075 |
cli_dbgmsg("cli_peheader: Can't read section header - possibly broken PE file\n"); |
5078 |
- free(section_hdrs); |
|
5079 |
- free(peinfo->sections); |
|
5080 |
- peinfo->sections = NULL; |
|
5081 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
5076 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
5077 |
+ goto done; |
|
5082 | 5078 |
} |
5083 | 5079 |
at += sizeof(struct pe_image_section_hdr) * peinfo->nsections; |
5084 | 5080 |
|
... | ... |
@@ -5122,10 +5133,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5122 | 5122 |
if (section->raw >= fsize || section->uraw >= fsize) { |
5123 | 5123 |
cli_dbgmsg("cli_peheader: Broken PE file - Section %d starts or exists beyond the end of file (Offset@ %lu, Total filesize %lu)\n", section_pe_idx, (unsigned long)section->raw, (unsigned long)fsize); |
5124 | 5124 |
if (peinfo->nsections == 1) { |
5125 |
- free(section_hdrs); |
|
5126 |
- free(peinfo->sections); |
|
5127 |
- peinfo->sections = NULL; |
|
5128 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
5125 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
5126 |
+ goto done; |
|
5129 | 5127 |
} |
5130 | 5128 |
|
5131 | 5129 |
for (j = i; j < peinfo->nsections - 1; j++) |
... | ... |
@@ -5161,10 +5170,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5161 | 5161 |
add_section_info(ctx, &peinfo->sections[i]); |
5162 | 5162 |
|
5163 | 5163 |
if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { |
5164 |
- free(section_hdrs); |
|
5165 |
- free(peinfo->sections); |
|
5166 |
- peinfo->sections = NULL; |
|
5167 |
- return CLI_PEHEADER_RET_JSON_TIMEOUT; |
|
5164 |
+ ret = CLI_PEHEADER_RET_JSON_TIMEOUT; |
|
5165 |
+ goto done; |
|
5168 | 5166 |
} |
5169 | 5167 |
} |
5170 | 5168 |
#endif |
... | ... |
@@ -5207,10 +5214,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5207 | 5207 |
if (!salign || (section->urva % salign)) { /* Bad section alignment */ |
5208 | 5208 |
cli_dbgmsg("cli_peheader: Broken PE - section's VirtualAddress is misaligned\n"); |
5209 | 5209 |
if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) { |
5210 |
- free(section_hdrs); |
|
5211 |
- free(peinfo->sections); |
|
5212 |
- peinfo->sections = NULL; |
|
5213 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
5210 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
5211 |
+ goto done; |
|
5214 | 5212 |
} |
5215 | 5213 |
} |
5216 | 5214 |
|
... | ... |
@@ -5218,22 +5223,16 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5218 | 5218 |
// section? Why the exception for uraw? |
5219 | 5219 |
if (section->urva >> 31 || section->uvsz >> 31 || (section->rsz && section->uraw >> 31) || peinfo->sections[i].ursz >> 31) { |
5220 | 5220 |
cli_dbgmsg("cli_peheader: Found PE values with sign bit set\n"); |
5221 |
- |
|
5222 |
- free(section_hdrs); |
|
5223 |
- free(peinfo->sections); |
|
5224 |
- peinfo->sections = NULL; |
|
5225 |
- |
|
5226 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
5221 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
5222 |
+ goto done; |
|
5227 | 5223 |
} |
5228 | 5224 |
|
5229 | 5225 |
if (!i) { |
5230 | 5226 |
if (section->urva != peinfo->hdr_size) { /* Bad first section RVA */ |
5231 | 5227 |
cli_dbgmsg("cli_peheader: First section doesn't start immediately after the header\n"); |
5232 | 5228 |
if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) { |
5233 |
- free(section_hdrs); |
|
5234 |
- free(peinfo->sections); |
|
5235 |
- peinfo->sections = NULL; |
|
5236 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
5229 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
5230 |
+ goto done; |
|
5237 | 5231 |
} |
5238 | 5232 |
} |
5239 | 5233 |
|
... | ... |
@@ -5243,10 +5242,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5243 | 5243 |
if (section->urva - peinfo->sections[i - 1].urva != peinfo->sections[i - 1].vsz) { /* No holes, no overlapping, no virtual disorder */ |
5244 | 5244 |
cli_dbgmsg("cli_peheader: Virtually misplaced section (wrong order, overlapping, non contiguous)\n"); |
5245 | 5245 |
if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) { |
5246 |
- free(section_hdrs); |
|
5247 |
- free(peinfo->sections); |
|
5248 |
- peinfo->sections = NULL; |
|
5249 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
5246 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
5247 |
+ goto done; |
|
5250 | 5248 |
} |
5251 | 5249 |
} |
5252 | 5250 |
|
... | ... |
@@ -5268,15 +5265,12 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5268 | 5268 |
|
5269 | 5269 |
peinfo->overlay_size = fsize - peinfo->overlay_start; |
5270 | 5270 |
|
5271 |
- free(section_hdrs); |
|
5272 |
- |
|
5273 | 5271 |
// NOTE: For DLLs the entrypoint is likely to be zero |
5274 |
- // TODO ^^^ Does this mean this doesn't work for DLLs? |
|
5272 |
+ // TODO Should this offset include peinfo->offset? |
|
5275 | 5273 |
if (!(peinfo->ep = cli_rawaddr(peinfo->vep, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size)) && err) { |
5276 | 5274 |
cli_dbgmsg("cli_peheader: Broken PE file - Can't map EntryPoint to a file offset\n"); |
5277 |
- free(peinfo->sections); |
|
5278 |
- peinfo->sections = NULL; |
|
5279 |
- return CLI_PEHEADER_RET_BROKEN_PE; |
|
5275 |
+ ret = CLI_PEHEADER_RET_BROKEN_PE; |
|
5276 |
+ goto done; |
|
5280 | 5277 |
} |
5281 | 5278 |
|
5282 | 5279 |
#if HAVE_JSON |
... | ... |
@@ -5284,9 +5278,8 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5284 | 5284 |
cli_jsonint(pe_json, "EntryPointOffset", peinfo->ep); |
5285 | 5285 |
|
5286 | 5286 |
if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { |
5287 |
- free(peinfo->sections); |
|
5288 |
- peinfo->sections = NULL; |
|
5289 |
- return CLI_PEHEADER_RET_JSON_TIMEOUT; |
|
5287 |
+ ret = CLI_PEHEADER_RET_JSON_TIMEOUT; |
|
5288 |
+ goto done; |
|
5290 | 5289 |
} |
5291 | 5290 |
} |
5292 | 5291 |
#endif |
... | ... |
@@ -5306,6 +5299,12 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5306 | 5306 |
const uint8_t *vptr, *baseptr; |
5307 | 5307 |
uint32_t rva, res_sz; |
5308 | 5308 |
|
5309 |
+ // TODO This code assumes peinfo->offset == 0, which might not always |
|
5310 |
+ // be the case. |
|
5311 |
+ if (0 != peinfo->offset) { |
|
5312 |
+ cli_dbgmsg("cli_peheader: Assumption Violated: Looking for version info when peinfo->offset != 0\n"); |
|
5313 |
+ } |
|
5314 |
+ |
|
5309 | 5315 |
memset(&vlist, 0, sizeof(vlist)); |
5310 | 5316 |
findres(0x10, 0xffffffff, map, peinfo, versioninfo_cb, &vlist); |
5311 | 5317 |
if (!vlist.count) |
... | ... |
@@ -5313,9 +5312,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5313 | 5313 |
|
5314 | 5314 |
if (cli_hashset_init(&peinfo->vinfo, 32, 80)) { |
5315 | 5315 |
cli_errmsg("cli_peheader: Unable to init vinfo hashset\n"); |
5316 |
- free(peinfo->sections); |
|
5317 |
- peinfo->sections = NULL; |
|
5318 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5316 |
+ goto done; |
|
5319 | 5317 |
} |
5320 | 5318 |
|
5321 | 5319 |
err = 0; |
... | ... |
@@ -5446,10 +5443,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5446 | 5446 |
|
5447 | 5447 |
if (cli_hashset_addkey(&peinfo->vinfo, (uint32_t)(vptr - baseptr + 6))) { |
5448 | 5448 |
cli_errmsg("cli_peheader: Unable to add rva to vinfo hashset\n"); |
5449 |
- cli_hashset_destroy(&peinfo->vinfo); |
|
5450 |
- free(peinfo->sections); |
|
5451 |
- peinfo->sections = NULL; |
|
5452 |
- return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5449 |
+ goto done; |
|
5453 | 5450 |
} |
5454 | 5451 |
|
5455 | 5452 |
if (cli_debug_flag) { |
... | ... |
@@ -5487,7 +5481,16 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ct |
5487 | 5487 |
// Do final preperations for peinfo to be passed back |
5488 | 5488 |
peinfo->is_dll = is_dll; |
5489 | 5489 |
|
5490 |
- return CLI_PEHEADER_RET_SUCCESS; |
|
5490 |
+ ret = CLI_PEHEADER_RET_SUCCESS; |
|
5491 |
+ |
|
5492 |
+done: |
|
5493 |
+ /* In the fail case, peinfo will get destroyed by the caller */ |
|
5494 |
+ |
|
5495 |
+ if (NULL != section_hdrs) { |
|
5496 |
+ free(section_hdrs); |
|
5497 |
+ } |
|
5498 |
+ |
|
5499 |
+ return ret; |
|
5491 | 5500 |
} |
5492 | 5501 |
|
5493 | 5502 |
// TODO We should sort based on VirtualAddress instead, since PointerToRawData |
... | ... |
@@ -1,6 +1,6 @@ |
1 | 1 |
/* |
2 |
- * Copyright (C) 2015, 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * Copyright (C) 2007-2008 Sourcefire, Inc. |
|
2 |
+ * Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
+ * Copyright (C) 2007-2013 Sourcefire, Inc. |
|
4 | 4 |
* |
5 | 5 |
* Authors: Alberto Wu, Tomasz Kojm, Andrew Williams |
6 | 6 |
* |
... | ... |
@@ -4529,7 +4529,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned |
4529 | 4529 |
if ((dd = opendir(dirname)) == NULL) { |
4530 | 4530 |
cli_errmsg("cli_loaddbdir(): Can't open directory %s\n", dirname); |
4531 | 4531 |
ret = CL_EOPEN; |
4532 |
- goto cleanup; |
|
4532 |
+ goto done; |
|
4533 | 4533 |
} |
4534 | 4534 |
|
4535 | 4535 |
dirname_len = strlen(dirname); |
... | ... |
@@ -4564,7 +4564,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned |
4564 | 4564 |
if (!dbfile) { |
4565 | 4565 |
cli_errmsg("cli_loaddbdir(): dbfile == NULL\n"); |
4566 | 4566 |
ret = CL_EMEM; |
4567 |
- goto cleanup; |
|
4567 |
+ goto done; |
|
4568 | 4568 |
} |
4569 | 4569 |
if (ends_with_sep) |
4570 | 4570 |
sprintf(dbfile, "%s%s", dirname, dent->d_name); |
... | ... |
@@ -4585,6 +4585,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned |
4585 | 4585 |
|
4586 | 4586 |
} else if (!strcmp(dent->d_name, "daily.cld")) { |
4587 | 4587 |
/* the daily db must be loaded before main */ |
4588 |
+ // TODO Why is this the case? |
|
4588 | 4589 |
load_priority = DB_LOAD_PRIORITY_DAILY_CLD; |
4589 | 4590 |
|
4590 | 4591 |
have_daily_cld = !access(dbfile, R_OK); |
... | ... |
@@ -4593,7 +4594,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned |
4593 | 4593 |
if (!daily_cld) { |
4594 | 4594 |
cli_errmsg("cli_loaddbdir(): error parsing header of %s\n", dbfile); |
4595 | 4595 |
ret = CL_EMALFDB; |
4596 |
- goto cleanup; |
|
4596 |
+ goto done; |
|
4597 | 4597 |
} |
4598 | 4598 |
} |
4599 | 4599 |
|
... | ... |
@@ -4606,7 +4607,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned |
4606 | 4606 |
if (!daily_cvd) { |
4607 | 4607 |
cli_errmsg("cli_loaddbdir(): error parsing header of %s\n", dbfile); |
4608 | 4608 |
ret = CL_EMALFDB; |
4609 |
- goto cleanup; |
|
4609 |
+ goto done; |
|
4610 | 4610 |
} |
4611 | 4611 |
} |
4612 | 4612 |
|
... | ... |
@@ -4639,7 +4640,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned |
4639 | 4639 |
if (NULL == entry) { |
4640 | 4640 |
cli_errmsg("cli_loaddbdir(): entry == NULL\n"); |
4641 | 4641 |
ret = CL_EMEM; |
4642 |
- goto cleanup; |
|
4642 |
+ goto done; |
|
4643 | 4643 |
} |
4644 | 4644 |
|
4645 | 4645 |
entry->path = dbfile; |
... | ... |
@@ -4651,18 +4652,20 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned |
4651 | 4651 |
/* The list entries are stored in priority order, so now just loop through |
4652 | 4652 |
* and load everything. |
4653 | 4653 |
* NOTE: If there's a daily.cld and a daily.cvd, we'll only load whichever |
4654 |
- * has the highest version number. */ |
|
4655 |
- |
|
4656 |
- // TODO Should we treat all cld/cvd pairs like we do the daily ones? |
|
4654 |
+ * has the highest version number. If they have the same version number |
|
4655 |
+ * we load daily.cld, since that will load faster (it won't attempt to |
|
4656 |
+ * verify the digital signature of the db). |
|
4657 |
+ * TODO It'd be ideal if we treated all cld/cvd pairs like we do the daily |
|
4658 |
+ * ones, and only loaded the one with the highest version. */ |
|
4657 | 4659 |
for (iter = head; iter != NULL; iter = iter->next) { |
4658 | 4660 |
|
4659 | 4661 |
if (DB_LOAD_PRIORITY_DAILY_CLD == iter->load_priority && have_daily_cvd) { |
4660 |
- if (daily_cld->version <= daily_cvd->version) { |
|
4662 |
+ if (daily_cld->version < daily_cvd->version) { |
|
4661 | 4663 |
continue; |
4662 | 4664 |
} |
4663 | 4665 |
|
4664 | 4666 |
} else if (DB_LOAD_PRIORITY_DAILY_CVD == iter->load_priority && have_daily_cld) { |
4665 |
- if (daily_cld->version > daily_cvd->version) { |
|
4667 |
+ if (daily_cld->version >= daily_cvd->version) { |
|
4666 | 4668 |
continue; |
4667 | 4669 |
} |
4668 | 4670 |
} |
... | ... |
@@ -4670,11 +4673,11 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned |
4670 | 4670 |
ret = cli_load(iter->path, engine, signo, options, NULL); |
4671 | 4671 |
if (ret) { |
4672 | 4672 |
cli_errmsg("cli_loaddbdir(): error loading database %s\n", iter->path); |
4673 |
- goto cleanup; |
|
4673 |
+ goto done; |
|
4674 | 4674 |
} |
4675 | 4675 |
} |
4676 | 4676 |
|
4677 |
-cleanup: |
|
4677 |
+done: |
|
4678 | 4678 |
for (iter = head; iter != NULL; iter = next) { |
4679 | 4679 |
next = iter->next; |
4680 | 4680 |
free(iter->path); |
... | ... |
@@ -4763,7 +4766,7 @@ int cl_load(const char *path, struct cl_engine *engine, unsigned int *signo, uns |
4763 | 4763 |
cli_dbgmsg("Bytecode engine disabled\n"); |
4764 | 4764 |
} |
4765 | 4765 |
|
4766 |
- if (cli_cache_init(engine)) |
|
4766 |
+ if (!engine->cache && cli_cache_init(engine)) |
|
4767 | 4767 |
return CL_EMEM; |
4768 | 4768 |
|
4769 | 4769 |
engine->dboptions |= dboptions; |
... | ... |
@@ -5085,6 +5088,11 @@ int cl_engine_free(struct cl_engine *engine) |
5085 | 5085 |
mpool_free(engine->mempool, root); |
5086 | 5086 |
} |
5087 | 5087 |
|
5088 |
+ if ((root = engine->hm_imp)) { |
|
5089 |
+ hm_free(root); |
|
5090 |
+ mpool_free(engine->mempool, root); |
|
5091 |
+ } |
|
5092 |
+ |
|
5088 | 5093 |
if ((root = engine->hm_fp)) { |
5089 | 5094 |
hm_free(root); |
5090 | 5095 |
mpool_free(engine->mempool, root); |
... | ... |
@@ -5255,6 +5263,9 @@ int cl_engine_compile(struct cl_engine *engine) |
5255 | 5255 |
if (engine->hm_mdb) |
5256 | 5256 |
hm_flush(engine->hm_mdb); |
5257 | 5257 |
|
5258 |
+ if (engine->hm_imp) |
|
5259 |
+ hm_flush(engine->hm_imp); |
|
5260 |
+ |
|
5258 | 5261 |
if (engine->hm_fp) |
5259 | 5262 |
hm_flush(engine->hm_fp); |
5260 | 5263 |
|
... | ... |
@@ -28,19 +28,14 @@ |
28 | 28 |
#include "str.h" |
29 | 29 |
#include "cvd.h" |
30 | 30 |
|
31 |
-// TODO Is it safe to remove .db2 and .db3 from here? These strings aren't |
|
32 |
-// referenced anywhere else in the source. |
|
33 |
- |
|
34 |
-// NOTE: We don't include .info in CLI_DBEXT because they are only used for |
|
35 |
-// one specific purpose - verifying the contents of database container files. |
|
36 |
-// This list is geared towards file extensions of files that users can provide |
|
37 |
-// to ClamAV directly. |
|
31 |
+/* NOTE: We don't include .info in CLI_DBEXT because they are only used for |
|
32 |
+ * one specific purpose - verifying the contents of database container files. |
|
33 |
+ * This list is geared towards file extensions of files that users can provide |
|
34 |
+ * to ClamAV directly. */ |
|
38 | 35 |
#ifdef HAVE_YARA |
39 | 36 |
#define CLI_DBEXT(ext) \ |
40 | 37 |
( \ |
41 | 38 |
cli_strbcasestr(ext, ".db") || \ |
42 |
- cli_strbcasestr(ext, ".db2") || \ |
|
43 |
- cli_strbcasestr(ext, ".db3") || \ |
|
44 | 39 |
cli_strbcasestr(ext, ".hdb") || \ |
45 | 40 |
cli_strbcasestr(ext, ".hdu") || \ |
46 | 41 |
cli_strbcasestr(ext, ".fp") || \ |
... | ... |
@@ -82,8 +77,6 @@ |
82 | 82 |
#define CLI_DBEXT(ext) \ |
83 | 83 |
( \ |
84 | 84 |
cli_strbcasestr(ext, ".db") || \ |
85 |
- cli_strbcasestr(ext, ".db2") || \ |
|
86 |
- cli_strbcasestr(ext, ".db3") || \ |
|
87 | 85 |
cli_strbcasestr(ext, ".hdb") || \ |
88 | 86 |
cli_strbcasestr(ext, ".hdu") || \ |
89 | 87 |
cli_strbcasestr(ext, ".fp") || \ |
... | ... |
@@ -1505,7 +1505,7 @@ static int cli_scanhtml(cli_ctx *ctx) |
1505 | 1505 |
static int cli_scanscript(cli_ctx *ctx) |
1506 | 1506 |
{ |
1507 | 1507 |
const unsigned char *buff; |
1508 |
- unsigned char *normalized; |
|
1508 |
+ unsigned char *normalized = NULL; |
|
1509 | 1509 |
struct text_norm_state state; |
1510 | 1510 |
char *tmpname = NULL; |
1511 | 1511 |
int ofd = -1, ret; |
... | ... |
@@ -1513,6 +1513,8 @@ static int cli_scanscript(cli_ctx *ctx) |
1513 | 1513 |
uint32_t maxpatlen, offset = 0; |
1514 | 1514 |
struct cli_matcher *groot; |
1515 | 1515 |
struct cli_ac_data gmdata, tmdata; |
1516 |
+ int gmdata_initialized = 0; |
|
1517 |
+ int tmdata_initialized = 0; |
|
1516 | 1518 |
struct cli_ac_data *mdata[2]; |
1517 | 1519 |
fmap_t *map; |
1518 | 1520 |
size_t at = 0; |
... | ... |
@@ -1537,25 +1539,26 @@ static int cli_scanscript(cli_ctx *ctx) |
1537 | 1537 |
/* CL_ENGINE_MAX_SCRIPTNORMALIZE */ |
1538 | 1538 |
if (curr_len > ctx->engine->maxscriptnormalize) { |
1539 | 1539 |
cli_dbgmsg("cli_scanscript: exiting (file larger than MaxScriptSize)\n"); |
1540 |
- return CL_CLEAN; |
|
1540 |
+ ret = CL_CLEAN; |
|
1541 |
+ goto done; |
|
1541 | 1542 |
} |
1542 | 1543 |
|
1543 | 1544 |
if (!(normalized = cli_malloc(SCANBUFF + maxpatlen))) { |
1544 | 1545 |
cli_dbgmsg("cli_scanscript: Unable to malloc %u bytes\n", SCANBUFF); |
1545 |
- return CL_EMEM; |
|
1546 |
+ ret = CL_EMEM; |
|
1547 |
+ goto done; |
|
1546 | 1548 |
} |
1547 | 1549 |
text_normalize_init(&state, normalized, SCANBUFF + maxpatlen); |
1548 | 1550 |
|
1549 | 1551 |
if ((ret = cli_ac_initdata(&tmdata, troot ? troot->ac_partsigs : 0, troot ? troot->ac_lsigs : 0, troot ? troot->ac_reloff_num : 0, CLI_DEFAULT_AC_TRACKLEN))) { |
1550 |
- free(normalized); |
|
1551 |
- return ret; |
|
1552 |
+ goto done; |
|
1552 | 1553 |
} |
1554 |
+ tmdata_initialized = 1; |
|
1553 | 1555 |
|
1554 | 1556 |
if ((ret = cli_ac_initdata(&gmdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) { |
1555 |
- cli_ac_freedata(&tmdata); |
|
1556 |
- free(normalized); |
|
1557 |
- return ret; |
|
1557 |
+ goto done; |
|
1558 | 1558 |
} |
1559 |
+ gmdata_initialized = 1; |
|
1559 | 1560 |
|
1560 | 1561 |
/* dump to disk only if explicitly asked to |
1561 | 1562 |
* or if necessary to check relative offsets, |
... | ... |
@@ -1662,9 +1665,18 @@ static int cli_scanscript(cli_ctx *ctx) |
1662 | 1662 |
|
1663 | 1663 |
done: |
1664 | 1664 |
cli_targetinfo_destroy(&info); |
1665 |
- free(normalized); |
|
1666 |
- cli_ac_freedata(&tmdata); |
|
1667 |
- cli_ac_freedata(&gmdata); |
|
1665 |
+ |
|
1666 |
+ if (NULL != normalized) { |
|
1667 |
+ free(normalized); |
|
1668 |
+ } |
|
1669 |
+ |
|
1670 |
+ if (tmdata_initialized) { |
|
1671 |
+ cli_ac_freedata(&tmdata); |
|
1672 |
+ } |
|
1673 |
+ |
|
1674 |
+ if (gmdata_initialized) { |
|
1675 |
+ cli_ac_freedata(&gmdata); |
|
1676 |
+ } |
|
1668 | 1677 |
|
1669 | 1678 |
if (ofd != -1) |
1670 | 1679 |
close(ofd); |