Rizin
unix-like reverse engineering framework and cli tools
pe_security.c File Reference
#include "pe.h"
#include <rz_hash.h>

Go to the source code of this file.

Functions

static const char *PE_() bin_pe_get_claimed_authentihash (RzBinPEObj *bin)
 
static ut64 buf_fwd_hash (const ut8 *buf, ut64 size, void *user)
 
char *PE_() bin_pe_compute_authentihash (RzBinPEObj *bin)
 
const char *PE_() bin_pe_get_authentihash (RzBinPEObj *bin)
 
int PE_() bin_pe_is_authhash_valid (RzBinPEObj *bin)
 
int PE_() bin_pe_init_security (RzBinPEObj *bin)
 
void PE_() free_security_directory (Pe_image_security_directory *security_directory)
 

Function Documentation

◆ bin_pe_compute_authentihash()

char* PE_() bin_pe_compute_authentihash ( RzBinPEObj bin)

Definition at line 21 of file pe_security.c.

21  {
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 }
#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_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
uint8_t ut8
Definition: lh5801.h:11
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")
static ut64 buf_fwd_hash(const ut8 *buf, ut64 size, void *user)
Definition: pe_security.c:17
#define PE_(name)
Definition: pe_specs.h:23
#define PE_IMAGE_DIRECTORY_ENTRY_SECURITY
Definition: pe_specs.h:147
#define PE_DWord
Definition: pe_specs.h:27
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
RZ_API int rz_str_replace_char(char *s, int a, int b)
Definition: str.c:169
Definition: malloc.c:26

References buf_fwd_hash(), free(), benchmark::md, NULL, PE_, PE_DWord, PE_IMAGE_DIRECTORY_ENTRY_SECURITY, rz_buf_fwd_scan(), rz_buf_size(), rz_hash_cfg_final(), rz_hash_cfg_free(), rz_hash_cfg_get_result(), rz_hex_bin2strdup(), rz_str_replace_char(), and strdup().

Referenced by bin_pe_get_authentihash().

◆ bin_pe_get_authentihash()

const char* PE_() bin_pe_get_authentihash ( RzBinPEObj bin)

Definition at line 60 of file pe_security.c.

60  {
61  if (!bin->authentihash) {
62  bin->authentihash = PE_(bin_pe_compute_authentihash)(bin);
63  }
64  return bin->authentihash;
65 }
char *PE_() bin_pe_compute_authentihash(RzBinPEObj *bin)
Definition: pe_security.c:21

References bin_pe_compute_authentihash(), and PE_.

Referenced by bin_pe_init_security().

◆ bin_pe_get_claimed_authentihash()

static const char* PE_() bin_pe_get_claimed_authentihash ( RzBinPEObj bin)
static

Definition at line 9 of file pe_security.c.

9  {
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 }
ut32 length
Definition: rz_asn1.h:75
ut8 * binary
Definition: rz_asn1.h:76

References rz_asn1_bin_t::binary, rz_asn1_bin_t::length, NULL, and rz_hex_bin2strdup().

Referenced by bin_pe_init_security().

◆ bin_pe_init_security()

int PE_() bin_pe_init_security ( RzBinPEObj bin)

Definition at line 71 of file pe_security.c.

71  {
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 }
voidpf void uLong size
Definition: ioapi.h:138
voidpf uLong offset
Definition: ioapi.h:144
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
static const char *PE_() bin_pe_get_claimed_authentihash(RzBinPEObj *bin)
Definition: pe_security.c:9
const char *PE_() bin_pe_get_authentihash(RzBinPEObj *bin)
Definition: pe_security.c:60
#define PE_WIN_CERT_TYPE_PKCS_SIGNED_DATA
Definition: pe_specs.h:433
#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
#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
#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

References Pe_certificate::bCertificate, bin_pe_get_authentihash(), bin_pe_get_claimed_authentihash(), Pe_image_security_directory::certificates, Pe_certificate::dwLength, free(), Pe_image_security_directory::length, malloc(), NULL, PE_, PE_DWord, PE_IMAGE_DIRECTORY_ENTRY_SECURITY, PE_WIN_CERT_TYPE_PKCS_SIGNED_DATA, realloc(), rz_buf_read_at(), rz_buf_read_le16_at, rz_buf_read_le32_at, RZ_FREE, RZ_LOG_ERROR, RZ_LOG_INFO, RZ_NEW0, rz_pkcs7_parse_cms(), rz_pkcs7_parse_spcinfo(), autogen_x86imm::tmp, Pe_certificate::wCertificateType, and Pe_certificate::wRevision.

Referenced by bin_pe_init().

◆ bin_pe_is_authhash_valid()

int PE_() bin_pe_is_authhash_valid ( RzBinPEObj bin)

Definition at line 67 of file pe_security.c.

67  {
68  return bin->is_authhash_valid;
69 }

◆ buf_fwd_hash()

static ut64 buf_fwd_hash ( const ut8 buf,
ut64  size,
void *  user 
)
static

Definition at line 17 of file pe_security.c.

17  {
18  return rz_hash_cfg_update((RzHashCfg *)user, buf, size) ? size : 0;
19 }
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
voidpf void * buf
Definition: ioapi.h:138

References rz_hash_cfg_update().

Referenced by bin_pe_compute_authentihash().

◆ free_security_directory()

void PE_() free_security_directory ( Pe_image_security_directory security_directory)

Definition at line 156 of file pe_security.c.

156  {
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 }

References free().

Referenced by rz_bin_pe_free().