History: Kernel Manipulation

This has been retrieved from the Old iPhone Dev Wiki.

Kernel Manipulation
Since the hardware cryptographic component seems to be used in the kernel as well (AppleImage2NORAccess) this page describes several attempts to manipulate an existing kernel extension or insert a new one from 1.0.2.

kextstat relevant dump
50 0 0xc031c000 0x5000 0x4000 com.apple.driver.AppleImage2NORAccess (1.0.0d1) 31 2 0xc0313000 0x9000 0x8000 com.apple.iokit.IOCryptoAcceleratorFamily (1.0.0)

Relevant links
Accessing Kernel Memory on the x86 Version of Mac OS X: http://www.osxbook.com/book/bonus/chapter8/kma/

Abusing Mach on Mac OS X: http://uninformed.org/index.cgi?v=4&a=3

More people playing with kexts on the iPhone: http://wickedpsyched.com/iphone/kerneltools/

Kexec from Darwin to Linux: iPhone_Linux

Kernel Virtual Memory Map: http://code.google.com/p/iphone-elite/wiki/MemoryMap

Kernel memory manipulation (discussion)
- Modify the bootpath to see if kmem=1 is supported ("cmd setenv boot-args kmem=1" "cmd saveenv") (or '/usr/sbin/nvram boot-args="kmem=1"')-> done, at least a /dev/kmem driver is present. Note, if you manage to break stuff by changing randomly some parameters like I did, start an iPhuc session and reset ("cmd setenv X") for the following variables: boot-args, boot-partiton, boot-path, boot-ramdisk then save ("cmd saveenv")

- Test if /dev/kmem is working -> done, /dev/kmem opened read only works as expected. Needs a patch to work in read-write mode (see below) ...

- Calling task_for_pid with a PID of 0 to access the kernel -> done. See "Enabling Mach VM access for the kernel task" below for instructions. [edit] Kernel memory manipulation (conclusion, by Bgm)

Bgm
Using boot-args "kmem=1" and modified launchd (see below) it is possible to set kern.securelevel to 0. In this mode /dev/kmem should be rw. Also it's possible to load kexts.

/sbin/launchd (1.0.2) and (1.1.1): change two bytes

0000D1DB: DA -> EA 0000D623: 1A -> EA

--> excellent, confirmed that /dev/kmem is rw now :) --Zf 07:01, 6 October 2007 (EDT)

Example perl script that changes part of a kext name from 'apple' to 'BGM_' in 1.0.2 kernel memory: use Fcntl; $a = hex("c04da690"); sysopen(HANDLE, "/dev/kmem", O_RDWR); $r = sysseek(HANDLE, $a, SEEK_SET); printf("seek = %x\n", $r); $buffer="xxxx"; $r = sysread(HANDLE, $buffer, 4); printf("read = %x,%s\n", $r, unpack("H*", $buffer)); $r = sysseek(HANDLE, $a, SEEK_SET); printf("seek = %x\n", $r); $r = syswrite(HANDLE, pack("H*", "42474D5F"), 4); printf("write: %x\n", $r); $r = sysseek(HANDLE, $a, SEEK_SET); printf("seek = %x\n", $r); $buffer="xxxx"; $r = sysread(HANDLE, $buffer, 4); printf("read = %x,%s\n", $r, unpack("H*", $buffer)); close(HANDLE);

kextstat output (last line) before
69   0 0xc04d8000 0x3000     0x2000     com.apple.nke.ipif (1.0.0d1)

kextstat output (last line) after
69   0 0xc04d8000 0x3000     0x2000     com.BGM_e.nke.ipif (1.0.0d1)

Enabling Mach VM access for the kernel task
Could be useful for loading kexts in a standard way, perhaps, otherwise that just makes it the first kernel patch :p

(offset given for kernel 1.0.2, use c011eb56 for kernel 1.1.1)

use Fcntl; $a = hex("C011db66"); sysopen(HANDLE, "/dev/kmem", O_RDWR); $r = sysseek(HANDLE, $a, SEEK_SET); printf("seek = %x\n", $r); $r = syswrite(HANDLE, pack("H*", "012B"), 2); printf("write: %x\n", $r); close(HANDLE);

