Rizin
unix-like reverse engineering framework and cli tools
bin_xnu_kernelcache.c File Reference
#include <rz_types.h>
#include <rz_util.h>
#include <rz_lib.h>
#include <rz_bin.h>
#include <rz_core.h>
#include <rz_syscall.h>
#include "../format/mach0/kernelcache.h"
#include "../format/xnu/mig_index.h"

Go to the source code of this file.

Classes

struct  _RPrelinkRange
 
struct  _RStubsInfo
 
struct  _RKext
 
struct  _RKextIndex
 
struct  _RzParsedPointer
 
struct  _RKmodInfo
 
struct  _r_sysent
 

Macros

#define VFILE_NAME_REBASED   "rebased"
 
#define KEXT_SHORT_NAME_FROM_SECTION(io_section)
 
#define KEXT_INFER_VSIZE(index, i)    ((i + 1 < index->length) ? index->entries[i + 1]->vaddr - index->entries[i]->vaddr : UT64_MAX)
 
#define KEXT_INFER_PSIZE(index, i)    ((i + 1 < index->length) ? index->entries[i + 1]->range.offset - index->entries[i]->range.offset : UT64_MAX)
 
#define RZ_K_CONSTRUCTOR_TO_ENTRY   0
 
#define RZ_K_CONSTRUCTOR_TO_SYMBOL   1
 
#define K_PPTR(p)   p_ptr(p, obj)
 
#define K_RPTR(buf)   rz_ptr(buf, obj)
 
#define IS_PTR_AUTH(x)   ((x & (1ULL << 63)) != 0)
 
#define IS_PTR_BIND(x)   ((x & (1ULL << 62)) != 0)
 
#define rz_kext_index_foreach(index, i, item)
 
#define IS_KERNEL_ADDR(x)   ((x & 0xfffffff000000000L) == 0xfffffff000000000L)
 
#define K_MIG_SUBSYSTEM_SIZE   (4 * 8)
 
#define K_MIG_ROUTINE_SIZE   (5 * 8)
 
#define K_MIG_MAX_ROUTINES   100
 

Typedefs

typedef struct _RPrelinkRange RPrelinkRange
 
typedef struct _RStubsInfo RStubsInfo
 
typedef struct _RKext RKext
 
typedef struct _RKextIndex RKextIndex
 
typedef struct _RzParsedPointer RzParsedPointer
 
typedef struct _RKmodInfo RKmodInfo
 
typedef struct _r_sysent RSysEnt
 

Functions

static ut64 p_ptr (ut64 decorated_addr, RzXNUKernelCacheObj *obj)
 
static ut64 rz_ptr (ut8 *buf, RzXNUKernelCacheObj *obj)
 
static RzXNUKernelCacheRebaseInforz_rebase_info_new_from_mach0 (RzBuffer *cache_buf, struct MACH0_(obj_t) *mach0)
 
static void rz_rebase_info_free (RzXNUKernelCacheRebaseInfo *info)
 
static RPrelinkRangeget_prelink_info_range_from_mach0 (struct MACH0_(obj_t) *mach0)
 
static RzListfilter_kexts (RzXNUKernelCacheObj *obj)
 
static RzListcarve_kexts (RzXNUKernelCacheObj *obj)
 
static RzListkexts_from_load_commands (RzXNUKernelCacheObj *obj)
 
static void sections_from_mach0 (RzList *ret, struct MACH0_(obj_t) *mach0, RzBinFile *bf, ut64 paddr, char *prefix, RzXNUKernelCacheObj *obj)
 
static void handle_data_sections (RzBinSection *sect)
 
static void symbols_from_mach0 (RzList *ret, struct MACH0_(obj_t) *mach0, RzBinFile *bf, ut64 paddr, int ordinal)
 
static RzListresolve_syscalls (RzXNUKernelCacheObj *obj, ut64 enosys_addr)
 
static RzListresolve_mig_subsystem (RzXNUKernelCacheObj *obj)
 
static void symbols_from_stubs (RzList *ret, HtPP *kernel_syms_by_addr, RzXNUKernelCacheObj *obj, RzBinFile *bf, RKext *kext, int ordinal)
 
static RStubsInfoget_stubs_info (struct MACH0_(obj_t) *mach0, ut64 paddr, RzXNUKernelCacheObj *obj)
 
static int prot2perm (int x)
 
static void rz_kext_free (RKext *kext)
 
static void rz_kext_fill_text_range (RKext *kext)
 
static int kexts_sort_vaddr_func (const void *a, const void *b)
 
static struct MACH0_ (obj_t)
 
static void ensure_kexts_initialized (RzXNUKernelCacheObj *obj)
 
static RKextIndexrz_kext_index_new (RzList *kexts)
 
static void rz_kext_index_free (RKextIndex *index)
 
static RKextrz_kext_index_vget (RKextIndex *index, ut64 vaddr)
 
static RzListentries (RzBinFile *bf)
 
static void process_kmod_init_term (RzXNUKernelCacheObj *obj, RKext *kext, RzList *ret, ut64 **inits, ut64 **terms)
 
static const char * kext_short_name (RKext *kext)
 
static void create_initterm_syms (RKext *kext, RzList *ret, int type, ut64 *pointers)
 
static void process_constructors (RzXNUKernelCacheObj *obj, struct MACH0_(obj_t) *mach0, RzList *ret, ut64 paddr, bool is_first, int mode, const char *prefix)
 
static RzBinAddrnewEntry (ut64 haddr, ut64 vaddr, int type)
 
static bool check_buffer (RzBuffer *b)
 
static RzListvirtual_files (RzBinFile *bf)
 
static RzListmaps (RzBinFile *bf)
 
static RzListsections (RzBinFile *bf)
 
static RzListsymbols (RzBinFile *bf)
 
static HtPP * mig_hash_new (void)
 
static ut64 extract_addr_from_code (ut8 *arm64_code, ut64 vaddr)
 
static RzBinInfoinfo (RzBinFile *bf)
 
static ut64 baddr (RzBinFile *bf)
 
static void destroy (RzBinFile *bf)
 
static void rz_kernel_cache_free (RzXNUKernelCacheObj *obj)
 

Variables

RzBinPlugin rz_bin_plugin_xnu_kernelcache
 
RzLibStruct rizin_plugin
 

Macro Definition Documentation

◆ IS_KERNEL_ADDR

#define IS_KERNEL_ADDR (   x)    ((x & 0xfffffff000000000L) == 0xfffffff000000000L)

Definition at line 1296 of file bin_xnu_kernelcache.c.

◆ IS_PTR_AUTH

#define IS_PTR_AUTH (   x)    ((x & (1ULL << 63)) != 0)

Definition at line 88 of file bin_xnu_kernelcache.c.

◆ IS_PTR_BIND

#define IS_PTR_BIND (   x)    ((x & (1ULL << 62)) != 0)

Definition at line 89 of file bin_xnu_kernelcache.c.

◆ K_MIG_MAX_ROUTINES

#define K_MIG_MAX_ROUTINES   100

Definition at line 1449 of file bin_xnu_kernelcache.c.

◆ K_MIG_ROUTINE_SIZE

#define K_MIG_ROUTINE_SIZE   (5 * 8)

Definition at line 1448 of file bin_xnu_kernelcache.c.

◆ K_MIG_SUBSYSTEM_SIZE

#define K_MIG_SUBSYSTEM_SIZE   (4 * 8)

Definition at line 1447 of file bin_xnu_kernelcache.c.

◆ K_PPTR

#define K_PPTR (   p)    p_ptr(p, obj)

Definition at line 85 of file bin_xnu_kernelcache.c.

◆ K_RPTR

#define K_RPTR (   buf)    rz_ptr(buf, obj)

Definition at line 86 of file bin_xnu_kernelcache.c.

◆ KEXT_INFER_PSIZE

#define KEXT_INFER_PSIZE (   index,
  i 
)     ((i + 1 < index->length) ? index->entries[i + 1]->range.offset - index->entries[i]->range.offset : UT64_MAX)

Definition at line 79 of file bin_xnu_kernelcache.c.

◆ KEXT_INFER_VSIZE

#define KEXT_INFER_VSIZE (   index,
  i 
)     ((i + 1 < index->length) ? index->entries[i + 1]->vaddr - index->entries[i]->vaddr : UT64_MAX)

Definition at line 76 of file bin_xnu_kernelcache.c.

◆ KEXT_SHORT_NAME_FROM_SECTION

#define KEXT_SHORT_NAME_FROM_SECTION (   io_section)
Value:
({ \
char *result = NULL; \
char *clone = strdup(io_section->name); \
char *cursor = strstr(clone, "__"); \
if (cursor) { \
cursor--; \
*cursor = 0; \
cursor--; \
cursor = strrchr(cursor, '.'); \
if (cursor) { \
*cursor = 0; \
cursor = strrchr(cursor, '.'); \
if (cursor) { \
result = strdup(cursor + 1); \
RZ_FREE(clone); \
} \
} \
} \
result ? result : clone; \
})
#define NULL
Definition: cris-opc.c:27
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")

Definition at line 55 of file bin_xnu_kernelcache.c.

◆ RZ_K_CONSTRUCTOR_TO_ENTRY

#define RZ_K_CONSTRUCTOR_TO_ENTRY   0

Definition at line 82 of file bin_xnu_kernelcache.c.

◆ RZ_K_CONSTRUCTOR_TO_SYMBOL

#define RZ_K_CONSTRUCTOR_TO_SYMBOL   1

Definition at line 83 of file bin_xnu_kernelcache.c.

◆ rz_kext_index_foreach

#define rz_kext_index_foreach (   index,
  i,
  item 
)
Value:
if (index) \
for (i = 0; i < index->length && (item = index->entries[i], 1); i++)
lzma_index ** i
Definition: index.h:629

◆ VFILE_NAME_REBASED

#define VFILE_NAME_REBASED   "rebased"

Definition at line 15 of file bin_xnu_kernelcache.c.

Typedef Documentation

◆ RKext

typedef struct _RKext RKext

◆ RKextIndex

typedef struct _RKextIndex RKextIndex

◆ RKmodInfo

typedef struct _RKmodInfo RKmodInfo

◆ RPrelinkRange

typedef struct _RPrelinkRange RPrelinkRange

◆ RStubsInfo

typedef struct _RStubsInfo RStubsInfo

◆ RSysEnt

typedef struct _r_sysent RSysEnt

◆ RzParsedPointer

Function Documentation

◆ baddr()

static ut64 baddr ( RzBinFile bf)
static

Definition at line 1791 of file bin_xnu_kernelcache.c.

1791  {
1792  if (!bf || !bf->o || !bf->o->bin_obj) {
1793  return 8LL;
1794  }
1795 
1797  return MACH0_(get_baddr)(obj->mach0);
1798 }
static struct MACH0_(obj_t)
ut64 MACH0_() get_baddr(struct MACH0_(obj_t) *bin)
Definition: mach0.c:3262
RzBinObject * o
Definition: rz_bin.h:305
void * bin_obj
Definition: rz_bin.h:293

References rz_bin_object_t::bin_obj, get_baddr(), MACH0_(), and rz_bin_file_t::o.

◆ carve_kexts()

static RzList * carve_kexts ( RzXNUKernelCacheObj obj)
static

Definition at line 400 of file bin_xnu_kernelcache.c.

