-
-
Save cowpod/c20989c01b138f37ad9ec19140079723 to your computer and use it in GitHub Desktop.
v0rtex offset finder script. Handles multiple kernelcaches
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!//bin/sh | |
export PATH=bin:$PATH | |
self=$0 | |
function print_help() { | |
echo "$self [IPSW path]" | |
echo "$self [device model] [ios build]" | |
echo | |
echo "Examples:" | |
echo "\t $self iPodtouch_10.3.3_14G60_Restore.ipsw" | |
echo "\t $self iPod7,1 14G60" | |
echo | |
echo "About: This script will prompt you in the ocurrence of multiple kernelcaches." | |
} | |
function install_radare2() { | |
brew ls --versions radare2 > /dev/null | |
if [ ! $? -eq 0 ]; then | |
brew update &> /dev/null | |
brew install radare2 &> /dev/null | |
fi | |
} | |
function install_partialzip() { | |
if [[ ! -f bin/partialzip ]]; then | |
echo "[#] Cloning partial-zip repo..." | |
git clone https://github.com/uroboro/partial-zip &> /dev/null | |
pushd partial-zip &> /dev/null | |
echo "[#] Building..." | |
cmake . &> /dev/null | |
make &> /dev/null | |
popd &> /dev/null | |
mkdir -p bin | |
cp partial-zip/partialzip bin/ | |
rm -rf partial-zip | |
echo "[#] Done!" | |
fi | |
} | |
function install_joker() { | |
if [[ ! -f bin/joker ]]; then | |
echo "[#] Downloading joker..." | |
curl -s http://newosxbook.com/tools/joker.tar -o /tmp/joker.tar | |
echo "[#] Extracting..." | |
tar -xf /tmp/joker.tar joker.universal | |
mkdir -p bin | |
mv joker.universal bin/joker | |
rm /tmp/joker.tar | |
echo "[#] Done!" | |
fi | |
} | |
function extract_from_ipsw() { | |
file="$1" | |
lines=0 | |
kernelcache_count_exec=$(unzip -l $file | grep kernelcache | awk '{ print $NF }') | |
kernelcache_count=$(echo "$kernelcache_count_exec" | wc -l | tr -d '[:space:]') | |
if [[ $kernelcache_count -gt 1 ]]; then | |
echo "[#] $kernelcache_count kernelcaches found." | |
echo "Available kernelcaches:" | |
echo $kernelcache_count_exec | tr " " "\n" | while read -r line; do command; | |
lines=$(expr $lines + 1); | |
echo "\t#$lines - $line"; | |
done | |
echo "Enter full kernelcache name, and press [ENTER]:" | |
read which_kernelcache | |
if [[ ! `echo "$kernelcache_count_exec" | grep "$which_kernelcache"` ]]; then | |
echo "[#] specified cache does not exist." | |
exit 1 | |
fi | |
else | |
if [[ $kernelcache_count -eq 1 ]]; then | |
echo "[#] $kernelcache_count kernelcache found" | |
which_kernelcache=$kernelcache_count_exec | |
fi | |
fi | |
echo "Selected kernelcache: $which_kernelcache" | |
kernel_name=$(unzip -l $file | grep -m 1 $which_kernelcache | awk '{ print $NF }') | |
unzip -p $file $kernel_name > kernelcache.comp | |
} | |
function extract_from_url() { | |
file="$1" | |
kernel_name=$(partialzip -l $file | grep -m 1 $which_kernelcache | awk '{ print $NF }') | |
partialzip $file $kernel_name | |
cp $kernel_name kernelcache.comp | |
} | |
skip_decompression=0 | |
if [ $# -eq 2 ]; then | |
if [[ "$1" == "-k" ]]; then | |
cp $2 kernelcache.comp | |
elif [[ "$1" == "-d" ]]; then | |
skip_decompression=1 | |
cp $2 kernelcache | |
else | |
install_partialzip | |
file=$(curl -s https://api.ipsw.me/v2.1/$1/$2/url) | |
extract_from_url $file | |
fi | |
elif [ $# -eq 1 ]; then | |
file=$1 | |
extract_from_ipsw $file | |
else | |
print_help | |
exit 0 | |
fi | |
# Decompress kernelcache | |
if [ "$skip_decompression" -eq "0" ]; then | |
if [ ! -f kernelcache.comp ]; then | |
echo "[#] No kernel cache to work with. Bailing." | |
exit 1 | |
fi | |
install_joker | |
joker -dec kernelcache.comp &> /dev/null | |
if [ ! -f /tmp/kernel ]; then | |
echo "[#] No compressed kernel cache to work with. Bailing." | |
exit 1 | |
fi | |
mv /tmp/kernel ./kernelcache | |
else | |
echo "[#] Skipping decompression" | |
fi | |
# Extract IOSurface kext | |
install_joker | |
joker -K com.apple.iokit.IOSurface kernelcache &> /dev/null | |
if [ ! -f /tmp/com.apple.iokit.IOSurface.kext ]; then | |
echo "[#] No usable kernel cache to work with. Bailing." | |
exit 1 | |
fi | |
mv /tmp/com.apple.iokit.IOSurface.kext ./ | |
strings kernelcache | grep 'Darwin K' | |
echo | |
function address_kernel_map() { | |
nm kernelcache | grep ' _kernel_map$' | awk '{ print "0x" $1 }' | |
} | |
function address_kernel_task() { | |
nm kernelcache | grep ' _kernel_task$' | awk '{ print "0x" $1 }' | |
} | |
function address_bzero() { | |
nm kernelcache | grep ' ___bzero$' | awk '{ print "0x" $1 }' | |
} | |
function address_bcopy() { | |
nm kernelcache | grep ' _bcopy$' | awk '{ print "0x" $1 }' | |
} | |
function address_copyin() { | |
nm kernelcache | grep ' _copyin$' | awk '{ print "0x" $1 }' | |
} | |
function address_copyout() { | |
nm kernelcache | grep ' _copyout$' | awk '{ print "0x" $1 }' | |
} | |
function address_rootvnode() { | |
nm kernelcache | grep ' _rootvnode$' | awk '{ print "0x" $1 }' | |
} | |
function address_kauth_cred_ref() { | |
nm kernelcache | grep ' _kauth_cred_ref$' | awk '{ print "0x" $1 }' | |
} | |
function address_osserializer_serialize() { | |
nm kernelcache | grep ' __ZNK12OSSerializer9serializeEP11OSSerialize$' | awk '{ print "0x" $1 }' | |
} | |
function address_host_priv_self() { | |
host_priv_self_addr=$(nm kernelcache | grep host_priv_self | awk '{ print "0x" $1 }') | |
r2 -q -e scr.color=false -c "pd 2 @ $host_priv_self_addr" kernelcache 2> /dev/null | sed -n 's/0x//gp' | awk '{ print $NF }' | tr '[a-f]\n' '[A-F] ' | awk '{ print "obase=16;ibase=16;" $1 "+" $2 }' | bc | tr '[A-F]' '[a-f]' | awk '{ print "0x" $1 }' | |
} | |
function address_ipc_port_alloc_special() { | |
r2 -e scr.color=false -q -c 'pd @ sym._convert_task_suspension_token_to_port' kernelcache 2> /dev/null | sed -n 's/.*bl sym.func.\([a-z01-9]*\)/0x\1/p' | sed -n 1p | |
} | |
function address_ipc_kobject_set() { | |
r2 -e scr.color=false -q -c 'pd @ sym._convert_task_suspension_token_to_port' kernelcache 2> /dev/null | sed -n 's/.*bl sym.func.\([a-z01-9]*\)/0x\1/p' | sed -n 2p | |
} | |
function address_ipc_port_make_send() { | |
r2 -e scr.color=false -q -c 'pd @ sym._convert_task_to_port' kernelcache 2>/dev/null | sed -n 's/.*bl sym.func.\([a-z01-9]*\)/0x\1/p' | sed -n 1p | |
} | |
function address_rop_add_x0_x0_0x10() { | |
r2 -q -e scr.color=true -c "\"/a add x0, x0, 0x10; ret\"" kernelcache 2> /dev/null | head -n1 | awk '{ print $1 }' | |
} | |
function address_rop_ldr_x0_x0_0x10() { | |
r2 -q -e scr.color=true -c "\"/a ldr x0, [x0, 0x10]; ret\"" kernelcache 2> /dev/null | head -n1 | awk '{ print $1 }' | |
} | |
function address_zone_map() { | |
string_addr=$(r2 -q -e scr.color=false -c 'iz~zone_init: kmem_suballoc failed' kernelcache 2> /dev/null | awk '{ print $1 }' | sed 's/.*=//') | |
xref1_addr=$(r2 -q -e scr.color=false -c "\"/c $string_addr\"" kernelcache 2> /dev/null | awk '{ print $1 }') | |
xref2_addr=$(r2 -q -e scr.color=false -c "\"/c $xref1_addr\"" kernelcache 2> /dev/null | awk '{ print $1 }') | |
addr=$(r2 -q -e scr.color=false -c "pd -8 @ $xref2_addr" kernelcache 2> /dev/null | head -n 2 | grep 0x | awk '{ print $NF }' | sed 's/0x//' | tr '[a-f]\n' '[A-F] ' | awk '{ print "obase=16;ibase=16;" $1 "+" $2 }' | bc | tr '[A-F]' '[a-f]') | |
echo "0x$addr" | |
} | |
function address_chgproccnt() { | |
priv_check_cred_addr=$(nm kernelcache | grep ' _priv_check_cred$' | awk '{ print "0x" $1 }') | |
r2 -q -e scr.color=false -c "pd 31 @ $priv_check_cred_addr" kernelcache 2> /dev/null | tail -n1 | awk '{ print $1 }' | |
} | |
function address_iosurfacerootuserclient_vtab() { | |
# Get __DATA_CONST.__const offset and size | |
data_const_const=$(r2 -q -e scr.color=false -c 'S' com.apple.iokit.IOSurface.kext 2> /dev/null | grep '__DATA_CONST.__const' | tr ' ' '\n' | grep '=') | |
va=$(echo $data_const_const | tr ' ' '\n' | sed -n 's/va=//p') | |
sz=$(echo $data_const_const | tr ' ' '\n' | sed -n 's/^sz=//p') | |
# Dump hex to tmp file | |
r2 -q -e scr.color=false -c "s $va; pxr $sz" com.apple.iokit.IOSurface.kext 2> /dev/null | awk '{ print $1 " " $2 }' > /tmp/hexdump.txt | |
IFS=$'\n' read -d '' -r -a hd < /tmp/hexdump.txt | |
lines=$(wc -l /tmp/hexdump.txt | awk '{ print $1 }') | |
# Go through each line, check if there are 2 consecutive zeros | |
found=0 | |
for (( i = 1; i < $lines; i++ )); do | |
# First zero | |
zero1=$(echo ${hd[$i]} | awk '{ print $2 }') | |
# Second zero | |
zero2=$(echo ${hd[$((i+1))]} | awk '{ print $2 }') | |
if [ "$zero1" == "0x0000000000000000" -a "$zero2" == "0x0000000000000000" ]; then | |
# vtable offset | |
offset=$(echo ${hd[$i+2]} | awk '{ print $1 }') | |
# echo "found possible offset at $offset" | |
# 8th pointer after vtable start | |
pointer8=$(echo ${hd[$((i+2+7))]} | awk '{ print $2 }') | |
if [ -z "$pointer8" ]; then | |
break | |
fi | |
# Retrieve class name | |
cmd_lookup=$(r2 -q -e scr.color=false -c "pd 3 @ $pointer8" com.apple.iokit.IOSurface.kext 2> /dev/null | awk '{ print $NF }' | tr '\n' ' ' | awk '{ print $1 "; " $2 }') | |
second_to_last=$(r2 -q -e scr.color=true -c "\"/c $cmd_lookup\"" com.apple.iokit.IOSurface.kext 2>/dev/null | tail -n 2 | head -n 1 | awk '{ print $1 }') | |
class_addr=$(r2 -q -e scr.color=false -c "pd 3 @ $second_to_last" com.apple.iokit.IOSurface.kext 2> /dev/null | tail -n 2 | awk '{ print $NF }' | tr '\n' ' ' | awk '{ print $1 "+" $2 }') | |
name=$(r2 -q -e scr.color=false -c "ps @ $class_addr" com.apple.iokit.IOSurface.kext 2> /dev/null | sed 's/[^a-zA-Z]//g') | |
if [[ ! -z "$name" && "$name" == "IOSurfaceRootUserClient" ]]; then | |
# Done! | |
found=1 | |
echo "$offset" | |
return 0 | |
fi | |
fi | |
done | |
echo "0xdeadbeefbabeface" | |
} | |
install_radare2 | |
printf "[#] Working...\r" | |
offset_zone_map=$(address_zone_map) | |
offset_kernel_map=$(address_kernel_map) | |
offset_kernel_task=$(address_kernel_task) | |
offset_host_priv_self=$(address_host_priv_self) | |
offset_bzero=$(address_bzero) | |
offset_bcopy=$(address_bcopy) | |
offset_copyin=$(address_copyin) | |
offset_copyout=$(address_copyout) | |
offset_chgproccnt=$(address_chgproccnt) | |
offset_rootvnode=$(address_rootvnode) | |
offset_kauth_cred_ref=$(address_kauth_cred_ref) | |
offset_ipc_port_alloc_special=$(address_ipc_port_alloc_special) | |
offset_ipc_kobject_set=$(address_ipc_kobject_set) | |
offset_ipc_port_make_send=$(address_ipc_port_make_send) | |
offset_iosurfacerootuserclient_vtab=$(address_iosurfacerootuserclient_vtab) | |
offset_rop_add_x0_x0_0x10=$(address_rop_add_x0_x0_0x10) | |
offset_osserializer_serialize=$(address_osserializer_serialize) | |
offset_rop_ldr_x0_x0_0x10=$(address_rop_ldr_x0_x0_0x10) | |
echo "[Offsets found for $which_kernelcache]" | |
echo "#define OFFSET_ZONE_MAP $offset_zone_map" | |
echo "#define OFFSET_KERNEL_MAP $offset_kernel_map" | |
echo "#define OFFSET_KERNEL_TASK $offset_kernel_task" | |
echo "#define OFFSET_REALHOST $offset_host_priv_self" | |
echo "#define OFFSET_BZERO $offset_bzero" | |
echo "#define OFFSET_BCOPY $offset_bcopy" | |
echo "#define OFFSET_COPYIN $offset_copyin" | |
echo "#define OFFSET_COPYOUT $offset_copyout" | |
echo "#define OFFSET_ROOTVNODE $offset_rootvnode" | |
echo "#define OFFSET_CHGPROCCNT $offset_chgproccnt" | |
echo "#define OFFSET_KAUTH_CRED_REF $offset_kauth_cred_ref" | |
echo "#define OFFSET_IPC_PORT_ALLOC_SPECIAL $offset_ipc_port_alloc_special" | |
echo "#define OFFSET_IPC_KOBJECT_SET $offset_ipc_kobject_set" | |
echo "#define OFFSET_IPC_PORT_MAKE_SEND $offset_ipc_port_make_send" | |
echo "#define OFFSET_IOSURFACEROOTUSERCLIENT_VTAB $offset_iosurfacerootuserclient_vtab" | |
echo "#define OFFSET_ROP_ADD_X0_X0_0x10 $offset_rop_add_x0_x0_0x10" | |
echo "#define OFFSET_OSSERIALIZER_SERIALIZE $offset_osserializer_serialize" | |
echo "#define OFFSET_ROP_LDR_X0_X0_0x10 $offset_rop_ldr_x0_x0_0x10" | |
# rm com.apple.iokit.IOSurface.kext kernelcache* | |
Can you use img4tool instead of joker to prevent BVX compression issues for some kernelcaches?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Doesn't seem to work with iPhone9,4 10.1.1 build 14B100:
iMac:~ Developer$ /Users/Developer/Desktop/find_offsets.sh /Users/Developer/Desktop/iPhone_7Plus_10.1.1_14B100_Restore.ipsw
[#] 2 kernelcaches found.
Available kernelcaches:
#1 - kernelcache.release.d11
#2 - kernelcache.release.d111
Enter full kernelcache name, and press [ENTER]:
kernelcache.release.d111
Selected kernelcache: kernelcache.release.d111
[#] No compressed kernel cache to work with. Bailing.
iMac:~ Developer$