Пример #1
0
__get_last_section(Pe *pe)
{
	Pe_Scn *scn = NULL;
	Pe_Scn *ret = NULL;

	while ((scn = pe_nextscn(pe, scn)) != NULL) {
		if (!ret) {
			ret = scn;
			continue;
		}

		if (ret->shdr->virtual_address < scn->shdr->virtual_address)
			ret = scn;
	}
	if (ret)
		return ret->shdr;

	return NULL;
}
Пример #2
0
int
generate_digest(pesign_context *ctx, Pe *pe)
{
	void *hash_base;
	size_t hash_size;
	struct pe32_opt_hdr *pe32opthdr = NULL;
	struct pe32plus_opt_hdr *pe64opthdr = NULL;
	PK11Context *pk11ctx;
	unsigned long hashed_bytes = 0;
	int rc = -1;

	if (!pe) {
		fprintf(stderr, "pesign: no output pe ready\n");
		exit(1);
	}

	struct pe_hdr pehdr;
	if (pe_getpehdr(pe, &pehdr) == NULL) {
		fprintf(stderr, "pesign: invalid output file header\n");
		exit(1);
	}

	void *map = NULL;
	size_t map_size = 0;

	/* 1. Load the image header into memory - should be done
	 * 2. Initialize SHA hash context. */
	map = pe_rawfile(pe, &map_size);
	if (!map) {
		fprintf(stderr, "pesign: could not get raw output file address\n");
		exit(1);
	}

	pk11ctx = PK11_CreateDigestContext(ctx->cms_ctx.digest_oid_tag);
	if (!pk11ctx) {
		fprintf(stderr, "pesign: could not initialize digest\n");
		exit(1);
	}
	PK11_DigestBegin(pk11ctx);

	/* 3. Calculate the distance from the base of the image header to the
	 * image checksum.
	 * 4. Hash the image header from start to the beginning of the
	 * checksum. */
	hash_base = map;
	switch (pe_kind(pe)) {
	case PE_K_PE_EXE: {
		void *opthdr = pe_getopthdr(pe);
		pe32opthdr = opthdr;
		hash_size = (uintptr_t)&pe32opthdr->csum - (uintptr_t)hash_base;
		break;
	}
	case PE_K_PE64_EXE: {
		void *opthdr = pe_getopthdr(pe);
		pe64opthdr = opthdr;
		hash_size = (uintptr_t)&pe64opthdr->csum - (uintptr_t)hash_base;
		break;
	}
	default:
		goto error;
	}
	PK11_DigestOp(pk11ctx, hash_base, hash_size);

	/* 5. Skip over the image checksum
	 * 6. Get the address of the beginning of the cert dir entry
	 * 7. Hash from the end of the csum to the start of the cert dirent. */
	hash_base += hash_size;
	hash_base += pe32opthdr ? sizeof(pe32opthdr->csum)
				: sizeof(pe64opthdr->csum);
	data_directory *dd;

	rc = pe_getdatadir(pe, &dd);
	if (rc < 0 || !dd)
		goto error;

	hash_size = (uintptr_t)&dd->certs - (uintptr_t)hash_base;
	PK11_DigestOp(pk11ctx, hash_base, hash_size);

	/* 8. Skip over the crt dir
	 * 9. Hash everything up to the end of the image header. */
	hash_base = &dd->base_relocations;
	hash_size = (pe32opthdr ? pe32opthdr->header_size
				: pe64opthdr->header_size) -
		((uintptr_t)&dd->base_relocations - (uintptr_t)map);
	PK11_DigestOp(pk11ctx, hash_base, hash_size);

	/* 10. Set SUM_OF_BYTES_HASHED to the size of the header. */
	hashed_bytes = pe32opthdr ? pe32opthdr->header_size
				: pe64opthdr->header_size;

	struct section_header *shdrs = calloc(pehdr.sections, sizeof (*shdrs));
	if (!shdrs)
		goto error;
	Pe_Scn *scn = NULL;
	for (int i = 0; i < pehdr.sections; i++) {
		scn = pe_nextscn(pe, scn);
		if (scn == NULL)
			break;
		pe_getshdr(scn, &shdrs[i]);
	}
	sort_shdrs(shdrs, pehdr.sections - 1);

	for (int i = 0; i < pehdr.sections; i++) {
		hash_base = (void *)((uintptr_t)map + shdrs[i].data_addr);
		hash_size = shdrs[i].raw_data_size;
		PK11_DigestOp(pk11ctx, hash_base, hash_size);

		hashed_bytes += hash_size;
	}

	if (map_size > hashed_bytes) {
		hash_base = (void *)((uintptr_t)map + hashed_bytes);
		hash_size = map_size - dd->certs.size - hashed_bytes;
		PK11_DigestOp(pk11ctx, hash_base, hash_size);
	}

	SECItem *digest = PORT_ArenaZAlloc(ctx->cms_ctx.arena,
					sizeof (SECItem));
	if (!digest)
		goto error_shdrs;

	digest->type = siBuffer;
	digest->data = PORT_ArenaZAlloc(ctx->cms_ctx.arena,
						ctx->cms_ctx.digest_size);
	digest->len = ctx->cms_ctx.digest_size;
	if (!digest->data)
		goto error_digest;

	PK11_DigestFinal(pk11ctx, digest->data, &digest->len,
						ctx->cms_ctx.digest_size);
	ctx->cms_ctx.pe_digest = digest;

	if (shdrs)
		free(shdrs);
	PK11_DestroyContext(pk11ctx, PR_TRUE);

	return 0;

error_digest:
	PORT_Free(digest->data);
error_shdrs:
	if (shdrs)
		free(shdrs);
error:
	PK11_DestroyContext(pk11ctx, PR_TRUE);
	fprintf(stderr, "pesign: could not digest file.\n");
	exit(1);
}