티스토리 뷰

출처 : http://networkpx.blogspot.com/2009/09/compiling-iphoneos-31-apps-with-xcode.html



Saturday, September 26, 2009

Compiling iPhoneOS (3.1) apps with Xcode 3.2 without Provisioning Profile

Note: I don't know if this method still works, and I don't care. (And do not use the dd method mentioned in the article. It is extremely fragile to patch a binary file.)

I want to compile.


This is easiest to solve. To compile you still need a certificate that can code-sign, but think this as a lip-service. Here is the procedure to create a self-signed code-signing certificate using Keychain Access. Make sure you create the certificate in the "login" (default) keychain, not the "System" keychain. After the certificate is created, perform these steps:
  1. Open /Developer/Platforms/iPhoneOS.platform/Info.plist. (Backup if you want to be safe.)
  2. Go to line 46. Replace the XCiPhoneOSCodeSignContext with XCCodeSignContext
  3. Go to line 79. Replace the XCiPhoneOSCodeSignContext with XCCodeSignContext
  4. Save the file.
  5. Restart Xcode.
  6. Compile!

After doing this, you can't use entitlements with Xcode anymore. But you have ldid -Sxyz.xml that does the same job.



The theory behind this is simple. When Xcode wants to code-sign, it has to consult DevToolsCore.framework on the procedures to code sign. The procedures are coded in the XCCodeSignContext class. The iPhoneOS placed more restrictions on the code-signing requirements, e.g. you must have a provision file. These extra procedures are provided in the class XCiPhoneOSCodeSignContext, as a plug-in at/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Plug-ins/iPhoneOS Build System Support.xcplugin. Xcode isn't omniscience, so something must tell it that XCiPhoneOSCodeSignContext should be used, instead of the default XCCodeSignContext. This thing is the /Developer/Platforms/iPhoneOS.platform/Info.plist. In the past (iPhoneOS 2.x day), you add the PROVISIONING_PROFILE_[ALLOWED|REQUIRED] keys to give extra instructions to the plug-in, which it can promptly ignore. That's why eventually you need to take the dangerous way of binary-patching the plug-in. But why not just hide XCiPhoneOSCodeSignContext entirely? This is my hack's principle - tell Xcode to meet the new boss, same as the old boss. 

I want to install and debug too.



(Note: I'm not fond of patching MobileInstallation.framework. In fact, on 3.1 there's no framework you can statically patch with.)

Unfortunately, installing is more complex than compiling because there are much more checking in the device side. Therefore the procedures will be so complex that ordinary developers should not follow ;).
  1. Make sure you have ldid on Mac. (e.g. this). Place it in /usr/local/bin.
  2. Create the file /usr/local/bin/ldid2. Make it executable. Fill it with:
    #!/bin/sh

    hasGTA=`expr "$*" : '.* -gta .*'`;
    objpath=${!#}/`expr ${!#} : '.*/\([^/]\{1,\}\)\.app$'`;

    if [[ $hasGTA == 0 ]]; then
    /usr/local/bin/ldid -S $objpath;
    else
    TF=`mktemp -t x`;
    echo "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"><plist version=\"1.0\"><dict><key>get-task-allow</key><true/></dict></plist>" > $TF;
    /usr/local/bin/ldid -S$TF $objpath;
    rm $TF;
    fi;
  3. Open /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Plug-ins/iPhoneOS Build System Support.xcplugin/Contents/Resources/iPhoneCodeSign.xcspec
  4. Replace the line saying CommandLine = "/usr/bin/codesign" with CommandLine = "/usr/local/bin/ldid2"
  5. Now, copy /usr/libexec/installd from your device to your Mac.
  6. Run this:
    install_name_tool -change /usr/lib/libmis.dylib /usr/lib/libmiss.dylib installd
    ldid -S installd
  7. Now, create a file named libmiss.c, and enter these into the file:
    extern int MISValidateSignature() { return 0; }
  8. Compile libmiss.c to libmiss.dylib with gcc targeting iPhone. Make sure t you have all these flags:
    -dynamiclib
    -install_name /usr/lib/libmiss.dylib
    -current_version 1
    -compatibility_version 1
    -Wl,-reexport-lmis
    -flat_namespace
  9. ldid -S libmiss.dylib, of course.
  10. Copy the new installd to the device's /usr/libexec, and the libmiss.dylib to the device's /usr/lib.
  11. Restart Xcode.
  12. Install!

If you want to debug, add the -gta flag in "Other Code Signing Flags" in your Xcode Project.

OK, so WTF is going on? The first 4 steps allows you to debug the app on the device. The essence of this is replace codesign with ldid. Why this is necessary? Because of the change in Part 1, entitlements are no longer respected. But to debug you must have the get-task-allow entitlement. To fix it, we have to entirely replace codesign with our executable that adds the entitlement ourselves. ldid2 is created with this purpose.

The rest of the steps allows mobile installation to succeed without validation. When the app is installed from Xcode, "mobile_installation_proxy" is invoked, which spawned "installd". The validation part of installd is this:
 +00cd4 0000af2c 0010A0E3 loc_000cd4: mov               r1,#0x0
+00cd8 0000af30 D19701EB bl MISValidateSignature (stub)
+00cdc 0000af34 005050E2 subs r5,r0,#0x0
+00ce0 0000af38 0600000A beq loc_000d00
+00ce4 0000af3c 54049FE5 ldr r0,[pc,#0x454] ; -> 0xb398 "verify_executable"
+00ce8 0000af40 5C149FE5 ldr r1,[pc,#0x45c] ; -> 0xb3a4 "Could not validate signature: %x"
+00cec 0000af44 0520A0E1 mov r2,r5 ; "_CodeSignature/CodeResources"
+00cf0 0000af48 C9E3FFEB bl proc_00003E74
+00cf4 0000af4c 0400A0E1 mov r0,r4
+00cf8 0000af50 B49701EB bl CFRelease (stub)
+00cfc 0000af54 060000EA b loc_000d1c
If we can force MISValidateSignature() to always return 0, any binaries will pass the test. This function is part of libmis.dylib, which is now part of the shared cache, so you can't binary patch this file. Replacing the implementation of a function is a perfect job with MobileSubstrate, unfortunately, no matter how I tried MS can't be injected. Therefore I use a trick: create a "proxy dynamic library" that changes only the MISValidateSignature function, and let the rest pass through. This is the purpose of libmiss.dylib. First, install_name_tool is used to repoint the libmis.dylib in installd to libmiss.dylib. Then, in libmiss.dylib we define a single function, MISValidateSignature, which returns 0 as we wanted. It linked with libmis.dylib, and reexport all the symbols so that the original symbols can still be found. But we have to use flat namespace to make sure our new MISValidateSignature can shadow the old one. Finally, there is a quirk in installd that required the dylib to be at version 1.0.0, so the -compatibility_version and -current_version flags are added.

'my Programing > iPhone' 카테고리의 다른 글

iPhone SDK 구버젼 받기 ...  (0) 2010.07.03
peakPowerForChannel  (0) 2010.01.28
drawSolidPoly  (0) 2010.01.27
UIAcceleration  (0) 2010.01.20
아이폰에 어플 올리기!! 성공!  (0) 2010.01.20
댓글