Have fun ...

Using gdb to debug on the iPhone (no need for OSX)

The goal here is to debug application on real-hardware. To do that you must follow some conditions :

  • Get gdb itself

    Good news, gdb is now available on cydia. So you can install it very easily. It comes all setup with all the needed signature / entitlements to have full functionalities. If you're interested in building it yourself, you'll find the original apple sources and the needed patches / build scripts on the telesphoreo repository

    The other way (previously only way) is to grab it from the SDK. Inside the .dmg you will find a package named iPhoneHostSideTools.pkg. Inside, there is Platforms/iPhoneOS.platform/Developer/usr/libexec/gdb/gdb-arm-apple-darwin. Just copy it to the iPhone, it's a universal binary that supports armv6 just fine.
    gdb is under GNU licence so you should be free to redistribute the binary as well I think.

    For information, the original Apple source are here.

    To enhance functionality you should add some entitlements to the apple binary. Use theses : for codesign, for ldid. To apply them :

    codesign -s "iPhone developer" --entitlements gdb.xcent -f gdb-arm-apple-darwin
    
    or
    
    ldid -Sgdb.xml gdb-arm-apple-darwin
    				
  • Taget armv6

    Apple's modified gdb is kinda picky. It will only work properly on ARMv6 arch. ARM isn't sufficient ... You can see the different in cpusubtype in the output of otool :

    lain:iPhone tnt$ otool -h test.arm
    test.arm:
    Mach header
          magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
     0xfeedface      12          0  0x00          2    12        860 0x00000085
    
    lain:iPhone tnt$ otool -h test.armv6
    test.armv6:
    Mach header
          magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
     0xfeedface      12          6  0x00          2    12        860 0x00000085
    				

    To make sure of that you must make sure you have -arch armv6 (or -march=armv6 -mcpu=arm1176jzf-s, depending on your compiler) in you CFLAGS / LDFLAGS. Like this :

    /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.0 -arch armv6 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk test.c -o test
    				
  • Sign the binary with entitlements

    Update: Actually if you used the entitlements I provide to sign gdb, or if you used the gdb of cydia, this step is no longer required.

    Next, you need to sign the binary you want to debug with entitlements. For details on that, see the 'Using XCode with Pwned iPhone', it's described there. I do it with codesign on OSX but ldid also support theses.

    If you're planning on doing it with ldid, the easier it to apt-get install it on your phone and do it there.

    ldid -Smyapp.xml myapp
    				

    The myapp.xml is the XML file describing the entitlements. I generate them using a simple script but for this simple purpose you could just always use a static one that would look like this :

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
      <dict>
        <key>application-identifier</key>
        <string>test</string>
        <key>get-task-allow</key>
        <true/>
      </dict>
    </plist>
    				

    Update : If you applied enhanced entitlements to gdb as described in the first point, you don't need entitlements on your binary.

Using XCode with Pwned iPhone

The idea here is to use the official SDK to create applications without having to pay for an 'official' certificate and provisioning profile.

Note that the instructions here are experimental. I can't be held responsible for whatever happens if you try them ... That being said, I can hardly imagine any issue that couldn't be solved by a DFU restore ...

Make Build & Go" + Debugging works

If you're not a fully registred / paying developer, you can use XCode to compile apps but some functions won't work. Like the 'Build & go' button, the automatic signing or the debugger. It's however possible to make them work ! Just follow the steps ...

  • Create a self-signed signing certificate

    Apple has a nice page explaining how to do that. Make sure to name your certificate 'iPhone developer'.

  • Add a custom build step to sign executables

    A pwned iPhone doesn't need a valid signature ... but it still needs one, or at least the hashes ... (for more details see on www.saurik.com). Jay Freeman made a small utility called ldid that add thoses hashes. However here we will use the official codesign utility, provided by Apple, with our self-signed identity.

    To make remote debugging work, we also need to add entitlements to the Application. This will be handled by codesign as well. We will however need a small python utility gen_entitlements.py to generate the entitlement file. Download it, place it somewhere on your disk and make it executable.

    So, to execute codesign properly during the build, you will need to add a custom build step to each of your XCode projects. Select the menu options "Project > New Build Phase > New Run Script Build Phase", and enter the following script (don't forget to replace /Users/youruser/bin by the correct path to gen_entitlements.py) :

    export CODESIGN_ALLOCATE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate
    if [ "${PLATFORM_NAME}" == "iphoneos" ]; then
    	/Users/youruser/bin/gen_entitlements.py "my.company.${PROJECT_NAME}" "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/${PROJECT_NAME}.xcent";
    	codesign -f -s "iPhone developer" --resource-rules "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/ResourceRules.plist" \
    		 --entitlements "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/${PROJECT_NAME}.xcent"  "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/"
    fi
    				
  • Remove signature checks from MobileInstallation & SpringBoard

    The final step is to bypass some security checks in some executable. The idea is simple to patch them, using a small software. Of course, after patching, you need to re-generate a signature for the new binaries to get loaded properly. All-in-all, it's easier to do all that on your Mac. So open a console and cut & paste the instructions (I assume you have ssh on the iPhone and that it's IP is 192.168.0.1) :

    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    osx:~ user$
    								
    mkdir iphone_tmp
    cd iphone_tmp
    scp root@192.168.0.1:/System/Library/PrivateFrameworks/MobileInstallation.framework/MobileInstallation .
    scp root@192.168.0.1:/System/Library/CoreServices/SpringBoard.app/SpringBoard .
    cp MobileInstallation MobileInstallation.bak
    cp SpringBoard SpringBoard.bak
    curl -O http://www.246tNt.com/iPhone/iphone_binary_patch
    curl -O http://www.246tNt.com/iPhone/SpringBoard.xcent
    chmod +x ./iphone_binary_patch
    ./iphone_binary_patch
    export CODESIGN_ALLOCATE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate
    codesign -s "iPhone developer" -f MobileInstallation
    codesign -s "iPhone developer" --entitlements SpringBoard.xcent -f SpringBoard
    scp MobileInstallation root@192.168.0.1:/System/Library/PrivateFrameworks/MobileInstallation.framework/MobileInstallation
    scp SpringBoard root@192.168.0.1:/System/Library/CoreServices/SpringBoard.app/SpringBoard
    							

    Finally, reboot the phone ... and enjoy :) Note that you may have to restart XCode and re-plug the iPhone for the connection to work. Also, if you had done previous attempts without following this how-to, you might need to clear the /var/mobile/Media/PublicStaging directory on the iPhone.

