Rizin
unix-like reverse engineering framework and cli tools
mach0_rebase.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 Florian Märkl <info@florianmaerkl.de>
2 // SPDX-FileCopyrightText: 2020 Francesco Tamagni <mrmacete@protonmail.ch>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
19 #include "mach0.h"
20 
21 #define IS_PTR_AUTH(x) ((x & (1ULL << 63)) != 0)
22 #define IS_PTR_BIND(x) ((x & (1ULL << 62)) != 0)
23 
24 RZ_API void MACH0_(rebase_buffer)(struct MACH0_(obj_t) * obj, ut64 off, ut8 *buf, ut64 count) {
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 }
155 
156 typedef struct {
157  struct MACH0_(obj_t) * obj;
158  ut64 off;
159 } BufCtx;
160 
161 static bool buf_init(RzBuffer *b, const void *user) {
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 }
170 
171 static bool buf_fini(RzBuffer *b) {
172  BufCtx *ctx = b->priv;
173  free(ctx);
174  return true;
175 }
176 
177 static bool buf_resize(RzBuffer *b, ut64 newsize) {
178  BufCtx *ctx = b->priv;
179  return rz_buf_resize(ctx->obj->b, newsize);
180 }
181 
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 }
192 
193 static st64 buf_write(RzBuffer *b, const ut8 *buf, ut64 len) {
194  BufCtx *ctx = b->priv;
195  return rz_buf_write_at(ctx->obj->b, ctx->off, buf, len);
196 }
197 
199  BufCtx *ctx = b->priv;
200  return rz_buf_size(ctx->obj->b);
201 }
202 
203 static st64 buf_seek(RzBuffer *b, st64 addr, int whence) {
204  BufCtx *ctx = b->priv;
205  return ctx->off = rz_seek_offset(ctx->off, rz_buf_size(b), addr, whence);
206 }
207 
209  BufCtx *ctx = b->priv;
210  return (ut8 *)rz_buf_data(ctx->obj->b, sz);
211 }
212 
213 static const RzBufferMethods buf_methods = {
214  .init = buf_init,
215  .fini = buf_fini,
216  .read = buf_read,
217  .write = buf_write,
218  .get_size = buf_get_size,
219  .resize = buf_resize,
220  .seek = buf_seek,
221  .get_whole_buf = buf_get_whole_buf
222 };
223 
224 RZ_API RzBuffer *MACH0_(new_rebasing_and_stripping_buf)(struct MACH0_(obj_t) * obj) {
225  return rz_buf_new_with_methods(&buf_methods, obj);
226 }
227 
228 RZ_API bool MACH0_(needs_rebasing_and_stripping)(struct MACH0_(obj_t) * obj) {
229  return !!obj->chained_starts;
230 }
231 
232 RZ_API bool MACH0_(segment_needs_rebasing_and_stripping)(struct MACH0_(obj_t) * obj, size_t seg_index) {
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 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
static io_buf in_buf
Input and output buffers.
Definition: coder.c:39
#define RZ_API
#define r
Definition: crypto_rc6.c:12
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
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
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
static ut8 * buf_get_whole_buf(RzBuffer *b, ut64 *sz)
Definition: mach0_rebase.c:208
RZ_API void MACH0_() rebase_buffer(struct MACH0_(obj_t) *obj, ut64 off, ut8 *buf, ut64 count)
Definition: mach0_rebase.c:24
static ut64 buf_get_size(RzBuffer *b)
Definition: mach0_rebase.c:198
#define IS_PTR_BIND(x)
Definition: mach0_rebase.c:22
static st64 buf_seek(RzBuffer *b, st64 addr, int whence)
Definition: mach0_rebase.c:203
#define IS_PTR_AUTH(x)
Definition: mach0_rebase.c:21
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 const RzBufferMethods buf_methods
Definition: mach0_rebase.c:213
RZ_API RzBuffer *MACH0_() new_rebasing_and_stripping_buf(struct MACH0_(obj_t) *obj)
Definition: mach0_rebase.c:224
RZ_API bool MACH0_() needs_rebasing_and_stripping(struct MACH0_(obj_t) *obj)
Definition: mach0_rebase.c:228
RZ_API bool MACH0_() segment_needs_rebasing_and_stripping(struct MACH0_(obj_t) *obj, size_t seg_index)
Definition: mach0_rebase.c:232
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
#define MACH0_(name)
Definition: mach0_specs.h:20
int off
Definition: pal.c:13
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
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
RZ_API bool rz_buf_resize(RZ_NONNULL RzBuffer *b, ut64 newsize)
Resize the buffer size.
Definition: buf.c:890
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
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
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
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
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
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 RZ_NEW0(x)
Definition: rz_types.h:284
#define PFMT64x
Definition: rz_types.h:393
#define RZ_MIN(x, y)
#define st64
Definition: rz_types_base.h:10
#define RZ_MAX(x, y)
static bind
Definition: sfsocketcall.h:114
#define b(i)
Definition: sha256.c:42
RzBufferInit init
Definition: rz_buf.h:32
static st64 delta
Definition: vmenus.c:2425
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58