Tuesday, February 10, 2009

How to decrypt iPhone IPA file

Decrypted IPA
Please take note that you don't need this method to decrypt the IPA file, if you already have the decrypted one downloaded from the net. This method applies to the app that you have directly purchased from App Store and want to decrypt it in order to be useful for others.

One of the decrypt methods is to use a jailbreak iPhone and run the script (source from pr0x.org Forum) below in iPhone to create the decrypted ipa.

To use this method you must have installed the app from App Store in jailbreak iPhone plus the following packages from Cydia
com.ericasadun.utilities gdb gawk zip ldid odcctools

Use the following commands in iPhone to install, if you don't like to use Cydia.
apt-get install com.ericasadun.utilities gdb gawk zip ldid odcctools

To find out the app names that your iPhone have installed, run this command in iPhone
find /var/mobile/Applications/ -iname *.app

and use this command to generated the decrypted ipa e.g.
./DCrypt.sh "Monkey Ball"


DCrypt.sh Select all

#!/bin/sh
#
# DeCrypt - v1.1 (2008-10-21)
# - v1.1 (2008-10-21)
# FloydianSlip
#
# Heavily based on xcrack
#
# Many thanks to:
# puy0, SaladFork, Flox, Flawless
#

echo "DeCrypt 1.1 (2008-10-21)"
echo "FloydianSlip"
echo

if [ ! -e /usr/bin/plutil ]; then
echo "Cannot find plutil (apt-get install com.ericasadun.utilities)"
exit 1
fi

if [ ! -e /usr/bin/gdb ]; then
echo "Cannot find gdb (apt-get install gdb)"
exit 1
fi

if [ ! -e /usr/bin/otool ]; then
echo "Cannot find otool (apt-get install odcctools)"
exit 1
fi

if [ ! -e /usr/bin/ldid ]; then
echo "Cannot find otool (apt-get install ldid)"
exit 1
fi


if [ ! -e /usr/bin/awk ]; then
echo "Cannot find awk (apt-get install gawk)"
exit 1
fi

if [ ! -e /usr/bin/zip ]; then
echo "Cannot find zip (apt-get install zip)"
exit 1
fi

