Add Authentihash support for PE (#15987) ##bin

* Add Certificate Table parser to PE plugin
* Add SpcIndirectDataContent ASN.1 structure parser
* Add Authentihash calculation and check
* Refactor r_bin_file_hash
* Add tests for Authentihash check
This commit is contained in:
Zi Fan 2020-02-20 12:03:16 -08:00 committed by GitHub
parent e71cd20268
commit 2c6fc43b7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 381 additions and 119 deletions

View File

@ -856,54 +856,37 @@ R_API bool r_bin_file_close(RBin *bin, int bd) {
return false;
}
R_API bool r_bin_file_hash(RBin *bin, ut64 limit, const char *file, RList/*<RBinFileHash>*/ **old_file_hashes) {
r_return_val_if_fail (bin, false);
R_API RList *r_bin_file_hash(RBin *bin, ut64 limit) {
r_return_val_if_fail (bin, NULL);
char hash[128];
RHash *ctx;
ut64 buf_len = 0, r = 0;
RBinFile *bf = bin->cur;
if (!bf) {
return false;
return NULL;
}
RBinObject *o = bf->o;
if (!o || !o->info) {
return false;
return NULL;
}
RIODesc *iod = r_io_desc_get (bin->iob.io, bf->fd);
if (!iod) {
return false;
}
if (!file && iod) {
file = iod->name;
return NULL;
}
buf_len = r_io_desc_size (iod);
// By SLURP_LIMIT normally cannot compute ...
if (buf_len > limit) {
if (old_file_hashes) {
// if (bin->verbose) {
eprintf ("Warning: r_bin_file_hash: file exceeds bin.hashlimit\n");
// }
}
return false;
eprintf ("Warning: r_bin_file_hash: file exceeds bin.hashlimit\n");
return NULL;
}
const size_t blocksize = 64000;
ut8 *buf = malloc (blocksize);
if (!buf) {
eprintf ("Cannot allocate computation buffer\n");
return false;
}
if (old_file_hashes) {
*old_file_hashes = NULL;
}
if (!r_list_empty (o->info->file_hashes)) {
if (old_file_hashes && o->info->file_hashes) {
*old_file_hashes = o->info->file_hashes;
} else {
r_list_free (o->info->file_hashes);
}
o->info->file_hashes = NULL;
return NULL;
}
ctx = r_hash_new (false, R_HASH_MD5 | R_HASH_SHA1 | R_HASH_SHA256);
while (r + blocksize < buf_len) {
r_io_desc_seek (iod, r, R_IO_SEEK_SET);
@ -928,12 +911,12 @@ R_API bool r_bin_file_hash(RBin *bin, ut64 limit, const char *file, RList/*<RBin
r_hash_do_end (ctx, R_HASH_MD5);
r_hex_bin2str (ctx->digest, R_HASH_SIZE_MD5, hash);
o->info->file_hashes = r_list_newf ((RListFree) r_bin_file_hash_free);
RList *file_hashes = r_list_newf ((RListFree) r_bin_file_hash_free);
RBinFileHash *md5h = R_NEW0 (RBinFileHash);
if (md5h) {
md5h->type = strdup ("md5");
md5h->hex = strdup (hash);
r_list_push (o->info->file_hashes, md5h);
r_list_push (file_hashes, md5h);
}
r_hash_do_end (ctx, R_HASH_SHA1);
r_hex_bin2str (ctx->digest, R_HASH_SIZE_SHA1, hash);
@ -942,7 +925,7 @@ R_API bool r_bin_file_hash(RBin *bin, ut64 limit, const char *file, RList/*<RBin
if (sha1h) {
sha1h->type = strdup ("sha1");
sha1h->hex = strdup (hash);
r_list_push (o->info->file_hashes, sha1h);
r_list_push (file_hashes, sha1h);
}
r_hash_do_end (ctx, R_HASH_SHA256);
r_hex_bin2str (ctx->digest, R_HASH_SIZE_SHA256, hash);
@ -951,13 +934,13 @@ R_API bool r_bin_file_hash(RBin *bin, ut64 limit, const char *file, RList/*<RBin
if (sha256h) {
sha256h->type = strdup ("sha256");
sha256h->hex = strdup (hash);
r_list_push (o->info->file_hashes, sha256h);
r_list_push (file_hashes, sha256h);
}
// TODO: add here more rows
free (buf);
r_hash_free (ctx);
return true;
return file_hashes;
}
R_IPI RBinClass *r_bin_class_new(const char *name, const char *super, int view) {

View File

@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <r_hash.h>
#include <r_types.h>
#include <r_util.h>
#include "pe.h"
@ -838,6 +839,66 @@ int PE_(bin_pe_get_actual_checksum)(struct PE_(r_bin_pe_obj_t)* bin) {
return computed_cs;
}
static char* PE_(bin_pe_get_claimed_authentihash)(struct PE_(r_bin_pe_obj_t)* bin) {
if (!bin->spcinfo) {
return NULL;
}
RASN1Binary *digest = bin->spcinfo->messageDigest.digest;
return r_hex_bin2strdup (digest->binary, digest->length);
}
static char* PE_(bin_pe_get_actual_authentihash)(struct PE_(r_bin_pe_obj_t)* bin) {
if (!bin->spcinfo) {
return NULL;
}
const char *hashtype = bin->spcinfo->messageDigest.digestAlgorithm.algorithm->string;
ut64 algobit = r_hash_name_to_bits (hashtype);
if (!(algobit & (R_HASH_MD5 | R_HASH_SHA1))) {
eprintf ("Authenticode only supports md5, sha1.\n");
return NULL;
}
ut32 checksum_paddr = bin->nt_header_offset + 4 + sizeof (PE_(image_file_header)) + 0x40;
ut32 security_entry_offset = bin->nt_header_offset + sizeof (PE_(image_nt_headers)) - 96;
PE_(image_data_directory) *data_dir_security = &bin->data_directory[PE_IMAGE_DIRECTORY_ENTRY_SECURITY];
PE_DWord security_dir_offset = data_dir_security->VirtualAddress;
ut32 security_dir_size = data_dir_security->Size;
RBuffer *buf = r_buf_new ();
r_buf_append_buf_slice (buf, bin->b, 0, checksum_paddr);
r_buf_append_buf_slice (buf, bin->b,
checksum_paddr + 4,
security_entry_offset - checksum_paddr - 4);
r_buf_append_buf_slice (buf, bin->b,
security_entry_offset + 8,
security_dir_offset - security_entry_offset - 8);
r_buf_append_buf_slice (buf, bin->b,
security_dir_offset + security_dir_size,
r_buf_size (bin->b) - security_dir_offset - security_dir_size);
ut64 len;
const ut8 *data = r_buf_data (buf, &len);
char *hashstr = NULL;
RHash *ctx = r_hash_new (true, algobit);
r_hash_do_begin (ctx, algobit);
int digest_size = r_hash_calculate (ctx, algobit, data, len);
r_hash_do_end (ctx, algobit);
hashstr = r_hex_bin2strdup (ctx->digest, digest_size);
r_buf_free (buf);
r_hash_free (ctx);
return hashstr;
}
const char* PE_(bin_pe_get_authentihash)(struct PE_(r_bin_pe_obj_t)* bin) {
return bin->authentihash;
}
int PE_(bin_pe_is_authhash_valid)(struct PE_(r_bin_pe_obj_t)* bin) {
return bin->is_authhash_valid;
}
static void computeOverlayOffset(ut64 offset, ut64 size, ut64 file_size, ut64* largest_offset, ut64* largest_size) {
if (offset + size <= file_size && offset + size > (*largest_offset + *largest_size)) {
*largest_offset = offset;
@ -2736,37 +2797,84 @@ R_API void PE_(bin_pe_parse_resource)(struct PE_(r_bin_pe_obj_t) *bin) {
_store_resource_sdb (bin);
}
static void bin_pe_get_certificate(struct PE_ (r_bin_pe_obj_t) * bin) {
ut64 size, vaddr;
ut8 *data = NULL;
int len;
static int bin_pe_init_security(struct PE_(r_bin_pe_obj_t) * bin) {
if (!bin || !bin->nt_headers) {
return;
return false;
}
bin->cms = NULL;
size = bin->data_directory[PE_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
vaddr = bin->data_directory[PE_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
if (size < 8) {
return;
if (bin->nt_headers->optional_header.NumberOfRvaAndSizes < 5) {
return false;
}
data = calloc (1, size);
if (!data) {
return;
PE_(image_data_directory) *data_dir_security = &bin->data_directory[PE_IMAGE_DIRECTORY_ENTRY_SECURITY];
PE_DWord paddr = data_dir_security->VirtualAddress;
ut32 size = data_dir_security->Size;
if (size < 8 || paddr > bin->size || paddr + size > bin->size) {
bprintf ("Invalid certificate table");
return false;
}
if (vaddr > bin->size || vaddr + size > bin->size) {
bprintf ("vaddr greater than the file\n");
free (data);
return;
Pe_image_security_directory *security_directory = R_NEW0 (Pe_image_security_directory);
if (!security_directory) {
return false;
}
//skipping useless header..
len = r_buf_read_at (bin->b, vaddr + 8, data, size - 8);
if (len < 1) {
R_FREE (data);
return;
bin->security_directory = security_directory;
PE_DWord offset = paddr;
while (offset < paddr + size) {
Pe_certificate **tmp = (Pe_certificate **)realloc (security_directory->certificates, (security_directory->length + 1) * sizeof(Pe_certificate *));
if (!tmp) {
return false;
}
Pe_certificate *cert = R_NEW0 (Pe_certificate);
if (!cert) {
return false;
}
cert->dwLength = r_buf_read_le32_at (bin->b, offset);
cert->dwLength += (8 - (cert->dwLength & 7)) & 7; // align32
if (offset + cert->dwLength > paddr + size) {
bprintf ("Invalid certificate entry");
R_FREE (cert);
return false;
}
cert->wRevision = r_buf_read_le16_at (bin->b, offset + 4);
cert->wCertificateType = r_buf_read_le16_at (bin->b, offset + 6);
if (!(cert->bCertificate = malloc (cert->dwLength - 6))) {
R_FREE (cert);
return false;
}
r_buf_read_at (bin->b, offset + 8, cert->bCertificate, cert->dwLength - 6);
if (!bin->cms && cert->wCertificateType == PE_WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
bin->cms = r_pkcs7_parse_cms (cert->bCertificate, cert->dwLength - 6);
bin->spcinfo = r_pkcs7_parse_spcinfo (bin->cms);
}
security_directory->certificates = tmp;
security_directory->certificates[security_directory->length] = cert;
security_directory->length++;
offset += cert->dwLength;
}
if (bin->cms && bin->spcinfo) {
char *actual_authentihash = PE_(bin_pe_get_actual_authentihash) (bin);
char *claimed_authentihash = PE_(bin_pe_get_claimed_authentihash) (bin);
bin->authentihash = actual_authentihash;
bin->is_authhash_valid = !strcmp (actual_authentihash, claimed_authentihash);
free (claimed_authentihash);
}
bin->cms = r_pkcs7_parse_cms (data, size);
bin->is_signed = bin->cms != NULL;
R_FREE (data);
return true;
}
static void free_security_directory(Pe_image_security_directory *security_directory) {
if (!security_directory) {
return;
}
ut64 numCert = 0;
for (; numCert < security_directory->length; numCert++) {
R_FREE (security_directory->certificates[numCert]);
}
free (security_directory->certificates);
free (security_directory);
}
static int bin_pe_init(struct PE_(r_bin_pe_obj_t)* bin) {
@ -2776,10 +2884,13 @@ static int bin_pe_init(struct PE_(r_bin_pe_obj_t)* bin) {
bin->export_directory = NULL;
bin->import_directory = NULL;
bin->resource_directory = NULL;
bin->security_directory = NULL;
bin->delay_import_directory = NULL;
bin->optional_header = NULL;
bin->data_directory = NULL;
bin->big_endian = 0;
bin->cms = NULL;
bin->spcinfo = NULL;
if (!bin_pe_init_hdr (bin)) {
eprintf ("Warning: File is not PE\n");
return false;
@ -2792,7 +2903,7 @@ static int bin_pe_init(struct PE_(r_bin_pe_obj_t)* bin) {
bin_pe_init_imports (bin);
bin_pe_init_exports (bin);
bin_pe_init_resource (bin);
bin_pe_get_certificate(bin);
bin_pe_init_security (bin);
bin->big_endian = PE_(r_bin_pe_is_big_endian) (bin);
@ -3831,12 +3942,15 @@ void* PE_(r_bin_pe_free)(struct PE_(r_bin_pe_obj_t)* bin) {
free (bin->export_directory);
free (bin->import_directory);
free (bin->resource_directory);
free_security_directory (bin->security_directory);
free (bin->delay_import_directory);
free (bin->tls_directory);
free (bin->sections);
free (bin->authentihash);
r_list_free (bin->rich_entries);
r_list_free (bin->resources);
r_pkcs7_free_cms (bin->cms);
r_pkcs7_free_spcinfo (bin->spcinfo);
r_buf_free (bin->b);
bin->b = NULL;
free (bin);

View File

@ -96,6 +96,7 @@ struct PE_(r_bin_pe_obj_t) {
PE_(image_tls_directory) * tls_directory;
Pe_image_resource_directory* resource_directory;
PE_(image_delay_import_directory) * delay_import_directory;
Pe_image_security_directory * security_directory;
// these pointers pertain to the .net relevant sections
PE_(image_clr_header) * clr_hdr;
@ -127,6 +128,9 @@ struct PE_(r_bin_pe_obj_t) {
RBuffer* b;
Sdb *kv;
RCMS* cms;
SpcIndirectDataContent *spcinfo;
char *authentihash;
bool is_authhash_valid;
bool is_signed;
};
@ -158,6 +162,8 @@ struct PE_(r_bin_pe_obj_t)* PE_(r_bin_pe_new_buf)(RBuffer* buf, bool verbose);
int PE_(r_bin_pe_get_debug_data)(struct PE_(r_bin_pe_obj_t)* bin, struct SDebugInfo* res);
int PE_(bin_pe_get_claimed_checksum)(struct PE_(r_bin_pe_obj_t)* bin);
int PE_(bin_pe_get_actual_checksum)(struct PE_(r_bin_pe_obj_t)* bin);
const char* PE_(bin_pe_get_authentihash)(struct PE_(r_bin_pe_obj_t)* bin);
int PE_(bin_pe_is_authhash_valid)(struct PE_(r_bin_pe_obj_t)* bin);
int PE_(bin_pe_get_overlay)(struct PE_(r_bin_pe_obj_t)* bin, ut64* size);
void PE_(r_bin_pe_check_sections)(struct PE_(r_bin_pe_obj_t)* bin, struct r_bin_pe_section_t** sects);
struct r_bin_pe_addr_t *PE_(check_unknow) (struct PE_(r_bin_pe_obj_t) *bin);

View File

@ -442,6 +442,26 @@ typedef struct {
ut32 Characteristics;
} Pe32_image_tls_directory, Pe64_image_tls_directory;
typedef struct {
ut32 dwLength;
ut16 wRevision;
ut16 wCertificateType;
ut8 *bCertificate;
} Pe_certificate;
typedef struct {
ut32 length;
Pe_certificate **certificates;
} Pe_image_security_directory;
#define PE_WIN_CERT_REVISION_1_0 0x0100
#define PE_WIN_CERT_REVISION_2_0 0x0200
#define PE_WIN_CERT_TYPE_X509 0x0001
#define PE_WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
#define PE_WIN_CERT_TYPE_RESERVED_1 0x0003
#define PE_WIN_CERT_TYPE_TS_STACK_SIGNED 0x0004
typedef struct {
ut32 Signature;
Pe32_image_file_header file_header;

View File

@ -475,6 +475,16 @@ static RBinInfo* info(RBinFile *bf) {
ret->actual_checksum = strdup (sdb_fmt ("0x%08x", actual_checksum));
ret->pe_overlay = pe_overlay > 0;
ret->signature = bin ? bin->is_signed : false;
ret->file_hashes = r_list_newf ((RListFree) r_bin_file_hash_free);
const char *authentihash = PE_(bin_pe_get_authentihash) (bf->o->bin_obj);
if (authentihash) {
RBinFileHash *authhash = R_NEW0 (RBinFileHash);
if (authhash) {
authhash->type = strdup ("authentihash");
authhash->hex = strdup (authentihash);
r_list_push (ret->file_hashes, authhash);
}
}
Sdb *db = sdb_ns (bf->sdb, "pe", true);
sdb_bool_set (db, "canary", has_canary (bf), 0);
sdb_bool_set (db, "highva", haschr (bf, IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA), 0);
@ -491,6 +501,8 @@ static RBinInfo* info(RBinFile *bf) {
sdb_num_set (db, "bits", ret->bits, 0);
sdb_set (db, "claimed_checksum", ret->claimed_checksum, 0);
sdb_set (db, "actual_checksum", ret->actual_checksum, 0);
sdb_set (db, "authentihash", PE_(bin_pe_get_authentihash) (bf->o->bin_obj), 0);
sdb_bool_set (db, "is_authhash_valid", PE_(bin_pe_is_authhash_valid) (bf->o->bin_obj), 0);
ret->has_va = true;

View File

@ -603,66 +603,52 @@ static int cmd_info(void *data, const char *input) {
case 't': // "it"
{
ut64 limit = r_config_get_i (core->config, "bin.hashlimit");
const char *fileName;
RBinInfo *info = r_bin_get_info (core->bin);
if (info) {
fileName = info->file;
} else {
int fd = r_io_fd_get_current (core->io);
RIODesc *desc = r_io_desc_get (core->io, fd);
fileName = desc? desc->name: NULL;
if (!info) {
eprintf ("r_bin_get_info: Cannot get bin info\n");
return 0;
}
const bool is_json = input[1] == 'j'; // "itj"
RList *old_file_hashes = NULL;
if (!r_bin_file_hash (core->bin, limit, fileName, &old_file_hashes)) {
eprintf ("r_bin_file_hash: Cannot get file hashes");
r_list_free (old_file_hashes);
return 0;
}
if (old_file_hashes && r_list_empty (old_file_hashes)) {
// clean the old hashes list to reduce comparison operations in case it is allocated but empty
r_list_free (old_file_hashes);
old_file_hashes = NULL;
}
if (!info) {
info = r_bin_get_info (core->bin);
}
if (!info) {
eprintf ("r_bin_get_info: Cannot get bin info");
r_list_free (old_file_hashes);
RList *new_file_hashes = r_bin_file_hash (core->bin, limit);
if (!new_file_hashes) {
eprintf ("r_bin_file_hash: Cannot get latest file hashes\n");
r_list_free (new_file_hashes);
return 0;
}
bool isInitialized = true;
bool equal = true;
// check are hashes changed
if (!r_list_empty (old_file_hashes) && !r_list_empty (info->file_hashes)) {
if (!is_equal_file_hashes (old_file_hashes, info->file_hashes, &equal)) {
eprintf ("is_equal_file_hashes: Cannot compare file hashes");
r_list_free (old_file_hashes);
return 0;
if (!info->file_hashes) {
info->file_hashes = new_file_hashes;
isInitialized = false;
} else {
// check are hashes changed
if (!r_list_empty (new_file_hashes) && !r_list_empty (info->file_hashes)) {
if (!is_equal_file_hashes (new_file_hashes, info->file_hashes, &equal)) {
eprintf ("is_equal_file_hashes: Cannot compare file hashes\n");
r_list_free (new_file_hashes);
return 0;
}
}
}
RBinFileHash *fh_old, *fh_new;
RListIter *hiter_old, *hiter_new;
const bool is_json = input[1] == 'j'; // "itj"
if (is_json) { // "itj"
PJ *pj = pj_new ();
if (!pj) {
eprintf ("JSON mode failed\n");
r_list_free (old_file_hashes);
r_list_free (new_file_hashes);
return 0;
}
pj_o (pj);
r_list_foreach (info->file_hashes, hiter_new, fh_new) {
pj_ks (pj, fh_new->type ? fh_new->type : "", fh_new->hex ? fh_new->hex : "");
r_list_foreach (info->file_hashes, hiter_old, fh_old) {
pj_ks (pj, fh_old->type, fh_old->hex);
}
if (!equal) {
// print old hashes prefixed with `o` character like `omd5` and `osha1`
r_list_foreach (old_file_hashes, hiter_old, fh_old) {
char *key = r_str_newf ("o%s", fh_old->type ? fh_old->type : "");
pj_ks (pj, key, fh_old->hex ? fh_old->hex : "");
// print new hashes prefixed with `n` character like `nmd5` and `nsha1`
r_list_foreach (new_file_hashes, hiter_new, fh_new) {
char *key = r_str_newf ("n%s", fh_new->type);
pj_ks (pj, key, fh_new->hex);
free (key);
}
}
@ -672,34 +658,40 @@ static int cmd_info(void *data, const char *input) {
} else { // "it"
if (!equal) {
eprintf ("File has been modified.\n");
hiter_new = r_list_iterator (info->file_hashes);
hiter_old = r_list_iterator (old_file_hashes);
while (r_list_iter_next(hiter_new) && r_list_iter_next (hiter_old)) {
fh_new = (RBinFileHash*)r_list_iter_get (hiter_new);
fh_old = (RBinFileHash*)r_list_iter_get (hiter_old);
if (strcmp (fh_new->type, fh_old->type)) {
eprintf ("Wrong file hashes structure");
bool isCompared = false;
r_list_foreach (info->file_hashes, hiter_old, fh_old) {
r_list_foreach (new_file_hashes, hiter_new, fh_new) {
if (!!strcmp (fh_new->type, fh_old->type)) {
continue;
}
if (!strcmp (fh_new->hex, fh_old->hex)) {
eprintf ("= %s %s\n", fh_new->type, fh_new->hex); // output one line because hash remains same `= hashtype hashval`
} else {
// output diff-like two lines, one with old hash val `- hashtype hashval` and one with new `+ hashtype hashval`
eprintf ("- %s %s\n+ %s %s\n",
fh_old->type, fh_old->hex,
fh_new->type, fh_new->hex);
}
isCompared = true;
break;
}
if (!strcmp (fh_new->hex, fh_old->hex)) {
eprintf ("= %s %s\n", fh_new->type, fh_new->hex); // output one line because hash remains same `= hashtype hashval`
} else {
// output diff-like two lines, one with old hash val `- hashtype hashval` and one with new `+ hashtype hashval`
eprintf ("- %s %s\n"
"+ %s %s\n",
fh_old->type, fh_old->hex,
fh_new->type, fh_new->hex);
if (!isCompared) {
eprintf ("= %s %s\n", fh_new->type, fh_new->hex);
}
isCompared = false;
}
} else { // hashes are equal
r_list_foreach (info->file_hashes, hiter_new, fh_new) {
r_cons_printf ("%s %s\n", fh_new->type ? fh_new->type : "", fh_new->hex ? fh_new->hex : "");
r_list_foreach (info->file_hashes, hiter_old, fh_old) {
r_cons_printf ("%s %s\n", fh_old->type, fh_old->hex);
}
}
newline = false;
}
if (!r_list_empty (old_file_hashes)) {
r_list_free (old_file_hashes);
if (isInitialized) {
r_list_free (new_file_hashes);
}
}
break;

View File

@ -762,7 +762,7 @@ R_API bool r_bin_file_set_cur_by_id(RBin *bin, ut32 bin_id);
R_API bool r_bin_file_set_cur_by_name(RBin *bin, const char *name);
R_API ut64 r_bin_file_delete_all(RBin *bin);
R_API bool r_bin_file_delete(RBin *bin, ut32 bin_id);
R_API bool r_bin_file_hash(RBin *bin, ut64 limit, const char *file, RList/*<RBinFileHash>*/ **old_file_hashes);
R_API RList *r_bin_file_hash(RBin *bin, ut64 limit);
R_API RBinPlugin *r_bin_file_cur_plugin(RBinFile *binfile);
R_API void r_bin_file_hash_free(RBinFileHash *fhash);

View File

@ -69,10 +69,27 @@ typedef struct r_pkcs7_container_t {
RPKCS7SignedData signedData;
} RCMS;
typedef struct {
RASN1String *type; //OID
RASN1Binary *data; // optional.
} SpcAttributeTypeAndOptionalValue;
typedef struct {
RX509AlgorithmIdentifier digestAlgorithm;
RASN1Binary *digest;
} SpcDigestInfo;
typedef struct {
SpcAttributeTypeAndOptionalValue data;
SpcDigestInfo messageDigest;
} SpcIndirectDataContent;
R_API RCMS *r_pkcs7_parse_cms(const ut8 *buffer, ut32 length);
R_API void r_pkcs7_free_cms(RCMS* container);
R_API char *r_pkcs7_cms_to_string(RCMS* container);
R_API PJ *r_pkcs7_cms_json(RCMS* container);
R_API SpcIndirectDataContent *r_pkcs7_parse_spcinfo(RCMS *cms);
R_API void r_pkcs7_free_spcinfo(SpcIndirectDataContent *spcinfo);
#ifdef __cplusplus
}

View File

@ -1221,8 +1221,15 @@ R_API int r_main_radare2(int argc, char **argv) {
if (compute_hashes && iod) {
// TODO: recall with limit=0 ?
ut64 limit = r_config_get_i (r->config, "bin.hashlimit");
(void)r_bin_file_hash (r->bin, limit, iod->name, NULL);
//eprintf ("WARNING: File hash not calculated\n");
RList *file_hashes = r_bin_file_hash (r->bin, limit);
if (file_hashes) {
if (r->bin->cur->o->info->file_hashes) {
r_list_join (r->bin->cur->o->info->file_hashes, file_hashes);
free (file_hashes);
} else {
r->bin->cur->o->info->file_hashes = file_hashes;
}
}
}
npath = r_config_get (r->config, "file.path");
if (!quiet && path && *path && npath && strcmp (path, npath)) {

View File

@ -633,3 +633,81 @@ R_API PJ *r_pkcs7_cms_json (RCMS *container) {
}
return pj;
}
static bool r_pkcs7_parse_spcdata(SpcAttributeTypeAndOptionalValue *data, RASN1Object *object) {
if (!data || !object || object->list.length < 1 ||
!object->list.objects[0]) {
return false;
}
data->type = r_asn1_stringify_oid (object->list.objects[0]->sector, object->list.objects[0]->length);
RASN1Object *obj1 = object->list.objects[1];
if (object->list.length > 1) {
if (obj1) {
data->data = r_asn1_create_binary (obj1->sector, obj1->length);
}
}
return true;
}
static bool r_pkcs7_parse_spcmessagedigest(SpcDigestInfo *messageDigest, RASN1Object *object) {
if (!messageDigest || !object || object->list.length < 2 ||
!object->list.objects[0] || !object->list.objects[1]) {
return false;
}
r_x509_parse_algorithmidentifier (&messageDigest->digestAlgorithm, object->list.objects[0]);
RASN1Object *obj1 = object->list.objects[1];
messageDigest->digest = r_asn1_create_binary (obj1->sector, obj1->length);
return true;
}
R_API SpcIndirectDataContent *r_pkcs7_parse_spcinfo(RCMS *cms) {
RASN1Object *object;
RASN1Binary *content;
SpcIndirectDataContent *spcinfo;
if (!cms) {
return NULL;
}
spcinfo = R_NEW0 (SpcIndirectDataContent);
if (!spcinfo) {
return NULL;
}
content = cms->signedData.contentInfo.content;
object = r_asn1_create_object (content->binary, content->length, content->binary);
if (!object || object->list.length < 2 || !object->list.objects ||
!object->list.objects[0] || !object->list.objects[1]) {
r_asn1_free_object (object);
free (spcinfo);
return NULL;
}
if (object->list.objects[0]) {
r_pkcs7_parse_spcdata (&spcinfo->data, object->list.objects[0]);
}
if (object->list.objects[1]) {
r_pkcs7_parse_spcmessagedigest (&spcinfo->messageDigest, object->list.objects[1]);
}
r_asn1_free_object (object);
return spcinfo;
}
static void r_pkcs7_free_spcdata(SpcAttributeTypeAndOptionalValue *data) {
if (data) {
r_asn1_free_string (data->type);
r_asn1_free_binary (data->data);
}
}
static void r_pkcs7_free_spcmessagedigest(SpcDigestInfo *messageDigest) {
if (messageDigest) {
r_asn1_free_binary (messageDigest->digest);
r_x509_free_algorithmidentifier (&messageDigest->digestAlgorithm);
}
}
R_API void r_pkcs7_free_spcinfo(SpcIndirectDataContent *spcinfo) {
if (spcinfo) {
r_pkcs7_free_spcdata (&spcinfo->data);
r_pkcs7_free_spcmessagedigest (&spcinfo->messageDigest);
}
}

View File

@ -0,0 +1,33 @@
NAME=check invalid authentihash
FILE=../bins/pe/signature.exe
EXPECT=<<EOF
false
authentihash c31534a14726a96a54602c3cb9eaa916412223d5
md5 23ea4cc8f6e59aa5121bdeb3394150ae
sha1 e2462a381cc60582efcf4dab129f4f08ff396bec
sha256 327ef49480f2fd20bb5f46f7f384ea1ae6ab405a16b17fc575a5e4598a42b570
{"authentihash":"c31534a14726a96a54602c3cb9eaa916412223d5","md5":"23ea4cc8f6e59aa5121bdeb3394150ae","sha1":"e2462a381cc60582efcf4dab129f4f08ff396bec","sha256":"327ef49480f2fd20bb5f46f7f384ea1ae6ab405a16b17fc575a5e4598a42b570"}
EOF
CMDS=<<EOF
k bin/cur/pe/is_authhash_valid
it
itj
EOF
RUN
NAME=check valid authentihash
FILE=../bins/pe/authentihash.exe
EXPECT=<<EOF
true
authentihash 2f425cda5b8d590f868a2f0cdbdae4d8c9d31bf7
md5 dbd0a3bf85cc041794480df9a8dd34a8
sha1 ae34b7b949997d6c65a1549cf234c53a7184a262
sha256 ea4b1a9b05b70c00e56d1939c3037d5aa07117ff871f01caa84f049f9766ae9e
{"authentihash":"2f425cda5b8d590f868a2f0cdbdae4d8c9d31bf7","md5":"dbd0a3bf85cc041794480df9a8dd34a8","sha1":"ae34b7b949997d6c65a1549cf234c53a7184a262","sha256":"ea4b1a9b05b70c00e56d1939c3037d5aa07117ff871f01caa84f049f9766ae9e"}
EOF
CMDS=<<EOF
k bin/cur/pe/is_authhash_valid
it
itj
EOF
RUN