/* radare - LGPL - Copyright 2009-2016 - nibble, pancake */ #include #include #include #include #include "mach0/fatmach0.h" #include "mach0/mach0.h" static RBinXtrData * extract(RBin *bin, int idx); static RList * extractall(RBin *bin); static RBinXtrData * oneshot(RBin *bin, const ut8 *buf, ut64 size, int idx); static RList * oneshotall(RBin *bin, const ut8 *buf, ut64 size ); static int free_xtr (void *xtr_obj) ; static int check(RBin *bin) { ut8 *h, buf[4]; int off, ret = false; RMmap *m = r_file_mmap (bin->file, false, 0); if (!m || !m->buf) { r_file_mmap_free (m); return false; } h = m->buf; if (m->len >= 0x300 && !memcmp (h, "\xca\xfe\xba\xbe", 4)) { // XXX assuming BE off = r_read_at_be32 (h, 4 * sizeof (int)); if (off > 0 && off < m->len) { memcpy (buf, h + off, 4); if (!memcmp (buf, "\xce\xfa\xed\xfe", 4) || !memcmp (buf, "\xfe\xed\xfa\xce", 4) || !memcmp (buf, "\xfe\xed\xfa\xcf", 4) || !memcmp (buf, "\xcf\xfa\xed\xfe", 4)) ret = true; } } r_file_mmap_free (m); return ret; } static int check_bytes(const ut8* bytes, ut64 sz) { const ut8 *h; ut8 buf[4]; int off, ret = false; if (!bytes || sz < 0x300) { return false; } // XXX assuming BE off = r_read_at_be32 (bytes, 4 * sizeof (int)); h = bytes; if (sz >= 0x300 && !memcmp (h, "\xca\xfe\xba\xbe", 4)) { // XXX assuming BE off = r_read_at_be32 (h, 4 * sizeof (int)); if (off > 0 && off < sz) { memcpy (buf, h+off, 4); if (!memcmp (buf, "\xce\xfa\xed\xfe", 4) || !memcmp (buf, "\xfe\xed\xfa\xce", 4) || !memcmp (buf, "\xfe\xed\xfa\xcf", 4) || !memcmp (buf, "\xcf\xfa\xed\xfe", 4)) ret = true; } } return ret; } // TODO: destroy must be void? static int destroy(RBin *bin) { return free_xtr (bin->cur->xtr_obj); } static int free_xtr (void *xtr_obj) { r_bin_fatmach0_free ((struct r_bin_fatmach0_obj_t*)xtr_obj); return true; } static bool load(RBin *bin) { return ((bin->cur->xtr_obj = r_bin_fatmach0_new (bin->file)) != NULL); } static int size(RBin *bin) { // TODO return 0; } static inline void fill_metadata_info_from_hdr(RBinXtrMetadata *meta, struct MACH0_(mach_header) *hdr) { meta->arch = MACH0_(get_cputype_from_hdr) (hdr); meta->bits = MACH0_(get_bits_from_hdr) (hdr); meta->machine = MACH0_(get_cpusubtype_from_hdr) (hdr); meta->type = MACH0_(get_filetype_from_hdr) (hdr); meta->libname = NULL; } static RBinXtrData * extract(RBin* bin, int idx) { int narch; RBinXtrData * res = NULL; struct r_bin_fatmach0_obj_t *fb = bin->cur->xtr_obj; struct r_bin_fatmach0_arch_t *arch; struct MACH0_(mach_header) *hdr = NULL; arch = r_bin_fatmach0_extract (fb, idx, &narch); if (!arch) return res; RBinXtrMetadata *metadata = R_NEW0 (RBinXtrMetadata); if (!metadata) { r_buf_free (arch->b); free (arch); return NULL; } hdr = MACH0_(get_hdr_from_bytes) (arch->b); if (!hdr) { free (arch); free (hdr); return NULL; } fill_metadata_info_from_hdr (metadata, hdr); res = r_bin_xtrdata_new (arch->b, arch->offset, arch->size, narch, metadata, bin->sdb); r_buf_free (arch->b); free (arch); free (hdr); return res; } static RBinXtrData * oneshot(RBin *bin, const ut8 *buf, ut64 size, int idx) { struct r_bin_fatmach0_obj_t *fb; struct r_bin_fatmach0_arch_t *arch; RBinXtrData *res = NULL; int narch; struct MACH0_(mach_header) *hdr; if (!bin || !bin->cur) { return NULL; } if (!bin->cur->xtr_obj) { bin->cur->xtr_obj = r_bin_fatmach0_from_bytes_new (buf, size); } fb = bin->cur->xtr_obj; arch = r_bin_fatmach0_extract (fb, idx, &narch); if (!arch) { return res; } RBinXtrMetadata *metadata = R_NEW0 (RBinXtrMetadata); if (!metadata) { free (arch); return NULL; } hdr = MACH0_(get_hdr_from_bytes) (arch->b); if (!hdr) { free (arch); free (metadata); return NULL; } fill_metadata_info_from_hdr (metadata, hdr); res = r_bin_xtrdata_new (arch->b, arch->offset, arch->size, narch, metadata, bin->sdb); r_buf_free (arch->b); free (arch); free (hdr); return res; } static RList * extractall(RBin *bin) { RList *res = NULL; int narch, i = 0; RBinXtrData *data = NULL; data = extract (bin, i); if (!data) return res; // XXX - how do we validate a valid narch? narch = data->file_count; res = r_list_newf (r_bin_xtrdata_free); r_list_append (res, data); for (i = 1; data && i < narch; i++) { data = NULL; data = extract (bin, i); r_list_append (res, data); } return res; } static RList * oneshotall(RBin *bin, const ut8 *buf, ut64 size) { RList *res = NULL; int narch, i = 0; RBinXtrData *data = oneshot (bin, buf, size, i); if (!data) return res; // XXX - how do we validate a valid narch? narch = data->file_count; res = r_list_newf (r_bin_xtrdata_free); r_list_append (res, data); for (i = 1; data && i < narch; i++) { data = NULL; data = oneshot (bin, buf, size, i); r_list_append (res, data); } return res; } struct r_bin_xtr_plugin_t r_bin_xtr_plugin_fatmach0 = { .name = "fatmach0", .desc = "fat mach0 bin extractor plugin", .license = "LGPL3", .check = &check, .load = &load, .size = &size, .extract = &extract, .extractall = &extractall, .destroy = &destroy, .extract_from_bytes = &oneshot, .extractall_from_bytes = &oneshotall, .free_xtr = &free_xtr, .check_bytes = &check_bytes, }; #ifndef CORELIB struct r_lib_struct_t radare_plugin = { .type = R_LIB_TYPE_BIN_XTR, .data = &r_bin_xtr_plugin_fatmach0, .version = R2_VERSION }; #endif