Rizin
unix-like reverse engineering framework and cli tools
analysis_objc.c File Reference
#include <rz_core.h>
#include "core_private.h"

Go to the source code of this file.

Classes

struct  RzCoreObjc
 

Functions

static void array_add (RzCoreObjc *o, ut64 va, ut64 xrefs_to)
 
static void kv_array_free (HtUPKv *kv)
 
static bool isValid (ut64 addr)
 
static bool isInvalid (ut64 addr)
 
static bool inBetween (RzBinSection *s, ut64 addr)
 
static ut32 readDword (RzCoreObjc *objc, ut64 addr, bool *success)
 
static ut64 readQword (RzCoreObjc *objc, ut64 addr, bool *success)
 
static void objc_analyze (RzCore *core)
 
static ut64 getRefPtr (RzCoreObjc *o, ut64 classMethodsVA, bool *rfound)
 
static bool objc_build_refs (RzCoreObjc *objc)
 
static RzCoreObjccore_objc_new (RzCore *core)
 
static void core_objc_free (RzCoreObjc *o)
 
static bool objc_find_refs (RzCore *core)
 
RZ_API bool cmd_analysis_objc (RzCore *core, bool auto_analysis)
 

Variables

const size_t objc2ClassSize = 0x28
 
const size_t objc2ClassInfoOffs = 0x20
 
const size_t objc2ClassMethSize = 0x18
 
const size_t objc2ClassBaseMethsOffs = 0x20
 
const size_t objc2ClassMethImpOffs = 0x10
 

Function Documentation

◆ array_add()

static void array_add ( RzCoreObjc o,
ut64  va,
ut64  xrefs_to 
)
static

Definition at line 30 of file analysis_objc.c.

30  {
31  bool found = false;
32  RzVector *vec = ht_up_find(o->up, va, &found);
33  if (!found || !vec) {
34  vec = rz_vector_new(sizeof(ut64), NULL, NULL);
35  ht_up_insert(o->up, va, vec);
36  }
37  ut64 *addr;
38  rz_vector_foreach(vec, addr) {
39  if (xrefs_to == *addr) {
40  return;
41  }
42  }
43  // extend vector and insert new element
44  rz_vector_push(vec, &xrefs_to);
45 }
#define NULL
Definition: cris-opc.c:27
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
RZ_API void * rz_vector_push(RzVector *vec, void *x)
Definition: vector.c:197
#define rz_vector_foreach(vec, it)
Definition: rz_vector.h:169
RZ_API RzVector * rz_vector_new(size_t elem_size, RzVectorFree free, void *free_user)
Definition: vector.c:42
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58

References addr, found, NULL, rz_vector_foreach, rz_vector_new(), rz_vector_push(), RzCoreObjc::up, and ut64().

Referenced by objc_build_refs().

◆ cmd_analysis_objc()

RZ_API bool cmd_analysis_objc ( RzCore core,
bool  auto_analysis 
)

Definition at line 301 of file analysis_objc.c.

301  {
302  rz_return_val_if_fail(core, 0);
303  if (!auto_analysis) {
304  objc_analyze(core);
305  }
306  return objc_find_refs(core);
307 }
static void objc_analyze(RzCore *core)
Definition: analysis_objc.c:80
static bool objc_find_refs(RzCore *core)
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108

References objc_analyze(), objc_find_refs(), and rz_return_val_if_fail.

Referenced by rz_analyze_all_objc_references_handler(), and rz_core_analysis_everything().

◆ core_objc_free()

static void core_objc_free ( RzCoreObjc o)
static

Definition at line 208 of file analysis_objc.c.

208  {
209  if (o) {
210  ht_up_free(o->up);
211  free(o);
212  }
213 }
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130

References free(), and RzCoreObjc::up.

Referenced by objc_find_refs().

◆ core_objc_new()

static RzCoreObjc* core_objc_new ( RzCore core)
static

Definition at line 173 of file analysis_objc.c.

