History: Kernel Manipulation

From The Apple Wiki

This has been retrieved from the Old iPhone Dev Wiki.

Kernel Manipulation[edit source]

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[edit source]

50 0 0xc031c000 0x5000 0x4000 com.apple.driver.AppleImage2NORAccess (1.0.0d1) <31 17 7 6 5 4 2>
31 2 0xc0313000 0x9000 0x8000 com.apple.iokit.IOCryptoAcceleratorFamily (1.0.0) <6 5 4 2>

Relevant links[edit source]

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)[edit source]

- 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[edit source]

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[edit source]

69    0 0xc04d8000 0x3000     0x2000     com.apple.nke.ipif (1.0.0d1) <5 2>

kextstat output (last line) after[edit source]

69    0 0xc04d8000 0x3000     0x2000     com.BGM_e.nke.ipif (1.0.0d1) <5 2>

Enabling Mach VM access for the kernel task[edit source]

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[edit source]

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

for kernel 1.1.1[edit source]

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

Kernel printk update[edit source]

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[edit source]

(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[edit source]

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

for kernel 1.1.1[edit source]

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

Kernel module[edit source]

(offset given for kernel 1.0.2, use 0xC010510C for addlog on kernel 1.1.1)

#include <mach/mach_types.h>
#include <sys/systm.h>
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;
}

Trust Zone[edit source]

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[edit source]

- 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.