if [ $# -ne 1 ]; then
echo "Usage: $(basename $0) <ApplicationName>"
echo
exit 1
fi

AppInput=$1

if [ -d "$AppInput" ]; then
tempLoc=$AppInput
else
echo "Locating $AppInput"
tempLoc=$(find /var/mobile/Applications -iname "$AppInput.app")
if [ -z "$tempLoc" ]; then
echo "Unable to locate $AppInput"
exit 1
fi
AppCount=$(find /var/mobile/Applications -iname "$AppInput.app" | wc -l)
if [ $AppCount -gt 1 ]; then
echo "Found two installation directories:"
find /var/mobile/Applications -iname "$AppInput.app"
exit 1
fi
fi

AppPath=$(dirname "$tempLoc")
AppName=$(basename "$tempLoc")
AppExec=$(plutil -v CFBundleExecutable "$tempLoc/Info.plist" 2>&1 | awk -F "] " '{ print $2 }')
AppVer=$(plutil -v CFBundleVersion "$tempLoc/Info.plist" 2>&1 | awk -F "] " '{ print $2 }')
AppDisplayName=$(plutil -v CFBundleDisplayName "$tempLoc/Info.plist" 2>&1 | awk -F "] " '{ print $2 }')

if [ ! -d "$AppPath" ]; then
echo "Unable to locate original installation directory"
exit 1
fi

if [ ! -d "$AppPath/$AppName" ]; then
echo "Unable to locate .app directory"
exit 1
fi

if [ ! -e "$AppPath/$AppName/$AppExec" ]; then
echo "Unable to locate executable"
exit 1
fi

echo "Found $AppName"

echo "Creating directories"
WorkDir="/tmp/DecryptApp-$(date +%Y%m%d-%H%M%S)"
NewAppDir="$HOME/Documents/Decrypted"

if [ -e "$WorkDir" ]; then
rm -rf "$WorkDir"
fi

mkdir -p "$WorkDir"

if [ ! -e "$NewAppDir" ]; then
mkdir -p "$NewAppDir"
fi

if [ ! -d "$WorkDir" -o ! -d "$NewAppDir" ]; then
echo "Unable to create Directories"
exit 1
fi

echo "Copying application files"

cp -a "$AppPath/$AppName/" "$WorkDir/"

if [ ! -e "$WorkDir/$AppName/$AppExec" ]; then
echo "Unable to copy application files"
rm -fr "$WorkDir"
exit 1
fi

echo "Analyzing application"

CryptID=$(otool -l "$WorkDir/$AppName/$AppExec" | grep cryptid | awk '{print $2}')
if [ $CryptID -ne "1" ]; then
echo "Application is not encrypted"
rm -fr "$WorkDir"
exit 1
fi

CryptSize=$(otool -l "$WorkDir/$AppName/$AppExec" | grep cryptsize | awk '{print $2}')
if [ ! $CryptSize ]; then
echo "Unable to find CryptSize"
rm -fr "$WorkDir"
exit 1
fi

CryptOff=$(otool -l "$WorkDir/$AppName/$AppExec" | grep cryptoff | awk '{print $2}')
if [ ! $CryptOff ]; then
echo "Unable to find CryptOff"
rm -fr "$WorkDir"
exit 1
fi

echo "Locating and patching CryptID"

# "/System/Library/Frameworks" in hex
PathAsHex="2f53797374656d2f4c6962726172792f4672616d65776f726b73"

# - Convert to hex on 1 long line, only take stuff before the path string,
# - Convert to 1 byte set per line, find 0x01 (line number is offset in the real file),
# - Strip newlines, reverse the order
oneLocations=($(od -A n -t x1 -v "$WorkDir/$AppName/$AppExec" | \
tr -d ' ','\n' | \
sed "s/$PathAsHex.*\$//" | \
sed "s/../&\n/g" | \
grep -n -s 01 | \
cut -d : -f 1 | \
sort -nr | \
tr "\n" " "))

for TryOffset in "${oneLocations[@]}"; do
cp -a "$WorkDir/$AppName/$AppExec" "$WorkDir/$AppName/$AppExec.trying"
foo=$(echo -ne "\x00" | dd bs=1 seek=$((TryOffset - 1)) conv=notrunc status=noxfer of="$WorkDir/$AppName/$AppExec.trying" 2>&1> /dev/null)
cid=$(otool -l "$WorkDir/$AppName/$AppExec.trying" | grep cryptid | awk '{print $2}')
if [ $cid -eq 0 ]; then
break
fi
rm "$WorkDir/$AppName/$AppExec.trying"
done

if [ ! -e "$WorkDir/$AppName/$AppExec.trying" ]; then
echo "Unable to find CryptID"
rm -fr "$WorkDir"
exit 1
fi

mv "$WorkDir/$AppName/$AppExec.trying" "$WorkDir/$AppName/$AppExec"

echo "Dumping unencrypted data from application"

echo -e "set sharedlibrary load-rules \".*\" \".*\" none\r\n\
set inferior-auto-start-dyld off\r\n\
set sharedlibrary preload-libraries off\r\n\
set sharedlibrary load-dyld-symbols off\r\n\
handle all nostop\r\n\
break *0x2000\r\n
commands 1\r\n\
dump memory $WorkDir/dump.bin 0x2000 $(($CryptSize + 0x2000))\r\n\
kill\r\n\
quit\r\n\
end\r\n\
start" > $WorkDir/batch.gdb

foo=$(gdb -q -e "$AppPath/$AppName/$AppExec" -x $WorkDir/batch.gdb -batch 2>&1> /dev/null)

rm $WorkDir/batch.gdb

echo "Verifiying data dump"

DumpSize=$(stat -c%s "$WorkDir/dump.bin")
if [ "$DumpSize" != "$CryptSize" ]; then
echo "Memory dump is not the right size or does not exist"
rm -fr "$WorkDir"
exit 1
fi

echo "Replacing encrypted data with data dump"
foo=$(dd seek=4096 bs=1 conv=notrunc if="$WorkDir/dump.bin" of="$WorkDir/$AppName/$AppExec" 2>&1> /dev/null)
rm "$WorkDir/dump.bin"

echo "Signing the application"
foo=$(ldid -s "$WorkDir/$AppName/$AppExec" 2>&1> /dev/null)
plutil -s 'SignerIdentity' -v 'Apple iPhone OS Application Signing' "$WorkDir/$AppName/Info.plist" 2>&1> /dev/null

if [ -e "$WorkDir/$AppName/SC_Info" ]; then
echo "Removing SC_Info"
rm -fr "$WorkDir/$AppName/SC_Info"
fi

if [ -e "$WorkDir/$AppName/_CodeSignature" ]; then
echo "Removing _CodeSignature"
rm -fr "$WorkDir/$AppName/_CodeSignature"
fi

if [ -h "$WorkDir/$AppName/CodeResources" ]; then
echo "Removing CodeResources"
rm -fr "$WorkDir/$AppName/CodeResources"
fi

if [ -e "$WorkDir/$AppName/ResourceRules.plist" ]; then
echo "Removing ResourceRules.plist"
rm -fr "$WorkDir/$AppName/ResourceRules.plist"
fi

echo "Building .ipa"

mkdir -p "$WorkDir/Payload"
if [ ! -e "$WorkDir/Payload" ]; then
echo "Failed to create Payload directory"
rm -fr "$WorkDir"
exit 1
fi
mv "$WorkDir/$AppName" "$WorkDir/Payload/"

echo "Copying iTunesArtwork"

if [ -e "$AppPath/iTunesArtwork" ]; then
cp -a "$AppPath/iTunesArtwork" "$WorkDir/"
else
echo "Unable to find iTunesArtwork"
fi

echo "Compressing the .ipa"
IPAName=$NewAppDir/$(echo $AppDisplayName | sed -e "s: :_:g")-v$AppVer.ipa
cd "$WorkDir"
zip -m -r "$IPAName" * 2>&1> /dev/null
cd - 2>&1> /dev/null
if [ ! -e "$IPAName" ]; then
echo "Failed to compress the .ipa"
rm -fr "$WorkDir"
exit 1
fi

echo "Removing temporary files"
rm -rf "$WorkDir"

echo "Done"
echo "Created decrypted .ipa at $IPAName"








If you only want to manually get the decrypted binary for reverse engineering. Suppose the Application Executable is called AppExec and installed in /var/mobile/Applications. This is the script and using the gdb to dump the decrypted binary

Let's use a free app AdHoc Helper (by Erica Sadun) as example


otool -l `find /var/mobile/Applications -iname AdHoc` | grep cryptsize

output-> cryptsize 8192

# get the cryptsize say 8192

gdb `find /var/mobile/Applications -iname AdHoc`

(gdb) b *0x2000
Breakpoint 1 at 0x2000
(gdb) r
(gdb) x/20i 0x2000
(gdb) dump binary memory /var/root/dump.bin 0x2000 (0x2000+8192)
(gdb) kill
Kill the program being debugged? (y or n) y
(gdb) quit

cd /var/root/
cp `find /var/mobile/Applications -iname AdHoc` .
dd seek=4096 bs=1 conv=notrunc if=dump.bin of=AdHoc

Monday, February 2, 2009

How to install iLife 09 on Mac OS X 10.5.5

iLife 09 requires Mac OS X 10.5.6

If you want to install it in 10.5.5, you need to change the SystemVersion.plist

sudo vi /System/Library/CoreServices/SystemVersion.plist

and change this

<key>ProductVersion</key>
<string>10.5.5</string>


to

<key>ProductVersion</key>
<string>10.5.6</string>


You cannot change the SystemVersion.plist back after installation, as iPhoto 09 and iMovie 09 will check this when launch.

If you want iPhoto 09 to skip the check*, you need to use a hex editor
open and change this file
/Applications/iPhoto.app/Contents/MacOS/iPhoto
then find (do multiple finds) and replace 10.5.6 to 10.5.5 and save it

*this trick does not work on iMovie 09