5 #include "../../i/private.h"
8 #define RO_META (1 << 0)
9 #define MAX_CLASS_NAME_LEN 256
12 #define FAST_DATA_MASK 0x00007ffffffffff8UL
14 #define FAST_DATA_MASK 0xfffffffcUL
17 #define METHOD_LIST_FLAG_IS_SMALL 0x80000000
18 #define METHOD_LIST_FLAG_IS_PREOPT 0x3
19 #define METHOD_LIST_ENTSIZE_FLAG_MASK 0xffff0003
21 #define RO_DATA_PTR(x) ((x)&FAST_DATA_MASK)
23 struct MACH0_(SMethodList) {
29 struct MACH0_(SMethod) {
35 struct MACH0_(SClass) {
43 struct MACH0_(SClassRoT) {
59 struct MACH0_(SProtocolList) {
64 struct MACH0_(SProtocol) {
75 struct MACH0_(SIVarList) {
81 struct MACH0_(SIVar) {
89 struct MACH0_(SObjcProperty) {
94 struct MACH0_(SObjcPropertyList) {
100 struct MACH0_(SCategory) {
122 struct MACH0_(obj_t) *
bin = (
struct MACH0_(obj_t) *)bf->
o->
bin_obj;
123 if (
bin->hdr.cputype == 12) {
124 if (
bin->hdr.cpusubtype == 9) {
141 struct MACH0_(obj_t) *
bin = (
struct MACH0_(obj_t) *)obj->
bin_obj;
146 const RzList *sctns =
bin->sections_cache;
155 rz_list_foreach (sctns,
iter,
s) {
156 if (
addr >=
s->vaddr && addr < s->vaddr +
s->vsize) {
161 *left =
s->vsize - (
addr -
s->vaddr);
189 return a->offset -
b->offset;
193 struct MACH0_(SIVarList) il = { 0 };
194 struct MACH0_(SIVar)
i;
202 ut8 sivarlist[
sizeof(
struct MACH0_(SIVarList))] = { 0 };
203 ut8 sivar[
sizeof(
struct MACH0_(SIVar))] = { 0 };
214 if (
r + left <
r ||
r +
sizeof(
struct MACH0_(SIVarList)) <
r) {
220 if (
r +
sizeof(
struct MACH0_(SIVarList)) > bf->
size) {
223 if (left <
sizeof(
struct MACH0_(SIVarList))) {
229 if (
len !=
sizeof(
struct MACH0_(SIVarList))) {
233 il.entsize =
rz_read_ble(&sivarlist[0], bigendian, 32);
234 il.count =
rz_read_ble(&sivarlist[4], bigendian, 32);
235 p +=
sizeof(
struct MACH0_(SIVarList));
236 offset +=
sizeof(
struct MACH0_(SIVarList));
238 for (j = 0; j < il.count; j++) {
245 if (
r + left <
r ||
r +
sizeof(
struct MACH0_(SIVar)) <
r) {
254 if (left <
sizeof(
struct MACH0_(SIVar))) {
260 if (
len !=
sizeof(
struct MACH0_(SIVar))) {
280 if (offset_at > bf->
size) {
283 if (offset_at +
sizeof(ivar_offset) > bf->
size) {
286 if (offset_at != 0 && left >=
sizeof(
mach0_ut)) {
293 field->
offset = ivar_offset;
297 struct MACH0_(obj_t) *
bin = (
struct MACH0_(obj_t) *)bf->
o->
bin_obj;
305 if (
bin->has_crypto) {
307 left = strlen(
name) + 1;
326 struct MACH0_(obj_t) *
bin = (
struct MACH0_(obj_t) *)bf->
o->
bin_obj;
327 int is_crypted =
bin->has_crypto;
335 if (is_crypted == 1) {
356 p +=
sizeof(
struct MACH0_(SIVar));
357 offset +=
sizeof(
struct MACH0_(SIVar));
359 if (!rz_list_empty(klass->
fields)) {
365 isa_field->
type =
strdup(
"struct objc_class *");
366 isa_field->
vaddr = 0;
376 struct MACH0_(SObjcPropertyList) opl;
377 struct MACH0_(SObjcProperty)
op;
384 ut8 sopl[
sizeof(
struct MACH0_(SObjcPropertyList))] = { 0 };
385 ut8 sop[
sizeof(
struct MACH0_(SObjcProperty))] = { 0 };
396 memset(&opl,
'\0',
sizeof(
struct MACH0_(SObjcPropertyList)));
397 if (
r + left <
r ||
r +
sizeof(
struct MACH0_(SObjcPropertyList)) <
r) {
403 if (
r +
sizeof(
struct MACH0_(SObjcPropertyList)) > bf->
size) {
406 if (left <
sizeof(
struct MACH0_(SObjcPropertyList))) {
412 if (
len !=
sizeof(
struct MACH0_(SObjcPropertyList))) {
417 opl.entsize =
rz_read_ble(&sopl[0], bigendian, 32);
420 p +=
sizeof(
struct MACH0_(SObjcPropertyList));
421 offset +=
sizeof(
struct MACH0_(SObjcPropertyList));
422 for (j = 0; j < opl.count; j++) {
434 if (
r + left <
r ||
r +
sizeof(
struct MACH0_(SObjcProperty)) <
r) {
440 if (
r +
sizeof(
struct MACH0_(SObjcProperty)) > bf->
size) {
444 if (left <
sizeof(
struct MACH0_(SObjcProperty))) {
450 if (
len !=
sizeof(
struct MACH0_(SObjcProperty))) {
458 struct MACH0_(obj_t) *
bin = (
struct MACH0_(obj_t) *)bf->
o->
bin_obj;
465 if (
bin->has_crypto) {
467 left = strlen(
name) + 1;
485 struct MACH0_(obj_t) *
bin = (
struct MACH0_(obj_t) *) bf->
o->
bin_obj;
486 int is_crypted =
bin->has_crypto;
491 if (is_crypted == 1) {
493 left = strlen (
name) + 1;
505 p +=
sizeof(
struct MACH0_(SObjcProperty));
506 offset +=
sizeof(
struct MACH0_(SObjcProperty));
517 struct MACH0_(SMethodList) ml;
524 ut8 sml[
sizeof(
struct MACH0_(SMethodList))] = { 0 };
525 ut8 sm[
sizeof(
struct MACH0_(SMethod))] = { 0 };
539 if (
r + left <
r ||
r +
sizeof(
struct MACH0_(SMethodList)) <
r) {
545 if (
r +
sizeof(
struct MACH0_(SMethodList)) > bf->
size) {
548 if (left <
sizeof(
struct MACH0_(SMethodList))) {
554 if (
len !=
sizeof(
struct MACH0_(SMethodList))) {
560 if (ml.count < 1 || ml.count >
ST32_MAX) {
568 ut8 mlflags = ml.entsize & 0x3;
570 p +=
sizeof(
struct MACH0_(SMethodList));
571 offset +=
sizeof(
struct MACH0_(SMethodList));
573 size_t read_size = is_small ? 3 *
sizeof(
ut32) :
sizeof(
struct MACH0_(SMethod));
575 for (
i = 0;
i < ml.count;
i++) {
584 struct MACH0_(SMethod)
m;
586 if (
r + left <
r ||
r + read_size <
r) {
592 if (
r + read_size > bf->
size) {
595 if (left < read_size) {
601 if (
len != read_size) {
615 name =
p + name_offset;
631 m.types =
p + types_offset + 4;
633 m.imp =
p + imp_offset + 8;
638 struct MACH0_(obj_t) *
bin = (
struct MACH0_(obj_t) *)bf->
o->
bin_obj;
645 if (
bin->has_crypto) {
647 left = strlen(
name) + 1;
663 struct MACH0_(obj_t) *
bin = (
struct MACH0_(obj_t) *)bf->
o->
bin_obj;
667 if (
r + left < r || r > bf->
size ||
r + left > bf->
size) {
670 if (
bin->has_crypto) {
671 rtype =
strdup(
"some_encrypted_data");
672 left = strlen(rtype) + 1;
690 if (!method->
vaddr) {
699 if (method->
vaddr & 1) {
718 struct MACH0_(SProtocolList)
pl = { 0 };
719 struct MACH0_(SProtocol)
pc;
720 char *class_name =
NULL;
725 ut8 spl[
sizeof(
struct MACH0_(SProtocolList))] = { 0 };
726 ut8 spc[
sizeof(
struct MACH0_(SProtocol))] = { 0 };
737 if (
r + left <
r ||
r +
sizeof(
struct MACH0_(SProtocolList)) <
r) {
743 if (
r +
sizeof(
struct MACH0_(SProtocolList)) > bf->
size) {
746 if (left <
sizeof(
struct MACH0_(SProtocolList))) {
752 if (
len !=
sizeof(
struct MACH0_(SProtocolList))) {
758 p +=
sizeof(
struct MACH0_(SProtocolList));
759 offset +=
sizeof(
struct MACH0_(SProtocolList));
760 for (
i = 0;
i <
pl.count;
i++) {
773 if (left <
sizeof(
ut32)) {
788 if (
r + left <
r ||
r +
sizeof(
struct MACH0_(SProtocol)) <
r) {
794 if (
r +
sizeof(
struct MACH0_(SProtocol)) > bf->
size) {
797 if (left <
sizeof(
struct MACH0_(SProtocol))) {
803 if (
len !=
sizeof(
struct MACH0_(SProtocol))) {
827 struct MACH0_(obj_t) *
bin = (
struct MACH0_(obj_t) *)bf->
o->
bin_obj;
834 if (
bin->has_crypto) {
836 left = strlen(
name) + 1;
853 if (
pc.instanceMethods > 0) {
856 if (
pc.classMethods > 0) {
876 char *ret, *klass, *
module;
877 if (!strncmp(
s,
"_TtC", 4)) {
883 modlen = strlen(
s +
off);
884 if (!
len ||
len >= modlen) {
889 if (
s[
skip] ==
'P') {
896 modlen = strlen(kstr);
897 if (!
len ||
len >= modlen) {
912 struct MACH0_(obj_t) *
bin;
933 if ((
r + left) <
r || (
r +
sizeof(
sc)) <
r) {
939 if (
r +
sizeof(
sc) > bf->
size) {
942 if (left <
sizeof(
sc)) {
946 if (
len !=
sizeof(
sc)) {
954 if (
r + left <
r ||
r +
sizeof(
sc) <
r) {
960 if (
r +
sizeof(
sc) > bf->
size) {
963 if (left <
sizeof(
sc)) {
967 #ifdef RZ_BIN_MACH064
972 if (
len !=
sizeof(
sc)) {
978 if (left < 1 ||
r + left <
r) {
984 if (
bin->has_crypto) {
985 return strdup(
"some_encrypted_data");
991 if (rc != name_len) {
1007 struct MACH0_(obj_t) *
bin;
1008 struct MACH0_(SClassRoT) cro = { 0 };
1013 ut8 scro[
sizeof(
struct MACH0_(SClassRoT))] = { 0 };
1025 if (
r + left <
r ||
r +
sizeof(cro) <
r) {
1028 if (
r > bf->
size ||
r +
sizeof(cro) >= bf->
size) {
1031 if (
r +
sizeof(cro) > bf->
size) {
1036 if (left <
sizeof(cro)) {
1051 #ifdef RZ_BIN_MACH064
1070 if ((
r =
va2pa(cro.name,
NULL, &left, bf))) {
1071 if (left < 1 ||
r + left <
r) {
1077 if (
bin->has_crypto) {
1079 left = strlen(klass->
name) + 1;
1085 if (rc != name_len) {
1095 #ifdef RZ_BIN_MACH064
1096 sdb_set(
bin->kv,
sdb_fmt(
"objc_class.format"),
"lllll isa super cache vtable data", 0);
1098 sdb_set(
bin->kv,
sdb_fmt(
"objc_class.format"),
"xxxxx isa super cache vtable data", 0);
1101 if (cro.baseMethods > 0) {
1105 if (cro.baseProtocols > 0) {
1109 if (cro.ivars > 0) {
1113 if (cro.baseProperties > 0) {
1117 if (is_meta_class) {
1118 *is_meta_class = (cro.flags &
RO_META) ? 1 : 0;
1128 struct MACH0_(SClass)
c = { 0 };
1129 const int size =
sizeof(
struct MACH0_(SClass));
1132 ut32 is_meta_class = 0;
1135 ut8 sc[
sizeof(
struct MACH0_(SClass))] = { 0 };
1138 if (!bf || !bf->o || !bf->o->info) {
1141 bigendian = bf->o->info->big_endian;
1145 if ((
r + left) <
r || (
r +
size) <
r) {
1151 if (
r +
size > bf->size) {
1155 RZ_LOG_ERROR(
"Cannot parse obj class info (out of bounds)\n");
1174 klass->addr =
c.isa;
1178 struct reloc_t reloc_at_class_addr;
1182 const char *_objc_class =
"_OBJC_CLASS_$_";
1183 const int _objc_class_len = strlen(_objc_class);
1186 target_class_name += _objc_class_len;
1187 klass->super =
strdup(target_class_name);
1194 if (q(
c.data + n_value) & 7) {
1198 if (!is_meta_class && !dupe) {
1202 (
c.isa + isa_n_value, bf,
buf, klass,
true,
relocs, oi);
1209 bool is_swift =
false;
1216 rz_list_foreach (bf->
o->
libs,
iter, lib) {
1217 if (strstr (lib,
"libswift")) {
1229 if (!strncmp (
str->string,
"_TtC", 4)) {
1245 ut64 num_of_unnamed_class = 0;
1249 bool is_found =
false;
1260 if (!bf->o->bin_obj || !bf->o->info) {
1263 bigendian = bf->o->info->big_endian;
1304 goto get_classes_error;
1311 goto get_classes_error;
1323 goto get_classes_error;
1328 goto get_classes_error;
1333 goto get_classes_error;
1336 if (paddr > bf->size || paddr +
size > bf->size) {
1337 goto get_classes_error;
1339 if (paddr +
size < paddr) {
1340 goto get_classes_error;
1344 goto get_classes_error;
1352 goto get_classes_error;
1354 num_of_unnamed_class++;
1374 bool is_found =
false;
1407 for (
i = 0;
i < s_size;
i += ptr_size) {
1411 if ((s_size -
i) < ptr_size) {
1448 struct MACH0_(SCategory)
c = { 0 };
1449 const int size =
sizeof(
struct MACH0_(SCategory));
1453 bool bigendian = bf->o->info->big_endian;
1454 ut8 sc[
sizeof(
struct MACH0_(SCategory))] = { 0 };
1460 if ((
r + left) <
r || (
r +
size) <
r) {
1463 if (
r > bf->size ||
r + left > bf->size) {
1466 if (
r +
size > bf->size) {
1470 RZ_LOG_ERROR(
"Cannot parse obj category info out of bounds\n");
1495 if (!category_name) {
1499 char *target_class_name =
NULL;
1500 if (
c.targetClass == 0) {
1505 struct reloc_t reloc_at_class_addr;
1506 reloc_at_class_addr.
addr =
p + ptr_size;
1513 const char *_objc_class =
"_OBJC_CLASS_$_";
1514 const int _objc_class_len = strlen(_objc_class);
1520 target_class_name += _objc_class_len;
1521 klass->name =
rz_str_newf(
"%s(%s)", target_class_name, category_name);
1523 mach0_ut ro_data_field =
c.targetClass + 4 * ptr_size;
1530 #ifdef RZ_BIN_MACH064
1540 char *demangled =
NULL;
1541 if (target_class_name) {
1553 if (
c.instanceMethods > 0) {
1557 if (
c.classMethods > 0) {
1561 if (
c.protocols > 0) {
1565 if (
c.properties > 0) {
1574 size_t ptr_size =
sizeof(
mach0_ut);
1578 if (
len != ptr_size) {
1592 if (paddr == 0 || left <
sizeof(
mach0_ut)) {
1602 if (paddr == 0 || *left <= 1) {
1609 if (
len < name_len) {
static RzILOpEffect * cls(cs_insn *insn)
RZ_IPI void rz_bin_class_free(RzBinClass *k)
RZ_API void rz_bin_string_free(void *_str)
RZ_API void rz_bin_field_free(RzBinField *field)
RzList * sections(RzBinFile *bf)
RzList * relocs(RzBinFile *bf)
int bits(struct state *s, int need)
const lzma_allocator const uint8_t size_t uint8_t * out
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
RZ_API char * sdb_fmt(const char *fmt,...)
void skip(file *in, unsigned n)
RZ_API void Ht_() free(HtName_(Ht) *ht)
RZ_API const KEY_TYPE bool * found
return memset(p, 0, total)
RZ_API RZ_BORROW RzListIter * rz_list_prepend(RZ_NONNULL RzList *list, void *data)
Appends at the beginning of the list a new element.
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
RZ_API void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
void * malloc(size_t size)
void * calloc(size_t number, size_t size)
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")
struct section_t *MACH0_() get_sections(struct MACH0_(obj_t) *bin)
RZ_BORROW RzSkipList *MACH0_() get_relocs(struct MACH0_(obj_t) *bin)
RZ_API RzBuffer *MACH0_() new_rebasing_and_stripping_buf(struct MACH0_(obj_t) *obj)
RZ_API bool MACH0_() needs_rebasing_and_stripping(struct MACH0_(obj_t) *obj)
#define MAX_CLASS_NAME_LEN
static void get_protocol_list_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass, objc_cache_opt_info *oi)
RZ_API void MACH0_() get_class_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass, bool dupe, RzSkipList *relocs, objc_cache_opt_info *oi)
struct MACH0_(SMethodList)
static char * demangle_classname(const char *s)
static mach0_ut get_isa_value(void)
static char * read_str(RzBinFile *bf, RzBuffer *buf, mach0_ut p, ut32 *offset, ut32 *left)
#define METHOD_LIST_FLAG_IS_PREOPT
RZ_API void MACH0_() get_category_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass, RzSkipList *relocs, objc_cache_opt_info *oi)
static bool read_ptr_pa(RzBinFile *bf, RzBuffer *buf, ut64 paddr, mach0_ut *out)
#define METHOD_LIST_FLAG_IS_SMALL
static int sort_by_offset(const void *_a, const void *_b)
static void get_ivar_list_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass)
static RzList *MACH0_() parse_categories(RzBinFile *bf, RzBuffer *buf, RzSkipList *relocs, objc_cache_opt_info *oi)
static void get_method_list_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, char *class_name, RzBinClass *klass, bool is_static, objc_cache_opt_info *oi)
#define METHOD_LIST_ENTSIZE_FLAG_MASK
static const char * skipnum(const char *s)
static void get_class_ro_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, ut32 *is_meta_class, RzBinClass *klass, objc_cache_opt_info *oi)
static void get_objc_property_list(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass)
static bool is_thumb(RzBinFile *bf)
static char * get_class_name(mach0_ut p, RzBinFile *bf, RzBuffer *buf)
RZ_API RzList *MACH0_() parse_classes(RzBinFile *bf, objc_cache_opt_info *oi)
static bool read_ptr_va(RzBinFile *bf, RzBuffer *buf, ut64 vaddr, mach0_ut *out)
static mach0_ut va2pa(mach0_ut p, ut32 *offset, ut32 *left, RzBinFile *bf)
static void copy_sym_name_with_namespace(char *class_name, char *read_name, RzBinSymbol *sym)
#define rz_bin_plugin_mach
RZ_API int sdb_num_set(Sdb *s, const char *key, ut64 v, ut32 cas)
insn_type_descr_t types[]
#define rz_return_if_fail(expr)
#define rz_return_val_if_fail(expr, val)
#define RZ_BIN_METH_CLASS
#define RZ_BIN_TYPE_METH_STR
#define RZ_BIN_TYPE_FUNC_STR
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.
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
static ut64 rz_read_ble(const void *src, bool big_endian, int size)
void(* RzListFree)(void *ptr)
#define RZ_LOG_INFO(fmtstr,...)
#define RZ_LOG_ERROR(fmtstr,...)
RZ_API RzSkipListNode * rz_skiplist_find(RzSkipList *list, void *data)
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char * rz_str_ndup(RZ_NULLABLE const char *ptr, int len)
Create new copy of string ptr limited to size len.
static const char * rz_str_get_null(const char *str)
RZ_API bool rz_str_startswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string starts with a specifc sequence of characters (case sensitive)
RZ_API int sdb_set(Sdb *s, const char *key, const char *val, ut32 cas)
static struct sockaddr static addrlen static backlog const void static flags void flags
static struct sockaddr static addrlen static backlog const void msg
XX curplugin == o->plugin.
void error(const char *msg)
if(dbg->bits==RZ_SYS_BITS_64)
ut64(WINAPI *w32_GetEnabledXStateFeatures)()