400  {
401  struct section_t *sections = NULL;
402  if (!(sections = MACH0_(get_sections)(obj->mach0))) {
403  return NULL;
404  }
405 
406  ut64 pa2va_exec = 0;
407  ut64 pa2va_data = 0;
408  ut64 kmod_start = 0, kmod_end = 0;
409  ut64 kmod_info = 0, kmod_info_end = 0;
410  int incomplete = 4;
411  RKmodInfo *all_infos = NULL;
412 
413  int i = 0;
414  for (; !sections[i].last && incomplete > 0; i++) {
415  if (strstr(sections[i].name, "__TEXT_EXEC.__text")) {
416  pa2va_exec = sections[i].addr - sections[i].offset;
417  incomplete--;
418  }
419  if (strstr(sections[i].name, "__DATA.__data")) {
420  pa2va_data = sections[i].addr - sections[i].offset;
421  incomplete--;
422  }
423  if (strstr(sections[i].name, "__PRELINK_INFO.__kmod_start")) {
424  kmod_start = sections[i].offset;
425  kmod_end = kmod_start + sections[i].size;
426  incomplete--;
427  }
428  if (strstr(sections[i].name, "__PRELINK_INFO.__kmod_info")) {
429  kmod_info = sections[i].offset;
430  kmod_info_end = kmod_info + sections[i].size;
431  incomplete--;
432  }
433  }
434 
435  RZ_FREE(sections);
436 
437  if (incomplete) {
438  return NULL;
439  }
440 
442  if (!kexts) {
443  return NULL;
444  }
445 
446  int n_kmod_info = (kmod_info_end - kmod_info) / 8;
447  if (n_kmod_info == 0) {
448  goto beach;
449  }
450 
451  all_infos = RZ_NEWS0(RKmodInfo, n_kmod_info);
452  if (!all_infos) {
453  goto beach;
454  }
455 
456  ut8 bytes[8];
457  int j = 0;
458  for (; j < n_kmod_info; j++) {
459  ut64 entry_offset = j * 8 + kmod_info;
460 
461  if (rz_buf_read_at(obj->cache_buf, entry_offset, bytes, 8) < 8) {
462  goto beach;
463  }
464 
465  ut64 kmod_info_paddr = K_RPTR(bytes) - pa2va_data;
466 
467  ut64 field_name = kmod_info_paddr + 0x10;
468  ut64 field_start = kmod_info_paddr + 0xb4;
469 
470  if (rz_buf_read_at(obj->cache_buf, field_start, bytes, 8) < 8) {
471  goto beach;
472  }
473 
474  all_infos[j].start = K_RPTR(bytes);
475 
476  if (rz_buf_read_at(obj->cache_buf, field_name, (ut8 *)all_infos[j].name, 0x40) < 0x40) {
477  goto beach;
478  }
479 
480  all_infos[j].name[0x40] = 0;
481  }
482 
483  ut64 cursor = kmod_start;
484  for (; cursor < kmod_end; cursor += 8) {
485  ut8 bytes[8];
486  if (rz_buf_read_at(obj->cache_buf, cursor, bytes, 8) < 8) {
487  goto beach;
488  }
489 
490  RKext *kext = RZ_NEW0(RKext);
491  if (!kext) {
492  goto beach;
493  }
494 
495  kext->vaddr = K_RPTR(bytes);
496  kext->range.offset = kext->vaddr - pa2va_exec;
497 
498  kext->mach0 = create_kext_mach0(obj, kext);
499  if (!kext->mach0) {
500  rz_kext_free(kext);
501  continue;
502  }
503 
505  kext->vaddr = K_PPTR(kext->vaddr);
506  kext->pa2va_exec = pa2va_exec;
507  kext->pa2va_data = pa2va_data;
508 
509  ut64 text_start = kext->vaddr;
510  ut64 text_end = text_start + kext->text_range.size;
511 
512  if (text_start == text_end) {
513  rz_kext_free(kext);
514  continue;
515  }
516 
517  for (j = 0; j < n_kmod_info; j++) {
518  if (text_start > all_infos[j].start || all_infos[j].start >= text_end) {
519  continue;
520  }
521 
522  kext->name = strdup(all_infos[j].name);
523  kext->own_name = true;
524  break;
525  }
526 
527  if (!kext->name) {
528  rz_kext_free(kext);
529  continue;
530  }
531 
532  rz_list_push(kexts, kext);
533  }
534 
535  RZ_FREE(all_infos);
536  return kexts;
537 
538 beach:
539  rz_list_free(kexts);
540  RZ_FREE(all_infos);
541  return NULL;
542 }
static ut8 bytes[32]
Definition: asm_arc.c:23
static void rz_kext_free(RKext *kext)
static void rz_kext_fill_text_range(RKext *kext)
static RzList * sections(RzBinFile *bf)
#define K_RPTR(buf)
#define K_PPTR(p)
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 static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void start
Definition: sflib.h:133
uint8_t ut8
Definition: lh5801.h:11
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_BORROW RzListIter * rz_list_push(RZ_NONNULL RzList *list, void *item)
Alias for rz_list_append.
Definition: list.c:60
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
@ field_name
Definition: parser.c:1737
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
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NEWS0(x, y)
Definition: rz_types.h:282
#define RZ_FREE(x)
Definition: rz_types.h:369
RzXNUKernelCacheFileRange text_range
RzXNUKernelCacheFileRange range
char name[0x41]
Definition: z80asm.h:102
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References bytes, rz_xnu_kernelcache_obj_t::cache_buf, field_name, get_sections(), i, K_PPTR, K_RPTR, MACH0_(), _RKext::name, _RKmodInfo::name, NULL, rz_xnu_kernelcache_file_range_t::offset, _RKext::range, rz_buf_read_at(), RZ_FREE, rz_kext_fill_text_range(), rz_kext_free(), rz_list_free(), rz_list_newf(), rz_list_push(), RZ_NEW0, RZ_NEWS0, sections(), rz_xnu_kernelcache_file_range_t::size, _RKmodInfo::start, start, strdup(), _RKext::text_range, ut64(), and _RKext::vaddr.

Referenced by ensure_kexts_initialized().

◆ check_buffer()

static bool check_buffer ( RzBuffer b)
static

Definition at line 977 of file bin_xnu_kernelcache.c.

977  {
978  if (rz_buf_size(b) > 4) {
979  ut8 buf[4];
980  rz_buf_read_at(b, 0, buf, sizeof(buf));
981  if (!memcmp(buf, "\xcf\xfa\xed\xfe", 4)) {
983  }
984  }
985  return false;
986 }
voidpf void * buf
Definition: ioapi.h:138
RZ_API bool rz_xnu_kernelcache_buf_is_kernelcache(RzBuffer *b)
Definition: kernelcache.c:13
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
#define b(i)
Definition: sha256.c:42

References b, rz_buf_read_at(), rz_buf_size(), and rz_xnu_kernelcache_buf_is_kernelcache().

◆ create_initterm_syms()

static void create_initterm_syms ( RKext kext,
RzList ret,
int  type,
ut64 pointers 
)
static

Definition at line 873 of file bin_xnu_kernelcache.c.

873  {
874  int i = 0;
875  int count = 0;
876  for (; pointers[i]; i++) {
877  ut64 func_vaddr = pointers[i];
878  ut64 text_start = kext->vaddr;
879  ut64 text_end = text_start + kext->text_range.size;
880 
881  if (text_start == text_end) {
882  continue;
883  }
884 
885  if (text_start > func_vaddr || func_vaddr >= text_end) {
886  continue;
887  }
888 
890  if (!sym) {
891  break;
892  }
893 
894  sym->name = rz_str_newf("%s.%s.%d", kext_short_name(kext), (type == RZ_BIN_ENTRY_TYPE_INIT) ? "init" : "fini", count++);
895  sym->vaddr = func_vaddr;
896  sym->paddr = func_vaddr - kext->pa2va_exec;
897  sym->size = 0;
898  sym->forwarder = "NONE";
899  sym->bind = "GLOBAL";
900  sym->type = "FUNC";
901 
902  rz_list_append(ret, sym);
903  }
904 }
static const char * kext_short_name(RKext *kext)
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
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
int type
Definition: mipsasm.c:17
#define RZ_BIN_ENTRY_TYPE_INIT
Definition: rz_bin.h:35
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
const char * bind
Definition: rz_bin.h:681
const char * type
Definition: rz_bin.h:682
char * name
Definition: rz_bin.h:675
const char * forwarder
Definition: rz_bin.h:680

References rz_bin_symbol_t::bind, count, rz_bin_symbol_t::forwarder, i, kext_short_name(), rz_bin_symbol_t::name, rz_bin_symbol_t::paddr, RZ_BIN_ENTRY_TYPE_INIT, rz_list_append(), RZ_NEW0, rz_str_newf(), rz_xnu_kernelcache_file_range_t::size, rz_bin_symbol_t::size, _RKext::text_range, type, rz_bin_symbol_t::type, ut64(), _RKext::vaddr, and rz_bin_symbol_t::vaddr.

Referenced by process_kmod_init_term().

◆ destroy()

static void destroy ( RzBinFile bf)
static

Definition at line 1800 of file bin_xnu_kernelcache.c.

1800  {
1802 }
static void rz_kernel_cache_free(RzXNUKernelCacheObj *obj)

References rz_bin_object_t::bin_obj, rz_bin_file_t::o, and rz_kernel_cache_free().

◆ ensure_kexts_initialized()

static void ensure_kexts_initialized ( RzXNUKernelCacheObj obj)
static

Definition at line 190 of file bin_xnu_kernelcache.c.

190  {
191  if (obj->kexts_initialized) {
192  return;
193  }
194  obj->kexts_initialized = true;
195 
196  RzList *kexts = NULL;
197 
198  if (obj->prelink_info) {
199  kexts = filter_kexts(obj);
200  }
201 
202  if (kexts && !rz_list_length(kexts)) {
203  rz_list_free(kexts);
204  kexts = NULL;
205  }
206 
207  if (!kexts) {
208  kexts = kexts_from_load_commands(obj);
209  }
210 
211  if (kexts && !rz_list_length(kexts)) {
212  rz_list_free(kexts);
213  kexts = NULL;
214  }
215 
216  if (!kexts) {
217  kexts = carve_kexts(obj);
218  }
219 
220  obj->kexts = rz_kext_index_new(kexts);
221 }
static RzList * filter_kexts(RzXNUKernelCacheObj *obj)
static RzList * carve_kexts(RzXNUKernelCacheObj *obj)
static RzList * kexts_from_load_commands(RzXNUKernelCacheObj *obj)
static RKextIndex * rz_kext_index_new(RzList *kexts)
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
RCFValueDict * prelink_info
Definition: kernelcache.h:33
struct _RKextIndex * kexts
Definition: kernelcache.h:36

References carve_kexts(), filter_kexts(), rz_xnu_kernelcache_obj_t::kexts, kexts_from_load_commands(), rz_xnu_kernelcache_obj_t::kexts_initialized, NULL, rz_xnu_kernelcache_obj_t::prelink_info, rz_kext_index_new(), rz_list_free(), and rz_list_length().

Referenced by maps(), sections(), symbols(), and symbols_from_stubs().

◆ entries()

static RzList* entries ( RzBinFile bf)
static

Definition at line 778 of file bin_xnu_kernelcache.c.

778  {
779  RzList *ret;
780  RzBinObject *obj = bf ? bf->o : NULL;
781 
782  if (!obj || !obj->bin_obj || !(ret = rz_list_newf(free))) {
783  return NULL;
784  }
785 
787  ut64 entry_vaddr = kobj->mach0->entry;
788  if (kobj->pa2va_exec <= entry_vaddr) {
789  ut64 entry_paddr = entry_vaddr - kobj->pa2va_exec;
790  RzBinAddr *ba = newEntry(entry_paddr, entry_vaddr, 0);
791  if (ba) {
792  rz_list_append(ret, ba);
793  }
794  }
795 
796  process_constructors(kobj, kobj->mach0, ret, 0, true, RZ_K_CONSTRUCTOR_TO_ENTRY, NULL);
797 
798  return ret;
799 }
static RzBinAddr * newEntry(ut64 haddr, ut64 vaddr, int type)
#define RZ_K_CONSTRUCTOR_TO_ENTRY
static void process_constructors(RzXNUKernelCacheObj *obj, struct MACH0_(obj_t) *mach0, RzList *ret, ut64 paddr, bool is_first, int mode, const char *prefix)
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4

References rz_bin_object_t::bin_obj, free(), if(), newEntry(), NULL, rz_bin_file_t::o, rz_xnu_kernelcache_obj_t::pa2va_exec, process_constructors(), RZ_K_CONSTRUCTOR_TO_ENTRY, rz_list_append(), rz_list_newf(), and ut64().

◆ extract_addr_from_code()

static ut64 extract_addr_from_code ( ut8 arm64_code,
ut64  vaddr 
)
static

Definition at line 1616 of file bin_xnu_kernelcache.c.

1616  {
1617  ut64 addr = vaddr & ~0xfff;
1618 
1619  ut64 adrp = rz_read_le32(arm64_code);
1620  ut64 adrp_offset = ((adrp & 0x60000000) >> 29) | ((adrp & 0xffffe0) >> 3);
1621  addr += adrp_offset << 12;
1622 
1623  ut64 ldr = rz_read_le32(arm64_code + 4);
1624  addr += ((ldr & 0x3ffc00) >> 10) << ((ldr & 0xc0000000) >> 30);
1625 
1626  return addr;
1627 }
static RzILOpEffect * ldr(cs_insn *insn, bool is_thumb)
Definition: arm_il32.c:564
static ut32 adrp(ArmOp *op, ut64 addr, ut32 k)
Definition: armass64.c:853
static ut32 rz_read_le32(const void *src)
Definition: rz_endian.h:239
static int addr
Definition: z80asm.c:58

References addr, adrp(), ldr(), rz_read_le32(), ut64(), and _RKext::vaddr.

Referenced by symbols_from_stubs().

◆ filter_kexts()

static RzList * filter_kexts ( RzXNUKernelCacheObj obj)
static

Definition at line 284 of file bin_xnu_kernelcache.c.

