summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Grenier <grenier@cgsecurity.org>2020-06-18 19:08:51 +0200
committerChristophe Grenier <grenier@cgsecurity.org>2020-06-18 19:08:51 +0200
commit069da2d664d94044350ff78d439b93b3e65b0b47 (patch)
tree57ea5633864b99eab84826c4fee3c380185049a1
parent0ed7db8bc9a92aff19c2cdcdb81e215a49701aca (diff)
PhotoRec: better check for wmf with placeable record
-rw-r--r--src/file_wmf.c50
1 files changed, 40 insertions, 10 deletions
diff --git a/src/file_wmf.c b/src/file_wmf.c
index e0a5d17..554fdca 100644
--- a/src/file_wmf.c
+++ b/src/file_wmf.c
@@ -55,37 +55,67 @@ struct wmf_header
uint16_t members;
} __attribute__ ((gcc_struct, __packed__));
-static int header_check_wmf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+struct wmf_placeable_record
+{
+ uint32_t key;
+ uint16_t hwmf;
+ uint64_t boundingbox;
+ uint16_t inch;
+ uint32_t reserved;
+ uint16_t checksum;
+} __attribute__ ((gcc_struct, __packed__));
+
+static uint64_t wmf_check_meta_header(const struct wmf_header *hdr)
{
- const struct wmf_header *hdr=(const struct wmf_header *)buffer;
- if(le16(hdr->num_objects)==0)
+ const uint64_t size=2*le32(hdr->size);
+ const unsigned int num_objects=le16(hdr->num_objects);
+ const unsigned int max_record=le32(hdr->max_record);
+ if(size < sizeof(struct wmf_header))
return 0;
- if(2*le32(hdr->max_record) + le16(hdr->num_objects) - 1 >= 2*le32(hdr->size))
+ if(num_objects==0)
+ return 0;
+ if(2*max_record + num_objects - 1 >= size)
+ return 0;
+ return size;
+}
+
+static int header_check_wmf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const uint64_t size=wmf_check_meta_header((const struct wmf_header *)buffer);
+ if(size==0)
return 0;
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_wmf.extension;
- file_recovery_new->calculated_file_size=(uint64_t)2*le32(hdr->size);
+ file_recovery_new->calculated_file_size=size;
file_recovery_new->data_check=&data_check_size;
file_recovery_new->file_check=&file_check_size;
return 1;
}
-static int header_check_other_wmf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+static int header_check_wmf_placeable(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- if(buffer[0x10]!=0 || buffer[0x11]!=0)
+ const struct wmf_placeable_record *meta=(const struct wmf_placeable_record *)buffer;
+ const struct wmf_header *hdr=(const struct wmf_header *)&buffer[0x16];
+ uint64_t size;
+ /* Check META_PLACEABLE */
+ if(le32(meta->reserved) != 0)
+ return 0;
+ size=wmf_check_meta_header(hdr);
+ if(size==0)
return 0;
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_wmf.extension;
+ file_recovery_new->calculated_file_size=0x16+size;
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
return 1;
}
static void register_header_check_wmf(file_stat_t *file_stat)
{
static const unsigned char apm_header[6] = { 0xd7, 0xcd, 0xc6, 0x9a, 0x00, 0x00 };
- static const unsigned char emf_header[6] = { 0x20, 0x45, 0x4D, 0x46, 0x00, 0x00 };
/* WMF: file_type=disk, header size=9, version=3.0 */
static const unsigned char wmf_header[6] = { 0x01, 0x00, 0x09, 0x00, 0x00, 0x03 };
- register_header_check(0, apm_header,sizeof(apm_header), &header_check_other_wmf, file_stat);
- register_header_check(0, emf_header,sizeof(emf_header), &header_check_other_wmf, file_stat);
+ register_header_check(0, apm_header,sizeof(apm_header), &header_check_wmf_placeable, file_stat);
register_header_check(0, wmf_header,sizeof(wmf_header), &header_check_wmf, file_stat);
}