Rizin
unix-like reverse engineering framework and cli tools
kernelcache.c File Reference
#include "kernelcache.h"

Go to the source code of this file.

Classes

struct  RebaseCtx
 
struct  BufCtx
 

Typedefs

typedef bool(* OnRebaseFunc) (ut64 offset, ut64 decorated_addr, void *user_data)
 

Functions

static ut64 rebase_offset_to_paddr (RzXNUKernelCacheObj *obj, struct section_t *sections, ut64 offset)
 
static ut64 iterate_rebase_list (RzBuffer *cache_buf, ut64 multiplier, ut64 start_offset, OnRebaseFunc func, void *user_data)
 
static bool on_rebase_pointer (ut64 offset, ut64 decorated_addr, void *user)
 
RZ_API bool rz_xnu_kernelcache_buf_is_kernelcache (RzBuffer *b)
 
static void rebase_info_populate (RzXNUKernelCacheRebaseInfo *info, RzXNUKernelCacheObj *obj)
 
static void rebase_buffer (RzXNUKernelCacheObj *obj, ut64 off, ut8 *buf, ut64 count)
 
RZ_API bool rz_xnu_kernelcache_parse_pointer (RzXNUKernelCacheParsedPointer *ptr, ut64 decorated_addr, RzXNUKernelCacheObj *obj)
 
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 RzBufferrz_xnu_kernelcache_new_rebasing_buf (RzXNUKernelCacheObj *obj)
 
RZ_API bool rz_xnu_kernelcache_needs_rebasing (RzXNUKernelCacheObj *obj)
 

Variables

static const RzBufferMethods buf_methods
 

Typedef Documentation

◆ OnRebaseFunc

typedef bool(* OnRebaseFunc) (ut64 offset, ut64 decorated_addr, void *user_data)

Definition at line 8 of file kernelcache.c.

Function Documentation

◆ buf_fini()

static bool buf_fini ( RzBuffer b)
static

Definition at line 255 of file kernelcache.c.

255  {
256  BufCtx *ctx = b->priv;
257  free(ctx);
258  return true;
259 }
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 287 of file kernelcache.c.

287  {
288  BufCtx *ctx = b->priv;
289  return rz_buf_size(ctx->obj->cache_buf);
290 }
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 297 of file kernelcache.c.

297  {
298  BufCtx *ctx = b->priv;
299  return (ut8 *)rz_buf_data(ctx->obj->cache_buf, sz);
300 }
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 245 of file kernelcache.c.

245  {
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 }
#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 266 of file kernelcache.c.

266  {
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 }
size_t len
Definition: 6502dis.c:15
#define r
Definition: crypto_rc6.c:12
voidpf void * buf
Definition: ioapi.h:138
static void rebase_buffer(RzXNUKernelCacheObj *obj, ut64 off, ut8 *buf, ut64 count)
Definition: kernelcache.c:169
#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
RzXNUKernelCacheRebaseInfo * rebase_info
Definition: kernelcache.h:38

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

◆ buf_resize()

static bool buf_resize ( RzBuffer b,
ut64  newsize 
)
static

Definition at line 261 of file kernelcache.c.

261  {
262  BufCtx *ctx = b->priv;
263  return rz_buf_resize(ctx->obj->cache_buf, newsize);
264 }
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 292 of file kernelcache.c.

292  {
293  BufCtx *ctx = b->priv;
294  return ctx->off = rz_seek_offset(ctx->off, rz_buf_size(b), addr, whence);
295 }
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 282 of file kernelcache.c.

282  {
283  BufCtx *ctx = b->priv;
284  return rz_buf_write_at(ctx->obj->cache_buf, ctx->off, buf, len);
285 }
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().

◆ iterate_rebase_list()

static ut64 iterate_rebase_list ( RzBuffer cache_buf,
ut64  multiplier,
ut64  start_offset,
OnRebaseFunc  func,
void *  user_data 
)
static

Definition at line 93 of file kernelcache.c.

93  {
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 }
static ut8 bytes[32]
Definition: asm_arc.c:23
static ut64 rz_read_le64(const void *src)
Definition: rz_endian.h:266
#define UT64_MAX
Definition: rz_types_base.h:86
static st64 delta
Definition: vmenus.c:2425
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References bytes, delta, rz_buf_read_at(), rz_read_le64(), ut64(), and UT64_MAX.

Referenced by rebase_buffer(), and rebase_info_populate().

◆ on_rebase_pointer()

static bool on_rebase_pointer ( ut64  offset,
ut64  decorated_addr,
void *  user 
)
static

Definition at line 197 of file kernelcache.c.

197  {
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 }
static io_buf in_buf
Input and output buffers.
Definition: coder.c:39
voidpf uLong offset
Definition: ioapi.h:144
RZ_API bool rz_xnu_kernelcache_parse_pointer(RzXNUKernelCacheParsedPointer *ptr, ut64 decorated_addr, RzXNUKernelCacheObj *obj)
Definition: kernelcache.c:218
int off
Definition: pal.c:13
static void rz_write_le64(void *dest, ut64 val)
Definition: rz_endian.h:277

References rz_xnu_kernelcache_parsed_pointer_t::address, in_buf, off, rz_write_le64(), rz_xnu_kernelcache_parse_pointer(), and ut64().

Referenced by rebase_buffer().

◆ rebase_buffer()

