Rizin
unix-like reverse engineering framework and cli tools
mach0_rebase.c File Reference

Modified read proxy of Mach-O binaries for use as part of a virtual file. More...

#include "mach0.h"

Go to the source code of this file.

Classes

struct  BufCtx
 

Macros

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

Functions

RZ_API void MACH0_() rebase_buffer (struct MACH0_(obj_t) *obj, ut64 off, ut8 *buf, ut64 count)
 
static bool buf_init (RzBuffer *b, const void *user)
 
static bool buf_fini (RzBuffer *b)
 
static bool buf_resize (RzBuffer *b, ut64 newsize)
 
static st64 buf_read (RzBuffer *b, ut8 *buf, ut64 len)
 
static st64 buf_write (RzBuffer *b, const ut8 *buf, ut64 len)
 
static ut64 buf_get_size (RzBuffer *b)
 
static st64 buf_seek (RzBuffer *b, st64 addr, int whence)
 
static ut8buf_get_whole_buf (RzBuffer *b, ut64 *sz)
 
RZ_API RzBuffer *MACH0_() new_rebasing_and_stripping_buf (struct MACH0_(obj_t) *obj)
 
RZ_API bool MACH0_() needs_rebasing_and_stripping (struct MACH0_(obj_t) *obj)
 
RZ_API bool MACH0_() segment_needs_rebasing_and_stripping (struct MACH0_(obj_t) *obj, size_t seg_index)
 

Variables

static const RzBufferMethods buf_methods
 

Detailed Description

Modified read proxy of Mach-O binaries for use as part of a virtual file.

This is used in Mach-O binaries that either contain LC_DYLD_CHANGED_FIXUPS/LC_DYLD_EXPORTS_TRIE load commands or BIND_OPCODE_THREADED in their dyld info. This is especially present in, but not limited to binaries with the "arm64e" architecture, as Apple calls it, which is essentially arm64 with pointer authentication. In particular, we strip away additional info stored inside of pointers in the binary so we get the raw pointers out for convenient analysis.

see also mach0_relocs.c for additional modification of the data that might happen.

Definition in file mach0_rebase.c.

Macro Definition Documentation

◆ IS_PTR_AUTH

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

Definition at line 21 of file mach0_rebase.c.

◆ IS_PTR_BIND

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

Definition at line 22 of file mach0_rebase.c.

Function Documentation

◆ buf_fini()

static bool buf_fini ( RzBuffer b)
static

Definition at line 171 of file mach0_rebase.c.

171  {
172  BufCtx *ctx = b->priv;
173  free(ctx);
174  return true;
175 }
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
#define b(i)
Definition: sha256.c:42

References b, and free().

◆ buf_get_size()

static ut64 buf_get_size ( RzBuffer b)
static

Definition at line 198 of file mach0_rebase.c.

198  {
199  BufCtx *ctx = b->priv;
200  return rz_buf_size(ctx->obj->b);
201 }
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225

References b, and rz_buf_size().

◆ buf_get_whole_buf()

static ut8* buf_get_whole_buf ( RzBuffer b,
ut64 sz 
)
static

Definition at line 208 of file mach0_rebase.c.

208  {
209  BufCtx *ctx = b->priv;
210  return (ut8 *)rz_buf_data(ctx->obj->b, sz);
211 }
uint8_t ut8
Definition: lh5801.h:11
RZ_DEPRECATE RZ_API RZ_BORROW ut8 * rz_buf_data(RZ_NONNULL RzBuffer *b, RZ_NONNULL RZ_OUT ut64 *size)
Return a borrowed array of bytes representing the buffer data.
Definition: buf.c:1287

References b, and rz_buf_data().

◆ buf_init()

static bool buf_init ( RzBuffer b,
const void *  user 
)
static

Definition at line 161 of file mach0_rebase.c.

161  {
162  BufCtx *ctx = RZ_NEW0(BufCtx);
163  if (!ctx) {
164  return false;
165  }
166  ctx->obj = (void *)user;
167  b->priv = ctx;
168  return true;
169 }
#define RZ_NEW0(x)
Definition: rz_types.h:284

References b, and RZ_NEW0.

◆ buf_read()