284  {
285  RCFValueArray *kext_array = NULL;
286  RzListIter *iter;
287  RCFKeyValue *item;
288  rz_list_foreach (obj->prelink_info->pairs, iter, item) {
289  if (!strcmp(item->key, "_PrelinkInfoDictionary")) {
290  kext_array = (RCFValueArray *)item->value;
291  break;
292  }
293  }
294 
295  if (!kext_array) {
296  return NULL;
297  }
298 
300  if (!kexts) {
301  return NULL;
302  }
303 
304  bool is_sorted = true;
305  RKext *prev_kext = NULL;
306  RCFValueDict *kext_item;
307  rz_list_foreach (kext_array->values, iter, kext_item) {
308  RKext *kext = RZ_NEW0(RKext);
309  if (!kext) {
310  RZ_FREE(kexts);
311  return NULL;
312  }
313 
314  int kext_incomplete = 5;
315  RzListIter *internal_iter;
316  rz_list_foreach (kext_item->pairs, internal_iter, item) {
317  if (!strcmp(item->key, "CFBundlePackageType")) {
318  if (item->value->type != RZ_CF_STRING) {
319  break;
320  }
322  if (strcmp(type->value, "KEXT")) {
323  break;
324  }
325  kext_incomplete--;
326  }
327 
328  if (!strcmp(item->key, "_PrelinkExecutableLoadAddr")) {
329  if (item->value->type == RZ_CF_INTEGER) {
330  kext_incomplete--;
331  kext->vaddr = ((RCFValueInteger *)item->value)->value;
332  kext->range.offset = kext->vaddr - obj->pa2va_exec;
333  }
334  }
335 
336  if (!strcmp(item->key, "_PrelinkExecutableSize")) {
337  kext_incomplete--;
338  if (item->value->type == RZ_CF_INTEGER) {
339  kext->range.size = ((RCFValueInteger *)item->value)->value;
340  } else {
341  kext->range.size = 0;
342  }
343  }
344 
345  if (!strcmp(item->key, "_PrelinkKmodInfo")) {
346  if (item->value->type == RZ_CF_INTEGER) {
347  kext_incomplete--;
348  kext->mod_info = ((RCFValueInteger *)item->value)->value;
349  kext->mod_info -= obj->pa2va_data;
350  }
351  }
352 
353  if (!strcmp(item->key, "CFBundleIdentifier")) {
354  if (item->value->type == RZ_CF_STRING) {
355  kext_incomplete--;
356  kext->name = ((RCFValueString *)item->value)->value;
357  }
358  }
359  }
360 
361  if (kext_incomplete) {
362  rz_kext_free(kext);
363  continue;
364  }
365 
366  if (prev_kext && kext->vaddr < prev_kext->vaddr) {
367  is_sorted = false;
368  }
369  prev_kext = kext;
370 
371  kext->mach0 = create_kext_mach0(obj, kext);
372  if (!kext->mach0) {
373  rz_kext_free(kext);
374  continue;
375  }
376 
378 
379  rz_list_push(kexts, kext);
380  }
381 
382  if (!is_sorted) {
383  eprintf("SORTING KEXTs...\n");
385  }
386  return kexts;
387 }
static int kexts_sort_vaddr_func(const void *a, const void *b)
RZ_API void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
Definition: list.c:743
#define eprintf(x, y...)
Definition: rlcc.c:7
@ RZ_CF_STRING
Definition: rz_cf_dict.h:14
@ RZ_CF_INTEGER
Definition: rz_cf_dict.h:15
char * key
Definition: rz_cf_dict.h:27
RCFValue * value
Definition: rz_cf_dict.h:28
RzList * values
Definition: rz_cf_dict.h:38
RzList * pairs
Definition: rz_cf_dict.h:33
RCFValueType type
Definition: rz_cf_dict.h:23

References eprintf, if(), kexts_sort_vaddr_func(), _CFKeyValue::key, _RKext::mod_info, _RKext::name, NULL, rz_xnu_kernelcache_file_range_t::offset, rz_xnu_kernelcache_obj_t::pa2va_data, rz_xnu_kernelcache_obj_t::pa2va_exec, _CFValueDict::pairs, rz_xnu_kernelcache_obj_t::prelink_info, _RKext::range, RZ_CF_INTEGER, RZ_CF_STRING, RZ_FREE, rz_kext_fill_text_range(), rz_kext_free(), rz_list_newf(), rz_list_push(), rz_list_sort(), RZ_NEW0, rz_xnu_kernelcache_file_range_t::size, type, _CFValue::type, _RKext::vaddr, _CFKeyValue::value, and _CFValueArray::values.

Referenced by ensure_kexts_initialized().

◆ get_prelink_info_range_from_mach0()

static RPrelinkRange * get_prelink_info_range_from_mach0 ( struct MACH0_(obj_t) *  mach0)
static

Definition at line 223 of file bin_xnu_kernelcache.c.

223  {
224  struct section_t *sections = NULL;
225  if (!(sections = MACH0_(get_sections)(mach0))) {
226  return NULL;
227  }
228 
229  RPrelinkRange *prelink_range = RZ_NEW0(RPrelinkRange);
230  if (!prelink_range) {
231  RZ_FREE(sections);
232  return NULL;
233  }
234 
235  int incomplete = 3;
236  int i = 0;
237  for (; !sections[i].last; i++) {
238  if (strstr(sections[i].name, "__PRELINK_INFO.__info")) {
239  prelink_range->range.offset = sections[i].offset;
240  prelink_range->range.size = sections[i].size;
241  if (!--incomplete) {
242  break;
243  }
244  }
245 
246  if (strstr(sections[i].name, "__PRELINK_TEXT.__text")) {
247  prelink_range->pa2va_exec = sections[i].addr - sections[i].offset;
248  if (!--incomplete) {
249  break;
250  }
251  }
252 
253  if (strstr(sections[i].name, "__PRELINK_DATA.__data")) {
254  prelink_range->pa2va_data = sections[i].addr - sections[i].offset;
255  if (!--incomplete) {
256  break;
257  }
258  }
259  }
260 
261  RZ_FREE(sections);
262 
263  if (incomplete == 1 && !prelink_range->pa2va_data) {
264  struct MACH0_(segment_command) * seg;
265  int nsegs = RZ_MIN(mach0->nsegs, 128);
266  size_t i;
267  for (i = 0; i < nsegs; i++) {
268  seg = &mach0->segs[i];
269  if (!strcmp(seg->segname, "__DATA")) {
270  prelink_range->pa2va_data = seg->vmaddr - seg->fileoff;
271  incomplete--;
272  break;
273  }
274  }
275  }
276 
277  if (incomplete) {
278  RZ_FREE(prelink_range);
279  }
280 
281  return prelink_range;
282 }
#define RZ_MIN(x, y)
RzXNUKernelCacheFileRange range

References get_sections(), i, MACH0_(), NULL, rz_xnu_kernelcache_file_range_t::offset, _RPrelinkRange::pa2va_data, _RPrelinkRange::pa2va_exec, _RPrelinkRange::range, RZ_FREE, RZ_MIN, RZ_NEW0, sections(), and rz_xnu_kernelcache_file_range_t::size.

◆ get_stubs_info()

static RStubsInfo * get_stubs_info ( struct MACH0_(obj_t) *  mach0,
ut64  paddr,
RzXNUKernelCacheObj obj 
)
static

Definition at line 1729 of file bin_xnu_kernelcache.c.

1729  {
1730  struct section_t *sections = NULL;
1731  if (!(sections = MACH0_(get_sections)(mach0))) {
1732  return NULL;
1733  }
1734 
1735  RStubsInfo *stubs_info = RZ_NEW0(RStubsInfo);
1736  if (!stubs_info) {
1737  return NULL;
1738  }
1739 
1740  int incomplete = 2;
1741  int i = 0;
1742  for (; !sections[i].last; i++) {
1743  if (strstr(sections[i].name, "__DATA_CONST.__got")) {
1744  stubs_info->got.offset = sections[i].offset + paddr;
1745  stubs_info->got.size = sections[i].size;
1746  stubs_info->got_addr = K_PPTR(sections[i].addr);
1747  if (!--incomplete) {
1748  break;
1749  }
1750  }
1751 
1752  if (strstr(sections[i].name, "__TEXT_EXEC.__stubs")) {
1753  stubs_info->stubs.offset = sections[i].offset + paddr;
1754  stubs_info->stubs.size = sections[i].size;
1755  if (!--incomplete) {
1756  break;
1757  }
1758  }
1759  }
1760 
1761  RZ_FREE(sections);
1762 
1763  if (incomplete) {
1764  RZ_FREE(stubs_info);
1765  }
1766 
1767  return stubs_info;
1768 }
RzXNUKernelCacheFileRange got
RzXNUKernelCacheFileRange stubs

References addr, get_sections(), _RStubsInfo::got, _RStubsInfo::got_addr, i, K_PPTR, MACH0_(), NULL, rz_xnu_kernelcache_file_range_t::offset, RZ_FREE, RZ_NEW0, sections(), rz_xnu_kernelcache_file_range_t::size, and _RStubsInfo::stubs.

Referenced by symbols_from_stubs().

◆ handle_data_sections()

static void handle_data_sections ( RzBinSection sect)
static

Definition at line 1156 of file bin_xnu_kernelcache.c.

1156  {
1157  if (strstr(sect->name, "_cstring")) {
1158  sect->is_data = true;
1159  } else if (strstr(sect->name, "_os_log")) {
1160  sect->is_data = true;
1161  } else if (strstr(sect->name, "_objc_methname")) {
1162  sect->is_data = true;
1163  } else if (strstr(sect->name, "_objc_classname")) {
1164  sect->is_data = true;
1165  } else if (strstr(sect->name, "_objc_methtype")) {
1166  sect->is_data = true;
1167  }
1168 }
char * name
Definition: rz_bin.h:619

References rz_bin_section_t::is_data, and rz_bin_section_t::name.

Referenced by sections_from_mach0().

◆ info()

static RzBinInfo* info ( RzBinFile bf)
static

Definition at line 1770 of file bin_xnu_kernelcache.c.

1770  {
1771  RzBinInfo *ret = NULL;
1772  bool big_endian = 0;
1773  if (!(ret = RZ_NEW0(RzBinInfo))) {
1774  return NULL;
1775  }
1776  ret->file = strdup(bf->file);
1777  ret->bclass = strdup("kernelcache");
1778  ret->rclass = strdup("ios");
1779  ret->os = strdup("iOS");
1780  ret->arch = strdup("arm"); // XXX
1781  ret->machine = strdup(ret->arch);
1782  ret->subsystem = strdup("xnu");
1783  ret->type = strdup("kernel-cache");
1784  ret->bits = 64;
1785  ret->has_va = true;
1786  ret->big_endian = big_endian;
1787  ret->dbg_info = 0;
1788  return ret;
1789 }
char * file
Definition: rz_bin.h:299
int has_va
Definition: rz_bin.h:228
char * type
Definition: rz_bin.h:211
char * os
Definition: rz_bin.h:219
char * subsystem
Definition: rz_bin.h:220
char * machine
Definition: rz_bin.h:216
char * bclass
Definition: rz_bin.h:212
char * file
Definition: rz_bin.h:210
ut64 dbg_info
Definition: rz_bin.h:240
char * rclass
Definition: rz_bin.h:213
char * arch
Definition: rz_bin.h:214
int big_endian
Definition: rz_bin.h:235

References rz_bin_info_t::arch, rz_bin_info_t::bclass, rz_bin_info_t::big_endian, rz_bin_info_t::bits, rz_bin_info_t::dbg_info, rz_bin_info_t::file, rz_bin_file_t::file, rz_bin_info_t::has_va, rz_bin_info_t::machine, NULL, rz_bin_info_t::os, rz_bin_info_t::rclass, RZ_NEW0, strdup(), rz_bin_info_t::subsystem, and rz_bin_info_t::type.

Referenced by rz_rebase_info_free().

◆ kext_short_name()

static const char* kext_short_name ( RKext kext)
static

Definition at line 868 of file bin_xnu_kernelcache.c.

868  {
869  const char *sn = strrchr(kext->name, '.');
870  return sn ? sn + 1 : kext->name;
871 }

References _RKext::name.

Referenced by create_initterm_syms(), symbols(), and symbols_from_stubs().

◆ kexts_from_load_commands()

static RzList * kexts_from_load_commands ( RzXNUKernelCacheObj obj)
static

Definition at line 544 of file bin_xnu_kernelcache.c.

544  {
546  if (!kexts) {
547  return NULL;
548  }
549 
550  ut32 i;
551  ut32 ncmds;
552  if (!rz_buf_read_le32_at(obj->cache_buf, 16, &ncmds)) {
553  rz_list_free(kexts);
554  return NULL;
555  }
556 
558 
559  ut32 cursor = sizeof(struct MACH0_(mach_header));
560  for (i = 0; i < ncmds && cursor < length; i++) {
561  ut32 cmdtype;
562  if (!rz_buf_read_le32_at(obj->cache_buf, cursor, &cmdtype)) {
563  rz_list_free(kexts);
564  return NULL;
565  }
566 
567  ut32 cmdsize;
568  if (!rz_buf_read_le32_at(obj->cache_buf, cursor + 4, &cmdsize)) {
569  rz_list_free(kexts);
570  return NULL;
571  }
572 
573  if (cmdtype != LC_KEXT) {
574  cursor += cmdsize;
575  continue;
576  }
577 
578  ut64 vaddr;
579  if (!rz_buf_read_le64_at(obj->cache_buf, cursor + 8, &vaddr)) {
580  rz_list_free(kexts);
581  return NULL;
582  }
583 
584  ut64 paddr;
585  if (!rz_buf_read_le64_at(obj->cache_buf, cursor + 16, &paddr)) {
586  rz_list_free(kexts);
587  return NULL;
588  }
589 
590  st32 padded_name_length = (st32)cmdsize - 32;
591  if (padded_name_length <= 0) {
592  cursor += cmdsize;
593  continue;
594  }
595 
596  char *padded_name = calloc(1, padded_name_length);
597  if (!padded_name) {
598  goto beach;
599  }
600  if (rz_buf_read_at(obj->cache_buf, cursor + 32, (ut8 *)padded_name, padded_name_length) != padded_name_length) {
601  free(padded_name);
602  goto early;
603  }
604 
605  RKext *kext = RZ_NEW0(RKext);
606  if (!kext) {
607  free(padded_name);
608  goto beach;
609  }
610 
611  kext->vaddr = vaddr;
612  kext->range.offset = paddr;
613 
614  kext->mach0 = create_kext_shared_mach0(obj, kext);
615  if (!kext->mach0) {
616  free(padded_name);
617  rz_kext_free(kext);
618  cursor += cmdsize;
619  continue;
620  }
621 
623  kext->vaddr = K_PPTR(kext->vaddr);
624  kext->pa2va_exec = obj->pa2va_exec;
625  kext->pa2va_data = obj->pa2va_data;
626  kext->name = strdup(padded_name);
627  kext->own_name = true;
628  free(padded_name);
629  rz_list_push(kexts, kext);
630 
631  cursor += cmdsize;
632  }
633 early:
634  return kexts;
635 beach:
636  rz_list_free(kexts);
637  return NULL;
638 }
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 static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
uint32_t ut32
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
@ LC_KEXT
#define rz_buf_read_le32_at(b, addr, result)
Definition: rz_buf.h:271
#define rz_buf_read_le64_at(b, addr, result)
Definition: rz_buf.h:272
#define st32
Definition: rz_types_base.h:12