static void rebase_buffer ( RzXNUKernelCacheObj obj,
ut64  off,
ut8 buf,
ut64  count 
)
static

Definition at line 169 of file kernelcache.c.

169  {
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 }
lzma_index ** i
Definition: index.h:629
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 void rebase_info_populate(RzXNUKernelCacheRebaseInfo *info, RzXNUKernelCacheObj *obj)
Definition: kernelcache.c:121
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
RzXNUKernelCacheFileRange * ranges
Definition: kernelcache.h:20

References rz_xnu_kernelcache_obj_t::cache_buf, count, test_evm::end, i, iterate_rebase_list(), rz_xnu_kernelcache_rebase_info_t::multiplier, rz_xnu_kernelcache_rebase_info_t::n_ranges, off, rz_xnu_kernelcache_file_range_t::offset, on_rebase_pointer(), rz_xnu_kernelcache_rebase_info_t::ranges, rz_xnu_kernelcache_obj_t::rebase_info, rebase_info_populate(), rz_xnu_kernelcache_obj_t::rebasing_buffer, rz_xnu_kernelcache_file_range_t::size, start, and ut64().

Referenced by buf_read().

◆ rebase_info_populate()

static void rebase_info_populate ( RzXNUKernelCacheRebaseInfo info,
RzXNUKernelCacheObj obj 
)
static

Definition at line 121 of file kernelcache.c.

121  {
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 }
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
RzList * sections(RzBinFile *bf)
Definition: bin_ne.c:110
#define NULL
Definition: cris-opc.c:27
void cleanup(void)
Definition: enough.c:244
static ut64 rebase_offset_to_paddr(RzXNUKernelCacheObj *obj, struct section_t *sections, ut64 offset)
Definition: kernelcache.c:151
struct section_t *MACH0_() get_sections(struct MACH0_(obj_t) *bin)
Definition: mach0.c:2411
#define RZ_FREE(x)
Definition: rz_types.h:369

References rz_xnu_kernelcache_obj_t::cache_buf, cleanup(), test_evm::end, get_sections(), i, info(), iterate_rebase_list(), MACH0_, NULL, rz_xnu_kernelcache_obj_t::rebase_info_populated, rebase_offset_to_paddr(), RZ_FREE, sections(), ut64(), and UT64_MAX.

Referenced by rebase_buffer().

◆ rebase_offset_to_paddr()

static ut64 rebase_offset_to_paddr ( RzXNUKernelCacheObj obj,
struct section_t sections,
ut64  offset 
)
static

Definition at line 151 of file kernelcache.c.

151  {
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 }

References addr, i, rz_xnu_kernelcache_rebase_info_t::kernel_base, rz_xnu_kernelcache_obj_t::rebase_info, sections(), ut64(), and section_t::vsize.

Referenced by rebase_info_populate().

◆ rz_xnu_kernelcache_buf_is_kernelcache()

RZ_API bool rz_xnu_kernelcache_buf_is_kernelcache ( RzBuffer b)

Definition at line 13 of file kernelcache.c.

13  {
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 }
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
@ 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 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
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
filetype
Definition: z80asm.h:78

References b, CPU_TYPE_ARM64, flags, i, LC_KEXT, LC_LAZY_LOAD_DYLIB, LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, LC_SEGMENT_64, LC_UNIXTHREAD, length, MACH0_, MH_FILESET, MH_PIE, rz_buf_read_le32_at, rz_buf_read_le64_at, rz_buf_size(), st64, autogen_x86imm::tmp, and ut64().

Referenced by check_buffer().

◆ rz_xnu_kernelcache_needs_rebasing()

RZ_API bool rz_xnu_kernelcache_needs_rebasing ( RzXNUKernelCacheObj obj)

Definition at line 317 of file kernelcache.c.

317  {
318  return obj->rebase_info || obj->mach0->chained_starts;
319 }

References rz_xnu_kernelcache_obj_t::rebase_info.

◆ rz_xnu_kernelcache_new_rebasing_buf()

RZ_API RzBuffer* rz_xnu_kernelcache_new_rebasing_buf ( RzXNUKernelCacheObj obj)

Definition at line 313 of file kernelcache.c.

313  {
314  return rz_buf_new_with_methods(&buf_methods, obj);
315 }
static const RzBufferMethods buf_methods
Definition: kernelcache.c:302
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().

◆ rz_xnu_kernelcache_parse_pointer()

RZ_API bool rz_xnu_kernelcache_parse_pointer ( RzXNUKernelCacheParsedPointer ptr,
ut64  decorated_addr,
RzXNUKernelCacheObj obj 
)

Definition at line 218 of file kernelcache.c.

218  {
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 }

References rz_xnu_kernelcache_parsed_pointer_t::address, rz_xnu_kernelcache_rebase_info_t::kernel_base, and rz_xnu_kernelcache_obj_t::rebase_info.

Referenced by on_rebase_pointer(), and p_ptr().

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: kernelcache.c:297
static ut64 buf_get_size(RzBuffer *b)
Definition: kernelcache.c:287
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
static st64 buf_read(RzBuffer *b, ut8 *buf, ut64 len)
Definition: kernelcache.c:266
static bool buf_fini(RzBuffer *b)
Definition: kernelcache.c:255
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

Definition at line 302 of file kernelcache.c.

Referenced by rz_xnu_kernelcache_new_rebasing_buf().