static st64 buf_read ( RzBuffer b,
ut8 buf,
ut64  len 
)
static

Definition at line 182 of file mach0_rebase.c.

182  {
183  BufCtx *ctx = b->priv;
184  st64 r = rz_buf_read_at(ctx->obj->b, ctx->off, buf, len);
185  if (r <= 0 || !len) {
186  return r;
187  }
189  (ctx->obj, ctx->off, buf, RZ_MIN(r, len));
190  return r;
191 }
size_t len
Definition: 6502dis.c:15
#define r
Definition: crypto_rc6.c:12
voidpf void * buf
Definition: ioapi.h:138
RZ_API void MACH0_() rebase_buffer(struct MACH0_(obj_t) *obj, ut64 off, ut8 *buf, ut64 count)
Definition: mach0_rebase.c:24
#define MACH0_(name)
Definition: mach0_specs.h:20
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
#define RZ_MIN(x, y)
#define st64
Definition: rz_types_base.h:10

References b, len, MACH0_, r, rebase_buffer(), rz_buf_read_at(), RZ_MIN, and st64.

◆ buf_resize()

static bool buf_resize ( RzBuffer b,
ut64  newsize 
)
static

Definition at line 177 of file mach0_rebase.c.

177  {
178  BufCtx *ctx = b->priv;
179  return rz_buf_resize(ctx->obj->b, newsize);
180 }
RZ_API bool rz_buf_resize(RZ_NONNULL RzBuffer *b, ut64 newsize)
Resize the buffer size.
Definition: buf.c:890

References b, and rz_buf_resize().

◆ buf_seek()

static st64 buf_seek ( RzBuffer b,
st64  addr,
int  whence 
)
static

Definition at line 203 of file mach0_rebase.c.

203  {
204  BufCtx *ctx = b->priv;
205  return ctx->off = rz_seek_offset(ctx->off, rz_buf_size(b), addr, whence);
206 }
static ut64 rz_seek_offset(ut64 cur, ut64 length, st64 addr, int whence)
change cur according to addr and whence (RZ_BUF_SET/RZ_BUF_CUR/RZ_BUF_END)
Definition: rz_buf.h:67
static int addr
Definition: z80asm.c:58

References addr, b, rz_buf_size(), and rz_seek_offset().

◆ buf_write()

static st64 buf_write ( RzBuffer b,
const ut8 buf,
ut64  len 
)
static

Definition at line 193 of file mach0_rebase.c.

193  {
194  BufCtx *ctx = b->priv;
195  return rz_buf_write_at(ctx->obj->b, ctx->off, buf, len);
196 }
RZ_API st64 rz_buf_write_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL const ut8 *buf, ut64 len)
Write len bytes of the buffer at the specified address.
Definition: buf.c:1197

References b, len, and rz_buf_write_at().

◆ needs_rebasing_and_stripping()

RZ_API bool MACH0_() needs_rebasing_and_stripping ( struct MACH0_(obj_t) *  obj)

Definition at line 228 of file mach0_rebase.c.

228  {
229  return !!obj->chained_starts;
230 }

Referenced by get_virtual_files(), and parse_classes().

◆ new_rebasing_and_stripping_buf()

RZ_API RzBuffer* MACH0_() new_rebasing_and_stripping_buf ( struct MACH0_(obj_t) *  obj)

Definition at line 224 of file mach0_rebase.c.

224  {
225  return rz_buf_new_with_methods(&buf_methods, obj);
226 }
static const RzBufferMethods buf_methods
Definition: mach0_rebase.c:213
RZ_API RZ_OWN RzBuffer * rz_buf_new_with_methods(RZ_NONNULL const RzBufferMethods *methods, void *init_user)
Creates a new buffer with a specific back end.
Definition: buf.c:525

References buf_methods, and rz_buf_new_with_methods().

Referenced by get_virtual_files(), and parse_classes().

◆ rebase_buffer()

RZ_API void MACH0_() rebase_buffer ( struct MACH0_(obj_t) *  obj,
ut64  off,
ut8 buf,
ut64  count 
)

Definition at line 24 of file mach0_rebase.c.