References rz_xnu_kernelcache_obj_t::cache_buf, calloc(), free(), i, K_PPTR, LC_KEXT, length, _RKext::name, NULL, rz_xnu_kernelcache_file_range_t::offset, rz_xnu_kernelcache_obj_t::pa2va_data, rz_xnu_kernelcache_obj_t::pa2va_exec, _RKext::range, rz_buf_read_at(), rz_buf_read_le32_at, rz_buf_read_le64_at, rz_buf_size(), rz_kext_fill_text_range(), rz_kext_free(), rz_list_free(), rz_list_newf(), rz_list_push(), RZ_NEW0, st32, strdup(), ut64(), and _RKext::vaddr.

Referenced by ensure_kexts_initialized().

◆ kexts_sort_vaddr_func()

static int kexts_sort_vaddr_func ( const void *  a,
const void *  b 
)
static

Definition at line 678 of file bin_xnu_kernelcache.c.

678  {
679  RKext *A = (RKext *)a;
680  RKext *B = (RKext *)b;
681  int vaddr_compare = A->vaddr - B->vaddr;
682  if (vaddr_compare == 0) {
683  return A->text_range.size - B->text_range.size;
684  }
685  return vaddr_compare;
686 }
#define A(x)
Definition: arc.h:165
#define B(x)
Definition: arc.h:166
#define a(i)
Definition: sha256.c:41

References a, A, b, and B.

Referenced by filter_kexts().

◆ MACH0_()

static struct MACH0_ ( obj_t  )
static

Definition at line 113 of file bin_xnu_kernelcache.c.

133  {
134  RzBuffer *fbuf = rz_buf_ref(buf);
135  struct MACH0_(opts_t) opts;
137  (&opts, bf);
138  struct MACH0_(obj_t) *main_mach0 = MACH0_(new_buf)(fbuf, &opts);
139  if (!main_mach0) {
140  return false;
141  }
142 
143  RzXNUKernelCacheRebaseInfo *rebase_info = rz_rebase_info_new_from_mach0(fbuf, main_mach0);
144  RzXNUKernelCacheObj *obj = NULL;
145 
146  RPrelinkRange *prelink_range = get_prelink_info_range_from_mach0(main_mach0);
147  if (!prelink_range) {
148  goto beach;
149  }
150 
152  if (!obj) {
153  RZ_FREE(prelink_range);
154  goto beach;
155  }
156 
157  RCFValueDict *prelink_info = NULL;
158  if (main_mach0->hdr.filetype != MH_FILESET && prelink_range->range.size) {
159  prelink_info = rz_cf_value_dict_parse(fbuf, prelink_range->range.offset,
160  prelink_range->range.size, RZ_CF_OPTION_SKIP_NSDATA);
161  if (!prelink_info) {
162  RZ_FREE(prelink_range);
163  RZ_FREE(obj);
164  goto beach;
165  }
166  }
167 
168  obj->mach0 = main_mach0;
169  obj->rebase_info = rebase_info;
170  obj->prelink_info = prelink_info;
171  obj->cache_buf = fbuf;
172  obj->pa2va_exec = prelink_range->pa2va_exec;
173  obj->pa2va_data = prelink_range->pa2va_data;
174 
175  o->bin_obj = obj;
176 
179  }
180 
181  return true;
182 
183 beach:
184  rz_buf_free(fbuf);
186  (main_mach0);
187  return false;
188 }
static RzXNUKernelCacheRebaseInfo * rz_rebase_info_new_from_mach0(RzBuffer *cache_buf, struct MACH0_(obj_t) *mach0)
static RPrelinkRange * get_prelink_info_range_from_mach0(struct MACH0_(obj_t) *mach0)
RZ_API RzBuffer * rz_xnu_kernelcache_new_rebasing_buf(RzXNUKernelCacheObj *obj)
Definition: kernelcache.c:313
RZ_API bool rz_xnu_kernelcache_needs_rebasing(RzXNUKernelCacheObj *obj)
Definition: kernelcache.c:317
void *MACH0_() mach0_free(struct MACH0_(obj_t) *mo)
Definition: mach0.c:2057
void MACH0_() opts_set_default(struct MACH0_(opts_t) *options, RzBinFile *bf)
Definition: mach0.c:2103
@ MH_FILESET
Definition: mach0_defines.h:83
RZ_API RzBuffer * rz_buf_ref(RzBuffer *b)
Increment the reference count of the buffer.
Definition: buf.c:668
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
RZ_API RCFValueDict * rz_cf_value_dict_parse(RzBuffer *file_buf, ut64 offset, ut64 size, int options)
Definition: rz_cf_dict.c:68
#define RZ_CF_OPTION_SKIP_NSDATA
Definition: rz_cf_dict.h:8
RzXNUKernelCacheRebaseInfo * rebase_info
Definition: kernelcache.h:38

Referenced by baddr(), carve_kexts(), get_prelink_info_range_from_mach0(), get_stubs_info(), process_constructors(), process_kmod_init_term(), resolve_mig_subsystem(), resolve_syscalls(), rz_kernel_cache_free(), rz_kext_fill_text_range(), rz_kext_free(), rz_rebase_info_new_from_mach0(), sections_from_mach0(), and symbols_from_mach0().

◆ maps()

static RzList* maps ( RzBinFile bf)
static

Definition at line 1008 of file bin_xnu_kernelcache.c.

1008  {
1009  RzBinObject *obj = bf ? bf->o : NULL;
1010  if (!obj || !obj->bin_obj) {
1011  return NULL;
1012  }
1014  if (!ret) {
1015  return NULL;
1016  }
1017 
1020 
1021  int nsegs = RZ_MIN(kobj->mach0->nsegs, 128);
1022  int i;
1023  for (i = 0; i < nsegs; i++) {
1025  if (!map) {
1026  break;
1027  }
1028  char segname[17];
1029  struct MACH0_(segment_command) *seg = &kobj->mach0->segs[i];
1030  rz_str_ncpy(segname, seg->segname, 17);
1031  rz_str_filter(segname);
1032  map->name = rz_str_newf("%d.%s", i, segname);
1033  map->paddr = seg->fileoff + bf->o->boffset;
1034  map->psize = seg->vmsize;
1035  map->vsize = seg->vmsize;
1036  map->vaddr = seg->vmaddr;
1037  if (!map->vaddr) {
1038  map->vaddr = map->paddr;
1039  }
1040  map->perm = prot2perm(seg->initprot);
1041  map->vfile_name = kobj->rebased_buf ? strdup(VFILE_NAME_REBASED) : NULL;
1042  rz_list_append(ret, map);
1043  }
1044 
1045  return ret;
1046 }
RZ_API void rz_bin_map_free(RzBinMap *map)
Definition: bin.c:1023
static int prot2perm(int x)
static void ensure_kexts_initialized(RzXNUKernelCacheObj *obj)
#define VFILE_NAME_REBASED
size_t map(int syms, int left, int len)
Definition: enough.c:237
RZ_API size_t rz_str_ncpy(char *dst, const char *src, size_t n)
Secure string copy with null terminator.
Definition: str.c:923
RZ_API void rz_str_filter(char *str)
Convert all non-printable characters in str with '.'.
Definition: str.c:2359
Description of a single memory mapping into virtual memory from a binary.
Definition: rz_bin.h:602
ut64 boffset
Definition: rz_bin.h:262

References rz_bin_object_t::bin_obj, rz_bin_object_t::boffset, ensure_kexts_initialized(), i, map(), NULL, rz_bin_file_t::o, prot2perm(), rz_xnu_kernelcache_obj_t::rebased_buf, rz_bin_map_free(), rz_list_append(), rz_list_newf(), RZ_MIN, RZ_NEW0, rz_str_filter(), rz_str_ncpy(), rz_str_newf(), strdup(), and VFILE_NAME_REBASED.

◆ mig_hash_new()

static HtPP* mig_hash_new ( void  )
static

Definition at line 1451 of file bin_xnu_kernelcache.c.

1451  {
1452  HtPP *hash = sdb_ht_new();
1453  if (!hash) {
1454  return NULL;
1455  }
1456 
1457  int i;
1458  for (i = 0; i < RZ_MIG_INDEX_LEN; i += 2) {
1459  const char *num = mig_index[i];
1460  const char *name = mig_index[i + 1];
1461  sdb_ht_insert(hash, num, name);
1462  }
1463 
1464  return hash;
1465 }
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode static oldfd struct tms static buf static getgid static geteuid const char static filename static arg static mask struct ustat static ubuf static getppid static setsid static egid sigset_t static set struct timeval struct timezone static tz fd_set fd_set fd_set struct timeval static timeout const char char static bufsiz const char static swapflags void static offset const char static length static mode static who const char struct statfs static buf unsigned unsigned num
Definition: sflib.h:126
#define RZ_MIG_INDEX_LEN
Definition: mig_index.h:20
static const char * mig_index[RZ_MIG_INDEX_LEN]
Definition: mig_index.h:22
RZ_API HtPP * sdb_ht_new(void)
Definition: sdbht.c:11
RZ_API bool sdb_ht_insert(HtPP *ht, const char *key, const char *value)
Definition: sdbht.c:43

References i, mig_index, NULL, num, RZ_MIG_INDEX_LEN, sdb_ht_insert(), and sdb_ht_new().

Referenced by resolve_mig_subsystem().

◆ newEntry()

static RzBinAddr* newEntry ( ut64  haddr,
ut64  vaddr,
int  type 
)
static

Definition at line 964 of file bin_xnu_kernelcache.c.

964  {
965  RzBinAddr *ptr = RZ_NEW0(RzBinAddr);
966  if (!ptr) {
967  return NULL;
968  }
969  ptr->paddr = haddr;
970  ptr->vaddr = vaddr;
971  ptr->hpaddr = haddr;
972  ptr->bits = 64;
973  ptr->type = type;
974  return ptr;
975 }
ut64 vaddr
Definition: rz_bin.h:186
ut64 paddr
Definition: rz_bin.h:187
ut64 hpaddr
Definition: rz_bin.h:189

References rz_bin_addr_t::bits, rz_bin_addr_t::hpaddr, NULL, rz_bin_addr_t::paddr, RZ_NEW0, type, rz_bin_addr_t::type, _RKext::vaddr, and rz_bin_addr_t::vaddr.

Referenced by entries(), and process_constructors().

◆ p_ptr()

static ut64 p_ptr ( ut64  decorated_addr,
RzXNUKernelCacheObj obj 
)
static

Definition at line 389 of file bin_xnu_kernelcache.c.

389  {
391  rz_xnu_kernelcache_parse_pointer(&ptr, decorated_addr, obj);
392  return ptr.address;
393 }
RZ_API bool rz_xnu_kernelcache_parse_pointer(RzXNUKernelCacheParsedPointer *ptr, ut64 decorated_addr, RzXNUKernelCacheObj *obj)
Definition: kernelcache.c:218

References rz_xnu_kernelcache_parsed_pointer_t::address, and rz_xnu_kernelcache_parse_pointer().

◆ process_constructors()

static void process_constructors ( RzXNUKernelCacheObj obj,
struct MACH0_(obj_t) *  mach0,
RzList ret,
ut64  paddr,
bool  is_first,
int  mode,
const char *  prefix 
)
static

Definition at line 906 of file bin_xnu_kernelcache.c.

906  {
907  struct section_t *sections = NULL;
908  if (!(sections = MACH0_(get_sections)(mach0))) {
909  return;
910  }
911  int i, type;
912  for (i = 0; !sections[i].last; i++) {
913  if (sections[i].size == 0) {
914  continue;
915  }
916 
917  if (strstr(sections[i].name, "_mod_fini_func") || strstr(sections[i].name, "_mod_term_func")) {
919  } else if (strstr(sections[i].name, "_mod_init_func")) {
920  type = is_first ? 0 : RZ_BIN_ENTRY_TYPE_INIT;
921  is_first = false;
922  } else {
923  continue;
924  }
925 
926  ut8 *buf = calloc(sections[i].size, 1);
927  if (!buf) {
928  break;
929  }
930  if (rz_buf_read_at(obj->cache_buf, sections[i].offset + paddr, buf, sections[i].size) < sections[i].size) {
931  free(buf);
932  break;
933  }
934  int j;
935  int count = 0;
936  for (j = 0; j < sections[i].size; j += 8) {
937  ut64 addr64 = K_RPTR(buf + j);
938  ut64 paddr64 = sections[i].offset + paddr + j;
940  RzBinAddr *ba = newEntry(paddr64, addr64, type);
941  rz_list_append(ret, ba);
942  } else if (mode == RZ_K_CONSTRUCTOR_TO_SYMBOL) {
944  if (!sym) {
945  break;
946  }
947 
948  sym->name = rz_str_newf("%s.%s.%d", prefix, (type == RZ_BIN_ENTRY_TYPE_INIT) ? "init" : "fini", count++);
949  sym->vaddr = addr64;
950  sym->paddr = paddr64;
951  sym->size = 0;
952  sym->forwarder = "NONE";
953  sym->bind = "GLOBAL";
954  sym->type = "FUNC";
955 
956  rz_list_append(ret, sym);
957  }
958  }
959  free(buf);
960  }
961  free(sections);
962 }
#define RZ_K_CONSTRUCTOR_TO_SYMBOL
unsigned short prefix[65536]
Definition: gun.c:163
voidpf void uLong size
Definition: ioapi.h:138
const char int mode
Definition: ioapi.h:137
#define RZ_BIN_ENTRY_TYPE_FINI
Definition: rz_bin.h:36