for kernel 1.0.2
echo -en "\x01\x2B" | dd of=/dev/kmem seek=3222395750 bs=1 count=2

for kernel 1.1.1
echo -en "\x01\x2B" | dd of=/dev/kmem seek=3222399830 bs=1 count=2

Kernel printk update
bgm has been working really, really hard we now have the following that can be inserted into the kernel:

http://iphone-elite.googlecode.com/files/HelloKernel.zip

Code highlights that caused us issues for the load before are now fixed by bgm:

void (*p)(const char * fmt, ...) = 0xc010411c + 1; // addlog THUMB!!!

We can now load code into the kernel with kextload - this is *huge* progress!

Perl code
(offset given for kernel 1.0.2, use C0057428 for kernel 1.1.1) use Fcntl; $a = hex("c0056d64"); sysopen(HANDLE, "/dev/kmem", O_RDWR); $r = sysseek(HANDLE, $a, SEEK_SET); printf("seek = %x\n", $r); $buffer="xxxx"; $r = sysread(HANDLE, $buffer, 6); printf("read = %x,%s\n", $r, unpack("H*", $buffer)); $r = sysseek(HANDLE, $a, SEEK_SET); printf("seek = %x\n", $r); $r = syswrite(HANDLE, pack("H*", "081c111c85e7"), 6); printf("write: %x\n", $r); $r = sysseek(HANDLE, $a, SEEK_SET); printf("seek = %x\n", $r); $buffer="xxxx"; $r = sysread(HANDLE, $buffer, 6); printf("read = %x,%s\n", $r, unpack("H*", $buffer)); close(HANDLE);

for kernel 1.0.2
echo -en "\x08\x1C\x11\x1C\x85\xE7" | dd of=/dev/kmem seek=3221581156 bs=1 count=6

for kernel 1.1.1
echo -en "\x08\x1C\x11\x1C\x85\xE7" | dd of=/dev/kmem seek=3221582888 bs=1 count=6

Kernel module
(offset given for kernel 1.0.2, use 0xC010510C for addlog on kernel 1.1.1) void (*p)(const char * fmt, ...) = 0xc010411c + 1; // addlog THUMB!!! kern_return_t HelloKernel_start (kmod_info_t * ki, void * d) { (*p)("KEXT loaded!\n"); return KERN_SUCCESS; } kern_return_t HelloKernel_stop (kmod_info_t * ki, void * d) { (*p)("KEXT unloaded!\n"); return KERN_SUCCESS; }
 * 1) include 
 * 2) include 

Trust Zone
It is possible to read TrustZone control registers from a kext.

The c1, Secure Configuration Register contains all 0's which indicates running in 'Secure World'.

So we are not limited by the TrustZone in any way.

--bgm.

Pending Tasks
- Reverse libupdate_brain.dylib from the old updates to see how AppleImage2NORAccess is working

- Understanding how kextload works (for example trying to reload AppleImage2NORAccess from the disk after unloading it)

-- The problem here may be two-fold. For the sake of obfuscation and system efficiency almost every KEXT on the iPhone is kept in a prelinked kernel cache file (e.g. "kernelcache.release.s5l8900xrb"). The problem here that of the three types of kernel caches, there is no tool to easily unlinked the KEXTs out of the a prelinked cache. The second problem, is related to the first. When loading a KEXT you have to define OSBundleLibraries in the KEXT's Info.plist file. This dictionary I believe has to minimally refer to one of several KPIs, such as "com.apple.kpi.bsd". Well, these KPIs are defined in a pseudo-extension called System.kext. Last I saw on the iPhone 1.0.2, this KEXT did not exist (since everything was prelinked into one file, it wasn't necessary to have separately). So I have been writing a tool that minimally extracted the System.kext KPIs out of the kernelcache and reconstructed the System.kext (or used 'lipo' to add fatten the System.kext from a normal OS X desktop installation.) The kextload command refuses to load any KEXT without a OSBundleLibraries dictionary referring to an existing KEXT for symbol resolution. -- Theosis 10:05, 5 October 2007 (EDT)

- Add to kern_proto.h.