173  {
175  if (!sections) {
176  return false;
177  }
179  o->core = core;
180  o->word_size = (core->rasm->bits == 64) ? 8 : 4;
181  if (o->word_size != 8) {
182  RZ_LOG_WARN("aao is experimental on 32bit binaries\n");
183  }
184 
185  RzBinSection *s;
186  RzListIter *iter;
187  rz_list_foreach (sections, iter, s) {
188  const char *name = s->name;
189  if (strstr(name, "__objc_data")) {
190  o->_data = s;
191  } else if (strstr(name, "__objc_selrefs")) {
192  o->_selrefs = s;
193  } else if (strstr(name, "__objc_msgrefs")) {
194  o->_msgrefs = s;
195  } else if (strstr(name, "__objc_const")) {
196  o->_const = s;
197  }
198  }
199  if (!o->_const || ((o->_selrefs || o->_msgrefs) && !(o->_data && o->_const))) {
200  free(o);
201  return NULL;
202  }
203  o->up = ht_up_new(NULL, kv_array_free, NULL);
204 
205  return o;
206 }
static void kv_array_free(HtUPKv *kv)
Definition: analysis_objc.c:47
RZ_DEPRECATE RZ_API RZ_BORROW RzList * rz_bin_get_sections(RZ_NONNULL RzBin *bin)
Definition: bin.c:597
RzList * sections(RzBinFile *bf)
Definition: bin_ne.c:110
static RzSocket * s
Definition: rtr.c:28
#define RZ_LOG_WARN(fmtstr,...)
Definition: rz_log.h:56
#define RZ_NEW0(x)
Definition: rz_types.h:284
RzBinSection * _selrefs
Definition: analysis_objc.c:18
RzBinSection * _const
Definition: analysis_objc.c:20
RzCore * core
Definition: analysis_objc.c:15
RzBinSection * _msgrefs
Definition: analysis_objc.c:19
RzBinSection * _data
Definition: analysis_objc.c:21
size_t word_size
Definition: analysis_objc.c:17
Definition: z80asm.h:102
int bits
Definition: rz_asm.h:100
RzBin * bin
Definition: rz_core.h:298
RzAsm * rasm
Definition: rz_core.h:323

References RzCoreObjc::_const, RzCoreObjc::_data, RzCoreObjc::_msgrefs, RzCoreObjc::_selrefs, rz_core_t::bin, rz_asm_t::bits, RzCoreObjc::core, free(), kv_array_free(), NULL, rz_core_t::rasm, rz_bin_get_sections(), RZ_LOG_WARN, RZ_NEW0, s, sections(), RzCoreObjc::up, and RzCoreObjc::word_size.

Referenced by objc_find_refs().

◆ getRefPtr()

static ut64 getRefPtr ( RzCoreObjc o,
ut64  classMethodsVA,
bool rfound 
)
static

Definition at line 93 of file analysis_objc.c.

93  {
94  *rfound = false;
95 
96  bool readSuccess;
97  ut64 namePtr = readQword(o, classMethodsVA, &readSuccess);
98  if (!readSuccess) {
99  return UT64_MAX;
100  }
101 
102  size_t cnt = 0;
103  ut64 ref = UT64_MAX;
104  bool isMsgRef = false;
105 
106  RzVector *vec = ht_up_find(o->up, namePtr, rfound);
107  if (!*rfound || !vec) {
108  *rfound = false;
109  return false;
110  }
111  ut64 *addr;
112  rz_vector_foreach(vec, addr) {
113  const ut64 at = *addr;
114  if (inBetween(o->_selrefs, at)) {
115  isMsgRef = false;
116  ref = at;
117  } else if (inBetween(o->_msgrefs, at)) {
118  isMsgRef = true;
119  ref = at;
120  } else if (inBetween(o->_const, at)) {
121  cnt++;
122  }
123  }
124  if (cnt > 1 || ref == 0 || ref == UT64_MAX) {
125  *rfound = false;
126  return UT64_MAX;
127  }
128  return isMsgRef ? ref - 8 : ref;
129 }
static bool inBetween(RzBinSection *s, ut64 addr)
Definition: analysis_objc.c:59
static ut64 readQword(RzCoreObjc *objc, ut64 addr, bool *success)
Definition: analysis_objc.c:74
#define UT64_MAX
Definition: rz_types_base.h:86