References rz_bin_symbol_t::bind, rz_xnu_kernelcache_obj_t::cache_buf, calloc(), count, rz_bin_symbol_t::forwarder, free(), get_sections(), i, K_RPTR, MACH0_(), rz_bin_symbol_t::name, newEntry(), NULL, rz_bin_symbol_t::paddr, prefix, RZ_BIN_ENTRY_TYPE_FINI, RZ_BIN_ENTRY_TYPE_INIT, rz_buf_read_at(), RZ_K_CONSTRUCTOR_TO_ENTRY, RZ_K_CONSTRUCTOR_TO_SYMBOL, rz_list_append(), RZ_NEW0, rz_str_newf(), sections(), rz_bin_symbol_t::size, type, rz_bin_symbol_t::type, ut64(), and rz_bin_symbol_t::vaddr.

Referenced by entries(), and symbols().

◆ process_kmod_init_term()

static void process_kmod_init_term ( RzXNUKernelCacheObj obj,
RKext kext,
RzList ret,
ut64 **  inits,
ut64 **  terms 
)
static

Definition at line 801 of file bin_xnu_kernelcache.c.

801  {
802  if (!*inits || !*terms) {
803  struct section_t *sections = NULL;
804  if (!(sections = MACH0_(get_sections)(obj->mach0))) {
805  return;
806  }
807 
808  int i = 0;
809  for (; !sections[i].last; i++) {
810  if (sections[i].size == 0) {
811  continue;
812  }
813 
814  ut64 start_paddr = 0;
815  ut64 *target = NULL;
816  int n_ptrs = 0;
817 
818  if (!*inits && strstr(sections[i].name, "__kmod_init")) {
819  int n_inits = sections[i].size / 8;
820  if (n_inits <= 0) {
821  continue;
822  }
823  *inits = RZ_NEWS0(ut64, n_inits + 1);
824  target = *inits;
825  n_ptrs = n_inits;
826  }
827  if (!*terms && strstr(sections[i].name, "__kmod_term")) {
828  int n_terms = sections[i].size / 8;
829  if (n_terms <= 0) {
830  continue;
831  }
832  *terms = RZ_NEWS0(ut64, n_terms + 1);
833  target = *terms;
834  n_ptrs = n_terms;
835  }
836  if (!target || !n_ptrs) {
837  continue;
838  }
839  start_paddr = sections[i].offset;
840  int j = 0;
841  ut8 bytes[8];
842  for (; j < n_ptrs; j++) {
843  if (rz_buf_read_at(obj->cache_buf, start_paddr + j * 8, bytes, 8) < 8) {
844  break;
845  }
846  target[j] = K_RPTR(bytes);
847  }
848  target[j] = 0;
849  }
850 
851  RZ_FREE(sections);
852  }
853 
854  if (*inits) {
855  create_initterm_syms(kext, ret, RZ_BIN_ENTRY_TYPE_INIT, *inits);
856  }
857  if (*terms) {
858  create_initterm_syms(kext, ret, RZ_BIN_ENTRY_TYPE_FINI, *terms);
859  }
860 }
static void create_initterm_syms(RKext *kext, RzList *ret, int type, ut64 *pointers)

References bytes, rz_xnu_kernelcache_obj_t::cache_buf, create_initterm_syms(), get_sections(), i, K_RPTR, MACH0_(), NULL, RZ_BIN_ENTRY_TYPE_FINI, RZ_BIN_ENTRY_TYPE_INIT, rz_buf_read_at(), RZ_FREE, RZ_NEWS0, sections(), and ut64().

Referenced by symbols().

◆ prot2perm()

static int prot2perm ( int  x)
static

Definition at line 1108 of file bin_xnu_kernelcache.c.

1108  {
1109  int r = 0;
1110  if (x & 1)
1111  r |= 4;
1112  if (x & 2)
1113  r |= 2;
1114  if (x & 4)
1115  r |= 1;
1116  return r;
1117 }
#define r
Definition: crypto_rc6.c:12
int x
Definition: mipsasm.c:20

References r, and x.

Referenced by maps(), and sections().

◆ resolve_mig_subsystem()

static RzList * resolve_mig_subsystem ( RzXNUKernelCacheObj obj)
static

Definition at line 1467 of file bin_xnu_kernelcache.c.

1467  {
1468  struct section_t *sections = NULL;
1469  if (!(sections = MACH0_(get_sections)(obj->mach0))) {
1470  return NULL;
1471  }
1472 
1473  HtPP *mig_hash = NULL;
1474  RzList *subsystem = NULL;
1475  ut8 *data_const = NULL;
1476  ut64 data_const_offset = 0, data_const_size = 0, data_const_vaddr = 0;
1477  ut64 text_exec_offset = 0, text_exec_size = 0, text_exec_vaddr = 0;
1478  int incomplete = 2;
1479  int i = 0;
1480  for (; !sections[i].last && incomplete > 0; i++) {
1481  if (strstr(sections[i].name, "__DATA_CONST.__const")) {
1482  data_const_offset = sections[i].offset;
1483  data_const_size = sections[i].size;
1484  data_const_vaddr = K_PPTR(sections[i].addr);
1485  incomplete--;
1486  }
1487  if (strstr(sections[i].name, "__TEXT_EXEC.__text")) {
1488  text_exec_offset = sections[i].offset;
1489  text_exec_size = sections[i].size;
1490  text_exec_vaddr = K_PPTR(sections[i].addr);
1491  incomplete--;
1492  }
1493  }
1494 
1495  if (!data_const_offset || !data_const_size || !data_const_vaddr ||
1496  !text_exec_offset || !text_exec_size || !text_exec_vaddr) {
1497  goto beach;
1498  }
1499 
1500  data_const = malloc(data_const_size);
1501  if (!data_const) {
1502  goto beach;
1503  }
1504  if (rz_buf_read_at(obj->cache_buf, data_const_offset, data_const, data_const_size) < data_const_size) {
1505  goto beach;
1506  }
1507 
1509  if (!subsystem) {
1510  goto beach;
1511  }
1512 
1513  mig_hash = mig_hash_new();
1514  if (!mig_hash) {
1515  goto beach;
1516  }
1517 
1518  ut8 *cursor = data_const;
1519  ut8 *end = data_const + data_const_size;
1520  while (cursor < end) {
1521  ut64 subs_p = K_PPTR(rz_read_le64(cursor));
1522  if (subs_p < text_exec_vaddr || subs_p >= text_exec_vaddr + text_exec_size) {
1523  cursor += 8;
1524  continue;
1525  }
1526  ut32 subs_min_idx = rz_read_le32(cursor + 8);
1527  ut32 subs_max_idx = rz_read_le32(cursor + 12);
1528  ut32 n_routines = (subs_max_idx - subs_min_idx);
1529  if (subs_min_idx >= subs_max_idx || (subs_max_idx - subs_min_idx) > K_MIG_MAX_ROUTINES) {
1530  cursor += 16;
1531  continue;
1532  }
1533 
1534  ut64 *routines = (ut64 *)malloc(n_routines * sizeof(ut64));
1535  if (!routines) {
1536  goto beach;
1537  }
1538  ut8 *array_cursor = cursor + K_MIG_SUBSYSTEM_SIZE;
1539  ut8 *end_array = array_cursor + n_routines * K_MIG_ROUTINE_SIZE;
1540  bool is_consistent = true;
1541  int idx = 0;
1542  while (array_cursor < end_array) {
1543  ut64 should_be_null = rz_read_le64(array_cursor);
1544  if (should_be_null != 0) {
1545  is_consistent = false;
1546  break;
1547  }
1548 
1549  ut64 routine_p = K_PPTR(rz_read_le64(array_cursor + 8));
1550  if (routine_p != 0 && (routine_p < text_exec_vaddr || routine_p >= text_exec_vaddr + text_exec_size)) {
1551  is_consistent = false;
1552  break;
1553  }
1554 
1555  routines[idx++] = routine_p;
1556  array_cursor += K_MIG_ROUTINE_SIZE;
1557  }
1558 
1559  if (is_consistent) {
1560  for (idx = 0; idx < n_routines; idx++) {
1561  ut64 routine_p = routines[idx];
1562  if (!routine_p) {
1563  continue;
1564  }
1565 
1567  if (!sym) {
1568  RZ_FREE(routines);
1569  goto beach;
1570  }
1571 
1572  int num = idx + subs_min_idx;
1573  bool found = false;
1574  const char *key = sdb_fmt("%d", num);
1575  const char *name = sdb_ht_find(mig_hash, key, &found);
1576  if (found && name && *name) {
1577  sym->name = rz_str_newf("mig.%d.%s", num, name);
1578  } else {
1579  sym->name = rz_str_newf("mig.%d", num);
1580  }
1581 
1582  sym->vaddr = routine_p;
1583  sym->paddr = sym->vaddr - text_exec_vaddr + text_exec_offset;
1584  sym->size = 0;
1585  sym->forwarder = "NONE";
1586  sym->bind = "GLOBAL";
1587  sym->type = "OBJECT";
1588  rz_list_append(subsystem, sym);
1589  }
1590 
1591  cursor += K_MIG_SUBSYSTEM_SIZE + n_routines * K_MIG_ROUTINE_SIZE;
1592  } else {
1593  cursor += 8;
1594  }
1595 
1596  RZ_FREE(routines);
1597  }
1598 
1599  sdb_ht_free(mig_hash);
1600  RZ_FREE(data_const);
1601  RZ_FREE(sections);
1602  return subsystem;
1603 
1604 beach:
1605  if (subsystem) {
1606  rz_list_free(subsystem);
1607  }
1608  if (mig_hash) {
1609  sdb_ht_free(mig_hash);
1610  }
1611  RZ_FREE(data_const);
1612  RZ_FREE(sections);
1613  return NULL;
1614 }
RZ_API void rz_bin_symbol_free(RzBinSymbol *sym)
Definition: bin.c:175
static HtPP * mig_hash_new(void)
#define K_MIG_SUBSYSTEM_SIZE
#define K_MIG_ROUTINE_SIZE
#define K_MIG_MAX_ROUTINES
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 static offset struct stat static buf void long static basep static whence static length const void static len key
Definition: sflib.h:118
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
RZ_API const KEY_TYPE bool * found
Definition: ht_inc.h:130
void * malloc(size_t size)
Definition: malloc.c:123
int idx
Definition: setup.py:197
static ut64 rz_read_le64(const void *src)
Definition: rz_endian.h:266
RZ_API char * sdb_ht_find(HtPP *ht, const char *key, bool *found)
Definition: sdbht.c:59
RZ_API void sdb_ht_free(HtPP *ht)
Definition: sdbht.c:63

References addr, rz_bin_symbol_t::bind, rz_xnu_kernelcache_obj_t::cache_buf, test_evm::end, rz_bin_symbol_t::forwarder, found, get_sections(), i, setup::idx, K_MIG_MAX_ROUTINES, K_MIG_ROUTINE_SIZE, K_MIG_SUBSYSTEM_SIZE, K_PPTR, key, MACH0_(), malloc(), mig_hash_new(), rz_bin_symbol_t::name, NULL, num, rz_bin_symbol_t::paddr, rz_bin_symbol_free(), rz_buf_read_at(), RZ_FREE, rz_list_append(), rz_list_free(), rz_list_newf(), RZ_NEW0, rz_read_le32(), rz_read_le64(), rz_str_newf(), sdb_fmt(), sdb_ht_find(), sdb_ht_free(), sections(), rz_bin_symbol_t::size, rz_bin_symbol_t::type, ut64(), and rz_bin_symbol_t::vaddr.

Referenced by symbols().

◆ resolve_syscalls()

static RzList * resolve_syscalls ( RzXNUKernelCacheObj obj,
ut64  enosys_addr 
)
static

Definition at line 1306 of file bin_xnu_kernelcache.c.

