Rizin
unix-like reverse engineering framework and cli tools
mach0_classes.h File Reference
#include <rz_bin.h>
#include "mach0/mach0_specs.h"
#include "mach0/mach0.h"

Go to the source code of this file.

Macros

#define mach0_ut   ut32
 
#define rz_bin_plugin_mach   rz_bin_plugin_mach0
 

Functions

RZ_API RzList *MACH0_() parse_classes (RzBinFile *bf, 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)
 
RZ_API void MACH0_() get_category_t (mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass, RzSkipList *relocs, objc_cache_opt_info *oi)
 

Macro Definition Documentation

◆ mach0_ut

#define mach0_ut   ut32

Definition at line 17 of file mach0_classes.h.

◆ rz_bin_plugin_mach

#define rz_bin_plugin_mach   rz_bin_plugin_mach0

Definition at line 18 of file mach0_classes.h.

Function Documentation

◆ get_category_t()

RZ_API void MACH0_() get_category_t ( mach0_ut  p,
RzBinFile bf,
RzBuffer buf,
RzBinClass klass,
RzSkipList relocs,
objc_cache_opt_info oi 
)

Definition at line 1445 of file mach0_classes.c.

1445  {
1446  rz_return_if_fail(bf && bf->o && bf->o->info);
1447 
1448  struct MACH0_(SCategory) c = { 0 };
1449  const int size = sizeof(struct MACH0_(SCategory));
1450  mach0_ut r = 0;
1451  ut32 offset = 0, left = 0;
1452  int len;
1453  bool bigendian = bf->o->info->big_endian;
1454  ut8 sc[sizeof(struct MACH0_(SCategory))] = { 0 };
1455  ut32 i;
1456 
1457  if (!(r = va2pa(p, &offset, &left, bf))) {
1458  return;
1459  }
1460  if ((r + left) < r || (r + size) < r) {
1461  return;
1462  }
1463  if (r > bf->size || r + left > bf->size) {
1464  return;
1465  }
1466  if (r + size > bf->size) {
1467  return;
1468  }
1469  if (left < size) {
1470  RZ_LOG_ERROR("Cannot parse obj category info out of bounds\n");
1471  return;
1472  }
1473  len = rz_buf_read_at(buf, r, sc, size);
1474  if (len != size) {
1475  return;
1476  }
1477 
1478  ut32 ptr_size = sizeof(mach0_ut);
1479  ut32 bits = 8 * ptr_size;
1480 
1481  i = 0;
1482  c.name = rz_read_ble(&sc[i], bigendian, bits);
1483  i += ptr_size;
1484  c.targetClass = rz_read_ble(&sc[i], bigendian, bits);
1485  i += ptr_size;
1486  c.instanceMethods = rz_read_ble(&sc[i], bigendian, bits);
1487  i += ptr_size;
1488  c.classMethods = rz_read_ble(&sc[i], bigendian, bits);
1489  i += ptr_size;
1490  c.protocols = rz_read_ble(&sc[i], bigendian, bits);
1491  i += ptr_size;
1492  c.properties = rz_read_ble(&sc[i], bigendian, bits);
1493 
1494  char *category_name = read_str(bf, buf, c.name, &offset, &left);
1495  if (!category_name) {
1496  return;
1497  }
1498 
1499  char *target_class_name = NULL;
1500  if (c.targetClass == 0) {
1501  if (!relocs) {
1502  RZ_FREE(category_name);
1503  return;
1504  }
1505  struct reloc_t reloc_at_class_addr;
1506  reloc_at_class_addr.addr = p + ptr_size;
1507  RzSkipListNode *found = rz_skiplist_find(relocs, &reloc_at_class_addr);
1508  if (!found) {
1509  RZ_FREE(category_name);
1510  return;
1511  }
1512 
1513  const char *_objc_class = "_OBJC_CLASS_$_";
1514  const int _objc_class_len = strlen(_objc_class);
1515  target_class_name = (char *)((struct reloc_t *)found->data)->name;
1516  if (!rz_str_startswith(target_class_name, _objc_class)) {
1517  RZ_FREE(category_name);
1518  return;
1519  }
1520  target_class_name += _objc_class_len;
1521  klass->name = rz_str_newf("%s(%s)", target_class_name, category_name);
1522  } else {
1523  mach0_ut ro_data_field = c.targetClass + 4 * ptr_size;
1524  mach0_ut ro_data;
1525  if (!read_ptr_va(bf, buf, ro_data_field, &ro_data)) {
1526  RZ_FREE(category_name);
1527  return;
1528  }
1529  mach0_ut name_field = RO_DATA_PTR(ro_data) + 3 * 4 + ptr_size;
1530 #ifdef RZ_BIN_MACH064
1531  name_field += 4;
1532 #endif
1533  mach0_ut name_at;
1534  if (!read_ptr_va(bf, buf, name_field & ~1, &name_at)) {
1535  RZ_FREE(category_name);
1536  return;
1537  }
1538 
1539  target_class_name = read_str(bf, buf, name_at, &offset, &left);
1540  char *demangled = NULL;
1541  if (target_class_name) {
1542  demangled = demangle_classname(target_class_name);
1543  }
1544  klass->name = rz_str_newf("%s(%s)", rz_str_get_null(demangled), category_name);
1545  RZ_FREE(target_class_name);
1546  RZ_FREE(demangled);
1547  }
1548 
1549  klass->addr = p;
1550 
1551  RZ_FREE(category_name);
1552 
1553  if (c.instanceMethods > 0) {
1554  get_method_list_t(c.instanceMethods, bf, buf, klass->name, klass, false, oi);
1555  }
1556 
1557  if (c.classMethods > 0) {
1558  get_method_list_t(c.classMethods, bf, buf, klass->name, klass, true, oi);
1559  }
1560 
1561  if (c.protocols > 0) {
1562  get_protocol_list_t(c.protocols, bf, buf, klass, oi);
1563  }
1564 
1565  if (c.properties > 0) {
1566  get_objc_property_list(c.properties, bf, buf, klass);
1567  }
1568 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
RzList * relocs(RzBinFile *bf)
Definition: bin_ne.c:114
int bits(struct state *s, int need)
Definition: blast.c:72
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
uint32_t ut32
static char sc[]
Definition: egg_cb.c:6
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
void * p
Definition: libc.cpp:67
static void get_protocol_list_t(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass, objc_cache_opt_info *oi)
static char * demangle_classname(const char *s)
static char * read_str(RzBinFile *bf, RzBuffer *buf, mach0_ut p, ut32 *offset, ut32 *left)
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 RO_DATA_PTR(x)
Definition: mach0_classes.c:21
static void get_objc_property_list(mach0_ut p, RzBinFile *bf, RzBuffer *buf, RzBinClass *klass)
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)
#define mach0_ut
Definition: mach0_classes.h:17
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
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
static ut64 rz_read_ble(const void *src, bool big_endian, int size)
Definition: rz_endian.h:517
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API RzSkipListNode * rz_skiplist_find(RzSkipList *list, void *data)
Definition: skiplist.c:210
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
static const char * rz_str_get_null(const char *str)
Definition: rz_str.h:190
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)
Definition: str.c:3286
#define RZ_FREE(x)
Definition: rz_types.h:369
#define c(i)
Definition: sha256.c:43
Definition: z80asm.h:102
Definition: mach0.h:71
ut64 addr
Definition: mach0.h:73
char * name
Definition: rz_bin.h:647
RzBinObject * o
Definition: rz_bin.h:305
int big_endian
Definition: rz_bin.h:235
RzBinInfo * info
Definition: rz_bin.h:287