Deciphering protected Applications

Some applications on the iPhone are ciphered. This can be a problem if you want to study / extend them or whatever. So here's a quick explanation on one applicable method to go around it.

DO NOT USE THIS TO PIRATE/DISTRIBUTE AppStore applications. First because this is illegal and wrong and as a developer you should know that. But also because you'd be caught quickly since this method doesn't remove your personal iTunes account infos from the package bundle.

This is not a step by step how-to but if you have a valid reason for wanting to decompile such apps you'll know how to fill-in the gaps.

  • Look up some infos using otool

    The first step is to gather info on the binary using "otool -l MyAppp". Look at the LC_ENCRYPTION_INFO load command :

    Load command 9
              cmd LC_ENCRYPTION_INFO
          cmdsize 20 cryptoff  4096
     cryptsize 122880
     cryptid   1
    

    The cryptid 1 tells us it's encrypted. And more precisely that it starts at offset 4096 (0x1000) in the file and for a length of 122880 bytes.

    If you now look at the LC_SEGMENT, more precisely the __TEXT segment which is the encrypted one, you'll notice that basically all of it is encrypted except the first 4096 bytes which are the MachO header.

    Load command 1
          cmd LC_SEGMENT
      cmdsize 328
      segname __TEXT
       vmaddr 0x00001000
       vmsize 0x0001f000
      fileoff 0
     filesize 126976
      maxprot 0x00000007
     initprot 0x00000005
       nsects 4
        flags 0x0
    Section
      sectname __text
       segname __TEXT
          addr 0x00002000
          size 0x00019844
        offset 4096
         align 2^2 (4)
        reloff 0
        nreloc 0
         flags 0x80000400
     reserved1 0
     reserved2 0
    Section
      sectname __symbol_stub4
       segname __TEXT
          addr 0x0001b844
          size 0x000007ec
        offset 108612
         align 2^2 (4)
        reloff 0
        nreloc 0
         flags 0x80000408
     reserved1 0 (index into indirect symbol table)
     reserved2 12 (size of stubs)
    Section
      sectname __cstring
       segname __TEXT
          addr 0x0001c030
          size 0x000015b0
        offset 110640
         align 2^2 (4)
        reloff 0
        nreloc 0
         flags 0x00000002
     reserved1 0
     reserved2 0
    Section
      sectname __const
       segname __TEXT
          addr 0x0001d5e0
          size 0x00001ee4
        offset 116192
         align 2^2 (4)
        reloff 0
        nreloc 0
         flags 0x00000000
     reserved1 0
     reserved2 0
    
  • Accessing the deciphered segment

    So, to decrypt this, we go the easy way ... we let the phone do it for us. The i dea is to use gdb to make a dump of the process memory when it's running. At thi s point, the MachO loader in the kernel will already have loaded the binary and decrypted it for us.

    iPhone$ gdb-arm-apple-darwin /path/to/MyApp.app/MyApp
    (gdb) run
     <CTRL-C>
    (gdb) dump memory dump.bin 0x2000 0x20000
    (gdb) quit
  • Note that we didn't dump the first 4096 bytes of __TEXT. It's useless since they are not crypted and in any case we shouldn't modify the MachO header in the final files with the one in memory.

  • Putting it all back together

    The next step is to simply "put-back" that deciphered __TEXT segment inside the original binary. It's pretty easily done with dd or any hex editor. You then need to edit the LC_ENCRYPTION_INFO command to set cryptid to 0. And finally, re-sign the application with codesign or ldid.

    And voila ... you can now run / work on and decompile this application like any other else.