Chapters

Hide chapters

Advanced Apple Debugging & Reverse Engineering

Third Edition · iOS 12 · Swift 4.2 · Xcode 10

Before You Begin

Section 0: 3 chapters
Show chapters Hide chapters

Section III: Low Level

Section 3: 7 chapters
Show chapters Hide chapters

Section IV: Custom LLDB Commands

Section 4: 8 chapters
Show chapters Hide chapters

20. Code Signing
Written by Derek Selander

Ah, code signing: an iOS developer’s nemesis. Code signing is hardly at the top of every iOS developer’s agenda, but a strong knowledge of how code signing works can be extremely useful for solving problems, as well as establishing yourself as a lichpin in your development team. There’s nothing more “ask-for-a-raise-worthy” than a developer who can re-sign an outdated Swift 2.2 iOS app, instead of having to fix the potentially thousands of Swift compiler errors when time is against you.

This chapter will give you a basic overview of how code signing works by having you pick apart the open-source iOS Wordpress v10.9 application found here:

You’ll explore the stages of the app’s code signature before being sent to the iTunes Connect Store. In addition, you’ll re-sign the Wordpress app so it can run on your very own iOS device!

Setting up

In order to complete everything in this chapter, you’ll need a number of items. First, you’ll need a proper iOS Apple Developer account to generate Provisioning Profiles. You’ll also need a physical iOS device to install the Wordpress iOS application.

You’ll also need to grab and install my mobdevim command, available here:

This small command line tool does a number of things, including installing applications onto the device, querying device information and grabbing console logs when connected to an iOS device. Using this tool makes it significantly easier to install an iOS app on your device and hunt for errors if the app has been incorrectly signed. You can install iOS apps in Xcode through the Devices and Simulators window, but the Xcode authors really make it a painful to do this.

Follow the instructions on the mobdevsim repo to install the tool. Once you have mobdevim setup, plug in your iOS device via cable and give it a test run.

mobdevim -f

This will query the device info. Provided it worked, you’ll get something similar to:

Connected to: "LOLz" (c3a8533d6dc4fa74d6748a2cd935f00e1e949af1)

name    LOLz
UDID    c3a8533d6dc4fa74d6748a2cd935f00e1e949af1

State   Activated
Type    iPhone
Version 12.0.0
Number  (555) 867-5309
Region  LL/A
Battery 65%
... truncated ...

You can get a full list of the available commands by executing mobdevim -h.

After installing this command, and making sure you have a valid way to sign your iOS applications with a developer account, you’ll be all set up for the rest of this chapter!

Terminology

To really appreciate how code signing works, you need to understand three key components: public/private keys, entitlements, and provisioning profiles. You’ll start with a breadth-first look, then dive into a depth-first look at each.

The public/private key is used to sign your application. This is your digital signature which Apple knows about and how Apple verifies you as, well, you. The private key is used to crytographically sign the app as well as its capabilities, or entitlements. The entitlements are really just an XML string embedded in your app which says what the app can, and can’t, do.

The grouping of the entitlements, the list of approved devices, and the public key to verify the code signature are all bundled together in a provisioning profile in your application. All the information is enforced through the signature created by your private key and can be verified by your public key.

That is a lot to take in, and it gets more confusing from here. So let’s investigate each component of the profile separately.

Public/private keys

This is probably the hardest thing to understand when learning about the code signing process, since public/private keys introduce cryptography, which quickly becomes a rabbit hole of knowledge, formats, formatting, and gotchas.

Simply put, there’s two different types of cryptography: symmetric cryptography, and asymmetric cryptography.

Symmetric cryptography is a type of cryptography that contains only one key. If person A tries to send a secret message to person B, they both must know that shared secret in order to encrypt and decrypt the message.