1306  {
1307  struct section_t *sections = NULL;
1308  if (!(sections = MACH0_(get_sections)(obj->mach0))) {
1309  return NULL;
1310  }
1311 
1312  RzList *syscalls = NULL;
1313  RzSyscall *syscall = NULL;
1314  ut8 *data_const = NULL;
1315  ut64 data_const_offset = 0, data_const_size = 0, data_const_vaddr = 0;
1316  int i = 0;
1317  for (; !sections[i].last; i++) {
1318  if (strstr(sections[i].name, "__DATA_CONST.__const")) {
1319  data_const_offset = sections[i].offset;
1320  data_const_size = sections[i].size;
1321  data_const_vaddr = K_PPTR(sections[i].addr);
1322  break;
1323  }
1324  }
1325 
1326  if (!data_const_offset || !data_const_size || !data_const_vaddr) {
1327  goto beach;
1328  }
1329 
1330  data_const = malloc(data_const_size);
1331  if (!data_const) {
1332  goto beach;
1333  }
1334  if (rz_buf_read_at(obj->cache_buf, data_const_offset, data_const, data_const_size) < data_const_size) {
1335  goto beach;
1336  }
1337 
1338  ut8 *cursor = data_const;
1339  ut8 *end = data_const + data_const_size;
1340  while (cursor < end) {
1341  ut64 test = rz_read_le64(cursor);
1342  if (test == enosys_addr) {
1343  break;
1344  }
1345  cursor += 8;
1346  }
1347 
1348  if (cursor >= end) {
1349  goto beach;
1350  }
1351 
1352  cursor -= 24;
1353  while (cursor >= data_const) {
1354  ut64 addr = rz_read_le64(cursor);
1355  ut64 x = rz_read_le64(cursor + 8);
1356  ut64 y = rz_read_le64(cursor + 16);
1357 
1358  if (IS_KERNEL_ADDR(addr) &&
1359  (x == 0 || IS_KERNEL_ADDR(x)) &&
1360  (y != 0 && !IS_KERNEL_ADDR(y))) {
1361  cursor -= 24;
1362  continue;
1363  }
1364 
1365  cursor += 24;
1366  break;
1367  }
1368 
1369  if (cursor < data_const) {
1370  goto beach;
1371  }
1372 
1374  if (!syscalls) {
1375  goto beach;
1376  }
1377 
1378  syscall = rz_syscall_new();
1379  if (!syscall) {
1380  goto beach;
1381  }
1382  rz_syscall_setup(syscall, "arm", 64, NULL, "ios");
1383  if (!syscall->db) {
1385  goto beach;
1386  }
1387 
1388  ut64 sysent_vaddr = cursor - data_const + data_const_vaddr;
1389 
1391  if (!sym) {
1392  goto beach;
1393  }
1394 
1395  sym->name = rz_str_newf("sysent");
1396  sym->vaddr = sysent_vaddr;
1397  sym->paddr = cursor - data_const + data_const_offset;
1398  sym->size = 0;
1399  sym->forwarder = "NONE";
1400  sym->bind = "GLOBAL";
1401  sym->type = "OBJECT";
1402  rz_list_append(syscalls, sym);
1403 
1404  i = 1;
1405  cursor += 24;
1406  int num_syscalls = sdb_count(syscall->db);
1407  while (cursor < end && i < num_syscalls) {
1408  ut64 addr = rz_read_le64(cursor);
1409  RzSyscallItem *item = rz_syscall_get(syscall, i, 0x80);
1410  if (item && item->name) {
1412  if (!sym) {
1413  rz_syscall_item_free(item);
1414  goto beach;
1415  }
1416 
1417  sym->name = rz_str_newf("syscall.%d.%s", i, item->name);
1418  sym->vaddr = addr;
1419  sym->paddr = addr;
1420  sym->size = 0;
1421  sym->forwarder = "NONE";
1422  sym->bind = "GLOBAL";
1423  sym->type = "FUNC";
1424  rz_list_append(syscalls, sym);
1425  }
1426 
1427  rz_syscall_item_free(item);
1428  cursor += 24;
1429  i++;
1430  }
1431 
1433  RZ_FREE(data_const);
1434  RZ_FREE(sections);
1435  return syscalls;
1436 
1437 beach:
1439  if (syscalls) {
1440  rz_list_free(syscalls);
1441  }
1442  RZ_FREE(data_const);
1443  RZ_FREE(sections);
1444  return NULL;
1445 }
#define IS_KERNEL_ADDR(x)
-lz4-versions
RZ_API int sdb_count(Sdb *s)
Definition: sdb.c:163
const char * syscall
Definition: internal.h:270
RZ_API RzSyscall * rz_syscall_new(void)
Creates a new RzSyscall type.
Definition: syscall.c:67
RZ_API void rz_syscall_free(RzSyscall *s)
Frees an RzSyscall type.
Definition: syscall.c:79
RZ_API void rz_syscall_item_free(RzSyscallItem *si)
Definition: syscall.c:325
RZ_API RzSyscallItem * rz_syscall_get(RzSyscall *s, int num, int swi)
Definition: syscall.c:345
RZ_API bool rz_syscall_setup(RzSyscall *s, const char *arch, int bits, const char *cpu, const char *os)
Definition: syscall.c:234

References addr, rz_bin_symbol_t::bind, rz_xnu_kernelcache_obj_t::cache_buf, test_evm::end, rz_bin_symbol_t::forwarder, get_sections(), i, IS_KERNEL_ADDR, K_PPTR, MACH0_(), malloc(), rz_bin_symbol_t::name, rz_syscall_item_t::name, NULL, rz_bin_symbol_t::paddr, rz_bin_symbol_free(), rz_buf_read_at(), RZ_FREE, rz_list_append(), rz_list_free(), rz_list_newf(), RZ_NEW0, rz_read_le64(), rz_str_newf(), rz_syscall_free(), rz_syscall_get(), rz_syscall_item_free(), rz_syscall_new(), rz_syscall_setup(), sdb_count(), sections(), rz_bin_symbol_t::size, syscall, rz_bin_symbol_t::type, ut64(), rz_bin_symbol_t::vaddr, and x.

Referenced by symbols().

◆ rz_kernel_cache_free()

static void rz_kernel_cache_free ( RzXNUKernelCacheObj obj)
static

Definition at line 1804 of file bin_xnu_kernelcache.c.

1804  {
1805  if (!obj) {
1806  return;
1807  }
1808 
1809  if (obj->mach0) {
1811  (obj->mach0);
1812  obj->mach0 = NULL;
1813  obj->cache_buf = NULL;
1814  }
1815 
1816  if (obj->cache_buf) {
1817  rz_buf_free(obj->cache_buf);
1818  obj->cache_buf = NULL;
1819  }
1820 
1821  if (obj->prelink_info) {
1823  obj->prelink_info = NULL;
1824  }
1825 
1826  if (obj->kexts) {
1827  rz_kext_index_free(obj->kexts);
1828  obj->kexts = NULL;
1829  }
1830 
1831  if (obj->rebase_info) {
1833  obj->rebase_info = NULL;
1834  }
1835 
1836  RZ_FREE(obj);
1837 }
static void rz_kext_index_free(RKextIndex *index)
static void rz_rebase_info_free(RzXNUKernelCacheRebaseInfo *info)
RZ_API void rz_cf_value_dict_free(RCFValueDict *dict)
Definition: rz_cf_dict.c:352

References rz_xnu_kernelcache_obj_t::cache_buf, rz_xnu_kernelcache_obj_t::kexts, MACH0_(), mach0_free(), NULL, rz_xnu_kernelcache_obj_t::prelink_info, rz_xnu_kernelcache_obj_t::rebase_info, rz_buf_free(), rz_cf_value_dict_free(), RZ_FREE, rz_kext_index_free(), and rz_rebase_info_free().

Referenced by destroy().

◆ rz_kext_fill_text_range()

static void rz_kext_fill_text_range ( RKext kext)
static

Definition at line 659 of file bin_xnu_kernelcache.c.

659  {
660  struct section_t *sections = NULL;
661  if (!(sections = MACH0_(get_sections)(kext->mach0))) {
662  return;
663  }
664 
665  int i = 0;
666  for (; !sections[i].last; i++) {
667  if (strstr(sections[i].name, "__TEXT_EXEC.__text")) {
668  kext->text_range.offset = sections[i].offset;
669  kext->text_range.size = sections[i].size;
670  kext->vaddr = sections[i].addr;
671  break;
672  }
673  }
674 
675  RZ_FREE(sections);
676 }

References get_sections(), i, MACH0_(), NULL, rz_xnu_kernelcache_file_range_t::offset, RZ_FREE, sections(), rz_xnu_kernelcache_file_range_t::size, _RKext::text_range, and _RKext::vaddr.

Referenced by carve_kexts(), filter_kexts(), and kexts_from_load_commands().

◆ rz_kext_free()

static void rz_kext_free ( RKext kext)
static

Definition at line 640 of file bin_xnu_kernelcache.c.

640  {
641  if (!kext) {
642  return;
643  }
644 
645  if (kext->mach0) {
647  (kext->mach0);
648  kext->mach0 = NULL;
649  }
650 
651  if (kext->own_name && kext->name) {
652  RZ_FREE(kext->name);
653  kext->name = NULL;
654  }
655 
656  RZ_FREE(kext);
657 }

References MACH0_(), mach0_free(), _RKext::name, NULL, and RZ_FREE.

Referenced by carve_kexts(), filter_kexts(), kexts_from_load_commands(), and rz_kext_index_free().

◆ rz_kext_index_free()

static void rz_kext_index_free ( RKextIndex index)
static

Definition at line 720 of file bin_xnu_kernelcache.c.

720  {
721  if (!index) {
722  return;
723  }
724 
725  int i = 0;
726  RKext *kext;
727  rz_kext_index_foreach(index, i, kext) {
728  rz_kext_free(kext);
729  index->entries[i] = NULL;
730  }
731 
732  index->length = 0;
733  RZ_FREE(index);
734 }
#define rz_kext_index_foreach(index, i, item)

References _RKextIndex::entries, i, _RKextIndex::length, NULL, RZ_FREE, rz_kext_free(), and rz_kext_index_foreach.

Referenced by rz_kernel_cache_free().

◆ rz_kext_index_new()

static RKextIndex* rz_kext_index_new ( RzList kexts)
static

Definition at line 688 of file bin_xnu_kernelcache.c.

688  {
689  if (!kexts) {
690  return NULL;
691  }
692 
693  int length = rz_list_length(kexts);
694  if (!length) {
695  return NULL;
696  }
697 
698  RKextIndex *index = RZ_NEW0(RKextIndex);
699  if (!index) {
700  return NULL;
701  }
702 
703  index->entries = malloc(length * sizeof(RKext *));
704  if (!index->entries) {
705  RZ_FREE(index);
706  return NULL;
707  }
708 
709  RzListIter *iter;
710  RKext *kext;
711  int i = 0;
712  rz_list_foreach (kexts, iter, kext) {
713  index->entries[i++] = kext;
714  }
715  index->length = i;
716 
717  return index;
718 }

References _RKextIndex::entries, i, _RKextIndex::length, length, malloc(), NULL, RZ_FREE, rz_list_length(), and RZ_NEW0.

Referenced by ensure_kexts_initialized().

◆ rz_kext_index_vget()

static RKext* rz_kext_index_vget ( RKextIndex index,
ut64  vaddr 
)
static

Definition at line 736 of file bin_xnu_kernelcache.c.

736  {
737  int imid;
738  int imin = 0;
739  int imax = index->length - 1;
740 
741  while (imin < imax) {
742  imid = (imin + imax) / 2;
743  RKext *entry = index->entries[imid];
744  if ((entry->vaddr + entry->text_range.size) <= vaddr || (entry->vaddr == vaddr && entry->text_range.size == 0)) {
745  imin = imid + 1;
746  } else {
747  imax = imid;
748  }
749  }
750 
751  RKext *minEntry = index->entries[imin];
752  if ((imax == imin) && (minEntry->vaddr <= vaddr) && ((minEntry->vaddr + minEntry->text_range.size) > vaddr)) {
753  return minEntry;
754  }
755  return NULL;
756 }
Definition: zipcmp.c:77
zip_uint64_t size
Definition: zipcmp.c:79

References _RKextIndex::entries, _RKextIndex::length, NULL, rz_xnu_kernelcache_file_range_t::size, entry::size, _RKext::text_range, and _RKext::vaddr.

Referenced by symbols_from_stubs().

◆ rz_ptr()

static ut64 rz_ptr ( ut8 buf,
RzXNUKernelCacheObj obj 
)
static

Definition at line 395 of file bin_xnu_kernelcache.c.

395  {
396  ut64 decorated_addr = rz_read_le64(buf);
397  return K_PPTR(decorated_addr);
398 }

References K_PPTR, rz_read_le64(), and ut64().

◆ rz_rebase_info_free()

static void rz_rebase_info_free ( RzXNUKernelCacheRebaseInfo info)
static

Definition at line 1919 of file bin_xnu_kernelcache.c.

1919  {
1920  if (!info) {
1921  return;
1922  }
1923 
1924  if (info->ranges) {
1925  RZ_FREE(info->ranges);
1926  info->ranges = NULL;
1927  }
1928 
1929  RZ_FREE(info);
1930 }
static RzBinInfo * info(RzBinFile *bf)

References info(), NULL, and RZ_FREE.

Referenced by rz_kernel_cache_free().

◆ rz_rebase_info_new_from_mach0()

static RzXNUKernelCacheRebaseInfo * rz_rebase_info_new_from_mach0 ( RzBuffer cache_buf,
struct MACH0_(obj_t) *  mach0 
)
static

Definition at line 1839 of file bin_xnu_kernelcache.c.

