diff --git a/libclamav/ole2_extract.c b/libclamav/ole2_extract.c index d6e1c0a4f4..35bdc01e4c 100644 --- a/libclamav/ole2_extract.c +++ b/libclamav/ole2_extract.c @@ -235,7 +235,8 @@ int ole2_list_delete(ole2_list_t *list) return CL_SUCCESS; } -static void insert_metadata(cli_ctx * ctx, const char * const key, bool value){ +static void insert_metadata(cli_ctx *ctx, const char *const key, bool value) +{ if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) { if (NULL != key) { if (ctx->wrkproperty == ctx->properties) { @@ -245,17 +246,17 @@ static void insert_metadata(cli_ctx * ctx, const char * const key, bool value){ } } -static void print_heuristic(cli_ctx * ctx, const char * const warning){ +static void print_heuristic(cli_ctx *ctx, const char *const warning) +{ /*Sets value if '--alert-encrypted-doc' option is provided.*/ if (SCAN_HEURISTIC_ENCRYPTED_DOC && (NULL != warning)) { cl_error_t status = cli_append_potentially_unwanted(ctx, warning); - if (CL_SUCCESS != status) { + if (CL_SUCCESS != status) { cli_errmsg("OLE2 : Unable to warn potentially unwanted signature '%s'\n", "Heuristics.Encrypted.OLE2"); } } } - #ifdef HAVE_PRAGMA_PACK #pragma pack() #endif @@ -607,8 +608,6 @@ static cl_error_t handler_enum(ole2_header_t *hdr, property_t *prop, const char static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx, void *handler_ctx); static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx, void *handler_ctx); - - /* * Compare strings ignoring case. * This is a somewhat special case, since name is actually a utf-16 encoded string, stored @@ -621,7 +620,8 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char * * * @return int: Return '0' if the values are equivalent, something else otherwise. */ -static int ole2_cmp_name(const char * const name, uint32_t name_size, const char * const keyword){ +static int ole2_cmp_name(const char *const name, uint32_t name_size, const char *const keyword) +{ char decoded[64]; uint32_t i = 0, j = 0; @@ -640,7 +640,7 @@ static int ole2_cmp_name(const char * const name, uint32_t name_size, const char /* * File Information Block Base. - * Naming is consistent with + * Naming is consistent with * https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/26fb6c06-4e5c-4778-ab4e-edbf26a545bb * */ typedef struct fib_base_type { @@ -660,32 +660,35 @@ typedef struct fib_base_type { uint32_t reserved6; } fib_base_t; -static void copy_fib_base(fib_base_t * pFib, const uint8_t * const ptr){ +static void copy_fib_base(fib_base_t *pFib, const uint8_t *const ptr) +{ memcpy(pFib, ptr, sizeof(fib_base_t)); pFib->wIdent = ole2_endian_convert_16(pFib->wIdent); - pFib->nFib = ole2_endian_convert_16(pFib->nFib); + pFib->nFib = ole2_endian_convert_16(pFib->nFib); pFib->unused = ole2_endian_convert_16(pFib->unused); - pFib->lid = ole2_endian_convert_16(pFib->lid); + pFib->lid = ole2_endian_convert_16(pFib->lid); pFib->pnNext = ole2_endian_convert_16(pFib->pnNext); /*Don't know whether to do this or not.*/ pFib->ABCDEFGHIJKLM = ole2_endian_convert_16(pFib->ABCDEFGHIJKLM); - pFib->nFibBack = ole2_endian_convert_16(pFib->nFibBack); - pFib->nFibBack = ole2_endian_convert_32(pFib->lKey); + pFib->nFibBack = ole2_endian_convert_16(pFib->nFibBack); + pFib->nFibBack = ole2_endian_convert_32(pFib->lKey); pFib->reserved3 = ole2_endian_convert_16(pFib->reserved3); pFib->reserved4 = ole2_endian_convert_16(pFib->reserved4); pFib->reserved5 = ole2_endian_convert_32(pFib->reserved5); pFib->reserved6 = ole2_endian_convert_32(pFib->reserved6); } -static inline bool is_encrypted(const fib_base_t * const pFib){ +static inline bool is_encrypted(const fib_base_t *const pFib) +{ return pFib->ABCDEFGHIJKLM & (1 << 8); } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" -static void dump_fib_base(fib_base_t * pFib){ +static void dump_fib_base(fib_base_t *pFib) +{ fprintf(stderr, "%s::%d::%x\n", __FUNCTION__, __LINE__, pFib->wIdent); } @@ -696,37 +699,38 @@ static void dump_fib_base(fib_base_t * pFib){ * I have not looked into it in detail, but if it is a 1-byte xor, it could be possible to brute-force it in some cases. * */ -static inline bool is_obfuscated(const fib_base_t * const pFib){ +static inline bool is_obfuscated(const fib_base_t *const pFib) +{ return pFib->ABCDEFGHIJKLM & (1 << 15); } #pragma GCC diagnostic pop - typedef struct { bool velvet_sweatshop; bool encrypted; - const char * encryption_type; + const char *encryption_type; } encryption_status_t; -const char * const RC4_ENCRYPTION = "RC4Encryption"; -const char * const XOR_OBFUSCATION = "XORObfuscation"; -const char * const AES128_ENCRYPTION = "EncryptedWithAES128"; -const char * const AES192_ENCRYPTION = "EncryptedWithAES192"; -const char * const AES256_ENCRYPTION = "EncryptedWithAES256"; +const char *const RC4_ENCRYPTION = "RC4Encryption"; +const char *const XOR_OBFUSCATION = "XORObfuscation"; +const char *const AES128_ENCRYPTION = "EncryptedWithAES128"; +const char *const AES192_ENCRYPTION = "EncryptedWithAES192"; +const char *const AES256_ENCRYPTION = "EncryptedWithAES256"; -const uint16_t XLS_XOR_OBFUSCATION = 0; -const uint16_t XLS_RC4_ENCRYPTION = 1; +const uint16_t XLS_XOR_OBFUSCATION = 0; +const uint16_t XLS_RC4_ENCRYPTION = 1; const uint32_t MINISTREAM_CUTOFF_SIZE = 0x1000; -static uint32_t get_stream_data_offset(ole2_header_t * hdr, const property_t * word_block, uint16_t sector) { - uint32_t offset = (1 << hdr->log2_big_block_size); +static uint32_t get_stream_data_offset(ole2_header_t *hdr, const property_t *word_block, uint16_t sector) +{ + uint32_t offset = (1 << hdr->log2_big_block_size); uint32_t sector_size = offset; - uint32_t fib_offset = 0; + uint32_t fib_offset = 0; - if (word_block->size < MINISTREAM_CUTOFF_SIZE){ + if (word_block->size < MINISTREAM_CUTOFF_SIZE) { fib_offset = offset + sector_size * hdr->sbat_root_start; fib_offset += (word_block->start_block * (1 << hdr->log2_small_block_size)); } else { @@ -736,15 +740,15 @@ static uint32_t get_stream_data_offset(ole2_header_t * hdr, const property_t * w return fib_offset; } - -/* See information about the File Information Block here +/* See information about the File Information Block here * https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/26fb6c06-4e5c-4778-ab4e-edbf26a545bb * for more information. */ -static void test_for_encryption(const property_t * word_block, ole2_header_t * hdr, encryption_status_t * pEncryptionStatus) { +static void test_for_encryption(const property_t *word_block, ole2_header_t *hdr, encryption_status_t *pEncryptionStatus) +{ - const uint8_t * ptr = NULL; - fib_base_t fib = {0}; + const uint8_t *ptr = NULL; + fib_base_t fib = {0}; uint32_t fib_offset = get_stream_data_offset(hdr, word_block, word_block->start_block); @@ -754,15 +758,15 @@ static void test_for_encryption(const property_t * word_block, ole2_header_t * h } ptr = fmap_need_off_once(hdr->map, fib_offset, sizeof(fib_base_t)); - if (NULL == ptr){ + if (NULL == ptr) { cli_dbgmsg("ERROR: Invalid offset for File Information Block %d (0x%x)\n", fib_offset, fib_offset); return; } copy_fib_base(&fib, ptr); -#define FIB_BASE_IDENTIFIER 0xa5ec +#define FIB_BASE_IDENTIFIER 0xa5ec - if (FIB_BASE_IDENTIFIER != fib.wIdent){ + if (FIB_BASE_IDENTIFIER != fib.wIdent) { cli_dbgmsg("ERROR: Invalid identifier for File Information Block %d (0x%x)\n", fib.wIdent, fib.wIdent); return; } @@ -778,8 +782,9 @@ static void test_for_encryption(const property_t * word_block, ole2_header_t * h } } -static bool read_uint16(const uint8_t * const ptr, uint32_t ptr_size, uint32_t * idx, uint16_t * dst){ - if (*idx + sizeof(uint16_t) >= ptr_size){ +static bool read_uint16(const uint8_t *const ptr, uint32_t ptr_size, uint32_t *idx, uint16_t *dst) +{ + if (*idx + sizeof(uint16_t) >= ptr_size) { return false; } @@ -789,22 +794,23 @@ static bool read_uint16(const uint8_t * const ptr, uint32_t ptr_size, uint32_t * return true; } -static bool find_file_pass(const uint8_t * const ptr, uint32_t ptr_size, uint32_t * idx) { +static bool find_file_pass(const uint8_t *const ptr, uint32_t ptr_size, uint32_t *idx) +{ uint16_t val, size; const uint32_t FILE_PASS_NUM = 47; - while (true){ - if (!read_uint16(ptr, ptr_size, idx, &val)){ + while (true) { + if (!read_uint16(ptr, ptr_size, idx, &val)) { return false; } - if (!read_uint16(ptr, ptr_size, idx, &size)){ + if (!read_uint16(ptr, ptr_size, idx, &size)) { return false; } - if (FILE_PASS_NUM == val){ + if (FILE_PASS_NUM == val) { return true; } @@ -819,56 +825,55 @@ static bool find_file_pass(const uint8_t * const ptr, uint32_t ptr_size, uint32_ * Search for the FilePass structure. * https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/cf9ae8d5-4e8c-40a2-95f1-3b31f16b5529 */ -static void test_for_xls_encryption(const property_t * word_block, ole2_header_t * hdr, encryption_status_t * pEncryptionStatus) { +static void test_for_xls_encryption(const property_t *word_block, ole2_header_t *hdr, encryption_status_t *pEncryptionStatus) +{ uint16_t tmp16; uint32_t idx; uint32_t stream_data_offset = get_stream_data_offset(hdr, word_block, word_block->start_block); - uint32_t block_size = (1 << hdr->log2_big_block_size); - const uint8_t * const ptr = fmap_need_off_once(hdr->map, stream_data_offset, block_size); - if (NULL == ptr){ + uint32_t block_size = (1 << hdr->log2_big_block_size); + const uint8_t *const ptr = fmap_need_off_once(hdr->map, stream_data_offset, block_size); + if (NULL == ptr) { cli_dbgmsg("ERROR: Invalid offset for File Information Block %d (0x%x)\n", stream_data_offset, stream_data_offset); return; } /*Validate keyword*/ idx = 0; - if (!read_uint16(ptr, block_size, &idx, &tmp16)){ + if (!read_uint16(ptr, block_size, &idx, &tmp16)) { return; } /*Invalid keyword*/ - if (2057 != tmp16){ + if (2057 != tmp16) { return; } /*Skip past this size.*/ memcpy(&tmp16, &(ptr[idx]), 2); - if (!read_uint16(ptr, block_size, &idx, &tmp16)){ + if (!read_uint16(ptr, block_size, &idx, &tmp16)) { return; } idx += tmp16; - if (!find_file_pass(ptr, block_size, &idx)){ + if (!find_file_pass(ptr, block_size, &idx)) { return; } - if (!read_uint16(ptr, block_size, &idx, &tmp16)){ + if (!read_uint16(ptr, block_size, &idx, &tmp16)) { return; } if (XLS_RC4_ENCRYPTION == tmp16) { pEncryptionStatus->encryption_type = RC4_ENCRYPTION; - pEncryptionStatus->encrypted = true; + pEncryptionStatus->encrypted = true; } else if (XLS_XOR_OBFUSCATION == tmp16) { pEncryptionStatus->encryption_type = XOR_OBFUSCATION; - pEncryptionStatus->encrypted = true; + pEncryptionStatus->encrypted = true; } } - - /** * @brief Walk an ole2 property tree, calling the handler for each file found * @@ -885,8 +890,8 @@ static void test_for_xls_encryption(const property_t * word_block, ole2_header_t static int ole2_walk_property_tree(ole2_header_t *hdr, const char *dir, int32_t prop_index, ole2_walk_property_tree_file_handler handler, unsigned int rec_level, unsigned int *file_count, - cli_ctx *ctx, unsigned long *scansize, void *handler_ctx, - encryption_status_t * pEncryptionStatus) + cli_ctx *ctx, unsigned long *scansize, void *handler_ctx, + encryption_status_t *pEncryptionStatus) { property_t prop_block[4]; int32_t idx, current_block, i, curindex; @@ -970,15 +975,15 @@ static int ole2_walk_property_tree(ole2_header_t *hdr, const char *dir, int32_t continue; } - if (0 == ole2_cmp_name(prop_block[idx].name, prop_block[idx].name_size, "WORDDocument")){ + if (0 == ole2_cmp_name(prop_block[idx].name, prop_block[idx].name_size, "WORDDocument")) { test_for_encryption(&(prop_block[idx]), hdr, pEncryptionStatus); - } else if (0 == ole2_cmp_name(prop_block[idx].name, prop_block[idx].name_size, "WorkBook")){ + } else if (0 == ole2_cmp_name(prop_block[idx].name, prop_block[idx].name_size, "WorkBook")) { test_for_xls_encryption(&(prop_block[idx]), hdr, pEncryptionStatus); - } else if (0 == ole2_cmp_name(prop_block[idx].name, prop_block[idx].name_size, "PowerPoint Document")){ + } else if (0 == ole2_cmp_name(prop_block[idx].name, prop_block[idx].name_size, "PowerPoint Document")) { test_for_encryption(&(prop_block[idx]), hdr, pEncryptionStatus); - } else if (0 == ole2_cmp_name(prop_block[idx].name, prop_block[idx].name_size, "EncryptionInfo")){ + } else if (0 == ole2_cmp_name(prop_block[idx].name, prop_block[idx].name_size, "EncryptionInfo")) { pEncryptionStatus->encrypted = true; - } else if (0 == ole2_cmp_name(prop_block[idx].name, prop_block[idx].name_size, "EncryptedPackage")){ + } else if (0 == ole2_cmp_name(prop_block[idx].name, prop_block[idx].name_size, "EncryptedPackage")) { pEncryptionStatus->encrypted = true; } @@ -1141,7 +1146,6 @@ static int ole2_walk_property_tree(ole2_header_t *hdr, const char *dir, int32_t return CL_SUCCESS; } - /* Write file Handler - write the contents of the entry to a file */ static cl_error_t handler_writefile(ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx, void *handler_ctx) { @@ -2536,8 +2540,6 @@ static bool verify_key_aes(const encryption_key_t *const key, encryption_verifie return bRet; } - - /*Definitions for initialize_encryption_key*/ #define SE_HEADER_FCRYPTOAPI (1 << 2) #define SE_HEADER_FEXTERNAL (1 << 4) @@ -2566,8 +2568,8 @@ static bool verify_key_aes(const encryption_key_t *const key, encryption_verifie static bool initialize_encryption_key( const uint8_t *encryptionInfoStreamPtr, size_t remainingBytes, - encryption_key_t *encryptionKey, - encryption_status_t * pEncryptionStatus) + encryption_key_t *encryptionKey, + encryption_status_t *pEncryptionStatus) { bool bRet = false; size_t idx = 0; @@ -2640,7 +2642,7 @@ static bool initialize_encryption_key( cli_dbgmsg("ole2: Key length does not match algorithm id\n"); goto done; } - bAES = true; + bAES = true; pEncryptionStatus->encryption_type = AES128_ENCRYPTION; break; case SE_HEADER_EI_AES192: @@ -2649,7 +2651,7 @@ static bool initialize_encryption_key( cli_dbgmsg("ole2: Key length does not match algorithm id\n"); goto done; } - bAES = true; + bAES = true; pEncryptionStatus->encryption_type = AES192_ENCRYPTION; goto done; case SE_HEADER_EI_AES256: @@ -2658,7 +2660,7 @@ static bool initialize_encryption_key( cli_dbgmsg("ole2: Key length does not match algorithm id\n"); goto done; } - bAES = true; + bAES = true; pEncryptionStatus->encryption_type = AES256_ENCRYPTION; goto done; case SE_HEADER_EI_RC4: @@ -2755,7 +2757,7 @@ static bool initialize_encryption_key( bRet = true; done: - if (pEncryptionStatus->encryption_type){ + if (pEncryptionStatus->encryption_type) { pEncryptionStatus->encrypted = true; } pEncryptionStatus->velvet_sweatshop = bRet; @@ -2783,8 +2785,8 @@ cl_error_t cli_ole2_extract(const char *dirname, cli_ctx *ctx, struct uniq **fil unsigned long scansize, scansize2; const void *phdr; encryption_key_t key; - bool bEncrypted = false; - size_t encryption_offset = 0; + bool bEncrypted = false; + size_t encryption_offset = 0; encryption_status_t encryption_status = {0}; cli_dbgmsg("in cli_ole2_extract()\n"); @@ -2959,9 +2961,9 @@ cl_error_t cli_ole2_extract(const char *dirname, cli_ctx *ctx, struct uniq **fil insert_metadata(ctx, "Encrypted", encryption_status.encrypted); insert_metadata(ctx, "EncryptedWithVelvetSweatshop", encryption_status.velvet_sweatshop); - if (encryption_status.velvet_sweatshop){ + if (encryption_status.velvet_sweatshop) { print_heuristic(ctx, "Heuristics.Encrypted.OLE2.VelvetSweatshop"); - } else if (encryption_status.encrypted){ + } else if (encryption_status.encrypted) { print_heuristic(ctx, "Heuristics.Encrypted.OLE2"); }