In asymmetric cryptography, there are two keys: a public key (which can be known by everyone) and a private key (which is kept secret to you). Both person A and B have their own unique private key and their own unique public key. That way, they can share information without either person knowing the other person’s private key. The implementation of this is beyond the scope of this chapter, but you should learn more about this concept on your own time if this is new to you.

If you can remember when you set up your Apple developer account, you went through the process of Requesting a Certificate From A Certificate Authority. You created a public/private key, sent up the public key to Apple servers (by the .csr file). The end result of this process created a signature that is signed by Apple and is how Apple uniquely recognizes you. This means that Apple — and by extension, you — use asymmetric cryptography for distributing applications.

You can view the names, or identities, of your public/private key pairs used for signing your applications with the following Terminal command:

security find-identity -p codesigning -v

This command queries the macOS system keychain, looking for valid identities that contain a private key (-v) and whose type can codesign (-p codesigning).

This ouput will display identities that are valid, which can produce a code signed application. If you look for identities that contain the phrase “iPhone Developer], it’s likely that this identity can be used to sign an iOS application on your device.

For example, I got the following output for identities that contained the term “iPhone Developer”:

1) 2DFE888B7BD07710444C2E4A7B9847BA8B55C220 "iPhone Developer: Derek Selander (8AW8QLCX5U)"

If you got something similar, your computer is properly set up to sign a valid iOS application on your macOS machine.

You can view this identity in the GUI-equivalent program Keychain Access. Open Keychain Access, navigate to My Certificates, then search for your equivalent string by omitting the quotes.

Notice that you havea public key, or a certificate, as well as the private key found below. Certificates can be recreated, but private keys are worth more than gold. Never, ever, delete a private key! If you do, you forefit your proof that you’re you, and you’ll need to recreate a new identity through Apple.

Let me revisit a point you might have missed in the above paragraph. A certificate, in this sense, is only the public key. So if you were to use Keychain Access to export your identity, and you wanted to format it in a .cer (certificate) format, you’d only be exporting the public key. If you want to export the private key as well, you must use the PKCS12 format (.p12) to properly export the full identity, private key and all.

This is important to know if you wanted to export the identity so another developer could, say, generate a build with a matching distribution (i.e. App Store) identity. But be careful: whoever has the private key can assume the full identity for that company, at least from Apple’s perspective!

Jumping back to the Terminal equivalent, you can export the public certificates using the following command:

security find-certificate -c "iPhone Developer: Derek Selander (8AW8QLCX5U)" -p

This will output the public, x509 certificate of iPhone Developer: Derek Selander (8AW8QLCX5U) to stdout and format it in PEM format. There’s two ways to display a certificate: DER and PEM. PEM can be read by the Terminal (since it’s in base64 encoding) while DER, in highly professional coding terms, will produce gobbledygook and make the Terminal beep a lot.

Repeat the above command and write the output to /tmp/public_cert.cer. Be sure to replace the identity with your own identity:

security find-certificate  -c "iPhone Developer: Derek Selander (8AW8QLCX5U)"  -p > /tmp/public_cert.cer

Use the Terminal command to cat this newly created file:

cat /tmp/public_cert.cer 

You’ll see something similar to:

-----BEGIN CERTIFICATE-----
MIIFnDCCBISgAwIBAgIIFMKm2AG4HekwDQYJKoZIhvcNAQELBQAwgZYxCzAJBgNV
BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
...

This is how you can tell this certificate is in PEM. Terminal isn’t cranky, and the header -----BEGIN CERTIFICATE----- is included. This would not be the case if the certificate was in DER format.

From here, you can use the openssl Terminal command to query the public, x509 certificate:

openssl x509 -in /tmp/public_cert.cer -inform PEM -text -noout

Yes, that’s a lot of params!

  • The x509 option says that the openssl command should be able to work with a x509 certificate.
  • You provide the -in to the path of public_cert.cer with the decoding format of PEM (-inform PEM).
  • You specify you don’t want to output a certificate with the -noout param.
  • But instead, you do want the certificate in a (somewhat) readable “text” format with the -text option.