24  {
25  rz_return_if_fail(obj && buf);
26  ut64 eob = off + count;
27  int nsegs_to_rebase = RZ_MIN(obj->nchained_starts, obj->nsegs);
28  for (int i = 0; i < nsegs_to_rebase; i++) {
29  if (!obj->chained_starts[i]) {
30  continue;
31  }
32  ut64 page_size = obj->chained_starts[i]->page_size;
33  ut64 start = obj->segs[i].fileoff;
34  ut64 end = start + obj->segs[i].filesize;
35  if (end < off || start > eob) {
36  continue;
37  }
38  ut64 page_idx = (RZ_MAX(start, off) - start) / page_size;
39  ut64 page_end_idx = (RZ_MIN(eob, end) - start) / page_size;
40  for (; page_idx <= page_end_idx; page_idx++) {
41  if (page_idx >= obj->chained_starts[i]->page_count) {
42  break;
43  }
44  ut16 page_start = obj->chained_starts[i]->page_start[page_idx];
45  if (page_start == DYLD_CHAINED_PTR_START_NONE) {
46  continue;
47  }
48  ut64 cursor = start + page_idx * page_size + page_start;
49  while (cursor < eob && cursor < end) {
50  ut8 tmp[8];
51  if (rz_buf_read_at(obj->b, cursor, tmp, 8) != 8) {
52  break;
53  }
54  ut64 raw_ptr = rz_read_le64(tmp);
55  bool is_auth = IS_PTR_AUTH(raw_ptr);
56  ut64 ptr_value = raw_ptr;
57  ut64 delta;
58  ut64 stride = 8;
59  switch (obj->chained_starts[i]->pointer_format) {
61  bool is_bind = IS_PTR_BIND(raw_ptr);
62  if (is_auth && is_bind) {
64  (struct dyld_chained_ptr_arm64e_auth_bind *)&raw_ptr;
65  delta = p->next;
66  } else if (!is_auth && is_bind) {
68  (struct dyld_chained_ptr_arm64e_bind *)&raw_ptr;
69  delta = p->next;
70  } else if (is_auth && !is_bind) {
72  (struct dyld_chained_ptr_arm64e_auth_rebase *)&raw_ptr;
73  delta = p->next;
74  ptr_value = p->target + obj->baddr;
75  } else {
77  (struct dyld_chained_ptr_arm64e_rebase *)&raw_ptr;
78  delta = p->next;
79  ptr_value = ((ut64)p->high8 << 56) | p->target;
80  }
81  break;
82  }
85  stride = 4;
86  if (is_auth) {
89  delta = p->next;
90  ptr_value = p->target + obj->baddr;
91  } else {
93  (struct dyld_chained_ptr_arm64e_cache_rebase *)&raw_ptr;
94  delta = p->next;
95  ptr_value = ((ut64)p->high8 << 56) | p->target;
96  ptr_value += obj->baddr;
97  }
98  break;
99  }
101  stride = 4;
103  (struct dyld_chained_ptr_64_bind *)&raw_ptr;
104  if (bind->bind) {
105  delta = bind->next;
106  } else {
107  struct dyld_chained_ptr_64_rebase *p =
108  (struct dyld_chained_ptr_64_rebase *)&raw_ptr;
109  delta = p->next;
110  ptr_value = obj->baddr + (((ut64)p->high8 << 56) | p->target);
111  }
112  break;
113  }
115  stride = 8;
117  (struct dyld_chained_ptr_arm64e_bind24 *)&raw_ptr;
118  if (bind->bind) {
119  delta = bind->next;
120  } else {
121  if (bind->auth) {
123  (struct dyld_chained_ptr_arm64e_auth_rebase *)&raw_ptr;
124  delta = p->next;
125  ptr_value = p->target + obj->baddr;
126  } else {
128  (struct dyld_chained_ptr_arm64e_rebase *)&raw_ptr;
129  delta = p->next;
130  ptr_value = obj->baddr + (((ut64)p->high8 << 56) | p->target);
131  }
132  }
133  break;
134  }
135  default:
136  RZ_LOG_WARN("Unsupported Mach-O pointer format: %u at paddr 0x%" PFMT64x "\n",
137  obj->chained_starts[i]->pointer_format, cursor);
138  goto break_it_all;
139  }
140  ut64 in_buf = cursor - off;
141  if (cursor >= off && cursor <= eob - 8) {
142  rz_write_le64(&buf[in_buf], ptr_value);
143  }
144  cursor += delta * stride;
145  if (!delta) {
146  break;
147  }
148  continue;
149  break_it_all:
150  break;
151  }
152  }
153  }
154 }
lzma_index ** i
Definition: index.h:629
static io_buf in_buf
Input and output buffers.
Definition: coder.c:39
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
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
uint16_t ut16
void * p
Definition: libc.cpp:67
@ DYLD_CHAINED_PTR_START_NONE
@ DYLD_CHAINED_PTR_64_OFFSET
@ DYLD_CHAINED_PTR_ARM64E_USERLAND24
@ DYLD_CHAINED_PTR_ARM64E
@ DYLD_CHAINED_PTR_64_KERNEL_CACHE
@ DYLD_CHAINED_PTR_ARM64E_KERNEL
#define IS_PTR_BIND(x)
Definition: mach0_rebase.c:22
#define IS_PTR_AUTH(x)
Definition: mach0_rebase.c:21
int off
Definition: pal.c:13
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
static ut64 rz_read_le64(const void *src)
Definition: rz_endian.h:266
static void rz_write_le64(void *dest, ut64 val)
Definition: rz_endian.h:277
#define RZ_LOG_WARN(fmtstr,...)
Definition: rz_log.h:56
#define PFMT64x
Definition: rz_types.h:393
#define RZ_MAX(x, y)
static bind
Definition: sfsocketcall.h:114
static st64 delta
Definition: vmenus.c:2425
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References bind, count, delta, DYLD_CHAINED_PTR_64_KERNEL_CACHE, DYLD_CHAINED_PTR_64_OFFSET, DYLD_CHAINED_PTR_ARM64E, DYLD_CHAINED_PTR_ARM64E_KERNEL, DYLD_CHAINED_PTR_ARM64E_USERLAND24, DYLD_CHAINED_PTR_START_NONE, test_evm::end, i, in_buf, IS_PTR_AUTH, IS_PTR_BIND, off, p, PFMT64x, rz_buf_read_at(), RZ_LOG_WARN, RZ_MAX, RZ_MIN, rz_read_le64(), rz_return_if_fail, rz_write_le64(), start, autogen_x86imm::tmp, and ut64().

