Rizin
unix-like reverse engineering framework and cli tools
kernelcache.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 Florian Märkl <info@florianmaerkl.de>
2 // SPDX-FileCopyrightText: 2019-2020 Francesco Tamagni <mrmacete@protonmail.ch>
3 // SPDX-FileCopyrightText: 2019 pancake <pancake@nopcode.org>
4 // SPDX-License-Identifier: LGPL-3.0-only
5 
6 #include "kernelcache.h"
7 
8 typedef bool (*OnRebaseFunc)(ut64 offset, ut64 decorated_addr, void *user_data);
10 static ut64 iterate_rebase_list(RzBuffer *cache_buf, ut64 multiplier, ut64 start_offset, OnRebaseFunc func, void *user_data);
11 static bool on_rebase_pointer(ut64 offset, ut64 decorated_addr, void *user);
12 
15  if (length < sizeof(struct MACH0_(mach_header))) {
16  return false;
17  }
18  ut32 cputype;
19  if (!rz_buf_read_le32_at(b, 4, &cputype)) {
20  return false;
21  }
22  if (cputype != CPU_TYPE_ARM64) {
23  return false;
24  }
25  ut32 filetype;
26  if (!rz_buf_read_le32_at(b, 12, &filetype)) {
27  return false;
28  }
29  if (filetype == MH_FILESET) {
30  return true;
31  }
32  ut32 flags;
33  if (!rz_buf_read_le32_at(b, 24, &flags)) {
34  return false;
35  }
36  if (!(flags & MH_PIE)) {
37  return false;
38  }
39  ut32 ncmds;
40  if (!rz_buf_read_le32_at(b, 16, &ncmds)) {
41  return false;
42  }
43  bool has_unixthread = false;
44  bool has_negative_vaddr = false;
45  bool has_kext = false;
46 
47  ut32 cursor = sizeof(struct MACH0_(mach_header));
48  for (size_t i = 0; i < ncmds && cursor < length; i++) {
49 
50  ut32 cmdtype;
51  if (!rz_buf_read_le32_at(b, cursor, &cmdtype)) {
52  return false;
53  }
54 
55  ut32 cmdsize;
56  if (!rz_buf_read_le32_at(b, cursor + 4, &cmdsize)) {
57  return false;
58  }
59 
60  switch (cmdtype) {
61  case LC_KEXT:
62  has_kext = true;
63  break;
64  case LC_UNIXTHREAD:
65  has_unixthread = true;
66  break;
67  case LC_LOAD_DYLIB:
68  case LC_LOAD_WEAK_DYLIB:
69  case LC_LAZY_LOAD_DYLIB:
70  return false;
71  case LC_SEGMENT_64: {
72  if (has_negative_vaddr) {
73  break;
74  }
75  ut64 tmp;
76  if (!rz_buf_read_le64_at(b, cursor + 24, &tmp)) {
77  return false;
78  }
79 
80  st64 vmaddr = convert_to_two_complement_64(tmp);
81  if (vmaddr < 0) {
82  has_negative_vaddr = true;
83  }
84  } break;
85  }
86 
87  cursor += cmdsize;
88  }
89 
90  return has_kext || (has_unixthread && has_negative_vaddr);
91 }
92 
93 static ut64 iterate_rebase_list(RzBuffer *cache_buf, ut64 multiplier, ut64 start_offset, OnRebaseFunc func, void *user_data) {
94  ut8 bytes[8];
95  ut64 cursor = start_offset;
96 
97  while (true) {
98  if (rz_buf_read_at(cache_buf, cursor, bytes, 8) < 8) {
99  return UT64_MAX;
100  }
101 
102  ut64 decorated_addr = rz_read_le64(bytes);
103 
104  if (func) {
105  bool carry_on = func(cursor, decorated_addr, user_data);
106  if (!carry_on) {
107  break;
108  }
109  }
110 
111  ut64 delta = ((decorated_addr >> 51) & 0x7ff) * multiplier;
112  if (delta == 0) {
113  break;
114  }
115  cursor += delta;
116  }
117 
118  return cursor;
119 }
120 
122  struct section_t *sections = NULL;
123  int i = 0;
124 
125  if (obj->rebase_info_populated) {
126  return;
127  }
128  obj->rebase_info_populated = true;
129 
130  for (; i < info->n_ranges; i++) {
131  if (info->ranges[i].size != UT64_MAX) {
132  goto cleanup;
133  } else if (sections == NULL) {
134  if (!(sections = MACH0_(get_sections)(obj->mach0))) {
135  return;
136  }
137  }
138  info->ranges[i].offset = rebase_offset_to_paddr(obj, sections, info->ranges[i].offset);
139  ut64 end = iterate_rebase_list(obj->cache_buf, info->multiplier, info->ranges[i].offset, NULL, NULL);
140  if (end != UT64_MAX) {
141  info->ranges[i].size = end - info->ranges[i].offset + 8;
142  } else {
143  info->ranges[i].size = 0;
144  }
145  }
146 
147 cleanup:
148  RZ_FREE(sections);
149 }
150 
152  ut64 vaddr = obj->rebase_info->kernel_base + offset;
153  int i = 0;
154  for (; !sections[i].last; i++) {
155  if (sections[i].addr <= vaddr && vaddr < (sections[i].addr + sections[i].vsize)) {
156  return sections[i].offset + (vaddr - sections[i].addr);
157  }
158  }
159  return offset;
160 }
161 
162 typedef struct {
165  int count;
167 } RebaseCtx;
168 
170  if (obj->rebasing_buffer) {
171  return;
172  }
173  obj->rebasing_buffer = true;
174 
176 
177  ut64 eob = off + count;
178  int i = 0;
179  RebaseCtx ctx;
180  ctx.off = off;
181  ctx.eob = eob;
182  ctx.buf = buf;
183  ctx.count = count;
184  ctx.obj = obj;
185 
186  for (; i < obj->rebase_info->n_ranges; i++) {
187  ut64 start = obj->rebase_info->ranges[i].offset;
188  ut64 end = start + obj->rebase_info->ranges[i].size;
189  if (end >= off && start <= eob) {
191  }
192  }
193 
194  obj->rebasing_buffer = false;
195 }
196 
197 static bool on_rebase_pointer(ut64 offset, ut64 decorated_addr, void *user) {
198  RebaseCtx *ctx = user;
199  if (offset < ctx->off) {
200  return true;
201  }
202  if (offset >= ctx->eob) {
203  return false;
204  }
205  ut64 in_buf = offset - ctx->off;
206  if (in_buf >= ctx->count || (in_buf + 8) > ctx->count) {
207  return false;
208  }
209 
211  rz_xnu_kernelcache_parse_pointer(&ptr, decorated_addr, ctx->obj);
212 
213  rz_write_le64(&ctx->buf[in_buf], ptr.address);
214 
215  return true;
216 }
217 
219  /*
220  * Logic taken from:
221  * https://github.com/Synacktiv/kernelcache-laundering/blob/master/ios12_kernel_cache_helper.py
222  */
223 
224  if ((decorated_addr & 0x4000000000000000LL) == 0 && obj->rebase_info) {
225  if (decorated_addr & 0x8000000000000000LL) {
226  ptr->address = obj->rebase_info->kernel_base + (decorated_addr & 0xFFFFFFFFLL);
227  } else {
228  ptr->address = ((decorated_addr << 13) & 0xFF00000000000000LL) | (decorated_addr & 0x7ffffffffffLL);
229  if (decorated_addr & 0x40000000000LL) {
230  ptr->address |= 0xfffc0000000000LL;
231  }
232  }
233  } else {
234  ptr->address = decorated_addr;
235  }
236 
237  return true;
238 }
239 
240 typedef struct {
242  ut64 off;
243 } BufCtx;
244 
245 static bool buf_init(RzBuffer *b, const void *user) {
246  BufCtx *ctx = RZ_NEW0(BufCtx);
247  if (!ctx) {
248  return false;
249  }
250  ctx->obj = (void *)user;
251  b->priv = ctx;
252  return true;
253 }
254 
255 static bool buf_fini(RzBuffer *b) {
256  BufCtx *ctx = b->priv;
257  free(ctx);
258  return true;
259 }
260 
261 static bool buf_resize(RzBuffer *b, ut64 newsize) {
262  BufCtx *ctx = b->priv;
263  return rz_buf_resize(ctx->obj->cache_buf, newsize);
264 }
265 
267  BufCtx *ctx = b->priv;
268  st64 r = rz_buf_read_at(ctx->obj->cache_buf, ctx->off, buf, len);
269  if (r <= 0 || !len) {
270  return r;
271  }
272  RzXNUKernelCacheObj *cache = ctx->obj;
273  if (cache->mach0->chained_starts) {
275  (ctx->obj->mach0, ctx->off, buf, RZ_MIN(r, len));
276  } else if (cache->rebase_info) {
277  rebase_buffer(cache, ctx->off, buf, RZ_MIN(r, len));
278  }
279  return r;
280 }
281 
282 static st64 buf_write(RzBuffer *b, const ut8 *buf, ut64 len) {
283  BufCtx *ctx = b->priv;
284  return rz_buf_write_at(ctx->obj->cache_buf, ctx->off, buf, len);
285 }
286 
288  BufCtx *ctx = b->priv;
289  return rz_buf_size(ctx->obj->cache_buf);
290 }
291 
292 static st64 buf_seek(RzBuffer *b, st64 addr, int whence) {
293  BufCtx *ctx = b->priv;
294  return ctx->off = rz_seek_offset(ctx->off, rz_buf_size(b), addr, whence);
295 }
296 
298  BufCtx *ctx = b->priv;
299  return (ut8 *)rz_buf_data(ctx->obj->cache_buf, sz);
300 }
301 
302 static const RzBufferMethods buf_methods = {
303  .init = buf_init,
304  .fini = buf_fini,
305  .read = buf_read,
306  .write = buf_write,
307  .get_size = buf_get_size,
308  .resize = buf_resize,
309  .seek = buf_seek,
310  .get_whole_buf = buf_get_whole_buf
311 };
312 
314  return rz_buf_new_with_methods(&buf_methods, obj);
315 }
316 
318  return obj->rebase_info || obj->mach0->chained_starts;
319 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
static ut8 bytes[32]
Definition: asm_arc.c:23
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
RzList * sections(RzBinFile *bf)
Definition: bin_ne.c:110
static io_buf in_buf
Input and output buffers.
Definition: coder.c:39
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#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
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 cleanup(void)
Definition: enough.c:244
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf uLong offset
Definition: ioapi.h:144
voidpf void * buf
Definition: ioapi.h:138
static ut8 * buf_get_whole_buf(RzBuffer *b, ut64 *sz)
Definition: kernelcache.c:297
static ut64 rebase_offset_to_paddr(RzXNUKernelCacheObj *obj, struct section_t *sections, ut64 offset)
Definition: kernelcache.c:151
static ut64 buf_get_size(RzBuffer *b)
Definition: kernelcache.c:287
static void rebase_buffer(RzXNUKernelCacheObj *obj, ut64 off, ut8 *buf, ut64 count)
Definition: kernelcache.c:169
static void rebase_info_populate(RzXNUKernelCacheRebaseInfo *info, RzXNUKernelCacheObj *obj)
Definition: kernelcache.c:121
static st64 buf_seek(RzBuffer *b, st64 addr, int whence)
Definition: kernelcache.c:292
static st64 buf_write(RzBuffer *b, const ut8 *buf, ut64 len)
Definition: kernelcache.c:282
RZ_API RzBuffer * rz_xnu_kernelcache_new_rebasing_buf(RzXNUKernelCacheObj *obj)
Definition: kernelcache.c:313
static st64 buf_read(RzBuffer *b, ut8 *buf, ut64 len)
Definition: kernelcache.c:266
RZ_API bool rz_xnu_kernelcache_needs_rebasing(RzXNUKernelCacheObj *obj)
Definition: kernelcache.c:317
static bool buf_fini(RzBuffer *b)
Definition: kernelcache.c:255
RZ_API bool rz_xnu_kernelcache_parse_pointer(RzXNUKernelCacheParsedPointer *ptr, ut64 decorated_addr, RzXNUKernelCacheObj *obj)
Definition: kernelcache.c:218
static const RzBufferMethods buf_methods
Definition: kernelcache.c:302
static bool on_rebase_pointer(ut64 offset, ut64 decorated_addr, void *user)
Definition: kernelcache.c:197
static ut64 iterate_rebase_list(RzBuffer *cache_buf, ut64 multiplier, ut64 start_offset, OnRebaseFunc func, void *user_data)
Definition: kernelcache.c:93
static bool buf_resize(RzBuffer *b, ut64 newsize)
Definition: kernelcache.c:261
static bool buf_init(RzBuffer *b, const void *user)
Definition: kernelcache.c:245
bool(* OnRebaseFunc)(ut64 offset, ut64 decorated_addr, void *user_data)
Definition: kernelcache.c:8
RZ_API bool rz_xnu_kernelcache_buf_is_kernelcache(RzBuffer *b)
Definition: kernelcache.c:13
uint8_t ut8
Definition: lh5801.h:11
struct section_t *MACH0_() get_sections(struct MACH0_(obj_t) *bin)
Definition: mach0.c:2411
@ LC_KEXT
@ LC_LOAD_WEAK_DYLIB
@ LC_UNIXTHREAD
@ LC_LOAD_DYLIB
@ LC_LAZY_LOAD_DYLIB
@ LC_SEGMENT_64
@ MH_FILESET
Definition: mach0_defines.h:83
@ MH_PIE
@ CPU_TYPE_ARM64
#define MACH0_(name)
Definition: mach0_specs.h:20
int off
Definition: pal.c:13
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
#define rz_buf_read_le32_at(b, addr, result)
Definition: rz_buf.h:271
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
#define rz_buf_read_le64_at(b, addr, result)
Definition: rz_buf.h:272
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_NEW0(x)
Definition: rz_types.h:284
#define RZ_FREE(x)
Definition: rz_types.h:369
#define RZ_MIN(x, y)
#define st64
Definition: rz_types_base.h:10
#define UT64_MAX
Definition: rz_types_base.h:86
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
#define b(i)
Definition: sha256.c:42
RzXNUKernelCacheObj * obj
Definition: kernelcache.c:241
ut8 * buf
Definition: kernelcache.c:164
RzXNUKernelCacheObj * obj
Definition: kernelcache.c:166
RzBufferInit init
Definition: rz_buf.h:32
RzXNUKernelCacheRebaseInfo * rebase_info
Definition: kernelcache.h:38
RzXNUKernelCacheFileRange * ranges
Definition: kernelcache.h:20
ut64 vsize
Definition: mach0.h:46
#define bool
Definition: sysdefs.h:146
static st64 delta
Definition: vmenus.c:2425
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58
filetype
Definition: z80asm.h:78