References RzCoreObjc::_const, RzCoreObjc::_msgrefs, RzCoreObjc::_selrefs, addr, inBetween(), readQword(), rz_vector_foreach, RzCoreObjc::up, ut64(), and UT64_MAX.

Referenced by objc_find_refs().

◆ inBetween()

static bool inBetween ( RzBinSection s,
ut64  addr 
)
inlinestatic

Definition at line 59 of file analysis_objc.c.

59  {
60  if (!s || isInvalid(addr)) {
61  return false;
62  }
63  const ut64 from = s->vaddr;
64  const ut64 to = from + s->vsize;
65  return RZ_BETWEEN(from, addr, to);
66 }
static bool isInvalid(ut64 addr)
Definition: analysis_objc.c:55
#define RZ_BETWEEN(x, y, z)
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr from
Definition: sfsocketcall.h:123
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr socklen_t static fromlen const void const struct sockaddr to
Definition: sfsocketcall.h:125

References addr, from, isInvalid(), RZ_BETWEEN, s, to, and ut64().

Referenced by getRefPtr().

◆ isInvalid()

static bool isInvalid ( ut64  addr)
inlinestatic

Definition at line 55 of file analysis_objc.c.

55  {
56  return !isValid(addr);
57 }
static bool isValid(ut64 addr)
Definition: analysis_objc.c:51

References addr, and isValid().

Referenced by inBetween(), and objc_find_refs().

◆ isValid()

static bool isValid ( ut64  addr)
inlinestatic

Definition at line 51 of file analysis_objc.c.

51  {
52  return (addr != 0LL && addr != UT64_MAX);
53 }

References addr, and UT64_MAX.

Referenced by is_delta_pointer_table(), isInvalid(), objc_build_refs(), rz_analysis_get_delta_jmptbl_info(), and rz_analysis_get_jmptbl_info().

◆ kv_array_free()

static void kv_array_free ( HtUPKv *  kv)
static

Definition at line 47 of file analysis_objc.c.

47  {
48  rz_vector_free(kv->value);
49 }
RZ_API void rz_vector_free(RzVector *vec)
Definition: vector.c:75

References rz_vector_free().

Referenced by core_objc_new().

◆ objc_analyze()

static void objc_analyze ( RzCore core)
static

Definition at line 80 of file analysis_objc.c.

