1 #include <mono/metadata/object-internals.h>
2 #include <mono/metadata/verify.h>
3 #include <mono/metadata/verify-internals.h>
4 #include <mono/metadata/opcodes.h>
5 #include <mono/metadata/tabledefs.h>
6 #include <mono/metadata/reflection.h>
7 #include <mono/metadata/debug-helpers.h>
8 #include <mono/metadata/mono-endian.h>
9 #include <mono/metadata/metadata.h>
10 #include <mono/metadata/metadata-internals.h>
11 #include <mono/metadata/class-internals.h>
12 #include <mono/metadata/tokentype.h>
18 TODO add fail fast mode
19 TODO add PE32+ support
20 TODO verify the entry point RVA and content.
29 guint32 data_dir_count;
32 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception) \
34 MonoVerifyInfoExtended *vinfo = g_new (MonoVerifyInfoExtended, 1); \
35 vinfo->info.status = __status; \
36 vinfo->info.message = ( __msg); \
37 vinfo->exception_type = (__exception); \
38 (__ctx)->errors = g_slist_prepend ((__ctx)->errors, vinfo); \
42 #define ADD_ERROR(__ctx, __msg) \
44 ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
48 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
51 pe_signature_offset (VerifyContext *ctx)
53 return read32 (ctx->data + 0x3c);
57 verify_msdos_header (VerifyContext *ctx)
60 if (ctx->size < 128) {
61 ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
64 if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
65 ADD_ERROR (ctx, g_strdup ("Invalid MS-DOS watermark"));
66 lfanew = pe_signature_offset (ctx);
67 if (lfanew > ctx->size - 4)
68 ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
72 verify_pe_header (VerifyContext *ctx)
74 guint32 offset = pe_signature_offset (ctx);
75 const char *pe_header = ctx->data + offset;
76 if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
77 ADD_ERROR (ctx, g_strdup ("Invalid PE header watermark"));
81 if (offset > ctx->size - 20)
82 ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
83 if (read16 (pe_header) != 0x14c)
84 ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
89 verify_pe_optional_header (VerifyContext *ctx)
91 guint32 offset = pe_signature_offset (ctx) + 4;
93 const char *pe_header = ctx->data + offset;
94 const char *pe_optional_header = pe_header + 20;
96 header_size = read16 (pe_header + 16);
99 if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
100 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
102 if (offset > ctx->size - header_size || header_size > ctx->size) {
103 ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
107 if (read16 (pe_optional_header) == 0x10b) {
108 if (header_size != 224)
109 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
111 if (read32 (pe_optional_header + 28) != 0x400000)
112 ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));
113 if (read32 (pe_optional_header + 32) != 0x2000)
114 ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmment %x", read32 (pe_optional_header + 32)));
115 if (read32 (pe_optional_header + 36) != 0x200)
116 ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmment %x", read32 (pe_optional_header + 36)));
117 /* All the junk in the middle is irrelevant, specially for mono. */
118 ctx->data_dir_count = read32 (pe_optional_header + 92);
119 if (ctx->data_dir_count > 0x10)
120 ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", ctx->data_dir_count));
122 if (read16 (pe_optional_header) == 0x20B)
123 ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
125 ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
132 mono_image_verify (const char *data, guint32 size)
135 memset (&ctx, 0, sizeof (VerifyContext));
140 verify_msdos_header (&ctx);
142 verify_pe_header (&ctx);
144 verify_pe_optional_header (&ctx);