The information about this public certificate will be displayed in the Terminal.

Remember this openssl command, as you’ll revisit the concept of x509 certificates when you read about the provisioning profiles which embed these public certificates inside of them.

Entitlements

Embedded in (almost) every compiled application is a set of entitlements: again, this is an XML string embedded in the application saying what an app can and can’t do. Other programs will check for permissions (or lack thereof) in the entitlements and grant or deny a request accordingly. Think of the capabilities section found in Xcode.

Many of these permission checks are carried out by other daemons which check your programs entitlements. For example, App Groups, iCloud Services, Push Notifications, Associated Domains all will modify the entitlments to your app. These capabilities shown in Xcode are but a small piece of the entitlements on Apple platforms as the majority of them are private to Apple and enforced through code signing.

You can see a complete list of entitlements found in the wild thanks to Jonathan Levin’s entitlement database, here:

Probably the most important entitlement, at least in this book, is the get-task-allow entitlement, found on all your software compiled with a developer certificate. This allows the program in question to be attached to a debugger.

On macOS, you can get around the lack of this entitlement by disabling SIP for any applications that don’t have the true value for this key. On iOS, you’ll be S.O.L. trying to debug an application that doesn’t have this entitlement, unless code verification has been disabled through jailbreaking.

You can view the entitlements of an application through the codesign Terminal command.

Find the entitlements of the macOS Finder application:

codesign -d --entitlements :- /System/Library/CoreServices/Finder.app/Contents/MacOS/Finder

The -d option says to display the option immediately following in the command, which is the --entitlements. You also have that weird looking :-, which does two things:

  • The - says to print to stdout
  • The : says to omit the blob header and length.

Just as in Mach-O, the code signature information is stored with a magic header, immediately followed by a length. The “:” says to strip this header information out of the output and only display the actual XML string of entitlements.

Provisioning profiles

Finally, the provisioning profiles are up for discussion. A provisioning profile includes the public x509 certificate, the list of approved devices, as well as the entitlements all embedded into one file.

The default location for provisioning profiles can be found here:

~/Library/MobileDevice/Provisioning Profiles/

Unfortunately, provisioning profiles are named by their UUID instead of by the name you (or Xcode) made up for them. This gives you a list of files that don’t give you a lot of context, at first glance, if you were to execute an ls in the directory.

ls ~/Library/MobileDevice/Provisioning\ Profiles/

Fortunately, you can use the security command again to dump the raw info. Pick any one of your .mobileprovision files and execute the security command, like this:

