* Parse a Windows PE executable. */
| 161 | * Parse a Windows PE executable. |
| 162 | */ |
| 163 | void parsePE(Binary *B) |
| 164 | { |
| 165 | const char *filename = B->filename; |
| 166 | uint8_t *data = B->patched.bytes; |
| 167 | size_t size = B->size; |
| 168 | PEInfo &info = B->pe; |
| 169 | |
| 170 | if (size < 0x3c + sizeof(uint32_t)) |
| 171 | error("failed to parse PE file \"%s\"; file size (%zu) is too small " |
| 172 | "for MS-DOS header", filename, size); |
| 173 | if (data[0] != 'M' || data[1] != 'Z') |
| 174 | error("failed to parse PE file \"%s\"; invalid MS-DOS stub header " |
| 175 | "magic number, expected \"MZ\"", filename); |
| 176 | uint32_t pe_offset = *(const uint32_t *)(data + 0x3c); |
| 177 | const size_t pe_hdr_size = sizeof(uint32_t) + sizeof(IMAGE_FILE_HEADER) + |
| 178 | sizeof(IMAGE_OPTIONAL_HEADER64); |
| 179 | if (pe_offset < 0x3c + sizeof(uint32_t) || pe_offset + pe_hdr_size > size) |
| 180 | error("failed to parse PE file \"%s\"; file size (%zu) is too small" |
| 181 | "for PE header(s)", filename, size); |
| 182 | if (data[pe_offset] != 'P' || |
| 183 | data[pe_offset+1] != 'E' || |
| 184 | data[pe_offset+2] != 0x0 || |
| 185 | data[pe_offset+3] != 0x0) |
| 186 | error("failed to parse PE file \"%s\"; invalid PE signature, " |
| 187 | "expected \"PE\\0\\0\"", filename); |
| 188 | PIMAGE_FILE_HEADER file_hdr = |
| 189 | (PIMAGE_FILE_HEADER)(data + pe_offset + sizeof(uint32_t)); |
| 190 | if (file_hdr->Machine != IMAGE_FILE_MACHINE_AMD64) |
| 191 | error("failed to parse PE file \"%s\"; invalid machine (0x%x), " |
| 192 | "expected x86_64 (0x%x)", filename, file_hdr->Machine, |
| 193 | IMAGE_FILE_MACHINE_AMD64); |
| 194 | if (file_hdr->SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER64)) |
| 195 | error("failed to parse PE file \"%s\"; invalid optional header " |
| 196 | "size (%zu), expected (>=%zu)", filename, |
| 197 | file_hdr->SizeOfOptionalHeader, |
| 198 | sizeof(IMAGE_OPTIONAL_HEADER64)); |
| 199 | PIMAGE_OPTIONAL_HEADER64 opt_hdr = |
| 200 | (PIMAGE_OPTIONAL_HEADER64)(file_hdr + 1); |
| 201 | static const uint16_t PE64_MAGIC = 0x020b; |
| 202 | if (opt_hdr->Magic != PE64_MAGIC) |
| 203 | error("failed to parse PE file \"%s\"; invalid magic number (0x%x), " |
| 204 | "expected PE64 (0x%x)", filename, opt_hdr->Magic, PE64_MAGIC); |
| 205 | uint32_t section_align = opt_hdr->SectionAlignment; |
| 206 | if (section_align == 0 || !IS_POW_2(section_align)) |
| 207 | error("failed to parse PE file \"%s\"; invalid section alignment (%u), " |
| 208 | "expected a power-of-two", filename, section_align); |
| 209 | uint32_t file_align = opt_hdr->FileAlignment; |
| 210 | if (file_align < 512 || !IS_POW_2(file_align)) |
| 211 | error("failed to parse PE file \"%s\"; invalid file alignment (%u), " |
| 212 | "expected (>=512, power-of-two)", filename, file_align); |
| 213 | uint64_t image_base = opt_hdr->ImageBase; |
| 214 | if (image_base % WINDOWS_VIRTUAL_ALLOC_SIZE != 0) |
| 215 | error("failed to parse PE file \"%s\"; invalid image base (0x%lx), " |
| 216 | "expected a multiple of virtual allocation granularity (%u)", |
| 217 | filename, image_base, WINDOWS_VIRTUAL_ALLOC_SIZE); |
| 218 | PIMAGE_SECTION_HEADER shdr = |
| 219 | (PIMAGE_SECTION_HEADER)&opt_hdr->DataDirectory[ |
| 220 | opt_hdr->NumberOfRvaAndSizes]; |
no test coverage detected