1279315Strasz/*- 2332615Strasz * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3332615Strasz * 4279315Strasz * Copyright (c) 2014 The FreeBSD Foundation 5279315Strasz * All rights reserved. 6279315Strasz * 7279315Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 8279315Strasz * from the FreeBSD Foundation. 9279315Strasz * 10279315Strasz * Redistribution and use in source and binary forms, with or without 11279315Strasz * modification, are permitted provided that the following conditions 12279315Strasz * are met: 13279315Strasz * 1. Redistributions of source code must retain the above copyright 14279315Strasz * notice, this list of conditions and the following disclaimer. 15279315Strasz * 2. Redistributions in binary form must reproduce the above copyright 16279315Strasz * notice, this list of conditions and the following disclaimer in the 17279315Strasz * documentation and/or other materials provided with the distribution. 18279315Strasz * 19279315Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20279315Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21279315Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22279315Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23279315Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24279315Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25279315Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26279315Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27279315Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28279315Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29279315Strasz * SUCH DAMAGE. 30279315Strasz * 31279315Strasz */ 32279315Strasz 33279315Strasz/* 34279315Strasz * PE format reference: 35279315Strasz * http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx 36279315Strasz */ 37279315Strasz 38279315Strasz#include <sys/cdefs.h> 39279315Strasz__FBSDID("$FreeBSD: stable/11/usr.sbin/uefisign/pe.c 332615 2018-04-16 17:13:54Z trasz $"); 40279315Strasz 41279315Strasz#include <assert.h> 42279315Strasz#include <err.h> 43279315Strasz#include <errno.h> 44279315Strasz#include <stddef.h> 45279315Strasz#include <stdio.h> 46279315Strasz#include <stdint.h> 47279315Strasz#include <stdlib.h> 48279315Strasz#include <string.h> 49279315Strasz#include <unistd.h> 50279315Strasz 51279315Strasz#include "uefisign.h" 52279315Strasz 53279315Strasz#ifndef CTASSERT 54279315Strasz#define CTASSERT(x) _CTASSERT(x, __LINE__) 55279315Strasz#define _CTASSERT(x, y) __CTASSERT(x, y) 56279315Strasz#define __CTASSERT(x, y) typedef char __assert_ ## y [(x) ? 1 : -1] 57279315Strasz#endif 58279315Strasz 59279315Straszstruct mz_header { 60279315Strasz uint8_t mz_signature[2]; 61279315Strasz uint8_t mz_dont_care[58]; 62279315Strasz uint16_t mz_lfanew; 63279315Strasz} __attribute__((packed)); 64279315Strasz 65279315Straszstruct coff_header { 66279315Strasz uint8_t coff_dont_care[2]; 67279315Strasz uint16_t coff_number_of_sections; 68279315Strasz uint8_t coff_dont_care_either[16]; 69279315Strasz} __attribute__((packed)); 70279315Strasz 71279315Strasz#define PE_SIGNATURE 0x00004550 72279315Strasz 73279315Straszstruct pe_header { 74279315Strasz uint32_t pe_signature; 75279315Strasz struct coff_header pe_coff; 76279315Strasz} __attribute__((packed)); 77279315Strasz 78279315Strasz#define PE_OPTIONAL_MAGIC_32 0x010B 79279315Strasz#define PE_OPTIONAL_MAGIC_32_PLUS 0x020B 80279315Strasz 81279315Strasz#define PE_OPTIONAL_SUBSYSTEM_EFI_APPLICATION 10 82279315Strasz#define PE_OPTIONAL_SUBSYSTEM_EFI_BOOT 11 83279315Strasz#define PE_OPTIONAL_SUBSYSTEM_EFI_RUNTIME 12 84279315Strasz 85279315Straszstruct pe_optional_header_32 { 86279315Strasz uint16_t po_magic; 87279315Strasz uint8_t po_dont_care[58]; 88279315Strasz uint32_t po_size_of_headers; 89279315Strasz uint32_t po_checksum; 90279315Strasz uint16_t po_subsystem; 91279315Strasz uint8_t po_dont_care_either[22]; 92279315Strasz uint32_t po_number_of_rva_and_sizes; 93279315Strasz} __attribute__((packed)); 94279315Strasz 95279315StraszCTASSERT(offsetof(struct pe_optional_header_32, po_size_of_headers) == 60); 96279315StraszCTASSERT(offsetof(struct pe_optional_header_32, po_checksum) == 64); 97279315StraszCTASSERT(offsetof(struct pe_optional_header_32, po_subsystem) == 68); 98279315StraszCTASSERT(offsetof(struct pe_optional_header_32, po_number_of_rva_and_sizes) == 92); 99279315Strasz 100279315Straszstruct pe_optional_header_32_plus { 101279315Strasz uint16_t po_magic; 102279315Strasz uint8_t po_dont_care[58]; 103279315Strasz uint32_t po_size_of_headers; 104279315Strasz uint32_t po_checksum; 105279315Strasz uint16_t po_subsystem; 106279315Strasz uint8_t po_dont_care_either[38]; 107279315Strasz uint32_t po_number_of_rva_and_sizes; 108279315Strasz} __attribute__((packed)); 109279315Strasz 110279315StraszCTASSERT(offsetof(struct pe_optional_header_32_plus, po_size_of_headers) == 60); 111279315StraszCTASSERT(offsetof(struct pe_optional_header_32_plus, po_checksum) == 64); 112279315StraszCTASSERT(offsetof(struct pe_optional_header_32_plus, po_subsystem) == 68); 113279315StraszCTASSERT(offsetof(struct pe_optional_header_32_plus, po_number_of_rva_and_sizes) == 108); 114279315Strasz 115279315Strasz#define PE_DIRECTORY_ENTRY_CERTIFICATE 4 116279315Strasz 117279315Straszstruct pe_directory_entry { 118279315Strasz uint32_t pde_rva; 119279315Strasz uint32_t pde_size; 120279315Strasz} __attribute__((packed)); 121279315Strasz 122279315Straszstruct pe_section_header { 123279315Strasz uint8_t psh_dont_care[16]; 124279315Strasz uint32_t psh_size_of_raw_data; 125279315Strasz uint32_t psh_pointer_to_raw_data; 126279315Strasz uint8_t psh_dont_care_either[16]; 127279315Strasz} __attribute__((packed)); 128279315Strasz 129279315StraszCTASSERT(offsetof(struct pe_section_header, psh_size_of_raw_data) == 16); 130279315StraszCTASSERT(offsetof(struct pe_section_header, psh_pointer_to_raw_data) == 20); 131279315Strasz 132279315Strasz#define PE_CERTIFICATE_REVISION 0x0200 133279315Strasz#define PE_CERTIFICATE_TYPE 0x0002 134279315Strasz 135279315Straszstruct pe_certificate { 136279315Strasz uint32_t pc_len; 137279315Strasz uint16_t pc_revision; 138279315Strasz uint16_t pc_type; 139279315Strasz char pc_signature[0]; 140279315Strasz} __attribute__((packed)); 141279315Strasz 142279315Straszvoid 143279315Straszrange_check(const struct executable *x, off_t off, size_t len, 144279315Strasz const char *name) 145279315Strasz{ 146279315Strasz 147279315Strasz if (off < 0) { 148279315Strasz errx(1, "%s starts at negative offset %jd", 149279315Strasz name, (intmax_t)off); 150279315Strasz } 151279315Strasz if (off >= (off_t)x->x_len) { 152279315Strasz errx(1, "%s starts at %jd, past the end of executable at %zd", 153279315Strasz name, (intmax_t)off, x->x_len); 154279315Strasz } 155279315Strasz if (len >= x->x_len) { 156279315Strasz errx(1, "%s size %zd is larger than the executable size %zd", 157279315Strasz name, len, x->x_len); 158279315Strasz } 159279315Strasz if (off + len > x->x_len) { 160279315Strasz errx(1, "%s extends to %jd, past the end of executable at %zd", 161279315Strasz name, (intmax_t)(off + len), x->x_len); 162279315Strasz } 163279315Strasz} 164279315Strasz 165279315Straszsize_t 166279315Straszsignature_size(const struct executable *x) 167279315Strasz{ 168279315Strasz const struct pe_directory_entry *pde; 169279315Strasz 170279315Strasz range_check(x, x->x_certificate_entry_off, 171279315Strasz x->x_certificate_entry_len, "Certificate Directory"); 172279315Strasz 173279315Strasz pde = (struct pe_directory_entry *) 174279315Strasz (x->x_buf + x->x_certificate_entry_off); 175279315Strasz 176279315Strasz if (pde->pde_rva != 0 && pde->pde_size == 0) 177279315Strasz warnx("signature size is 0, but its RVA is %d", pde->pde_rva); 178279315Strasz if (pde->pde_rva == 0 && pde->pde_size != 0) 179279315Strasz warnx("signature RVA is 0, but its size is %d", pde->pde_size); 180279315Strasz 181279315Strasz return (pde->pde_size); 182279315Strasz} 183279315Strasz 184279315Straszvoid 185279315Straszshow_certificate(const struct executable *x) 186279315Strasz{ 187279315Strasz struct pe_certificate *pc; 188279315Strasz const struct pe_directory_entry *pde; 189279315Strasz 190279315Strasz range_check(x, x->x_certificate_entry_off, 191279315Strasz x->x_certificate_entry_len, "Certificate Directory"); 192279315Strasz 193279315Strasz pde = (struct pe_directory_entry *) 194279315Strasz (x->x_buf + x->x_certificate_entry_off); 195279315Strasz 196279315Strasz if (signature_size(x) == 0) { 197279315Strasz printf("file not signed\n"); 198279315Strasz return; 199279315Strasz } 200279315Strasz 201279315Strasz#if 0 202279315Strasz printf("certificate chunk at offset %zd, size %zd\n", 203279315Strasz pde->pde_rva, pde->pde_size); 204279315Strasz#endif 205279315Strasz 206279315Strasz range_check(x, pde->pde_rva, pde->pde_size, "Certificate chunk"); 207279315Strasz 208279315Strasz pc = (struct pe_certificate *)(x->x_buf + pde->pde_rva); 209279315Strasz if (pc->pc_revision != PE_CERTIFICATE_REVISION) { 210279315Strasz errx(1, "wrong certificate chunk revision, is %d, should be %d", 211279315Strasz pc->pc_revision, PE_CERTIFICATE_REVISION); 212279315Strasz } 213279315Strasz if (pc->pc_type != PE_CERTIFICATE_TYPE) { 214279315Strasz errx(1, "wrong certificate chunk type, is %d, should be %d", 215279315Strasz pc->pc_type, PE_CERTIFICATE_TYPE); 216279315Strasz } 217279315Strasz printf("to dump PKCS7:\n " 218279315Strasz "dd if='%s' bs=1 skip=%zd | openssl pkcs7 -inform DER -print\n", 219279315Strasz x->x_path, pde->pde_rva + offsetof(struct pe_certificate, pc_signature)); 220279315Strasz printf("to dump raw ASN.1:\n " 221279315Strasz "openssl asn1parse -i -inform DER -offset %zd -in '%s'\n", 222279315Strasz pde->pde_rva + offsetof(struct pe_certificate, pc_signature), x->x_path); 223279315Strasz} 224279315Strasz 225279315Straszstatic void 226279315Straszparse_section_table(struct executable *x, off_t off, int number_of_sections) 227279315Strasz{ 228279315Strasz const struct pe_section_header *psh; 229279315Strasz int i; 230279315Strasz 231279315Strasz range_check(x, off, sizeof(*psh) * number_of_sections, 232279315Strasz "section table"); 233279315Strasz 234279315Strasz if (x->x_headers_len <= off + sizeof(*psh) * number_of_sections) 235279315Strasz errx(1, "section table outside of headers"); 236279315Strasz 237279315Strasz psh = (const struct pe_section_header *)(x->x_buf + off); 238279315Strasz 239279315Strasz if (number_of_sections >= MAX_SECTIONS) { 240279315Strasz errx(1, "too many sections: got %d, should be %d", 241279315Strasz number_of_sections, MAX_SECTIONS); 242279315Strasz } 243279315Strasz x->x_nsections = number_of_sections; 244279315Strasz 245279315Strasz for (i = 0; i < number_of_sections; i++) { 246279315Strasz if (psh->psh_pointer_to_raw_data < x->x_headers_len) 247279315Strasz errx(1, "section points inside the headers"); 248279315Strasz 249279315Strasz range_check(x, psh->psh_pointer_to_raw_data, 250279315Strasz psh->psh_size_of_raw_data, "section"); 251279315Strasz#if 0 252279315Strasz printf("section %d: start %d, size %d\n", 253279315Strasz i, psh->psh_pointer_to_raw_data, psh->psh_size_of_raw_data); 254279315Strasz#endif 255279315Strasz x->x_section_off[i] = psh->psh_pointer_to_raw_data; 256279315Strasz x->x_section_len[i] = psh->psh_size_of_raw_data; 257279315Strasz psh++; 258279315Strasz } 259279315Strasz} 260279315Strasz 261279315Straszstatic void 262279315Straszparse_directory(struct executable *x, off_t off, 263279315Strasz int number_of_rva_and_sizes, int number_of_sections) 264279315Strasz{ 265279315Strasz //int i; 266279315Strasz const struct pe_directory_entry *pde; 267279315Strasz 268279315Strasz //printf("Data Directory at offset %zd\n", off); 269279315Strasz 270279315Strasz if (number_of_rva_and_sizes <= PE_DIRECTORY_ENTRY_CERTIFICATE) { 271279315Strasz errx(1, "wrong NumberOfRvaAndSizes %d; should be at least %d", 272279315Strasz number_of_rva_and_sizes, PE_DIRECTORY_ENTRY_CERTIFICATE); 273279315Strasz } 274279315Strasz 275279315Strasz range_check(x, off, sizeof(*pde) * number_of_rva_and_sizes, 276279315Strasz "PE Data Directory"); 277279315Strasz if (x->x_headers_len <= off + sizeof(*pde) * number_of_rva_and_sizes) 278279315Strasz errx(1, "PE Data Directory outside of headers"); 279279315Strasz 280279315Strasz x->x_certificate_entry_off = 281279315Strasz off + sizeof(*pde) * PE_DIRECTORY_ENTRY_CERTIFICATE; 282279315Strasz x->x_certificate_entry_len = sizeof(*pde); 283279315Strasz#if 0 284279315Strasz printf("certificate directory entry at offset %zd, len %zd\n", 285279315Strasz x->x_certificate_entry_off, x->x_certificate_entry_len); 286279315Strasz 287279315Strasz pde = (struct pe_directory_entry *)(x->x_buf + off); 288279315Strasz for (i = 0; i < number_of_rva_and_sizes; i++) { 289279315Strasz printf("rva %zd, size %zd\n", pde->pde_rva, pde->pde_size); 290279315Strasz pde++; 291279315Strasz } 292279315Strasz#endif 293279315Strasz 294279315Strasz return (parse_section_table(x, 295279315Strasz off + sizeof(*pde) * number_of_rva_and_sizes, number_of_sections)); 296279315Strasz} 297279315Strasz 298279315Strasz/* 299279315Strasz * The PE checksum algorithm is undocumented; this code is mostly based on 300279315Strasz * http://forum.sysinternals.com/optional-header-checksum-calculation_topic24214.html 301279315Strasz * 302279315Strasz * "Sum the entire image file, excluding the CheckSum field in the optional 303279315Strasz * header, as an array of USHORTs, allowing any carry above 16 bits to be added 304279315Strasz * back onto the low 16 bits. Then add the file size to get a 32-bit value." 305279315Strasz * 306279315Strasz * Note that most software does not care about the checksum at all; perhaps 307279315Strasz * we could just set it to 0 instead. 308279315Strasz * 309289677Seadler * XXX: Endianness? 310279315Strasz */ 311279315Straszstatic uint32_t 312279315Straszcompute_checksum(const struct executable *x) 313279315Strasz{ 314279315Strasz uint32_t cksum = 0; 315279315Strasz uint16_t tmp; 316279315Strasz int i; 317279315Strasz 318279315Strasz range_check(x, x->x_checksum_off, x->x_checksum_len, "PE checksum"); 319279315Strasz 320279315Strasz assert(x->x_checksum_off % 2 == 0); 321279315Strasz 322279315Strasz for (i = 0; i + sizeof(tmp) < x->x_len; i += 2) { 323279315Strasz /* 324279315Strasz * Don't checksum the checksum. The +2 is because the checksum 325279315Strasz * is 4 bytes, and here we're iterating over 2 byte chunks. 326279315Strasz */ 327279315Strasz if (i == x->x_checksum_off || i == x->x_checksum_off + 2) { 328279315Strasz tmp = 0; 329279315Strasz } else { 330279315Strasz assert(i + sizeof(tmp) <= x->x_len); 331279315Strasz memcpy(&tmp, x->x_buf + i, sizeof(tmp)); 332279315Strasz } 333279315Strasz 334279315Strasz cksum += tmp; 335279315Strasz cksum += cksum >> 16; 336279315Strasz cksum &= 0xffff; 337279315Strasz } 338279315Strasz 339279315Strasz cksum += cksum >> 16; 340279315Strasz cksum &= 0xffff; 341279315Strasz 342279315Strasz cksum += x->x_len; 343279315Strasz 344279315Strasz return (cksum); 345279315Strasz} 346279315Strasz 347279315Straszstatic void 348279315Straszparse_optional_32_plus(struct executable *x, off_t off, 349279315Strasz int number_of_sections) 350279315Strasz{ 351283141Strasz#if 0 352279315Strasz uint32_t computed_checksum; 353283141Strasz#endif 354279315Strasz const struct pe_optional_header_32_plus *po; 355279315Strasz 356279315Strasz range_check(x, off, sizeof(*po), "PE Optional Header"); 357279315Strasz 358279315Strasz po = (struct pe_optional_header_32_plus *)(x->x_buf + off); 359279315Strasz switch (po->po_subsystem) { 360279315Strasz case PE_OPTIONAL_SUBSYSTEM_EFI_APPLICATION: 361279315Strasz case PE_OPTIONAL_SUBSYSTEM_EFI_BOOT: 362279315Strasz case PE_OPTIONAL_SUBSYSTEM_EFI_RUNTIME: 363279315Strasz break; 364279315Strasz default: 365279315Strasz errx(1, "wrong PE Optional Header subsystem 0x%x", 366279315Strasz po->po_subsystem); 367279315Strasz } 368279315Strasz 369279315Strasz#if 0 370279315Strasz printf("subsystem %d, checksum 0x%x, %d data directories\n", 371279315Strasz po->po_subsystem, po->po_checksum, po->po_number_of_rva_and_sizes); 372279315Strasz#endif 373279315Strasz 374279315Strasz x->x_checksum_off = off + 375279315Strasz offsetof(struct pe_optional_header_32_plus, po_checksum); 376279315Strasz x->x_checksum_len = sizeof(po->po_checksum); 377279315Strasz#if 0 378279315Strasz printf("checksum 0x%x at offset %zd, len %zd\n", 379279315Strasz po->po_checksum, x->x_checksum_off, x->x_checksum_len); 380279315Strasz 381279315Strasz computed_checksum = compute_checksum(x); 382279315Strasz if (computed_checksum != po->po_checksum) { 383279315Strasz warnx("invalid PE+ checksum; is 0x%x, should be 0x%x", 384279315Strasz po->po_checksum, computed_checksum); 385279315Strasz } 386283141Strasz#endif 387279315Strasz 388279315Strasz if (x->x_len < x->x_headers_len) 389279315Strasz errx(1, "invalid SizeOfHeaders %d", po->po_size_of_headers); 390279315Strasz x->x_headers_len = po->po_size_of_headers; 391279315Strasz //printf("Size of Headers: %d\n", po->po_size_of_headers); 392279315Strasz 393279315Strasz return (parse_directory(x, off + sizeof(*po), 394279315Strasz po->po_number_of_rva_and_sizes, number_of_sections)); 395279315Strasz} 396279315Strasz 397279315Straszstatic void 398279315Straszparse_optional_32(struct executable *x, off_t off, int number_of_sections) 399279315Strasz{ 400283141Strasz#if 0 401279315Strasz uint32_t computed_checksum; 402283141Strasz#endif 403279315Strasz const struct pe_optional_header_32 *po; 404279315Strasz 405279315Strasz range_check(x, off, sizeof(*po), "PE Optional Header"); 406279315Strasz 407279315Strasz po = (struct pe_optional_header_32 *)(x->x_buf + off); 408279315Strasz switch (po->po_subsystem) { 409279315Strasz case PE_OPTIONAL_SUBSYSTEM_EFI_APPLICATION: 410279315Strasz case PE_OPTIONAL_SUBSYSTEM_EFI_BOOT: 411279315Strasz case PE_OPTIONAL_SUBSYSTEM_EFI_RUNTIME: 412279315Strasz break; 413279315Strasz default: 414279315Strasz errx(1, "wrong PE Optional Header subsystem 0x%x", 415279315Strasz po->po_subsystem); 416279315Strasz } 417279315Strasz 418279315Strasz#if 0 419279315Strasz printf("subsystem %d, checksum 0x%x, %d data directories\n", 420279315Strasz po->po_subsystem, po->po_checksum, po->po_number_of_rva_and_sizes); 421279315Strasz#endif 422279315Strasz 423279315Strasz x->x_checksum_off = off + 424279315Strasz offsetof(struct pe_optional_header_32, po_checksum); 425279315Strasz x->x_checksum_len = sizeof(po->po_checksum); 426279315Strasz#if 0 427279315Strasz printf("checksum at offset %zd, len %zd\n", 428279315Strasz x->x_checksum_off, x->x_checksum_len); 429279315Strasz 430279315Strasz computed_checksum = compute_checksum(x); 431279315Strasz if (computed_checksum != po->po_checksum) { 432279315Strasz warnx("invalid PE checksum; is 0x%x, should be 0x%x", 433279315Strasz po->po_checksum, computed_checksum); 434279315Strasz } 435283141Strasz#endif 436279315Strasz 437279315Strasz if (x->x_len < x->x_headers_len) 438279315Strasz errx(1, "invalid SizeOfHeaders %d", po->po_size_of_headers); 439279315Strasz x->x_headers_len = po->po_size_of_headers; 440279315Strasz //printf("Size of Headers: %d\n", po->po_size_of_headers); 441279315Strasz 442279315Strasz return (parse_directory(x, off + sizeof(*po), 443279315Strasz po->po_number_of_rva_and_sizes, number_of_sections)); 444279315Strasz} 445279315Strasz 446279315Straszstatic void 447279315Straszparse_optional(struct executable *x, off_t off, int number_of_sections) 448279315Strasz{ 449279315Strasz const struct pe_optional_header_32 *po; 450279315Strasz 451279315Strasz //printf("Optional header offset %zd\n", off); 452279315Strasz 453279315Strasz range_check(x, off, sizeof(*po), "PE Optional Header"); 454279315Strasz 455279315Strasz po = (struct pe_optional_header_32 *)(x->x_buf + off); 456279315Strasz 457279315Strasz switch (po->po_magic) { 458279315Strasz case PE_OPTIONAL_MAGIC_32: 459279315Strasz return (parse_optional_32(x, off, number_of_sections)); 460279315Strasz case PE_OPTIONAL_MAGIC_32_PLUS: 461279315Strasz return (parse_optional_32_plus(x, off, number_of_sections)); 462279315Strasz default: 463279315Strasz errx(1, "wrong PE Optional Header magic 0x%x", po->po_magic); 464279315Strasz } 465279315Strasz} 466279315Strasz 467279315Straszstatic void 468279315Straszparse_pe(struct executable *x, off_t off) 469279315Strasz{ 470279315Strasz const struct pe_header *pe; 471279315Strasz 472279315Strasz //printf("PE offset %zd, PE size %zd\n", off, sizeof(*pe)); 473279315Strasz 474279315Strasz range_check(x, off, sizeof(*pe), "PE header"); 475279315Strasz 476279315Strasz pe = (struct pe_header *)(x->x_buf + off); 477279315Strasz if (pe->pe_signature != PE_SIGNATURE) 478279315Strasz errx(1, "wrong PE signature 0x%x", pe->pe_signature); 479279315Strasz 480279315Strasz //printf("Number of sections: %d\n", pe->pe_coff.coff_number_of_sections); 481279315Strasz 482279315Strasz parse_optional(x, off + sizeof(*pe), 483279315Strasz pe->pe_coff.coff_number_of_sections); 484279315Strasz} 485279315Strasz 486279315Straszvoid 487279315Straszparse(struct executable *x) 488279315Strasz{ 489279315Strasz const struct mz_header *mz; 490279315Strasz 491279315Strasz range_check(x, 0, sizeof(*mz), "MZ header"); 492279315Strasz 493279315Strasz mz = (struct mz_header *)x->x_buf; 494279315Strasz if (mz->mz_signature[0] != 'M' || mz->mz_signature[1] != 'Z') 495279315Strasz errx(1, "MZ header not found"); 496279315Strasz 497279315Strasz return (parse_pe(x, mz->mz_lfanew)); 498279315Strasz} 499279315Strasz 500279315Straszstatic off_t 501279315Straszappend(struct executable *x, void *ptr, size_t len) 502279315Strasz{ 503279315Strasz off_t off; 504279315Strasz 505279315Strasz /* 506279315Strasz * XXX: Alignment. 507279315Strasz */ 508279315Strasz off = x->x_len; 509279315Strasz x->x_buf = realloc(x->x_buf, x->x_len + len); 510279315Strasz if (x->x_buf == NULL) 511279315Strasz err(1, "realloc"); 512279315Strasz memcpy(x->x_buf + x->x_len, ptr, len); 513279315Strasz x->x_len += len; 514279315Strasz 515279315Strasz return (off); 516279315Strasz} 517279315Strasz 518279315Straszvoid 519279315Straszupdate(struct executable *x) 520279315Strasz{ 521279315Strasz uint32_t checksum; 522279315Strasz struct pe_certificate *pc; 523279315Strasz struct pe_directory_entry pde; 524279315Strasz size_t pc_len; 525279315Strasz off_t pc_off; 526279315Strasz 527279315Strasz pc_len = sizeof(*pc) + x->x_signature_len; 528279315Strasz pc = calloc(1, pc_len); 529279315Strasz if (pc == NULL) 530279315Strasz err(1, "calloc"); 531279315Strasz 532279315Strasz#if 0 533279315Strasz /* 534279315Strasz * Note that pc_len is the length of pc_certificate, 535279315Strasz * not the whole structure. 536279315Strasz * 537279315Strasz * XXX: That's what the spec says - but it breaks at least 538279315Strasz * sbverify and "pesign -S", so the spec is probably wrong. 539279315Strasz */ 540279315Strasz pc->pc_len = x->x_signature_len; 541279315Strasz#else 542279315Strasz pc->pc_len = pc_len; 543279315Strasz#endif 544279315Strasz pc->pc_revision = PE_CERTIFICATE_REVISION; 545279315Strasz pc->pc_type = PE_CERTIFICATE_TYPE; 546279315Strasz memcpy(&pc->pc_signature, x->x_signature, x->x_signature_len); 547279315Strasz 548279315Strasz pc_off = append(x, pc, pc_len); 549279315Strasz#if 0 550279315Strasz printf("added signature chunk at offset %zd, len %zd\n", 551279315Strasz pc_off, pc_len); 552279315Strasz#endif 553279315Strasz 554279315Strasz free(pc); 555279315Strasz 556279315Strasz pde.pde_rva = pc_off; 557279315Strasz pde.pde_size = pc_len; 558279315Strasz memcpy(x->x_buf + x->x_certificate_entry_off, &pde, sizeof(pde)); 559279315Strasz 560279315Strasz checksum = compute_checksum(x); 561279315Strasz assert(sizeof(checksum) == x->x_checksum_len); 562279315Strasz memcpy(x->x_buf + x->x_checksum_off, &checksum, sizeof(checksum)); 563279315Strasz#if 0 564279315Strasz printf("new checksum 0x%x\n", checksum); 565279315Strasz#endif 566279315Strasz} 567