PP_FILE=$(ls ~/Library/MobileDevice/Provisioning\ Profiles/*mobileprovision | head -1)
security cms -D -i "$PP_FILE"

The first command grabs one of the provisioning profiles and assigns it to the PP_FILE variable.

The PP_FILE variable is passed into the security command which decodes (-D) the cryptographic message syntax (cms) format of the provisioning profile, specifying the input path via the -i option.

The output will be in plist XML form. Your content will be very different from mine due to the different nature of the apps you’ve developed, the entitlements you’ve specified, the devices and code signatures you’ve used, as well as the environment you’ve used (i.e. development/distribution) to generate the provisioning profile.

I’ll discuss the output of one of my provisioning profiles as a guide to help explore your own. If you want to follow along word-for-word, my exact provisioning profile is included in the resource directory for this chapter.

From the output, here are some of the highlights:

  • TeamIdentifier contains the value H4U46V6494, the unique team ID Apple has given me for my team identity. Apple will generate a specific team ID for every account you pay for. For example, you’ll have a unique team ID for App Store builds and a different team ID for Enterprise builds.

  • Entitlements, unsurprisingly, contains the Entitlements of what the app can and can’t do with this signature. This is often the cause of problems in Xcode generated provisioning profiles since Xcode needs to update the App ID configuration (which is essentially the entitlements), and then generate a new provisioning profile with the correct values.

  • IsXcodeManaged is a Boolean value that indicates if Xcode manages this provisioning profile. The whole code-signing process has caused so many developer headaches that Apple is trying to do more of the work on their end, including signing an app with your distribution certificate. This is a double-edged sword since it’s easier to let Xcode manage this for you, but if Xcode does something you didn’t expect, the underlying error can be much more difficult to track down.

  • Name contains the value DS Twitter PP, which is the name of the provisioning profile that Apple displays to identify the provisioning profiles on https://developer.apple.com/account/ios/profile/limited.

  • ProvisionedDevices contains an array of approved devices this provisioning profile can install on, given by a device’s UDID.
  • DeveloperCertificates is an array that contains base64-encoded x509 certificates. This will contain the same public certificate that was extracted earlier via the security find-certificate command. These certificates are also encoded into the actual executables themselves when code signing an application. My provisioning profile contains two different certificates with the exact same name, with one certificate expiring in 2019, and one having already expired in 2018.

Phew! That was a lot of theory, but now you can move on to some actual codesigning work.

Exploring the WordPress app

Just like your typical debugging workflow on your iOS device, before an app is sent up to the Apple iTunes Connect mothership, you must compile an app with a provisioning profile. This provisioning profile is included in every pre-App Store .app under the name embedded.mobileprovision. It’s this provisioning profile that tells iOS the application is valid and came from you.

Head over to the resources for this chapter. Then open up the WordPress.app container found in the Pre App Store directory. If you’re using Finder, you can open up the container by right-clicking it and selecting the Show Package Contents.

Now head back over to your Terminal window. For the purpose of this tutorial, assign a Terminal variable, WORDPRESS to the fullpath to the WordPress.app, like so:

WORDPRESS="/full/path/to/WordPress.app/"

The provisioning profile

Find the embedded.mobileprovision provisioning profile inside of the WordPress application and use the security command on it.

security cms -D -i "$WORDPRESS/embedded.mobileprovision"

In this particular provisioning profile, you can see the following:

  • Apple has given the Automattic, Inc. company the team identifier of 3TMU3BH3NK.
  • The Wordpress app makes use of iCloud services, given the com.apple.developer.icloud* keys in the entitlements dictionary. It also looks to make use of certain extension like “App Groups”.
  • get-task-allow is false, meaning a debugger can’t be attached, as this was app was signed with a distribution signing identity.

Copy the base64-encoded data from the DeveloperCertificates key. It should begin with MIIFozCCBIu..., and make sure you copy the trailing equals signs if there are any.

Via Terminal, assign this value to a variable named CERT_DATA:

CERT_DATA=MIIFozCCBIu...

The variable CERT_DATA now contains the base64-encoded x509 certificate that was used to sign the application.

Now, decode this base64 data and pipe it to /tmp/wordpress_cert.cer:

echo "$CERT_DATA" | base64 -D > /tmp/wordpress_cert.cer

You now have the Wordpress certificate in DER format at /tmp/wordpress_cert.cer. You can now execute the following openssl command:

openssl x509 -in /tmp/wordpress_cert.cer -inform DER -text -noout

You’ll see the following output:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 786948871528664923 (0xaebcdd447dc4f5b)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority
        Validity
            Not Before: Jan 17 13:26:41 2018 GMT
            Not After : Jan 17 13:26:41 2019 GMT
        Subject: UID=PZYM8XX95Q, CN=iPhone Distribution: Automattic, Inc. (PZYM8XX95Q), OU=PZYM8XX95Q, O=Automattic, Inc., C=US
... truncated ...

This means that someone working at “Automattic, Inc” has an identity named “iPhone Distribution: Automattic, Inc. (PZYM8XX95Q)” on their keychain that was used to sign this application.

Embedded executables

Provided an application contains extensions (i.e. share extension, today widgets, or others), there will be even more signed packaged bundles found in the ./Plugins directory that contain their own application identifier and embedded.mobileprovision provisioning profile.

These give the application additional functionality outside the application.

You can verify this on your own time using the same security command while drilling into the containers in the ./Plugins directory, exploring each embedded.mobileprovision file respectively.

The _CodeSignature directory

Included in a real iOS application bundle (but not in the Simulator) is a folder named _CodeSignature that includes a single file named CodeResources. This is an XML plist file which is a checksum of every non-executable file found in this directory.

For example, if you were to execute:

cat "$WORDPRESS/_CodeSignature/CodeResources"  | head -10

you’ll see there is a checksum of value rSZAWMReahogETtlwDpstztW6Ug= for the file AboutViewController.nib

This can be calculated yourself via openssl:

openssl sha1 -binary "$WORDPRESS/AboutViewController.nib"  | base64

This will produce the matching rSZAWMReahogETtlwDpstztW6Ug= value.

Apple has begun the transition from SHA-1 checksums to SHA-256 for iOS applications with Xcode 10 producing checksums for both algorithms.

This CodeResources file itself has a checksum performed on the file, which is embedded in the actual WordPress application! This means that if a user were to modify any of the files, or even add a directory in the .app directory without resigning the WordPress app, the iOS application will fail to install on the user’s phone.

Resigning the WordPress app

Time for some codesigning fun!

you’ll now install the WordPress application onto your iOS device by re-signing the application with your Apple signature.

From a high level standpoint, you’ll need to do the following:

  1. Copy a valid provisioning profile to the embedded.mobileprovision in the WordPress .app directory.

  2. Change the Info.plist key CFBundleIdentifier to the new application identifier provided in the new provisioning profile.

  3. Re-sign the WordPress application via the identity included in the embedded provisioning profile with the proper entitlements (which is also included in the provisioning profile).

Provided you have a valid, non-expired, provisioning profile that inlcudes your iOS’s UDID, you can resign the WordPress app. You can obtain your device’s UDID by executing the mobdevim -f command when your device is plugged in… (or you can go to iTunes to find it, but that is way less cool).

You can search for valid provisioning profiles at ~/Library/MobileDevice/Provisioning Profiles/ or you can download a valid provisioning profile at https://developer.apple.com/.

If you have a valid provisioning profile with the above qualifications, you can skip the next step. You can determine if you have a valid provisioning profile by running the same security cms command as discussed above.

If you don’t have a valid provisioning profile that contains your device and is not expired, you’ll need to create a new provisioning profile in the Apple developer portal.

(Optional) Generate a valid provisioning profile

If you don’t have a provisioning profile that met the above requirements (UDID, not expired), you’ll need to head on over to https://developer.apple.com/ and create a new one.

Although Apple changes the UI/UX on this site from time to time, head on over to the closest equivalent to Certificates, IDs & Profiles. Once there, select App IDs then create a new App ID via the + button in the upper right corner.

You might be confused if you have multiple App ID prefixes (like me).

To resolve this, remember that everything stems from your signing identity. You can query this information yourself from the commands you performed earlier.

Provided you have a valid signing identity, you can use the following Terminal query:

security find-certificate -c "iPhone Developer: Derek Selander (8AW8QLCX5U)" -p > /tmp/public_cert.PEM

This extracts the public certificate from the identity. Now you can use openssl to search for the App ID prefix which is stored in the Organizational Unit (abbreviated as OU) in the x509 certificate.

openssl x509 -in /tmp/public_cert.PEM -inform pem -noout -text | grep OU=

I got the following output:

Issuer: C=US, O=Apple Inc., OU=Apple Worldwide Developer Relations, CN=Apple Worldwide Developer Relations Certification Authority

Subject: UID=V969KV7V2B, CN=iPhone Developer: Derek Selander (8AW8QLCX5U), OU=H4U46V6494, O=Derek Selander, C=US

In my case, the signing identity I want to use has the App Prefix H4U46V6494, so I’ll select that in the Apple Developer portal.

After creating the new App ID in https://developer.apple.com/, head on over to the Development section of the Provisioning Profiles. Click on the + to add a new provisioning profile.

Select iOS App Development, the click Continue.

At the next page, select the App ID you just created, then click Continue again.

Select all the valid iOS certificates that can be used to sign the iOS application.

Finally, select all the devices you would like this provisioning profile to be installed on.

Give the provisioning profile a valid name.

A general word of advice: If you work on a team of iOS developers, and you’re generating a Distribution provisioning profile, I would put your initials and date in the name. That way, people know who to track down in case something goes wrong, or if the provisioning profile is expiring.

Once complete, download your newly created provisioning profile. Be sure to save it in a location that you’ll remember since you’ll be referencing it in a moment.

Copying the provisioning profile

At this point, you should have a valid provisioning profile, which you’ll use to resign the WordPress application either by creating a new provisioning profile or by using an existing provisioning profile. Assign the PP_PATH Terminal variable to the fullpath of the provisioning profile you expect to use for this experiment.

Your path will be different than mine:

PP_PATH=~/Downloads/Code_Signing_Example_ProvisProfile_92618.mobileprovision

Copy the provisioning profile at PP_PATH to the embedded.mobileprovision file in the WordPress app.

In Terminal, execute:

cp "$PP_PATH" "$WORDPRESS/embedded.mobileprovision"

Deleting the plugins

The WordPress application has several extension applications embedded into the main app found in the ./Plugins directory. Each of these contains a unique provisioning profile with a unique application identifier. You could sign each of these extensions itself with a unique provisioning profile, but that will get way too complicated for this demo.

Instead, you’ll cripple part of the Wordpress functionality and not use these extensions. Delete the entire Plugins directory for the WordPress app.

So now the new, re-signed application will not have functionality for the iOS Today Extension, but that’s acceptable for this demo.

Modifying the Info.plist

I hope you’ve remembered the name of the App ID of the provisioning profile! You’ll need to plug that into the Info.plist’s key CFBundleIdentifier If you don’t remember it, you can query it from the provisioning profile.

Here’s how to grab that information:

security cms -D -i "$PP_PATH" | grep application-identifier -A1

This gave me the application identifier I need to plug into the Info.plist.

<key>application-identifier</key>
<string>H4U46V6494.com.selander.code-signing</string>

For me, my application identifier is H4U46V6494.com.selander.code-signing.

When you have your application identifier, replace this value in the WordPress’s Info.plist for the CFBundleIdentifier key.

plutil -replace CFBundleIdentifier -string H4U46V6494.com.selander.code-signing "$WORDPRESS/Info.plist"

While you’re at it, change the display name to further highlight that this is in fact something you can completely tweak to your will. Change around WordPress’s visual display name:

plutil -replace CFBundleDisplayName -string "Woot" "$WORDPRESS/Info.plist"

This will change around the visual display name to Woot instead of WordPress, provided you can install the application on your iOS device.

Extracting the entitlements

You’re almost there!

Your next task is to resign the app with valid entitlements found in the provisioning profile. Since the entitlements get embedded as a dictionary and not as XML in the provisioning profile, it might be easier to extract the entitlements from the main executable first, then patch that file with the new entitlements found in the provisioning profile.

Extract the entitlements to /tmp/ent.xml:

codesign -d --entitlements :/tmp/ent.xml "$WORDPRESS/WordPress"

Note: The above command appends to the file — it does not overwrite the file. If you execute this command multiple times, you’ll have an incorrectly formatted file, since there will be multiple entitlements at /tmp/ent.xml. If you execute this command multiple times, make sure to rm the file before executing it again.

Verify the entitlements are valid with a cat:

cat /tmp/ent.xml

Provided the entitlements work, you can extract the entitlements from the current provisioning profile and place them into this new file.

First, write out the provisioning profile XML to a file named /tmp/scratch:

security cms -D -i "$PP_PATH" > /tmp/scratch

Now use the xpath Terminal command to extract only the entitlement information to the clipboard.

By the way, you should play around with this command first before piping it to the clipboard (with pbcopy) so you understand the content it’s grabbing.

xpath /tmp/scratch '//*[text() = "Entitlements"]/following-sibling::dict' | pbcopy 

You now have the valid entitlements in your clipboard. Open up /tmp/ent.xml, remove the enclosing <dict>’s contents and replace with the contents of your clipboard.

Your finalized /tmp/ent.xml file should look like the following entitlements:

<?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>keychain-access-groups</key>
    <array>
        <string>H4U46V6494.*</string>       
    </array>
    <key>get-task-allow</key>
    <true />
    <key>application-identifier</key>
    <string>H4U46V6494.com.selander.code-signing</string>
    <key>com.apple.developer.team-identifier</key>
    <string>H4U46V6494</string>
</dict>
</plist>

This file is also included in the chapter directory in case you want to start with that instead.

Finally, signing the WordPress app

You now have performed all the setup. You have a valid signing identity; you have a valid provisioning profile embedded in the WordPress application at embedded.mobileprovision; you have removed the Plugins directory; and you have the entitlements of the new provisioning profile found at /tmp/ent.xml.

You can now sign the application with your signing identity!

Before you do that, make a duplicate backup of the WordPress app, because it’s easy to screw this part up, and it’s tricky to undo the action if you do screw up.

Once you have a duplicate of your WordPress application, use the codesign command with your signing identity on the WordPress applications Frameworks directory:

codesign -f -s "iPhone Developer: Derek Selander (8AW8QLCX5U)" "$WORDPRESS"/Frameworks/*

You need to sign this directory first.

codesign --entitlements /tmp/ent.xml -f -s "iPhone Developer: Derek Selander (8AW8QLCX5U)" "$WORDPRESS"

Now for the moment of truth! See if you can install the WordPress application. In Terminal, type:

mobdevim -i "$WORDPRESS"

Did it succeed?

Provided you have followed the steps exactly, you’ll see a new app with the WordPress logo with the name “Woot” underneath it!

Even better, provided you signed your application with a developer provisioning profile, you’ll have the get-task-allow entitlement, meaning you can debug this WordPress application!

Launch the newly installed WordPress application on your iOS device.

Fire up Xcode, select the Debug menu, select Attach to Process and search for the WordPress application.

Alternatively, you can also use mobdevim to debug your application without having to use Xcode.

Simply type the following:

mobdevim -d $WORDPRESS

This will set up LLDB to the state just before launch. Prove to yourself that you have complete control over this WordPress process by forcing WordPress to launch in Spanish, via specifying the iOS language environment variable.

(lldb) run -AppleLanguages "(es)"

Did it fail?

If the output says “success”, then you’re good to go. If not, open a new Terminal window and execute the following:

mobdevim -c | grep installd 

This will dump out all logs pertaining to the daemon installd. This daemon is responsible for installing your application and will provide useful logging information as to why your application failed to install. From there, you’ll need to careful review the above steps and repeat the process.

Once the log monitoring is running, repeat the above mobdevim -i "$WORDPRESS" command so you can capture the installation error.

If you can’t get it to work, I’ve included a shell script that will resign the WordPress application for you. It’s named dsresign and expects the path to the application as argument one, followed by the path to the provisioning profile you want to resign the application with.

Where to go from here?

This chapter has only scratched the surface of code signing. There is a lot more great content out there that focuses on other components to code signing.

If you want to truly know the in and outs of code signing, check out Jonathan Levin’s OS Internals Volume III Security & Insecurity, which discusses code signing at an unprecedented level and gives you a look at everything, right down to the C structs.

Also check out this article, which is one of the my favorite code signing articles out there from a developer standpoint:

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.