#include <signal.h>
#include <ctype.h>
+/*
+ TODO add fail fast mode
+ TODO add PE32+ support
+*/
+
typedef struct {
const char *data;
guint32 size;
#define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
+static guint32
+pe_signature_offset (VerifyContext *ctx)
+{
+ return read32 (ctx->data + 0x3c);
+}
+
static void
verify_msdos_header (VerifyContext *ctx)
{
}
if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
- lfanew = read32 (ctx->data + 0x3c);
+ lfanew = pe_signature_offset (ctx);
if (lfanew > ctx->size - 4)
ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
}
static void
verify_pe_header (VerifyContext *ctx)
{
- guint32 offset = read32 (ctx->data + 0x3c);
+ guint32 offset = pe_signature_offset (ctx);
const char *pe_header = ctx->data + offset;
if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
}
+static void
+verify_pe_optional_header (VerifyContext *ctx)
+{
+ guint32 offset = pe_signature_offset (ctx) + 4;
+ guint32 header_size;
+ const char *pe_header = ctx->data + offset;
+ const char *pe_optional_header = pe_header + 20;
+
+ header_size = read16 (pe_header + 16);
+ offset += 20;
+
+ if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
+ ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
+
+ if (offset > ctx->size - header_size || header_size > ctx->size)
+ ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
+
+ if (read16 (pe_optional_header) == 0x10b) {
+ if (header_size != 224)
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
+ } else {
+ if (read16 (pe_optional_header) == 0x20B)
+ ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
+ else
+ ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
+ }
+}
GSList*
mono_image_verify (const char *data, guint32 size)
CHECK_STATE();
verify_pe_header (&ctx);
CHECK_STATE();
+ verify_pe_optional_header (&ctx);
+ CHECK_STATE();
cleanup:
return ctx.errors;