References reloc_t::addr, bits(), c, demangle_classname(), found, get_method_list_t(), get_objc_property_list(), get_protocol_list_t(), i, len, mach0_ut, NULL, p, r, read_ptr_va(), read_str(), relocs(), RO_DATA_PTR, rz_buf_read_at(), RZ_FREE, RZ_LOG_ERROR, rz_read_ble(), rz_return_if_fail, rz_skiplist_find(), rz_str_get_null(), rz_str_newf(), rz_str_startswith(), sc, and va2pa().

Referenced by classes(), and parse_categories().

◆ get_class_t()

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 
)

Definition at line 1127 of file mach0_classes.c.

1127  {
1128  struct MACH0_(SClass) c = { 0 };
1129  const int size = sizeof(struct MACH0_(SClass));
1130  mach0_ut r = 0;
1131  ut32 offset = 0, left = 0;
1132  ut32 is_meta_class = 0;
1133  int len;
1134  bool bigendian;
1135  ut8 sc[sizeof(struct MACH0_(SClass))] = { 0 };
1136  ut32 i;
1137 
1138  if (!bf || !bf->o || !bf->o->info) {
1139  return;
1140  }
1141  bigendian = bf->o->info->big_endian;
1142  if (!(r = va2pa(p, &offset, &left, bf))) {
1143  return;
1144  }
1145  if ((r + left) < r || (r + size) < r) {
1146  return;
1147  }
1148  if (r > bf->size) {
1149  return;
1150  }
1151  if (r + size > bf->size) {
1152  return;
1153  }
1154  if (left < size) {
1155  RZ_LOG_ERROR("Cannot parse obj class info (out of bounds)\n");
1156  return;
1157  }
1158  len = rz_buf_read_at(buf, r, sc, size);
1159  if (len != size) {
1160  return;
1161  }
1162 
1163  i = 0;
1164  c.isa = rz_read_ble(&sc[i], bigendian, 8 * sizeof(mach0_ut));
1165  i += sizeof(mach0_ut);
1166  c.superclass = rz_read_ble(&sc[i], bigendian, 8 * sizeof(mach0_ut));
1167  i += sizeof(mach0_ut);
1168  c.cache = rz_read_ble(&sc[i], bigendian, 8 * sizeof(mach0_ut));
1169  i += sizeof(mach0_ut);
1170  c.vtable = rz_read_ble(&sc[i], bigendian, 8 * sizeof(mach0_ut));
1171  i += sizeof(mach0_ut);
1172  c.data = rz_read_ble(&sc[i], bigendian, 8 * sizeof(mach0_ut));
1173 
1174  klass->addr = c.isa;
1175  if (c.superclass) {
1176  klass->super = get_class_name(c.superclass, bf, buf);
1177  } else if (relocs) {
1178  struct reloc_t reloc_at_class_addr;
1179  reloc_at_class_addr.addr = p + sizeof(mach0_ut);
1180  RzSkipListNode *found = rz_skiplist_find(relocs, &reloc_at_class_addr);
1181  if (found) {
1182  const char *_objc_class = "_OBJC_CLASS_$_";
1183  const int _objc_class_len = strlen(_objc_class);
1184  char *target_class_name = (char *)((struct reloc_t *)found->data)->name;
1185  if (rz_str_startswith(target_class_name, _objc_class)) {
1186  target_class_name += _objc_class_len;
1187  klass->super = strdup(target_class_name);
1188  }
1189  }
1190  }
1191  get_class_ro_t(RO_DATA_PTR(c.data), bf, buf, &is_meta_class, klass, oi);
1192 
1193 #if SWIFT_SUPPORT
1194  if (q(c.data + n_value) & 7) {
1195  RZ_LOG_INFO("This is a Swift class");
1196  }
1197 #endif
1198  if (!is_meta_class && !dupe) {
1199  mach0_ut isa_n_value = get_isa_value();
1200  ut64 tmp = klass->addr;
1202  (c.isa + isa_n_value, bf, buf, klass, true, relocs, oi);
1203  klass->addr = tmp;
1204  }
1205 }
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")
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)
Definition: mach0_classes.c:23
static mach0_ut get_isa_value(void)
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 char * get_class_name(mach0_ut p, RzBinFile *bf, RzBuffer *buf)
#define RZ_LOG_INFO(fmtstr,...)
Definition: rz_log.h:54
char * super
Definition: rz_bin.h:649
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References reloc_t::addr, c, found, get_class_name(), get_class_ro_t(), get_isa_value(), i, len, MACH0_(), mach0_ut, p, r, relocs(), RO_DATA_PTR, rz_buf_read_at(), RZ_LOG_ERROR, RZ_LOG_INFO, rz_read_ble(), rz_skiplist_find(), rz_str_startswith(), sc, strdup(), autogen_x86imm::tmp, ut64(), and va2pa().