1839  {
1840  RzXNUKernelCacheFileRange *rebase_ranges = NULL;
1841  struct section_t *sections = NULL;
1842  if (!(sections = MACH0_(get_sections)(mach0))) {
1843  return NULL;
1844  }
1845 
1846  ut64 starts_offset = 0, starts_size = 0;
1847 
1848  int i = 0;
1849  for (; !sections[i].last; i++) {
1850  if (strstr(sections[i].name, "__TEXT.__thread_starts")) {
1851  starts_offset = sections[i].offset;
1852  starts_size = sections[i].size;
1853  break;
1854  }
1855  }
1856 
1857  RZ_FREE(sections);
1858 
1859  ut64 kernel_base = 0;
1860 
1861  struct MACH0_(segment_command) * seg;
1862  int nsegs = RZ_MIN(mach0->nsegs, 128);
1863  for (i = 0; i < nsegs; i++) {
1864  char segname[17];
1865  seg = &mach0->segs[i];
1866  rz_str_ncpy(segname, seg->segname, 17);
1867  if (!strncmp(segname, "__TEXT", 6) && segname[6] == '\0') {
1868  kernel_base = seg->vmaddr;
1869  break;
1870  }
1871  }
1872 
1873  if (starts_offset == 0 || starts_size == 0 || kernel_base == 0) {
1874  return NULL;
1875  }
1876 
1877  int n_starts = starts_size / 4;
1878  if (n_starts <= 1) {
1879  return NULL;
1880  }
1881  rebase_ranges = RZ_NEWS0(RzXNUKernelCacheFileRange, n_starts - 1);
1882  if (rebase_ranges == NULL) {
1883  return NULL;
1884  }
1885 
1886  ut64 multiplier = 4;
1887  for (i = 0; i != n_starts; i++) {
1888  ut8 bytes[4];
1889  if (rz_buf_read_at(cache_buf, starts_offset + i * 4, bytes, 4) < 4) {
1890  goto beach;
1891  }
1892 
1893  if (i == 0) {
1894  multiplier += 4 * (rz_read_le32(bytes) & 1);
1895  continue;
1896  }
1897 
1898  rebase_ranges[i - 1].offset = rz_read_le32(bytes);
1899  rebase_ranges[i - 1].size = UT64_MAX;
1900  }
1901 
1903  if (rebase_info == NULL) {
1904  goto beach;
1905  }
1906  rebase_info->ranges = rebase_ranges;
1907  rebase_info->n_ranges = n_starts - 1;
1908  rebase_info->multiplier = multiplier;
1909  rebase_info->kernel_base = kernel_base;
1910 
1911  return rebase_info;
1912 
1913 beach:
1914 
1915  RZ_FREE(rebase_ranges);
1916  return NULL;
1917 }
#define UT64_MAX
Definition: rz_types_base.h:86
RzXNUKernelCacheFileRange * ranges
Definition: kernelcache.h:20

References bytes, get_sections(), i, rz_xnu_kernelcache_rebase_info_t::kernel_base, MACH0_(), rz_xnu_kernelcache_rebase_info_t::multiplier, rz_xnu_kernelcache_rebase_info_t::n_ranges, NULL, rz_xnu_kernelcache_file_range_t::offset, rz_xnu_kernelcache_rebase_info_t::ranges, rz_buf_read_at(), RZ_FREE, RZ_MIN, RZ_NEW0, RZ_NEWS0, rz_read_le32(), rz_str_ncpy(), sections(), rz_xnu_kernelcache_file_range_t::size, ut64(), and UT64_MAX.

◆ sections()

static RzList* sections ( RzBinFile bf)
static

Definition at line 1048 of file bin_xnu_kernelcache.c.

1048  {
1049  RzList *ret = NULL;
1050  RzBinObject *obj = bf ? bf->o : NULL;
1051 
1052  if (!obj || !obj->bin_obj || !(ret = rz_list_newf((RzListFree)rz_bin_section_free))) {
1053  return NULL;
1054  }
1055 
1058 
1059  int iter;
1060  RKext *kext;
1061  rz_kext_index_foreach(kobj->kexts, iter, kext) {
1062  ut8 magicbytes[4];
1063 
1064  rz_buf_read_at(kobj->cache_buf, kext->range.offset, magicbytes, 4);
1065  int magic = rz_read_le32(magicbytes);
1066  switch (magic) {
1067  case MH_MAGIC_64:
1068  sections_from_mach0(ret, kext->mach0, bf, kext->range.offset, kext->name, kobj);
1069  break;
1070  default:
1071  eprintf("Unknown sub-bin\n");
1072  break;
1073  }
1074  }
1075 
1076  sections_from_mach0(ret, kobj->mach0, bf, 0, NULL, kobj);
1077 
1078  struct MACH0_(segment_command) * seg;
1079  int nsegs = RZ_MIN(kobj->mach0->nsegs, 128);
1080  int i;
1081  for (i = 0; i < nsegs; i++) {
1082  RzBinSection *ptr;
1083  char segname[17];
1084 
1085  if (!(ptr = RZ_NEW0(RzBinSection))) {
1086  break;
1087  }
1088 
1089  seg = &kobj->mach0->segs[i];
1090  rz_str_ncpy(segname, seg->segname, 17);
1091  rz_str_filter(segname);
1092  ptr->name = rz_str_newf("%d.%s", i, segname);
1093  ptr->size = seg->vmsize;
1094  ptr->vsize = seg->vmsize;
1095  ptr->paddr = seg->fileoff + bf->o->boffset;
1096  ptr->vaddr = seg->vmaddr;
1097  ptr->is_segment = true;
1098  if (!ptr->vaddr) {
1099  ptr->vaddr = ptr->paddr;
1100  }
1101  ptr->perm = prot2perm(seg->initprot);
1102  rz_list_append(ret, ptr);
1103  }
1104 
1105  return ret;
1106 }
RZ_API void rz_bin_section_free(RzBinSection *bs)
Definition: bin.c:1116
static void sections_from_mach0(RzList *ret, struct MACH0_(obj_t) *mach0, RzBinFile *bf, ut64 paddr, char *prefix, RzXNUKernelCacheObj *obj)
@ MH_MAGIC_64
Definition: mach0_defines.h:63
bool is_segment
Definition: rz_bin.h:634

References rz_bin_object_t::bin_obj, rz_bin_object_t::boffset, rz_xnu_kernelcache_obj_t::cache_buf, ensure_kexts_initialized(), eprintf, i, rz_bin_section_t::is_segment, rz_xnu_kernelcache_obj_t::kexts, MH_MAGIC_64, _RKext::name, rz_bin_section_t::name, NULL, rz_bin_file_t::o, rz_xnu_kernelcache_file_range_t::offset, rz_bin_section_t::paddr, rz_bin_section_t::perm, prot2perm(), _RKext::range, rz_bin_section_free(), rz_buf_read_at(), rz_kext_index_foreach, rz_list_append(), rz_list_newf(), RZ_MIN, RZ_NEW0, rz_read_le32(), rz_str_filter(), rz_str_ncpy(), rz_str_newf(), sections_from_mach0(), rz_bin_section_t::size, rz_bin_section_t::vaddr, and rz_bin_section_t::vsize.

Referenced by carve_kexts(), get_prelink_info_range_from_mach0(), get_stubs_info(), process_constructors(), process_kmod_init_term(), resolve_mig_subsystem(), resolve_syscalls(), rz_kext_fill_text_range(), rz_rebase_info_new_from_mach0(), and sections_from_mach0().

◆ sections_from_mach0()

static void sections_from_mach0 ( RzList ret,
struct MACH0_(obj_t) *  mach0,
RzBinFile bf,
ut64  paddr,
char *  prefix,
RzXNUKernelCacheObj obj 
)
static

Definition at line 1119 of file bin_xnu_kernelcache.c.

1119  {
1120  struct section_t *sections = NULL;
1121  if (!(sections = MACH0_(get_sections)(mach0))) {
1122  return;
1123  }
1124  int i;
1125  for (i = 0; !sections[i].last; i++) {
1126  RzBinSection *ptr;
1127  if (!(ptr = RZ_NEW0(RzBinSection))) {
1128  break;
1129  }
1130  if (prefix) {
1131  ptr->name = rz_str_newf("%s.%s", prefix, (char *)sections[i].name);
1132  } else {
1133  ptr->name = rz_str_newf("%s", (char *)sections[i].name);
1134  }
1135  if (strstr(ptr->name, "la_symbol_ptr")) {
1136  int len = sections[i].size / 8;
1137  ptr->format = rz_str_newf("Cd %d %d", 8, len);
1138  }
1139  handle_data_sections(ptr);
1140  ptr->size = sections[i].size;
1141  ptr->vsize = sections[i].vsize;
1142  ptr->paddr = sections[i].offset + bf->o->boffset + paddr;
1143  ptr->vaddr = K_PPTR(sections[i].addr);
1144  if (!ptr->vaddr) {
1145  ptr->vaddr = ptr->paddr;
1146  }
1147  ptr->perm = sections[i].perm;
1148  if (!ptr->perm && strstr(sections[i].name, "__TEXT_EXEC.__text")) {
1149  ptr->perm = 1 | 4;
1150  }
1151  rz_list_append(ret, ptr);
1152  }
1153  free(sections);
1154 }
size_t len
Definition: 6502dis.c:15
static void handle_data_sections(RzBinSection *sect)
char * format
Definition: rz_bin.h:630

References addr, rz_bin_object_t::boffset, rz_bin_section_t::format, free(), get_sections(), handle_data_sections(), i, K_PPTR, len, MACH0_(), rz_bin_section_t::name, NULL, rz_bin_file_t::o, rz_bin_section_t::paddr, rz_bin_section_t::perm, prefix, rz_list_append(), RZ_NEW0, rz_str_newf(), sections(), rz_bin_section_t::size, rz_bin_section_t::vaddr, and rz_bin_section_t::vsize.

Referenced by sections().

◆ symbols()

static RzList* symbols ( RzBinFile bf)
static

Definition at line 1170 of file bin_xnu_kernelcache.c.

1170  {
1172  if (!ret) {
1173  return NULL;
1174  }
1175 
1177 
1178  symbols_from_mach0(ret, obj->mach0, bf, 0, 0);
1179 
1180  HtPP *kernel_syms_by_addr = sdb_ht_new();
1181  if (!kernel_syms_by_addr) {
1182  rz_list_free(ret);
1183  return NULL;
1184  }
1185 
1186  RzListIter *iter;
1187  RzBinSymbol *sym;
1188  ut64 enosys_addr = 0;
1189  rz_list_foreach (ret, iter, sym) {
1190  const char *key = sdb_fmt("%" PFMT64x, sym->vaddr);
1191  sdb_ht_insert(kernel_syms_by_addr, key, sym->dname ? sym->dname : sym->name);
1192  if (!enosys_addr && strstr(sym->name, "enosys")) {
1193  enosys_addr = sym->vaddr;
1194  }
1195  }
1196 
1197  RzList *syscalls = resolve_syscalls(obj, enosys_addr);
1198  if (syscalls) {
1199  rz_list_foreach (syscalls, iter, sym) {
1200  const char *key = sdb_fmt("%" PFMT64x, sym->vaddr);
1201  sdb_ht_insert(kernel_syms_by_addr, key, sym->name);
1202  rz_list_append(ret, sym);
1203  }
1204  syscalls->free = NULL;
1205  rz_list_free(syscalls);
1206  }
1207 
1208  RzList *subsystem = resolve_mig_subsystem(obj);
1209  if (subsystem) {
1210  rz_list_foreach (subsystem, iter, sym) {
1211  const char *key = sdb_fmt("%" PFMT64x, sym->vaddr);
1212  sdb_ht_insert(kernel_syms_by_addr, key, sym->name);
1213  rz_list_append(ret, sym);
1214  }
1215  subsystem->free = NULL;
1216  rz_list_free(subsystem);
1217  }
1218 
1220 
1221  RKext *kext;
1222  int kiter;
1223  ut64 *inits = NULL;
1224  ut64 *terms = NULL;
1225  rz_kext_index_foreach(obj->kexts, kiter, kext) {
1226  ut8 magicbytes[4];
1227  rz_buf_read_at(obj->cache_buf, kext->range.offset, magicbytes, 4);
1228  int magic = rz_read_le32(magicbytes);
1229  switch (magic) {
1230  case MH_MAGIC_64:
1231  symbols_from_mach0(ret, kext->mach0, bf, kext->range.offset, rz_list_length(ret));
1232  symbols_from_stubs(ret, kernel_syms_by_addr, obj, bf, kext, rz_list_length(ret));
1233  process_constructors(obj, kext->mach0, ret, kext->range.offset, false, RZ_K_CONSTRUCTOR_TO_SYMBOL, kext_short_name(kext));
1234  process_kmod_init_term(obj, kext, ret, &inits, &terms);
1235 
1236  break;
1237  default:
1238  eprintf("Unknown sub-bin\n");
1239  break;
1240  }
1241  }
1242 
1243  RZ_FREE(inits);
1244  RZ_FREE(terms);
1245 
1246  sdb_ht_free(kernel_syms_by_addr);
1247 
1248  return ret;
1249 }
static RzList * resolve_syscalls(RzXNUKernelCacheObj *obj, ut64 enosys_addr)
static void symbols_from_mach0(RzList *ret, struct MACH0_(obj_t) *mach0, RzBinFile *bf, ut64 paddr, int ordinal)
static void process_kmod_init_term(RzXNUKernelCacheObj *obj, RKext *kext, RzList *ret, ut64 **inits, ut64 **terms)
static void symbols_from_stubs(RzList *ret, HtPP *kernel_syms_by_addr, RzXNUKernelCacheObj *obj, RzBinFile *bf, RKext *kext, int ordinal)
static RzList * resolve_mig_subsystem(RzXNUKernelCacheObj *obj)
#define PFMT64x
Definition: rz_types.h:393
char * dname
Definition: rz_bin.h:676
RzListFree free
Definition: rz_list.h:21