80  {
81  const char *notify = "Analyzing code to find selfref references";
82  rz_core_notify_begin(core, "%s", notify);
83  (void)rz_core_analysis_refs(core, 0);
84  if (!strcmp("arm", rz_config_get(core->config, "asm.arch"))) {
85  const bool emu_lazy = rz_config_get_i(core->config, "emu.lazy");
86  rz_config_set_i(core->config, "emu.lazy", true);
88  rz_config_set_i(core->config, "emu.lazy", emu_lazy);
89  }
90  rz_core_notify_done(core, "%s", notify);
91 }
RZ_API bool rz_core_analysis_refs(RZ_NONNULL RzCore *core, size_t nbytes)
Analyze xrefs and prints the result.
Definition: canalysis.c:3272
RZ_IPI void rz_core_analysis_esil_default(RzCore *core)
Definition: cil.c:409
RZ_API ut64 rz_config_get_i(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:119
RZ_API RzConfigNode * rz_config_set_i(RzConfig *cfg, RZ_NONNULL const char *name, const ut64 i)
Definition: config.c:419
RZ_API RZ_BORROW const char * rz_config_get(RzConfig *cfg, RZ_NONNULL const char *name)
Definition: config.c:75
RZ_API void rz_core_notify_begin(RZ_NONNULL RzCore *core, RZ_NONNULL const char *format,...)
Prints a message definining the beginning of a task.
Definition: core.c:33
RZ_API void rz_core_notify_done(RZ_NONNULL RzCore *core, RZ_NONNULL const char *format,...)
Prints a message definining the end of a task which succeeded.
Definition: core.c:60
RzConfig * config
Definition: rz_core.h:300

References rz_core_t::config, rz_config_get(), rz_config_get_i(), rz_config_set_i(), rz_core_analysis_esil_default(), rz_core_analysis_refs(), rz_core_notify_begin(), and rz_core_notify_done().

Referenced by cmd_analysis_objc().

◆ objc_build_refs()

static bool objc_build_refs ( RzCoreObjc objc)
static

Definition at line 131 of file analysis_objc.c.

131  {
132  ut64 off;
133  rz_return_val_if_fail(objc->_const && objc->_selrefs, false);
134 
135  const ut64 va_const = objc->_const->vaddr;
136  size_t ss_const = objc->_const->vsize;
137  const ut64 va_selrefs = objc->_selrefs->vaddr;
138  size_t ss_selrefs = objc->_selrefs->vsize;
139 
140  // TODO: check if ss_const or ss_selrefs are too big before going further
141  size_t maxsize = RZ_MAX(ss_const, ss_selrefs);
142  ut8 *buf = calloc(1, maxsize);
143  if (!buf) {
144  return false;
145  }
146  const size_t word_size = objc->word_size; // assuming 8 because of the read_le64
147  if (!rz_io_read_at(objc->core->io, objc->_const->vaddr, buf, ss_const)) {
148  RZ_LOG_ERROR("aao: Cannot read the whole const section %zu\n", ss_const);
149  return false;
150  }
151  for (off = 0; off + word_size < ss_const; off += word_size) {
152  ut64 va = va_const + off;
153  ut64 xrefs_to = rz_read_le64(buf + off);
154  if (isValid(xrefs_to)) {
155  array_add(objc, va, xrefs_to);
156  }
157  }
158  if (!rz_io_read_at(objc->core->io, va_selrefs, buf, ss_selrefs)) {
159  RZ_LOG_ERROR("aao: Cannot read the whole selrefs section\n");
160  return false;
161  }
162  for (off = 0; off + word_size < ss_selrefs; off += word_size) {
163  ut64 va = va_selrefs + off;
164  ut64 xrefs_to = rz_read_le64(buf + off);
165  if (isValid(xrefs_to)) {
166  array_add(objc, xrefs_to, va);
167  }
168  }
169  free(buf);
170  return true;
171 }
static void array_add(RzCoreObjc *o, ut64 va, ut64 xrefs_to)
Definition: analysis_objc.c:30
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
int off
Definition: pal.c:13
static ut64 rz_read_le64(const void *src)
Definition: rz_endian.h:266
RZ_API bool rz_io_read_at(RzIO *io, ut64 addr, ut8 *buf, int len)
Definition: io.c:300
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
#define RZ_MAX(x, y)
RzIO * io
Definition: rz_core.h:313

References RzCoreObjc::_const, RzCoreObjc::_selrefs, array_add(), calloc(), RzCoreObjc::core, free(), rz_core_t::io, isValid(), off, rz_io_read_at(), RZ_LOG_ERROR, RZ_MAX, rz_read_le64(), rz_return_val_if_fail, ut64(), rz_bin_section_t::vaddr, rz_bin_section_t::vsize, and RzCoreObjc::word_size.

Referenced by objc_find_refs().

◆ objc_find_refs()

static bool objc_find_refs ( RzCore core)
static

Definition at line 215 of file analysis_objc.c.

215  {
216  RzCoreObjc *objc = core_objc_new(core);
217  if (!objc) {
218  RZ_LOG_DEBUG("Could not find necessary Objective-C sections...\n");
219  return false;
220  }
221 
222  if (!objc_build_refs(objc)) {
223  core_objc_free(objc);
224  return false;
225  }
226  const char *notify = "Parsing metadata in ObjC to find hidden xrefs";
227  rz_core_notify_begin(core, "%s", notify);
228 
229  size_t total_xrefs = 0;
230  bool readSuccess = true;
231  for (ut64 off = 0; off < objc->_data->vsize && readSuccess; off += objc2ClassSize) {
232  if (!readSuccess || rz_cons_is_breaked()) {
233  break;
234  }
235 
236  ut64 va = objc->_data->vaddr + off;
237  // XXX do a single rz_io_read_at() and just rz_read_le64() here
238  ut64 classRoVA = readQword(objc, va + objc2ClassInfoOffs, &readSuccess);
239  if (!readSuccess || isInvalid(classRoVA)) {
240  continue;
241  }
242  ut64 classMethodsVA = readQword(objc, classRoVA + objc2ClassBaseMethsOffs, &readSuccess);
243  if (!readSuccess || isInvalid(classMethodsVA)) {
244  continue;
245  }
246 
247  ut32 count = readDword(objc, classMethodsVA + 4, &readSuccess);
248  if (!readSuccess || ((ut32)count == UT32_MAX)) {
249  continue;
250  }
251 
252  classMethodsVA += 8; // advance to start of class methods array
253  ut64 to = classMethodsVA + (objc2ClassMethSize * count);
254  if (classMethodsVA > to || classMethodsVA + 0xfffff < to) {
255  RZ_LOG_WARN("objc: the input binary might be malformed or this could be a bug.\n");
256  continue;
257  }
258  for (va = classMethodsVA; va < to; va += objc2ClassMethSize) {
259  if (rz_cons_is_breaked()) {
260  break;
261  }
262  bool found = false;
263  ut64 selRefVA = getRefPtr(objc, va, &found);
264  if (!found) {
265  continue;
266  }
267  bool succ = false;
268  ut64 funcVA = readQword(objc, va + objc2ClassMethImpOffs, &succ);
269  if (!succ) {
270  break;
271  }
272 
273  RzList *list = rz_analysis_xrefs_get_to(core->analysis, selRefVA);
274  if (list) {
275  RzListIter *iter;
276  RzAnalysisXRef *xref;
277  rz_list_foreach (list, iter, xref) {
279  total_xrefs++;
280  }
281  }
282  }
283  }
284  rz_core_notify_done(core, "%s", notify);
285 
286  const ut64 va_selrefs = objc->_selrefs->vaddr;
287  const ut64 ss_selrefs = va_selrefs + objc->_selrefs->vsize;
288 
289  rz_core_notify_begin(core, "Found %zu objc xrefs...", total_xrefs);
290  size_t total_words = 0;
291  const size_t word_size = objc->word_size;
292  for (ut64 a = va_selrefs; a < ss_selrefs; a += word_size) {
293  rz_meta_set(core->analysis, RZ_META_TYPE_DATA, a, word_size, NULL);
294  total_words++;
295  }
296  rz_core_notify_done(core, "Found %zu objc xrefs in %zu dwords.", total_xrefs, total_words);
297  core_objc_free(objc);
298  return true;
299 }
const size_t objc2ClassMethImpOffs
Definition: analysis_objc.c:28
const size_t objc2ClassSize
Definition: analysis_objc.c:24
static void core_objc_free(RzCoreObjc *o)
static RzCoreObjc * core_objc_new(RzCore *core)
static ut32 readDword(RzCoreObjc *objc, ut64 addr, bool *success)
Definition: analysis_objc.c:68
const size_t objc2ClassMethSize
Definition: analysis_objc.c:26
static bool objc_build_refs(RzCoreObjc *objc)
const size_t objc2ClassInfoOffs
Definition: analysis_objc.c:25
const size_t objc2ClassBaseMethsOffs
Definition: analysis_objc.c:27
static ut64 getRefPtr(RzCoreObjc *o, ut64 classMethodsVA, bool *rfound)
Definition: analysis_objc.c:93
RZ_API bool rz_cons_is_breaked(void)
Definition: cons.c:373
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
Definition: sflib.h:98
uint32_t ut32
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API bool rz_meta_set(RzAnalysis *a, RzAnalysisMetaType type, ut64 addr, ut64 size, const char *str)
Definition: meta.c:191
@ RZ_ANALYSIS_XREF_TYPE_CODE
Definition: rz_analysis.h:900
@ RZ_META_TYPE_DATA
Definition: rz_analysis.h:289
#define RZ_LOG_DEBUG(fmtstr,...)
Definition: rz_log.h:49
#define UT32_MAX
Definition: rz_types_base.h:99
#define a(i)
Definition: sha256.c:41
RzAnalysis * analysis
Definition: rz_core.h:322
RZ_API RzList * rz_analysis_xrefs_get_to(RzAnalysis *analysis, ut64 addr)
Definition: xrefs.c:173
RZ_API bool rz_analysis_xrefs_set(RzAnalysis *analysis, ut64 from, ut64 to, RzAnalysisXRefType type)
Definition: xrefs.c:117

References RzCoreObjc::_data, RzCoreObjc::_selrefs, a, rz_core_t::analysis, core_objc_free(), core_objc_new(), count, found, rz_analysis_ref_t::from, getRefPtr(), isInvalid(), list(), NULL, objc2ClassBaseMethsOffs, objc2ClassInfoOffs, objc2ClassMethImpOffs, objc2ClassMethSize, objc2ClassSize, objc_build_refs(), off, readDword(), readQword(), RZ_ANALYSIS_XREF_TYPE_CODE, rz_analysis_xrefs_get_to(), rz_analysis_xrefs_set(), rz_cons_is_breaked(), rz_core_notify_begin(), rz_core_notify_done(), RZ_LOG_DEBUG, RZ_LOG_WARN, rz_meta_set(), RZ_META_TYPE_DATA, to, UT32_MAX, ut64(), rz_bin_section_t::vaddr, rz_bin_section_t::vsize, and RzCoreObjc::word_size.

Referenced by cmd_analysis_objc().

◆ readDword()

static ut32 readDword ( RzCoreObjc objc,
ut64  addr,
bool success 
)
static

Definition at line 68 of file analysis_objc.c.

68  {
69  ut8 buf[4];
70  *success = rz_io_read_at(objc->core->io, addr, buf, sizeof(buf));
71  return rz_read_le32(buf);
72 }
static ut32 rz_read_le32(const void *src)
Definition: rz_endian.h:239

References addr, RzCoreObjc::core, rz_core_t::io, rz_io_read_at(), and rz_read_le32().

Referenced by objc_find_refs().

◆ readQword()

static ut64 readQword ( RzCoreObjc objc,
ut64  addr,
bool success 
)
static

Definition at line 74 of file analysis_objc.c.

74  {
75  ut8 buf[8] = { 0 };
76  *success = rz_io_read_at(objc->core->io, addr, buf, sizeof(buf));
77  return rz_read_le64(buf);
78 }

References addr, RzCoreObjc::core, rz_core_t::io, rz_io_read_at(), and rz_read_le64().

Referenced by getRefPtr(), and objc_find_refs().

Variable Documentation

◆ objc2ClassBaseMethsOffs

const size_t objc2ClassBaseMethsOffs = 0x20

Definition at line 27 of file analysis_objc.c.

Referenced by objc_find_refs().

◆ objc2ClassInfoOffs

const size_t objc2ClassInfoOffs = 0x20

Definition at line 25 of file analysis_objc.c.

Referenced by objc_find_refs().

◆ objc2ClassMethImpOffs

const size_t objc2ClassMethImpOffs = 0x10

Definition at line 28 of file analysis_objc.c.

Referenced by objc_find_refs().

◆ objc2ClassMethSize

const size_t objc2ClassMethSize = 0x18

Definition at line 26 of file analysis_objc.c.

Referenced by objc_find_refs().

◆ objc2ClassSize

const size_t objc2ClassSize = 0x28

Definition at line 24 of file analysis_objc.c.

Referenced by objc_find_refs().