Rizin
unix-like reverse engineering framework and cli tools
pe_security.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2008-2019 nibble <nibble.ds@gmail.com>
2 // SPDX-FileCopyrightText: 2008-2019 pancake <pancake@nopcode.org>
3 // SPDX-FileCopyrightText: 2008-2019 inisider <inisider@gmail.com>
4 // SPDX-License-Identifier: LGPL-3.0-only
5 
6 #include "pe.h"
7 #include <rz_hash.h>
8 
10  if (!bin->spcinfo) {
11  return NULL;
12  }
13  RASN1Binary *digest = bin->spcinfo->messageDigest.digest;
14  return rz_hex_bin2strdup(digest->binary, digest->length);
15 }
16 
17 static ut64 buf_fwd_hash(const ut8 *buf, ut64 size, void *user) {
18  return rz_hash_cfg_update((RzHashCfg *)user, buf, size) ? size : 0;
19 }
20 
22  if (!bin->spcinfo) {
23  return NULL;
24  }
25 
26  char *hashtype = strdup(bin->spcinfo->messageDigest.digestAlgorithm.algorithm->string);
27  rz_str_replace_char(hashtype, '-', 0);
28 
29  RzHashCfg *md = rz_hash_cfg_new_with_algo2(bin->hash, hashtype);
30  if (!md) {
31  free(hashtype);
32  return NULL;
33  }
34  ut32 checksum_paddr = bin->nt_header_offset + 4 + sizeof(PE_(image_file_header)) + 0x40;
35  ut32 security_entry_offset = bin->nt_header_offset + sizeof(PE_(image_nt_headers)) - 96;
36  PE_(image_data_directory) *data_dir_security = &bin->data_directory[PE_IMAGE_DIRECTORY_ENTRY_SECURITY];
37  PE_DWord security_dir_offset = data_dir_security->VirtualAddress;
38  ut32 security_dir_size = data_dir_security->Size;
39  rz_buf_fwd_scan(bin->b, 0, checksum_paddr, buf_fwd_hash, md);
40  rz_buf_fwd_scan(bin->b, checksum_paddr + 4, security_entry_offset - checksum_paddr - 4, buf_fwd_hash, md);
41  rz_buf_fwd_scan(bin->b, security_entry_offset + 8, security_dir_offset - security_entry_offset - 8, buf_fwd_hash, md);
42  rz_buf_fwd_scan(bin->b, security_dir_offset + security_dir_size, rz_buf_size(bin->b) - security_dir_offset - security_dir_size, buf_fwd_hash, md);
43 
44  RzHashSize digest_size = 0;
45  const ut8 *digest = NULL;
46  if (!rz_hash_cfg_final(md) ||
47  !(digest = rz_hash_cfg_get_result(md, hashtype, &digest_size))) {
48 
49  free(hashtype);
51  return NULL;
52  }
53 
54  char *hashstr = rz_hex_bin2strdup(digest, digest_size);
55  free(hashtype);
57  return hashstr;
58 }
59 
61  if (!bin->authentihash) {
62  bin->authentihash = PE_(bin_pe_compute_authentihash)(bin);
63  }
64  return bin->authentihash;
65 }
66 
68  return bin->is_authhash_valid;
69 }
70 
72  if (!bin || !bin->nt_headers) {
73  return false;
74  }
75  if (bin->nt_headers->optional_header.NumberOfRvaAndSizes < 5) {
76  return false;
77  }
78  PE_(image_data_directory) *data_dir_security = &bin->data_directory[PE_IMAGE_DIRECTORY_ENTRY_SECURITY];
79  PE_DWord paddr = data_dir_security->VirtualAddress;
80  ut32 size = data_dir_security->Size;
81  if (size < 8 || paddr > bin->size || paddr + size > bin->size) {
82  RZ_LOG_INFO("Invalid certificate table");
83  return false;
84  }
85 
87  if (!security_directory) {
88  return false;
89  }
90  bin->security_directory = security_directory;
91 
92  PE_DWord offset = paddr;
93  while (offset < paddr + size) {
94  Pe_certificate **tmp = (Pe_certificate **)realloc(security_directory->certificates, (security_directory->length + 1) * sizeof(Pe_certificate *));
95  if (!tmp) {
96  return false;
97  }
98  security_directory->certificates = tmp;
100  if (!cert) {
101  return false;
102  }
103  if (!rz_buf_read_le32_at(bin->b, offset, &cert->dwLength)) {
104  RZ_FREE(cert);
105  return false;
106  }
107  cert->dwLength += (8 - (cert->dwLength & 7)) & 7; // align32
108  if (offset + cert->dwLength > paddr + size) {
109  RZ_LOG_INFO("Invalid certificate entry");
110  RZ_FREE(cert);
111  return false;
112  }
113  if (!rz_buf_read_le16_at(bin->b, offset + 4, &cert->wRevision)) {
114  RZ_FREE(cert);
115  return false;
116  }
117  if (!rz_buf_read_le16_at(bin->b, offset + 6, &cert->wCertificateType)) {
118  RZ_FREE(cert);
119  return false;
120  }
121  if (cert->dwLength < 6) {
122  RZ_LOG_ERROR("Invalid cert.dwLength (must be > 6)\n");
123  RZ_FREE(cert);
124  return false;
125  }
126  if (!(cert->bCertificate = malloc(cert->dwLength - 6))) {
127  RZ_FREE(cert);
128  return false;
129  }
130  rz_buf_read_at(bin->b, offset + 8, cert->bCertificate, cert->dwLength - 6);
131 
133  bin->cms = rz_pkcs7_parse_cms(cert->bCertificate, cert->dwLength - 6);
134  bin->spcinfo = rz_pkcs7_parse_spcinfo(bin->cms);
135  }
136 
137  security_directory->certificates[security_directory->length] = cert;
138  security_directory->length++;
139  offset += cert->dwLength;
140  }
141 
142  if (bin->cms && bin->spcinfo) {
143  const char *actual_authentihash = PE_(bin_pe_get_authentihash)(bin);
144  const char *claimed_authentihash = PE_(bin_pe_get_claimed_authentihash)(bin);
145  if (actual_authentihash && claimed_authentihash) {
146  bin->is_authhash_valid = !strcmp(actual_authentihash, claimed_authentihash);
147  } else {
148  bin->is_authhash_valid = false;
149  }
150  free((void *)claimed_authentihash);
151  }
152  bin->is_signed = bin->cms != NULL;
153  return true;
154 }
155 
157  if (!security_directory) {
158  return;
159  }
160  size_t numCert = 0;
161  for (; numCert < security_directory->length; numCert++) {
162  free(security_directory->certificates[numCert]);
163  }
164  free(security_directory->certificates);
165  free(security_directory);
166 }
#define NULL
Definition: cris-opc.c:27
uint32_t ut32
RZ_API RZ_BORROW const ut8 * rz_hash_cfg_get_result(RZ_NONNULL RzHashCfg *md, RZ_NONNULL const char *name, RZ_NONNULL ut32 *size)
Returns the digest value of the requested algorithm name.
Definition: hash.c:445
RZ_API void rz_hash_cfg_free(RZ_NONNULL RzHashCfg *md)
Definition: hash.c:186
RZ_API bool rz_hash_cfg_update(RZ_NONNULL RzHashCfg *md, RZ_NONNULL const ut8 *data, ut64 size)
Inserts data into each the message digest contextes.
Definition: hash.c:337
RZ_API bool rz_hash_cfg_final(RZ_NONNULL RzHashCfg *md)
Generates the final value of the message digest contextes.
Definition: hash.c:359
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
#define RzBinPEObj
Definition: pe.h:126
char *PE_() bin_pe_compute_authentihash(RzBinPEObj *bin)
Definition: pe_security.c:21
int PE_() bin_pe_init_security(RzBinPEObj *bin)
Definition: pe_security.c:71
static ut64 buf_fwd_hash(const ut8 *buf, ut64 size, void *user)
Definition: pe_security.c:17
void PE_() free_security_directory(Pe_image_security_directory *security_directory)
Definition: pe_security.c:156
static const char *PE_() bin_pe_get_claimed_authentihash(RzBinPEObj *bin)
Definition: pe_security.c:9
int PE_() bin_pe_is_authhash_valid(RzBinPEObj *bin)
Definition: pe_security.c:67
const char *PE_() bin_pe_get_authentihash(RzBinPEObj *bin)
Definition: pe_security.c:60
#define PE_(name)
Definition: pe_specs.h:23
#define PE_WIN_CERT_TYPE_PKCS_SIGNED_DATA
Definition: pe_specs.h:433
#define PE_IMAGE_DIRECTORY_ENTRY_SECURITY
Definition: pe_specs.h:147
#define PE_DWord
Definition: pe_specs.h:27
#define rz_buf_read_le16_at(b, addr, result)
Definition: rz_buf.h:270
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136
#define rz_buf_read_le32_at(b, addr, result)
Definition: rz_buf.h:271
RZ_API ut64 rz_buf_fwd_scan(RZ_NONNULL RzBuffer *b, ut64 start, ut64 amount, RZ_NONNULL RzBufferFwdScan fwd_scan, RZ_NULLABLE void *user)
Scans buffer linearly in chunks calling fwd_scan for each chunk.
Definition: buf.c:1303
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
ut32 RzHashSize
Definition: rz_hash.h:24
RZ_API char * rz_hex_bin2strdup(const ut8 *in, int len)
Definition: hex.c:415
#define RZ_LOG_INFO(fmtstr,...)
Definition: rz_log.h:54
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API RCMS * rz_pkcs7_parse_cms(const ut8 *buffer, ut32 length)
Definition: pkcs7.c:308
RZ_API SpcIndirectDataContent * rz_pkcs7_parse_spcinfo(RCMS *cms)
Definition: pkcs7.c:674
RZ_API int rz_str_replace_char(char *s, int a, int b)
Definition: str.c:169
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_FREE(x)
Definition: rz_types.h:369
ut8 * bCertificate
Definition: pe_specs.h:421
ut16 wRevision
Definition: pe_specs.h:419
ut16 wCertificateType
Definition: pe_specs.h:420
Pe_certificate ** certificates
Definition: pe_specs.h:426
Definition: malloc.c:26
ut32 length
Definition: rz_asn1.h:75
ut8 * binary
Definition: rz_asn1.h:76
ut64(WINAPI *w32_GetEnabledXStateFeatures)()