Referenced by classes(), and parse_classes().

◆ parse_classes()

RZ_API RzList* MACH0_() parse_classes ( RzBinFile bf,
objc_cache_opt_info oi 
)

Definition at line 1243 of file mach0_classes.c.

1243  {
1244  RzList /*<RzBinClass>*/ *ret = NULL;
1245  ut64 num_of_unnamed_class = 0;
1246  RzBinClass *klass = NULL;
1247  ut32 i = 0, size = 0;
1248  RzList *sctns = NULL;
1249  bool is_found = false;
1250  mach0_ut p = 0;
1251  ut32 left = 0;
1252  int len;
1253  ut64 paddr;
1254  ut64 s_size;
1255  bool bigendian;
1256  ut8 pp[sizeof(mach0_ut)] = { 0 };
1257 
1258  rz_return_val_if_fail(bf && bf->o, NULL);
1259 
1260  if (!bf->o->bin_obj || !bf->o->info) {
1261  return NULL;
1262  }
1263  bigendian = bf->o->info->big_endian;
1264 
1265  RzBuffer *buf = bf->buf;
1266  RzBuffer *owned_buf = NULL;
1268  owned_buf = MACH0_(new_rebasing_and_stripping_buf)(bf->o->bin_obj);
1269  if (!owned_buf) {
1270  return NULL;
1271  }
1272  buf = owned_buf;
1273  }
1274 
1276 
1277  ret = MACH0_(parse_categories)(bf, buf, relocs, oi);
1278 
1279  /* check if it's Swift */
1280  // ret = parse_swift_classes (bf);
1281 
1282  // sebfing of section with name __objc_classlist
1283 
1284  struct section_t *sections = NULL;
1285  if (!(sections = MACH0_(get_sections)(bf->o->bin_obj))) {
1286  rz_buf_free(owned_buf);
1287  return ret;
1288  }
1289 
1290  for (i = 0; !sections[i].last; i++) {
1291  if (strstr(sections[i].name, "__objc_classlist")) {
1292  is_found = true;
1293  paddr = sections[i].offset;
1294  s_size = sections[i].size;
1295  break;
1296  }
1297  }
1298 
1299  RZ_FREE(sections);
1300 
1301  if (!is_found) {
1302  // retain just for debug
1303  // RZ_LOG_ERROR("there is no section __objc_classlist\n");
1304  goto get_classes_error;
1305  }
1306  // end of seaching of section with name __objc_classlist
1307 
1308  if (!ret && !(ret = rz_list_newf((RzListFree)rz_bin_class_free))) {
1309  // retain just for debug
1310  // RZ_LOG_ERROR("RzList<RzBinClass> allocation error\n");
1311  goto get_classes_error;
1312  }
1313  // start of getting information about each class in file
1314  for (i = 0; i < s_size; i += sizeof(mach0_ut)) {
1315  left = s_size - i;
1316  if (left < sizeof(mach0_ut)) {
1317  RZ_LOG_ERROR("Truncated classlist data\n");
1318  break;
1319  }
1320  if (!(klass = RZ_NEW0(RzBinClass))) {
1321  // retain just for debug
1322  // RZ_LOG_ERROR("RzBinClass allocation error\n");
1323  goto get_classes_error;
1324  }
1325  if (!(klass->methods = rz_list_new())) {
1326  // retain just for debug
1327  // RZ_LOG_ERROR("RzList<RzBinField> allocation error\n");
1328  goto get_classes_error;
1329  }
1330  if (!(klass->fields = rz_list_new())) {
1331  // retain just for debug
1332  // RZ_LOG_ERROR("RzList<RzBinSymbol> allocation error\n");
1333  goto get_classes_error;
1334  }
1335  size = sizeof(mach0_ut);
1336  if (paddr > bf->size || paddr + size > bf->size) {
1337  goto get_classes_error;
1338  }
1339  if (paddr + size < paddr) {
1340  goto get_classes_error;
1341  }
1342  len = rz_buf_read_at(buf, paddr + i, pp, sizeof(mach0_ut));
1343  if (len != sizeof(mach0_ut)) {
1344  goto get_classes_error;
1345  }
1346  p = rz_read_ble(&pp[0], bigendian, 8 * sizeof(mach0_ut));
1348  (p, bf, buf, klass, false, relocs, oi);
1349  if (!klass->name) {
1350  klass->name = rz_str_newf("UnnamedClass%" PFMT64d, num_of_unnamed_class);
1351  if (!klass->name) {
1352  goto get_classes_error;
1353  }
1354  num_of_unnamed_class++;
1355  }
1356  rz_list_append(ret, klass);
1357  }
1358  return ret;
1359 
1360 get_classes_error:
1361  rz_list_free(sctns);
1362  rz_list_free(ret);
1363  rz_buf_free(owned_buf);
1364  // XXX DOUBLE FREE rz_bin_class_free (klass);
1365  return NULL;
1366 }
RZ_IPI void rz_bin_class_free(RzBinClass *k)
Definition: bfile.c:512
RzList * sections(RzBinFile *bf)
Definition: bin_ne.c:110
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
struct section_t *MACH0_() get_sections(struct MACH0_(obj_t) *bin)
Definition: mach0.c:2411
RZ_BORROW RzSkipList *MACH0_() get_relocs(struct MACH0_(obj_t) *bin)
Definition: mach0_relocs.c:120
RZ_API RzBuffer *MACH0_() new_rebasing_and_stripping_buf(struct MACH0_(obj_t) *obj)
Definition: mach0_rebase.c:224
RZ_API bool MACH0_() needs_rebasing_and_stripping(struct MACH0_(obj_t) *obj)
Definition: mach0_rebase.c:228
static RzList *MACH0_() parse_categories(RzBinFile *bf, RzBuffer *buf, RzSkipList *relocs, objc_cache_opt_info *oi)
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define PFMT64d
Definition: rz_types.h:394
#define RZ_NEW0(x)
Definition: rz_types.h:284
RzList * fields
Definition: rz_bin.h:654
RzList * methods
Definition: rz_bin.h:653
RzBuffer * buf
Definition: rz_bin.h:303
void * bin_obj
Definition: rz_bin.h:293

References rz_bin_class_t::fields, get_class_t(), get_relocs(), get_sections(), i, len, MACH0_(), mach0_ut, rz_bin_class_t::methods, needs_rebasing_and_stripping(), new_rebasing_and_stripping_buf(), NULL, p, parse_categories(), PFMT64d, relocs(), rz_bin_class_free(), rz_buf_free(), rz_buf_read_at(), RZ_FREE, rz_list_append(), rz_list_free(), rz_list_new(), rz_list_newf(), RZ_LOG_ERROR, RZ_NEW0, rz_read_ble(), rz_return_val_if_fail, rz_str_newf(), sections(), and ut64().

Referenced by classes().