Referenced by buf_read().

◆ segment_needs_rebasing_and_stripping()

RZ_API bool MACH0_() segment_needs_rebasing_and_stripping ( struct MACH0_(obj_t) *  obj,
size_t  seg_index 
)

Definition at line 232 of file mach0_rebase.c.

232  {
233  if (seg_index >= obj->nsegs || seg_index >= obj->nchained_starts) {
234  return false;
235  }
236  return obj->chained_starts && obj->chained_starts[seg_index];
237 }

Referenced by get_maps_unpatched().

Variable Documentation

◆ buf_methods

const RzBufferMethods buf_methods
static
Initial value:
= {
.init = buf_init,
.fini = buf_fini,
.read = buf_read,
.write = buf_write,
.get_size = buf_get_size,
.resize = buf_resize,
.seek = buf_seek,
.get_whole_buf = buf_get_whole_buf
}
static ut8 * buf_get_whole_buf(RzBuffer *b, ut64 *sz)
Definition: mach0_rebase.c:208
static ut64 buf_get_size(RzBuffer *b)
Definition: mach0_rebase.c:198
static st64 buf_seek(RzBuffer *b, st64 addr, int whence)
Definition: mach0_rebase.c:203
static st64 buf_write(RzBuffer *b, const ut8 *buf, ut64 len)
Definition: mach0_rebase.c:193
static st64 buf_read(RzBuffer *b, ut8 *buf, ut64 len)
Definition: mach0_rebase.c:182
static bool buf_fini(RzBuffer *b)
Definition: mach0_rebase.c:171
static bool buf_resize(RzBuffer *b, ut64 newsize)
Definition: mach0_rebase.c:177
static bool buf_init(RzBuffer *b, const void *user)
Definition: mach0_rebase.c:161

Definition at line 213 of file mach0_rebase.c.

Referenced by new_rebasing_and_stripping_buf().