An attempt at standardising an iOS kernel r/w API.
Under Mach/Darwin/XNU, task ports are an API that, among other things, let you read and write memory of other processes. The idea is that every process has such a task port, even the kernel - referred to as tfp0 (from the task_for_pid(0)
call that would historically yield that port).
On macOS this port always been available to root processes in some form, whereas on iOS you were never able to obtain it. But since iOS jailbreaks needed to gain kernel r/w anyway, most of them would use that to defeat this restriction and set up a well-known interface by which root processes could once more obtain tfp0.
Starting with iOS 10.3, Apple began combatting this from a different angle: rather than prevent the lookup or creation of a task port pointing at the kernel's process struct, they would make the interface detect these capabilities and refuse to operate on them. For a long time, bypassing those checks were as simple as swapping out some pointers or creating a second virtual mapping for the same physical memory, but with iOS 14 it seems Apple's had enough: they are now going so far as to panic the kernel if they detect use of a task port whose task->map->pmap == kernel_pmap
. This is non-trivial to bypass on A12 and later due to PPL.
On checkra1n we of course patched this back into place as if nothing was amiss, but other jailbreaks don't have this luxury.
Given that any bypass is likely to get patched once it's used publicly, I think the time has come to abstract away the internal workings or kernel r/w and export a new API.
Libkrw serves two purposes:
- Defining a common API (via header file and .tbd linkable)
- Providing a default drop-in implementation around tfp0
This means that:
- On any existing jailbreak that supports tfp0, you should be able to install this library and things should just work.
- On any jailbreak going forward, the jailbreak author(s) would ship their own version of libkrw with a custom implementation, should they choose to conform to this API.
See include/libkrw.h
for function declarations and API specification.
- Copy
include/libkrw.h
andlibkrw.tbd
to your project. - Compile with
-I. -L. -lkrw
. - Don't forget the
task_for_pid-allow
entitlement. - If you're building a deb file, add this to your
control
:Depends: libkrw (>= 1.0.0)
Starting with version 1.1.0, libkrw supports a plugin interface so you no longer need to create a package to replace it.
- See
include/libkrw_plugin.h
for documentation. - Implement and export either a function called
krw_initializer
orkcall_initializer
that takes akrw_handlers_t
argument. - Install all handlers that you support.
- Compile with
-Wl,-bundle
. - Name it
/usr/lib/libkrw/[name].dylib
. - Add this to the
control
of your deb file:Depends: libkrw
The default implementation resides in src/libkrw_tfp0.c
.
It is automatically selected as a fallback when no plugins are present.
If you want to build it yourself, you can do so with:
make all # builds the dylib and tbd
make deb # builds the deb packages
The binary release is available from apt.bingner.com
.
But you're free to rebuild and host this library wherever you please.
MIT.