mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-17 04:39:36 +00:00
Parse CodeSign blobs and compute sha1/sha256 in mach0 binaries (#11491)
- rabin2 -OC # wip requires proper refactoring and redesign
This commit is contained in:
parent
08f8e48ca1
commit
4bb4a2ce30
@ -406,12 +406,12 @@ static int rabin_do_operation(const char *op) {
|
||||
break;
|
||||
case 'C':
|
||||
{
|
||||
RBinFile *cur = r_bin_cur (bin);
|
||||
RBinFile *cur = r_bin_cur (bin);
|
||||
RBinPlugin *plg = r_bin_file_cur_plugin (cur);
|
||||
if (!plg) {
|
||||
//are we in xtr?
|
||||
// are we in xtr?
|
||||
if (cur->xtr_data) {
|
||||
//load the first one
|
||||
// load the first one
|
||||
RBinXtrData *xtr_data = r_list_get_n (cur->xtr_data, 0);
|
||||
if (!r_bin_file_object_new_from_xtr_data (bin, cur,
|
||||
UT64_MAX, r_bin_get_laddr (bin), xtr_data)) {
|
||||
@ -424,10 +424,12 @@ static int rabin_do_operation(const char *op) {
|
||||
}
|
||||
}
|
||||
if (plg->signature) {
|
||||
const char *sign = plg->signature (cur, rad == R_CORE_BIN_JSON);
|
||||
r_cons_println (sign);
|
||||
r_cons_flush ();
|
||||
free ((char*) sign);
|
||||
char *sign = plg->signature (cur, rad == R_CORE_BIN_JSON);
|
||||
if (sign) {
|
||||
r_cons_println (sign);
|
||||
r_cons_flush ();
|
||||
free (sign);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -737,6 +739,7 @@ int main(int argc, char **argv) {
|
||||
case 'O':
|
||||
op = optarg;
|
||||
set_action (R_BIN_REQ_OPERATION);
|
||||
r_sys_setenv ("RABIN2_CODESIGN_VERBOSE", "1");
|
||||
if (isBinopHelp (op)) {
|
||||
printf ("Usage: iO [expression]:\n"
|
||||
" e/0x8048000 change entrypoint\n"
|
||||
|
@ -2,7 +2,7 @@ include ../config.mk
|
||||
include ../../global.mk
|
||||
|
||||
NAME=r_bin
|
||||
DEPS=r_util r_io r_socket r_magic
|
||||
DEPS=r_util r_io r_socket r_magic r_hash
|
||||
|
||||
.PHONY: pre
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <r_types.h>
|
||||
#include <r_util.h>
|
||||
#include "mach0.h"
|
||||
#include <r_hash.h>
|
||||
|
||||
#define bprintf if (bin->verbose) eprintf
|
||||
|
||||
@ -12,7 +13,7 @@ typedef struct _ulebr {
|
||||
} ulebr;
|
||||
|
||||
// OMG; THIS SHOULD BE KILLED; this var exposes the local native endian, which is completely unnecessary
|
||||
static bool little_;
|
||||
static bool little_ = false;
|
||||
|
||||
static ut64 read_uleb128(ulebr *r, ut8 *end) {
|
||||
ut64 result = 0;
|
||||
@ -536,6 +537,127 @@ static int parse_dysymtab(struct MACH0_(obj_t)* bin, ut64 off) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *readString (ut8 *p, int off, int len) {
|
||||
if (off < 0 || off >= len) {
|
||||
return NULL;
|
||||
}
|
||||
return r_str_ndup ((const char *)p + off, len - off);
|
||||
}
|
||||
|
||||
static void parseCodeDirectory (RBuffer *b, int offset, int datasize) {
|
||||
typedef struct __CodeDirectory {
|
||||
uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */
|
||||
uint32_t length; /* total length of CodeDirectory blob */
|
||||
uint32_t version; /* compatibility version */
|
||||
uint32_t flags; /* setup and mode flags */
|
||||
uint32_t hashOffset; /* offset of hash slot element at index zero */
|
||||
uint32_t identOffset; /* offset of identifier string */
|
||||
uint32_t nSpecialSlots; /* number of special hash slots */
|
||||
uint32_t nCodeSlots; /* number of ordinary (code) hash slots */
|
||||
uint32_t codeLimit; /* limit to main image signature range */
|
||||
uint8_t hashSize; /* size of each hash in bytes */
|
||||
uint8_t hashType; /* type of hash (cdHashType* constants) */
|
||||
uint8_t platform; /* unused (must be zero) */
|
||||
uint8_t pageSize; /* log2(page size in bytes); 0 => infinite */
|
||||
uint32_t spare2; /* unused (must be zero) */
|
||||
/* followed by dynamic content as located by offset fields above */
|
||||
uint32_t scatterOffset;
|
||||
uint32_t teamIDOffset;
|
||||
uint32_t spare3;
|
||||
ut64 codeLimit64;
|
||||
ut64 execSegBase;
|
||||
ut64 execSegLimit;
|
||||
ut64 execSegFlags;
|
||||
} CS_CodeDirectory;
|
||||
ut64 off = offset;
|
||||
int psize = datasize;
|
||||
ut8 *p = calloc (1, psize);
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
eprintf ("Offset: 0x%08"PFMT64x"\n", off);
|
||||
r_buf_read_at (b, off, p, datasize);
|
||||
CS_CodeDirectory cscd = {0};
|
||||
#define READFIELD(x) cscd.x = r_read_ble32 (p + r_offsetof (CS_CodeDirectory, x), 1)
|
||||
#define READFIELD8(x) cscd.x = p[r_offsetof (CS_CodeDirectory, x)]
|
||||
READFIELD (length);
|
||||
READFIELD (version);
|
||||
READFIELD (flags);
|
||||
READFIELD (hashOffset);
|
||||
READFIELD (identOffset);
|
||||
READFIELD (nSpecialSlots);
|
||||
READFIELD (nCodeSlots);
|
||||
READFIELD (hashSize);
|
||||
READFIELD (teamIDOffset);
|
||||
READFIELD8 (hashType);
|
||||
READFIELD (pageSize);
|
||||
READFIELD (codeLimit);
|
||||
eprintf ("Version: %x\n", cscd.version);
|
||||
eprintf ("Flags: %x\n", cscd.flags);
|
||||
eprintf ("Length: %d\n", cscd.length);
|
||||
eprintf ("PageSize: %d\n", cscd.pageSize);
|
||||
eprintf ("hashOffset: %d\n", cscd.hashOffset);
|
||||
eprintf ("codeLimit: %d\n", cscd.codeLimit);
|
||||
eprintf ("hashSize: %d\n", cscd.hashSize);
|
||||
eprintf ("hashType: %d\n", cscd.hashType);
|
||||
char *identity = readString (p, cscd.identOffset, psize);
|
||||
eprintf ("Identity: %s\n", identity);
|
||||
char *teamId = readString (p, cscd.teamIDOffset, psize);
|
||||
eprintf ("TeamID: %s\n", teamId);
|
||||
eprintf ("CodeSlots: %d\n", cscd.nCodeSlots);
|
||||
free (identity);
|
||||
free (teamId);
|
||||
|
||||
int hashSize = 20; // SHA1 is default
|
||||
int algoType = R_HASH_SHA1;
|
||||
switch (cscd.hashType) {
|
||||
case 0: // SHA1 == 20 bytes
|
||||
case 1: // SHA1 == 20 bytes
|
||||
hashSize = 20;
|
||||
algoType = R_HASH_SHA1;
|
||||
break;
|
||||
case 2: // SHA256 == 32 bytes
|
||||
hashSize = 32;
|
||||
algoType = R_HASH_SHA256;
|
||||
break;
|
||||
}
|
||||
ut8 *hash = p + cscd.hashOffset;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
RHash *ctx = r_hash_new (true, algoType);
|
||||
for (j = 0; j < cscd.nCodeSlots; j++) {
|
||||
int fof = 4096 * j;
|
||||
int idx = j * hashSize;
|
||||
eprintf ("0x%08"PFMT64x" ", off + cscd.hashOffset + idx);
|
||||
for (k = 0; k < hashSize; k++) {
|
||||
eprintf ("%02x", hash[idx + k]);
|
||||
}
|
||||
ut8 fofbuf[4096];
|
||||
int fofsz = R_MIN (sizeof (fofbuf), cscd.codeLimit - fof);
|
||||
r_buf_read_at (b, fof, fofbuf, sizeof (fofbuf));
|
||||
r_hash_do_begin (ctx, algoType);
|
||||
if (algoType == R_HASH_SHA1) {
|
||||
r_hash_do_sha1 (ctx, fofbuf, fofsz);
|
||||
} else {
|
||||
r_hash_do_sha256 (ctx, fofbuf, fofsz);
|
||||
}
|
||||
r_hash_do_end (ctx, algoType);
|
||||
if (memcmp (hash + idx, ctx->digest, hashSize)) {
|
||||
eprintf (" wx ");
|
||||
int i;
|
||||
for (i = 0; i < hashSize;i++) {
|
||||
eprintf ("%02x", ctx->digest[i]);
|
||||
}
|
||||
} else {
|
||||
eprintf (" OK");
|
||||
}
|
||||
eprintf ("\n");
|
||||
}
|
||||
r_hash_free (ctx);
|
||||
free (p);
|
||||
}
|
||||
|
||||
// parse the Load Command
|
||||
static bool parse_signature(struct MACH0_(obj_t) *bin, ut64 off) {
|
||||
int i,len;
|
||||
ut32 data;
|
||||
@ -566,7 +688,18 @@ static bool parse_signature(struct MACH0_(obj_t) *bin, ut64 off) {
|
||||
super.blob.magic = r_read_ble32 (bin->b->buf + data, little_);
|
||||
super.blob.length = r_read_ble32 (bin->b->buf + data + 4, little_);
|
||||
super.count = r_read_ble32 (bin->b->buf + data + 8, little_);
|
||||
for (i = 0; i < super.count; ++i) {
|
||||
char *verbose = r_sys_getenv ("RABIN2_CODESIGN_VERBOSE");
|
||||
bool isVerbose = false;
|
||||
if (verbose) {
|
||||
isVerbose = *verbose;
|
||||
free (verbose);
|
||||
}
|
||||
// to dump all certificates
|
||||
// [0x00053f75]> b 5K;/x 30800609;wtf @@ hit*
|
||||
// then do this:
|
||||
// $ openssl asn1parse -inform der -in a|less
|
||||
// $ openssl pkcs7 -inform DER -print_certs -text -in a
|
||||
for (i = 0; i < super.count; i++) {
|
||||
if ((ut8 *)(bin->b->buf + data + i) > (ut8 *)(bin->b->buf + bin->size)) {
|
||||
bin->signature = (ut8 *)strdup ("Malformed entitlement");
|
||||
break;
|
||||
@ -578,7 +711,9 @@ static bool parse_signature(struct MACH0_(obj_t) *bin, ut64 off) {
|
||||
}
|
||||
idx.type = r_read_ble32 (&bi.type, little_);
|
||||
idx.offset = r_read_ble32 (&bi.offset, little_);
|
||||
if (idx.type == CSSLOT_ENTITLEMENTS) {
|
||||
switch (idx.type) {
|
||||
case CSSLOT_ENTITLEMENTS:
|
||||
if (true || isVerbose) {
|
||||
ut64 off = data + idx.offset;
|
||||
if (off > bin->size || off + sizeof (struct blob_t) > bin->size) {
|
||||
bin->signature = (ut8 *)strdup ("Malformed entitlement");
|
||||
@ -590,19 +725,65 @@ static bool parse_signature(struct MACH0_(obj_t) *bin, ut64 off) {
|
||||
len = entitlements.length - sizeof (struct blob_t);
|
||||
if (len <= bin->size && len > 1) {
|
||||
bin->signature = calloc (1, len + 1);
|
||||
if (bin->signature) {
|
||||
ut8 *src = bin->b->buf + off + sizeof (struct blob_t);
|
||||
if (off + sizeof (struct blob_t) + len < bin->b->length) {
|
||||
memcpy (bin->signature, src, len);
|
||||
bin->signature[len] = '\0';
|
||||
return true;
|
||||
}
|
||||
bin->signature = (ut8 *)strdup ("Malformed entitlement");
|
||||
if (!bin->signature) {
|
||||
return false;
|
||||
}
|
||||
ut8 *src = bin->b->buf + off + sizeof (struct blob_t);
|
||||
if (off + sizeof (struct blob_t) + len < bin->b->length) {
|
||||
memcpy (bin->signature, src, len);
|
||||
bin->signature[len] = '\0';
|
||||
return true;
|
||||
}
|
||||
bin->signature = (ut8 *)strdup ("Malformed entitlement");
|
||||
return true;
|
||||
} else {
|
||||
bin->signature = (ut8 *)strdup ("Malformed entitlement");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CSSLOT_CODEDIRECTORY:
|
||||
if (isVerbose) {
|
||||
parseCodeDirectory (bin->b, data + idx.offset, link.datasize);
|
||||
}
|
||||
break;
|
||||
case 0x10000:
|
||||
// TODO
|
||||
break;
|
||||
case CSSLOT_REQUIREMENTS:
|
||||
#if 0
|
||||
// eprintf ("[TODO] CSSLOT_REQUIREMENTS\n");
|
||||
{
|
||||
ut8 p[5000];
|
||||
r_buf_read_at (bin->b, data + idx.offset + 0, p, sizeof (p));
|
||||
ut32 count = r_read_ble32 (p, 1);
|
||||
int i = 0;
|
||||
ut32 *words = (ut32*)p;
|
||||
// $ openssl asn1parse -inform der -in x
|
||||
int fd = open ("DUMP", O_RDWR|O_CREAT, 0644);
|
||||
if (fd != -1) {
|
||||
write (fd, words, sizeof(p));
|
||||
close (fd);
|
||||
}
|
||||
#if 0
|
||||
for (i = 0; i < count; i++) {
|
||||
int n = i * 3;
|
||||
eprintf ("Type (0x%08x) Offset (0x%08x) Expression (0x%08x)\n",
|
||||
words[n], words[n+1], words[n+2]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#if 0
|
||||
case CSSLOT_INFOSLOT: // 1;
|
||||
case CSSLOT_RESOURCEDIR: // 3;
|
||||
case CSSLOT_APPLICATION: // 4;
|
||||
// TODO
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
eprintf ("Unknown Code signature slot %d\n", idx.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bin->signature) {
|
||||
@ -2480,9 +2661,9 @@ void MACH0_(mach_headerfields)(RBinFile *file) {
|
||||
break;
|
||||
case LC_CODE_SIGNATURE:
|
||||
{
|
||||
ut32 *words = (ut32*)r_buf_get_at (buf, addr + 4, NULL);
|
||||
printf ("0x%08"PFMT64x" dataoff 0x%08x\n", addr + 4, words[0]);
|
||||
printf ("0x%08"PFMT64x" datasize %d\n", addr + 8, words[1]);
|
||||
ut32 *words = (ut32*)r_buf_get_at (buf, addr, NULL);
|
||||
printf ("0x%08"PFMT64x" dataoff 0x%08x\n", addr, words[0]);
|
||||
printf ("0x%08"PFMT64x" datasize %d\n", addr + 4, words[1]);
|
||||
printf ("# wtf mach0.sign %d @ 0x%x\n", words[1], words[0]);
|
||||
}
|
||||
break;
|
||||
|
@ -12,10 +12,16 @@
|
||||
|
||||
#define CSMAGIC_CODEDIRECTORY 0xfade0c02
|
||||
#define CSMAGIC_EMBEDDED_SIGNATURE 0xfade0cc0
|
||||
#define CSMAGIC_DETACHED_SIGNATURE 0xfade0cc1 /* multi-arch collection of embedded signatures */
|
||||
#define CSMAGIC_ENTITLEMENTS 0xfade7171
|
||||
#define CSMAGIC_REQUIREMENT 0xfade0c00 /* single Requirement blob */
|
||||
#define CSMAGIC_REQUIREMENTS 0xfade0c01 /* Requirements vector (internal requirements) */
|
||||
|
||||
#define CSSLOT_CODEDIRECTORY 0
|
||||
#define CSSLOT_INFOSLOT 1
|
||||
#define CSSLOT_REQUIREMENTS 2
|
||||
#define CSSLOT_RESOURCEDIR 3
|
||||
#define CSSLOT_APPLICATION 4
|
||||
#define CSSLOT_ENTITLEMENTS 5
|
||||
|
||||
struct section_t {
|
||||
|
@ -123,6 +123,7 @@ r_bin = library('r_bin', files,
|
||||
dependencies: [
|
||||
r_util_dep,
|
||||
r_io_dep,
|
||||
r_hash_dep,
|
||||
r_magic_dep,
|
||||
r_socket_dep,
|
||||
sdb_dep,
|
||||
|
@ -247,6 +247,7 @@ static const char *help_msg_pc[] = {
|
||||
"pcs", "", "string",
|
||||
"pcS", "", "shellscript that reconstructs the bin",
|
||||
"pcw", "", "C words (4 byte)",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *help_msg_pd[] = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user