References rz_bin_object_t::bin_obj, rz_xnu_kernelcache_obj_t::cache_buf, rz_bin_symbol_t::dname, ensure_kexts_initialized(), eprintf, rz_list_t::free, kext_short_name(), rz_xnu_kernelcache_obj_t::kexts, key, MH_MAGIC_64, rz_bin_symbol_t::name, NULL, rz_bin_file_t::o, rz_xnu_kernelcache_file_range_t::offset, PFMT64x, process_constructors(), process_kmod_init_term(), _RKext::range, resolve_mig_subsystem(), resolve_syscalls(), rz_bin_symbol_free(), rz_buf_read_at(), RZ_FREE, RZ_K_CONSTRUCTOR_TO_SYMBOL, rz_kext_index_foreach, rz_list_append(), rz_list_free(), rz_list_length(), rz_list_newf(), rz_read_le32(), sdb_fmt(), sdb_ht_free(), sdb_ht_insert(), sdb_ht_new(), symbols_from_mach0(), symbols_from_stubs(), ut64(), and rz_bin_symbol_t::vaddr.

Referenced by symbols_from_mach0().

◆ symbols_from_mach0()

static void symbols_from_mach0 ( RzList ret,
struct MACH0_(obj_t) *  mach0,
RzBinFile bf,
ut64  paddr,
int  ordinal 
)
static

Definition at line 1251 of file bin_xnu_kernelcache.c.

1251  {
1252  const struct symbol_t *symbols = MACH0_(get_symbols)(mach0);
1253  if (!symbols) {
1254  return;
1255  }
1256  int i;
1257  for (i = 0; !symbols[i].last; i++) {
1258  if (!symbols[i].name[0] || symbols[i].addr < 100) {
1259  continue;
1260  }
1262  if (!sym) {
1263  break;
1264  }
1265  sym->name = strdup(symbols[i].name);
1266  sym->vaddr = symbols[i].addr;
1267  if (sym->name[0] == '_') {
1268  char *dn = rz_bin_demangle(bf, sym->name, sym->name, sym->vaddr, false);
1269  if (dn) {
1270  sym->dname = dn;
1271  char *p = strchr(dn, '.');
1272  if (p) {
1273  if (IS_UPPER(sym->name[0])) {
1274  sym->classname = strdup(sym->name);
1275  sym->classname[p - sym->name] = 0;
1276  } else if (IS_UPPER(p[1])) {
1277  sym->classname = strdup(p + 1);
1278  p = strchr(sym->classname, '.');
1279  if (p) {
1280  *p = 0;
1281  }
1282  }
1283  }
1284  }
1285  }
1286  sym->forwarder = "NONE";
1287  sym->bind = (symbols[i].type == RZ_BIN_MACH0_SYMBOL_TYPE_LOCAL) ? "LOCAL" : "GLOBAL";
1288  sym->type = "FUNC";
1289  sym->paddr = symbols[i].offset + bf->o->boffset + paddr;
1290  sym->size = symbols[i].size;
1291  sym->ordinal = ordinal + i;
1292  rz_list_append(ret, sym);
1293  }
1294 }
RZ_API RZ_OWN char * rz_bin_demangle(RZ_NULLABLE RzBinFile *bf, RZ_NULLABLE const char *language, RZ_NULLABLE const char *symbol, ut64 vaddr, bool libs)
Demangles a symbol based on the language or the RzBinFile data.
Definition: bin.c:1295
static RzList * symbols(RzBinFile *bf)
void * p
Definition: libc.cpp:67
const struct symbol_t *MACH0_() get_symbols(struct MACH0_(obj_t) *bin)
Definition: mach0.c:2959
#define RZ_BIN_MACH0_SYMBOL_TYPE_LOCAL
Definition: mach0_specs.h:26
#define IS_UPPER(c)
Definition: rz_str_util.h:14
char * classname
Definition: rz_bin.h:678
ut32 ordinal
Definition: rz_bin.h:692
Definition: mach0.h:54

References addr, rz_bin_symbol_t::bind, rz_bin_object_t::boffset, rz_bin_symbol_t::classname, rz_bin_symbol_t::dname, rz_bin_symbol_t::forwarder, get_symbols(), i, IS_UPPER, MACH0_(), rz_bin_symbol_t::name, rz_bin_file_t::o, rz_bin_symbol_t::ordinal, p, rz_bin_symbol_t::paddr, rz_bin_demangle(), RZ_BIN_MACH0_SYMBOL_TYPE_LOCAL, rz_list_append(), RZ_NEW0, rz_bin_symbol_t::size, strdup(), symbols(), rz_bin_symbol_t::type, and rz_bin_symbol_t::vaddr.

Referenced by symbols().

◆ symbols_from_stubs()

static void symbols_from_stubs ( RzList ret,
HtPP *  kernel_syms_by_addr,
RzXNUKernelCacheObj obj,
RzBinFile bf,
RKext kext,
int  ordinal 
)
static

Definition at line 1629 of file bin_xnu_kernelcache.c.

1629  {
1630  RStubsInfo *stubs_info = get_stubs_info(kext->mach0, kext->range.offset, obj);
1631  if (!stubs_info) {
1632  return;
1633  }
1634  ut64 stubs_cursor = stubs_info->stubs.offset;
1635  ut64 stubs_end = stubs_cursor + stubs_info->stubs.size;
1636 
1637  for (; stubs_cursor < stubs_end; stubs_cursor += 12) {
1638  ut8 arm64_code[8];
1639  if (rz_buf_read_at(obj->cache_buf, stubs_cursor, arm64_code, 8) < 8) {
1640  break;
1641  }
1642 
1643  ut64 vaddr = stubs_cursor + obj->pa2va_exec;
1644  ut64 addr_in_got = extract_addr_from_code(arm64_code, vaddr);
1645 
1646  bool found = false;
1647  int level = 3;
1648 
1649  ut64 target_addr = UT64_MAX;
1650 
1651  while (!found && level-- > 0) {
1652  ut64 offset_in_got = addr_in_got - obj->pa2va_exec;
1653  ut64 addr;
1654  if (rz_buf_read_at(obj->cache_buf, offset_in_got, (ut8 *)&addr, 8) < 8) {
1655  break;
1656  }
1657 
1658  if (level == 2) {
1659  target_addr = addr;
1660  }
1661 
1662  const char *key = sdb_fmt("%" PFMT64x, addr);
1663  const char *name = sdb_ht_find(kernel_syms_by_addr, key, &found);
1664 
1665  if (found) {
1667  if (!sym) {
1668  break;
1669  }
1670  sym->name = rz_str_newf("stub.%s", name);
1671  sym->vaddr = vaddr;
1672  sym->paddr = stubs_cursor;
1673  sym->size = 12;
1674  sym->forwarder = "NONE";
1675  sym->bind = "LOCAL";
1676  sym->type = "FUNC";
1677  sym->ordinal = ordinal++;
1678  rz_list_append(ret, sym);
1679  break;
1680  }
1681 
1682  addr_in_got = addr;
1683  }
1684 
1685  if (found || target_addr == UT64_MAX) {
1686  continue;
1687  }
1688 
1690  RKext *remote_kext = rz_kext_index_vget(obj->kexts, target_addr);
1691  if (!remote_kext) {
1692  continue;
1693  }
1694 
1695  RzBinSymbol *remote_sym = RZ_NEW0(RzBinSymbol);
1696  if (!remote_sym) {
1697  break;
1698  }
1699 
1700  remote_sym->name = rz_str_newf("exp.%s.0x%" PFMT64x, kext_short_name(remote_kext), target_addr);
1701  remote_sym->vaddr = target_addr;
1702  remote_sym->paddr = target_addr - obj->pa2va_exec;
1703  remote_sym->size = 0;
1704  remote_sym->forwarder = "NONE";
1705  remote_sym->bind = "GLOBAL";
1706  remote_sym->type = "FUNC";
1707  remote_sym->ordinal = ordinal++;
1708  rz_list_append(ret, remote_sym);
1709 
1710  RzBinSymbol *local_sym = RZ_NEW0(RzBinSymbol);
1711  if (!local_sym) {
1712  break;
1713  }
1714 
1715  local_sym->name = rz_str_newf("stub.%s.0x%" PFMT64x, kext_short_name(remote_kext), target_addr);
1716  local_sym->vaddr = vaddr;
1717  local_sym->paddr = stubs_cursor;
1718  local_sym->size = 12;
1719  local_sym->forwarder = "NONE";
1720  local_sym->bind = "GLOBAL";
1721  local_sym->type = "FUNC";
1722  local_sym->ordinal = ordinal++;
1723  rz_list_append(ret, local_sym);
1724  }
1725 
1726  RZ_FREE(stubs_info);
1727 }
static ut64 extract_addr_from_code(ut8 *arm64_code, ut64 vaddr)
static RKext * rz_kext_index_vget(RKextIndex *index, ut64 vaddr)
static RStubsInfo * get_stubs_info(struct MACH0_(obj_t) *mach0, ut64 paddr, RzXNUKernelCacheObj *obj)
static int level
Definition: vmenus.c:2424

References addr, rz_bin_symbol_t::bind, rz_xnu_kernelcache_obj_t::cache_buf, ensure_kexts_initialized(), extract_addr_from_code(), rz_bin_symbol_t::forwarder, found, get_stubs_info(), kext_short_name(), rz_xnu_kernelcache_obj_t::kexts, key, level, rz_bin_symbol_t::name, rz_xnu_kernelcache_file_range_t::offset, rz_bin_symbol_t::ordinal, rz_xnu_kernelcache_obj_t::pa2va_exec, rz_bin_symbol_t::paddr, PFMT64x, _RKext::range, rz_buf_read_at(), RZ_FREE, rz_kext_index_vget(), rz_list_append(), RZ_NEW0, rz_str_newf(), sdb_fmt(), sdb_ht_find(), rz_xnu_kernelcache_file_range_t::size, rz_bin_symbol_t::size, _RStubsInfo::stubs, rz_bin_symbol_t::type, ut64(), UT64_MAX, _RKext::vaddr, and rz_bin_symbol_t::vaddr.

Referenced by symbols().

◆ virtual_files()

static RzList* virtual_files ( RzBinFile bf)
static

Definition at line 988 of file bin_xnu_kernelcache.c.

988  {
991  if (!ret) {
992  return NULL;
993  }
994  RzXNUKernelCacheObj *kobj = bf->o->bin_obj;
995  if (kobj->rebased_buf) {
997  if (!vf) {
998  return ret;
999  }
1000  vf->buf = kobj->rebased_buf;
1001  vf->buf_owned = false;
1003  rz_list_push(ret, vf);
1004  }
1005  return ret;
1006 }
RZ_API void rz_bin_virtual_file_free(RzBinVirtualFile *vfile)
Definition: bin.c:1012
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_NONNULL RzBuffer * buf
Definition: rz_bin.h:597
bool buf_owned
whether buf is owned and freed by this RzBinVirtualFile
Definition: rz_bin.h:598
RZ_OWN RZ_NONNULL char * name
Definition: rz_bin.h:596

References rz_bin_object_t::bin_obj, rz_bin_virtual_file_t::buf, rz_bin_virtual_file_t::buf_owned, rz_bin_virtual_file_t::name, NULL, rz_bin_file_t::o, rz_xnu_kernelcache_obj_t::rebased_buf, rz_bin_virtual_file_free(), rz_list_newf(), rz_list_push(), RZ_NEW0, rz_return_val_if_fail, strdup(), and VFILE_NAME_REBASED.

Variable Documentation

◆ rizin_plugin

RzLibStruct rizin_plugin
Initial value:
= {
.type = RZ_LIB_TYPE_BIN,
.data = &rz_bin_plugin_kernelcache,
.version = RZ_VERSION
}
@ RZ_LIB_TYPE_BIN
Definition: rz_lib.h:75
#define RZ_VERSION
Definition: rz_version.h:8

Definition at line 1949 of file bin_xnu_kernelcache.c.

◆ rz_bin_plugin_xnu_kernelcache

RzBinPlugin rz_bin_plugin_xnu_kernelcache
Initial value:
= {
.name = "kernelcache",
.desc = "kernelcache bin plugin",
.license = "LGPL3",
.destroy = &destroy,
.load_buffer = &load_buffer,
.entries = &entries,
.baddr = &baddr,
.virtual_files = &virtual_files,
.maps = &maps,
.symbols = &symbols,
.sections = &sections,
.check_buffer = &check_buffer,
.info = &info
}
static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb)
Definition: bin_any.c:50
static void destroy(RzBinFile *bf)
static bool check_buffer(RzBuffer *b)
static RzList * virtual_files(RzBinFile *bf)
static ut64 baddr(RzBinFile *bf)
static RzList * entries(RzBinFile *bf)
static RzList * maps(RzBinFile *bf)

Definition at line 1932 of file bin_xnu_kernelcache.c.