Update the PE checksum field using the somewhat-underdocumented
algorithm, so that we match the Microsoft implementation in our signature generation. [jejb: add endian to autogen.sh and fix for multi-sign] Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
parent
706bec1a95
commit
be1f3d8350
2 changed files with 62 additions and 1 deletions
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
ccan_modules="talloc read_write_all build_assert array_size"
|
ccan_modules="talloc read_write_all build_assert array_size endian"
|
||||||
|
|
||||||
# Add ccan upstream sources
|
# Add ccan upstream sources
|
||||||
if [ ! -e lib/ccan.git/Makefile ]
|
if [ ! -e lib/ccan.git/Makefile ]
|
||||||
|
|
61
src/image.c
61
src/image.c
|
@ -38,6 +38,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <ccan/endian/endian.h>
|
||||||
#include <ccan/talloc/talloc.h>
|
#include <ccan/talloc/talloc.h>
|
||||||
#include <ccan/read_write_all/read_write_all.h>
|
#include <ccan/read_write_all/read_write_all.h>
|
||||||
#include <ccan/build_assert/build_assert.h>
|
#include <ccan/build_assert/build_assert.h>
|
||||||
|
@ -134,6 +135,62 @@ static int align_up(int size, int align)
|
||||||
return (size + align - 1) & ~(align - 1);
|
return (size + align - 1) & ~(align - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint16_t csum_update_fold(uint16_t csum, uint16_t x)
|
||||||
|
{
|
||||||
|
uint32_t new = csum + x;
|
||||||
|
new = (new >> 16) + (new & 0xffff);
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t csum_bytes(uint16_t checksum, void *buf, size_t len)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
uint16_t *p;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i += sizeof(*p)) {
|
||||||
|
p = buf + i;
|
||||||
|
checksum = csum_update_fold(checksum, *p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void image_pecoff_update_checksum(struct image *image)
|
||||||
|
{
|
||||||
|
bool is_signed = image->sigsize && image->sigbuf;
|
||||||
|
uint32_t checksum;
|
||||||
|
struct cert_table_header *cert_table = image->cert_table;
|
||||||
|
|
||||||
|
/* We carefully only include the signature data in the checksum (and
|
||||||
|
* in the file length) if we're outputting the signature. Otherwise,
|
||||||
|
* in case of signature removal, the signature data is in the buffer
|
||||||
|
* we read in (as indicated by image->size), but we do *not* want to
|
||||||
|
* checksum it.
|
||||||
|
*
|
||||||
|
* We also skip the 32-bits of checksum data in the PE/COFF header.
|
||||||
|
*/
|
||||||
|
checksum = csum_bytes(0, image->buf,
|
||||||
|
(void *)image->checksum - (void *)image->buf);
|
||||||
|
checksum = csum_bytes(checksum,
|
||||||
|
image->checksum + 1,
|
||||||
|
(void *)(image->buf + image->data_size) -
|
||||||
|
(void *)(image->checksum + 1));
|
||||||
|
|
||||||
|
if (is_signed) {
|
||||||
|
checksum = csum_bytes(checksum,
|
||||||
|
cert_table, sizeof(*cert_table));
|
||||||
|
|
||||||
|
checksum = csum_bytes(checksum, image->sigbuf, image->sigsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
checksum += image->data_size;
|
||||||
|
|
||||||
|
if (is_signed)
|
||||||
|
checksum += sizeof(*cert_table) + image->sigsize;
|
||||||
|
|
||||||
|
*(image->checksum) = cpu_to_le32(checksum);
|
||||||
|
}
|
||||||
|
|
||||||
static int image_pecoff_parse(struct image *image)
|
static int image_pecoff_parse(struct image *image)
|
||||||
{
|
{
|
||||||
struct cert_table_header *cert_table;
|
struct cert_table_header *cert_table;
|
||||||
|
@ -508,6 +565,8 @@ int image_add_signature(struct image *image, void *sig, int size)
|
||||||
if (aligned_size != tot_size)
|
if (aligned_size != tot_size)
|
||||||
memset(start + size, 0, aligned_size - tot_size);
|
memset(start + size, 0, aligned_size - tot_size);
|
||||||
|
|
||||||
|
image->cert_table = cth;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,6 +646,8 @@ int image_write(struct image *image, const char *filename)
|
||||||
image->data_dir_sigtable->size = 0;
|
image->data_dir_sigtable->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
image_pecoff_update_checksum(image);
|
||||||
|
|
||||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
perror("open");
|
perror("open");
|
||||||
|
|
Loading…
Reference in a new issue