Tuesday, February 3, 2009

How to re-codesign iPhone binary ?

The codesign certificate from Apple is used by developers to compile the source code and deploy their iPhone Apps to device.

Have you ever think of how to re-codesign an already compiled iPhone binary and deploy that app to non-jailbroken iPhone without the source code and without re-compiling in Xcode ? That means only re-codesign the binary with the developer certificate again so that XCode can deploy it to development devices such as iPhone / iPod Touch. By using this method, you can patch the existing binary / add localization bundles or change the graphic files before re-codesign and deployment to device.

For example, there was a very nice app called NetShare which was pulled from the App Store, sometimes ago.

Would it be nice, if I can re-codesign (using the developer certificate) the NetShare binary and deploy it to my iPhone 3G, no jailbreak required. I can use it for tethering in cellular wireless.

I have done it, and the developer certificate is used to change the codesign signature and the app can be installed to non-jailbroken iPhone / iPod Touch successfully. This requires a hack on the original ipa file downloaded from App Store.

The following screen dump is captured from my iPod Touch second generation, no jailbreak. (I did not use redsn0w)

In my testing in iPhone 3G, Netshare can tether the 3G cellular networking using Mac OS X using the SOCKS Proxy. Safari Web Browing, iChat and iTunes work. But Microsoft Messenger and Mail do not work.




To implement the re-codesign, you first need a decrypted ipa, there are lots of them out there in the net. Don't ask me to give you.

Part I 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 (those ipa files floating in the net are already decrypted).

If you have that particular app installed in iPhone from AppStore directly, it needs to be decrypted in order to be useful. 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
apt-get install com.ericasadun.utilities gdb gawk zip ldid odcctools

To find out the app names with descending date order that your iPhone have installed, run this command in iPhone
find /var/mobile/Applications/ -iname *.app | xargs -0 ls -ldt

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"


Part II Installation of XCode Template

curl -O http://apiexplorer.googlecode.com/files/CrappStore.zip
unzip -o CrappStore.zip -d "/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Project Templates/Application/"



Part III XCode Build & Go

To install the decrypted ipa to non-jailbreak iPhone via XCode, you need the followings and a fully functional build & go iPhone device with iPhone SDK development environment with all Official certificates and Provisioning Profiles from Apple installed in Mac and iPhone /iPod Touch device
1) The XCode Template called CrappStore (see installation instruction in Part II above)
2) Official Developer Certificate from Apple installed in Mac
3) Official Development Provisioning Profile from Apple installed in Mac and iPhone / iPod Touch for development
4) XCode and iPhone SDK (I have tested it on iPhone SDK 2.2.1, but should work on earlier versions) installed in Mac (Intel)

Steps to Build & Go in Mac Xcode
1) Get the project name from the ipa file unzip -l Monkey_Ball-v1.02.ipa
2) Create a new project from the CrappStore XCode Template with Project Name same as the decrypted ipa e.g. "Monkey Ball"
3) Copy the decrypted ipa file (with extension .ipa) to the newly created Project folder (only copy one .ipa file to that project folder)
e.g. ~/Projects/Monkey\ Ball/Monkey_Ball-v1.02.ipa
4) Make sure iPhone / iPod Touch is connected to USB and recognized by XCode
5) Select Device - iPhone OS 2.0 (Project Settings)
6) Click Build & Go to Device Release. Or alternatively, you can simply build and then drag the product to the device's app list.
Done

It is possible to have other methods, but using the Xcode is the easiest one. Moreover, you can patch / mod it before deployment to device. If you have modified the app, remember to delete the ipa file in the project folder, so that it will not be unzipped again and overwrite your modding.






21 comments:

Anonymous said...

Could you upload the netshare re-codesign?

javacom said...

No, I cannot distribute the binary

Anonymous said...

Well, can you tell us how to do it so we don't have to reinvent the wheel?

(We'll get the binary ourselves.)

javacom said...

OK. I am finalising and will announce the method soon.

Anonymous said...

wicked, this trick really work, thanks!

Anonymous said...

doesn't work, mixture of appverifivation failures and user/bin/codesign failed with exit code 1...

any ideas?

cheers

javacom said...

If your binary does not work on codesign, probably it is the problem of your decrypted IPA. It must be from AppStore and decrypted using the stated method.

Anonymous said...

thanks, should the codesign directory within the ipa be deleted? and am assuming that a relevante bundle name assigned to your apple com.* name is also required? anything else from the process that should be excluded or included? many thanks

javacom said...

There is a script inside the Xcode Template and will show you what should be deleted. Codesign directory should be deleted as it will be generated when build & go

Anonymous said...

Hmm. Have you deleted template file from Google Code?

javacom said...

Yes, the template was removed.

Stephane said...

Any chance to get it back ?

Jan said...

do i have to be a registred iphone developer to do this?

Hossein said...

the crapstore link doesn't work
where can i get it

Anonymous said...

Hi javacom:
You did a great work. But I search everywhere. but can't find it. Can you share it with me? I want to do research on it.
my mail is :308047782@qq.com

Thank you very much.

cube3d said...

Hi guys

Thank you for your amazing research

If you send me a copy of crapstore.zip I will donate you.

God bless you!

Anonymous said...

Works on SDK 4.0 with 3GS on iOS4.0.. continue guyz!

Jake Lau said...

Thanks for shaing it! I just bought a new iPad with 3.2.2 firmware, no way to jailbreak it, but now with this method i can install those crack app there. Thanks so much!

asamatbagatov said...

Any way to install cracked apps without Provisioning Profile?

Anonymous said...

I'm trying to sign a copy of PdaNet, but it says "codesign failed with exit code 1" and when trying to sign the .app file manually, it says "code object is not signed."

Is there any way around this? I just want to tether without having to jailbreak.

Tx!

Anonymous said...

same here, xcode keeps telling "code object is not signed"