diff --git a/libclamav/pe.c b/libclamav/pe.c index 0f52d6586..66e306c64 100644 --- a/libclamav/pe.c +++ b/libclamav/pe.c @@ -2802,8 +2802,8 @@ int cli_checkfp_pe(cli_ctx *ctx, uint8_t *authsha1) { uint32_t e_lfanew; /* address of new exe header */ struct pe_image_file_hdr file_hdr; union { - struct pe_image_optional_hdr64 opt64; - struct pe_image_optional_hdr32 opt32; + struct pe_image_optional_hdr64 opt64; + struct pe_image_optional_hdr32 opt32; } pe_opt; const struct pe_image_section_hdr *section_hdr; ssize_t at; @@ -2816,65 +2816,69 @@ int cli_checkfp_pe(cli_ctx *ctx, uint8_t *authsha1) { SHA1Context sha1; if(!(DCONF & PE_CONF_CATALOG)) - return CL_EFORMAT; + return CL_EFORMAT; if(fmap_readn(map, &e_magic, 0, sizeof(e_magic)) != sizeof(e_magic)) - return CL_EFORMAT; + return CL_EFORMAT; if(EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) - return CL_EFORMAT; + return CL_EFORMAT; if(fmap_readn(map, &e_lfanew, 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) - return CL_EFORMAT; + return CL_EFORMAT; e_lfanew = EC32(e_lfanew); if(!e_lfanew) - return CL_EFORMAT; + return CL_EFORMAT; if(fmap_readn(map, &file_hdr, e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) - return CL_EFORMAT; + return CL_EFORMAT; if(EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE) - return CL_EFORMAT; + return CL_EFORMAT; nsections = EC16(file_hdr.NumberOfSections); if(nsections < 1 || nsections > 96) - return CL_EFORMAT; + return CL_EFORMAT; if(EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) - return CL_EFORMAT; + return CL_EFORMAT; at = e_lfanew + sizeof(struct pe_image_file_hdr); if(fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) - return CL_EFORMAT; + return CL_EFORMAT; + at += sizeof(struct pe_image_optional_hdr32); /* This will be a chicken and egg problem until we drop 9x */ if(EC16(optional_hdr64.Magic)==PE32P_SIGNATURE) { if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) - return CL_EFORMAT; - pe_plus = 1; + return CL_EFORMAT; + + pe_plus = 1; } if(!pe_plus) { /* PE */ - if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) { - /* Seek to the end of the long header */ - at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32); - } + if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) { + /* Seek to the end of the long header */ + at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32); + } - hdr_size = EC32(optional_hdr32.SizeOfHeaders); - dirs = optional_hdr32.DataDirectory; + hdr_size = EC32(optional_hdr32.SizeOfHeaders); + dirs = optional_hdr32.DataDirectory; } else { /* PE+ */ + size_t readlen = sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); /* read the remaining part of the header */ - if(fmap_readn(map, &optional_hdr32 + 1, at, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) - return CL_EFORMAT; - at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); - hdr_size = EC32(optional_hdr64.SizeOfHeaders); - dirs = optional_hdr64.DataDirectory; + if(fmap_readn(map, &optional_hdr32 + 1, at, readlen) != readlen) + return CL_EFORMAT; + + at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); + hdr_size = EC32(optional_hdr64.SizeOfHeaders); + dirs = optional_hdr64.DataDirectory; } if(!cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 2) && dirs[4].Size < 8) - return CL_BREAK; + return CL_BREAK; fsize = map->len; @@ -2883,57 +2887,58 @@ int cli_checkfp_pe(cli_ctx *ctx, uint8_t *authsha1) { section_hdr = fmap_need_off_once(map, at, sizeof(*section_hdr) * nsections); if(!section_hdr) - return CL_EFORMAT; + return CL_EFORMAT; + at += sizeof(*section_hdr) * nsections; exe_sections = (struct cli_exe_section *) cli_calloc(nsections, sizeof(struct cli_exe_section)); if(!exe_sections) - return CL_EMEM; + return CL_EMEM; for(i = 0; falign!=0x200 && iexe_sections[i].raw && !CLI_ISCONTAINED(0, (uint32_t) fsize, exe_sections[i].raw, exe_sections[i].rsz)) - exe_sections[i].rsz = fsize - exe_sections[i].raw; + if (exe_sections[i].rsz && fsize>exe_sections[i].raw && !CLI_ISCONTAINED(0, (uint32_t) fsize, exe_sections[i].raw, exe_sections[i].rsz)) + exe_sections[i].rsz = fsize - exe_sections[i].raw; - if (exe_sections[i].rsz && exe_sections[i].raw >= fsize) { - free(exe_sections); - return CL_EFORMAT; - } + if (exe_sections[i].rsz && exe_sections[i].raw >= fsize) { + free(exe_sections); + return CL_EFORMAT; + } - if (exe_sections[i].urva>>31 || exe_sections[i].uvsz>>31 || (exe_sections[i].rsz && exe_sections[i].uraw>>31) || exe_sections[i].ursz>>31) { - free(exe_sections); - return CL_EFORMAT; - } + if (exe_sections[i].urva>>31 || exe_sections[i].uvsz>>31 || (exe_sections[i].rsz && exe_sections[i].uraw>>31) || exe_sections[i].ursz>>31) { + free(exe_sections); + return CL_EFORMAT; + } } cli_qsort(exe_sections, nsections, sizeof(*exe_sections), sort_sects); SHA1Init(&sha1); -#define hash_chunk(where, size) \ - do { \ - const uint8_t *hptr; \ - if(!(size)) break; \ - if(!(hptr = fmap_need_off_once(map, where, size))){ \ - free(exe_sections); \ - return CL_EFORMAT; \ - } \ - SHA1Update(&sha1, hptr, size); \ +#define hash_chunk(where, size) \ + do { \ + const uint8_t *hptr; \ + if(!(size)) break; \ + if(!(hptr = fmap_need_off_once(map, where, size))){ \ + free(exe_sections); \ + return CL_EFORMAT; \ + } \ + SHA1Update(&sha1, hptr, size); \ } while(0) /* MZ to checksum */ @@ -2944,15 +2949,15 @@ int cli_checkfp_pe(cli_ctx *ctx, uint8_t *authsha1) { /* Checksum to security */ if(pe_plus) - hlen = offsetof(struct pe_image_optional_hdr64, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr64, CheckSum) - 4; + hlen = offsetof(struct pe_image_optional_hdr64, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr64, CheckSum) - 4; else - hlen = offsetof(struct pe_image_optional_hdr32, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr32, CheckSum) - 4; + hlen = offsetof(struct pe_image_optional_hdr32, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr32, CheckSum) - 4; hash_chunk(at, hlen); at += hlen + 8; if(at > hdr_size) { - free(exe_sections); - return CL_EFORMAT; + free(exe_sections); + return CL_EFORMAT; } /* Security to End of header */ @@ -2962,36 +2967,40 @@ int cli_checkfp_pe(cli_ctx *ctx, uint8_t *authsha1) { /* Sections */ at = hdr_size; for(i = 0; i < nsections; i++) { - if(!exe_sections[i].rsz) - continue; - hash_chunk(exe_sections[i].raw, exe_sections[i].rsz); - at += exe_sections[i].rsz; + if(!exe_sections[i].rsz) + continue; + + hash_chunk(exe_sections[i].raw, exe_sections[i].rsz); + at += exe_sections[i].rsz; } if(at < fsize) { - hlen = fsize - at; - if(dirs[4].Size > hlen) { - free(exe_sections); - return CL_EFORMAT; - } - hlen -= dirs[4].Size; - hash_chunk(at, hlen); - at += hlen; + hlen = fsize - at; + if(dirs[4].Size > hlen) { + free(exe_sections); + return CL_EFORMAT; + } + + hlen -= dirs[4].Size; + hash_chunk(at, hlen); + at += hlen; } free(exe_sections); SHA1Final(&sha1, authsha1); if(cli_debug_flag) { - char shatxt[SHA1_HASH_SIZE*2+1]; - for(i=0; iengine), map, at + 8, hlen, authsha1); }