From edf1d26d49c08580d8b9022be6429ccbab825533 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Tue, 12 Jun 2012 16:56:15 +0800 Subject: [PATCH] sbattach: Add too to manage detached signatures Add a third tool (`sbattach`) to attach and detach signatures from PE/COFF files. Signed-off-by: Jeremy Kerr --- Makefile.am | 6 +- sbattach.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 sbattach.c diff --git a/Makefile.am b/Makefile.am index 8b5c431..a87cb5a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ AM_CFLAGS = -Wall -Wextra -bin_PROGRAMS = sbsign sbverify +bin_PROGRAMS = sbsign sbverify sbattach coff_headers = coff/external.h coff/pe.h coff/i386.h coff/x86_64.h @@ -17,6 +17,10 @@ sbverify_SOURCES = sbverify.c $(common_SOURCES) sbverify_LDADD = $(common_LDADD) sbverify_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) +sbattach_SOURCES = sbattach.c $(common_SOURCES) +sbattach_LDADD = $(common_LDADD) +sbattach_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) + man1_MANS = docs/sbsign.1 docs/sbverify.1 EXTRA_DIST = docs/sbsign.1.in docs/sbverify.1.in diff --git a/sbattach.c b/sbattach.c new file mode 100644 index 0000000..7cce654 --- /dev/null +++ b/sbattach.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2012 Jeremy Kerr + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "config.h" + +#include "image.h" + +static const char *toolname = "sbattach"; + +static struct option options[] = { + { "attach", required_argument, NULL, 'a' }, + { "detach", required_argument, NULL, 'd' }, + { "remove", no_argument, NULL, 'r' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 }, +}; + +static void usage(void) +{ + printf("Usage: %s --attach \n" + " or: %s --detach [--remove] \n" + " or: %s --remove \n" + "Attach or detach a signature file to/from a boot image\n" + "\n" + "Options:\n" + "\t--attach set as the boot image's\n" + "\t signature table\n" + "\t--detach copy the boot image's signature table\n" + "\t to \n" + "\t--remove remove the boot image's signature\n" + "\t table from the original file\n", + toolname, toolname, toolname); +} + +static void version(void) +{ + printf("%s %s\n", toolname, VERSION); +} + +static int detach_sig(struct image *image, const char *sig_filename) +{ + return image_write_detached(image, sig_filename); +} + +static int attach_sig(struct image *image, const char *image_filename, + const char *sig_filename) +{ + struct stat statbuf; + uint8_t *sigbuf; + size_t size; + int fd, rc; + + sigbuf = NULL; + + fd = open(sig_filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can't open file %s: %s\n", sig_filename, + strerror(errno)); + return -1; + } + + rc = fstat(fd, &statbuf); + if (rc) { + perror("fstat"); + goto out; + } + + size = statbuf.st_size; + + sigbuf = talloc_array(image, uint8_t, size); + if (!sigbuf) { + perror("talloc"); + goto out; + } + + rc = read_all(fd, sigbuf, size); + if (!rc) { + fprintf(stderr, "Error reading %s: %s\n", sig_filename, + strerror(errno)); + goto out; + } + + image->sigbuf = sigbuf; + image->sigsize = size; + + rc = image_write(image, image_filename); + if (rc) + fprintf(stderr, "Error writing %s: %s\n", image_filename, + strerror(errno)); + +out: + close(fd); + talloc_free(sigbuf); + return rc; +} + +static int remove_sig(struct image *image, const char *image_filename) +{ + int rc; + + image->sigbuf = NULL; + image->sigsize = 0; + + rc = image_write(image, image_filename); + if (rc) + fprintf(stderr, "Error writing %s: %s\n", image_filename, + strerror(errno)); + + return rc; +} + +enum action { + ACTION_NONE, + ACTION_ATTACH, + ACTION_DETACH, +}; + +int main(int argc, char **argv) +{ + const char *image_filename, *sig_filename; + struct image *image; + enum action action; + bool remove; + int c, rc; + + action = ACTION_NONE; + sig_filename = NULL; + remove = false; + + for (;;) { + int idx; + c = getopt_long(argc, argv, "a:d:rhV", options, &idx); + if (c == -1) + break; + + switch (c) { + case 'a': + case 'd': + if (action != ACTION_NONE) { + fprintf(stderr, "Multiple actions specified\n"); + usage(); + return EXIT_FAILURE; + } + action = (c == 'a') ? ACTION_ATTACH : ACTION_DETACH; + sig_filename = optarg; + break; + case 'r': + remove = true; + break; + case 'V': + version(); + return EXIT_SUCCESS; + case 'h': + usage(); + return EXIT_SUCCESS; + } + } + + if (argc != optind + 1) { + usage(); + return EXIT_FAILURE; + } + image_filename = argv[optind]; + + /* sanity check action combinations */ + if (action == ACTION_ATTACH && remove) { + fprintf(stderr, "Can't use --remove with --attach\n"); + return EXIT_FAILURE; + } + + if (action == ACTION_NONE && !remove) { + fprintf(stderr, "No action (attach/detach/remove) specified\n"); + usage(); + return EXIT_FAILURE; + } + + image = image_load(image_filename); + if (!image) { + fprintf(stderr, "Can't load image file %s\n", image_filename); + return EXIT_FAILURE; + } + + image_pecoff_parse(image); + + rc = 0; + + if (action == ACTION_ATTACH) + rc = attach_sig(image, image_filename, sig_filename); + + else if (action == ACTION_DETACH) + rc = detach_sig(image, sig_filename); + + if (rc) + goto out; + + if (remove) + rc = remove_sig(image, image_filename); + +out: + talloc_free(image); + return (rc == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +}