How to perform iOS Code Injection on .ipa files
Image from
http://dyci.github.io/Code injection is process of introducing external code into an existing software system. In this post, I will share the tools and techniques needed to perform iOS Code Injection on iOS Apps. With XCode, it is possible to setup an experiment to showcase iOS Code injection in action. The idea is to create an independent set of codes, package it with the final app and somehow execute the new codes.
[Note: This code injection process has been proven to work on iOS 9.3, 10.0.2 and on XCode v7.3 and v8.0. I have yet to try this on other OS or XCode Versions]
We can create an independent binary package via Xcode in 2 ways:
- Dynamic Libary via (Cocoa Touch Framework) or
- Static Library via (Cocoa Touch Static Library)
Dynamic Library vs Static Library: Our options to create an external binary to contain our injection codesStatic Library
A unit of code linked at compile time.
Static Libraries need to be available during compilation of the .ipa in order for their codes to be executed
Swift is not supported for static libraries
There is no known way to instruct an .ipa to load a static library
We cant use static library directly . You may need to convert it into a dynamic Library first
Dynamic Library
A unit of code that is linked at run time. Xcode does require dependent Dynamic Library/Frameworks to be available during compilation but does not guarantee that these dependencies are packaged into the app. That is why sometimes you may encounter runtime dynamic library loading errors like
dyld: Library not loaded: @rpath/libswift_stdlib_core.dylib
We can build Swift codes for Dynamic Libraries
Load Dylib command is needed to be executed on the .ipa so that it will load the Dynamic Library into memory before the application is launched.
YES WE CAN USE THIS :)
With dylib (Dynamic Library) chosen as our custom code package, lets use XCode to present the code injection proof of concept.
Code Injection Proof of Concept via XCode
Code Injection Process through XCodeHere are the steps
Create a new XCode Project
Create a new iOS Application target.
Create a new “Cocoa Touch Framework” target. Lets call it “PatchPGO”
Create a new Objective-C Cocoa Touch Class. Lets call it “PatchLoader”. Add the following method in the .m file.
@implementation PatchLoader
static void __attribute__((constructor)) initialize(void){
NSLog(@"==== Code Injection in Action====");
/*
Place your code injection codes here
*/
}
@endUsing the "static void __attribute__((constructor))” as the modifier for the initialize method, we can specify what we want to do when the class gets loaded into memory before the application is launched. You can consider this as the “entry point” for codes to be injected into the iOS Application.
5. Run the iOS Application target to ensure that the log console outputs as what you would expect before the code injection.
6. Now link the Dynamic Framework file to your iOS Application. Ensure that the framework is embedded as required.
iOS App Target General Settings: Ensure your framework is linked
iOS App Target Build Phase: Ensure your framework is added under “Embed Frameworks” and its destination is “Frameworks”7. Now that your iOS Application target is properly linked, run the target and observe your logging console. Our NSLog message has successfully been injected into our iOS Application target app.
Code injection logging message appearsNotice that a change of behavior has been observed (new logging message) but the application target codes has not been modified. Behind the scenes, Xcode linked the library to the target before code-signing and installing the modified app. In the above code injection experiment via Xcode, the developer owns the app’s source code. Now, lets try to inject codes into an .ipa file where the developer do not own the source codes.
Code Injection Proof of Concept with .ipa file
Here are the steps
Download and .ipa file of your choice. You may find cracked .ipa files from 3rd party content providers (eg.
www.iphonecake.com)
Download optool
(https://github.com/alexzielenski/optool) or
download/clone my repository (
https://github.com/depoon/iOSDylibInjectionDemo). This repository contains optool and a script “
patchapp.sh” will load dylibs (via optool) into a given .ipa file. Details are in the README.
Create a folder in the iOSDylibInjectionDemo folder to contain the dynamic library binaries that we will inject into the .ipa. Lets call it ‘Dylibs’
Go to the framework (the one you created in XCode in the above experiment) folder and examine the contents of the framework folder.
How to locate the folder location of the Dynamic Framework in XCode: Right Click -> Show in Finder
Contents of the dynamic framework. Dynamic library binary is highlighted in blueLocate a file that bears the same name as the framework folder. That file is the dynamic library binary and we will need to use this file to modify our ipa file. Copy this binary into the folder we created in point 3. Your folder should now look like this
Dylibs folder containing our custom dynamic library codesIf your dynamic library contains Swift codes, you may need to copy the standard Xcode Swift dylib libraries into your “Dylibs” folder. The Swift dylibs can be found locally at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift
This is how your folder may look like after adding the standard Swift dylib files.
Standard Swift dylib copied and prepared for code injection5. Lets term the process of .ipa modification as “Patching”. Go to the iOSDylibPatchingDemo folder and run the following in terminal sh ./patchapp.sh cracked.ipa ./DYLIBS where “cracked.ipa” is the ipa you want to patch and “./DYLIBS” is the folder of dylibs you want to patch with. The patch script will output the patched .ipa file as “cracked-patch.ipa” and the complete the code injection process. However, at this point, we cannot install or side load this .ipa into any non-jailbroken device yet because even though the “cracked-patch.ipa” has the injected codes, the .ipa code signature is now invalid after we have tempered and modified its contents.
6. Download Cydia Impactor from
http://www.cydiaimpactor.com. Cydia impactor is a tool that allows us to install any .ipa onto a non-jailbroken device by resigning the .ipa and its contents using valid profiles and credentials linked with the device.
Cydia Impactor Mac AppYou can begin the .ipa installation process by dragging-and-dropping the “cracked-patch.ipa” into the Cydia Impactor Mac App. It will then prompt for your apple developer login and password.
![](//pubimage.360doc.com/wz/default.gif)
Cydia Impactor requesting your Apple Developer login and password during installationCydia Impactor (CI) attempts to log into Apple Developer Center and download your provisioning profile as well as retrieving your iOS development certificate in your local keychain. CI will then attempt to sign the .ipa contents in a depth first manner starting from the deepest folder level and then making its way up to the .ipa folder level. After which CI will install and sideload the .ipa into specified device. This process using CI works because the device will think that the .ipa is developed and signed by the user and allow the modified app to be launched on the device successfully. If you are uncomfortable with using Cydia Impactor, you can manually resign the .ipa on your own and sideload the .ipa using XCode.
Process of patching an .ipa file
Process of signing and installing an .ipa file into a non jailbroken device7. Observe the device console logs and search for the NSLog message we have inserted into our dynamic library earlier: "==== Code Injection in Action====". If you manage to find the log message, you can start to celebrate because you have successfully performed iOS Code Injection on an iOS .ipa file. You can perform this entire code injection process on any .ipa file.
Hmmmm…. this sounds evil to me
I presented this topic in the November iOS Dev Scout Meetup group (Singapore) and demonstrated how I used code injection to break the PokemonGo App game. During the meetup group, the audience brought up hacking ideas from adding keylogging functionality, to breaking the rules of other gaming apps. Coming up with codes to hack app is not easy as it requires alot of guess work along with hours trial-and-error to get it right.
A handful of evil ideas
Keylogging (
https://gist.github.com/johndel/6df8aee01055ed21dd9a#file-keylogger-swift-L65)
Method Swizzling (
http://nshipster.com/method-swizzling/)
Get classes, ivars, properties, methods information via Objective C runtime (
https://developer.apple.com/reference/objectivec/1657527-objective_c_runtime)
Get a list of registered classes (
https://developer.apple.com/reference/objectivec/1418579-objc_getclasslist)
With the ideas above, a rogue developer can practically read all classes and their ivars and methods used inside an app and use these information to plan out a mischievous hack. Best of all, there is no need for to use jailbroken devices.
If you are interested to read about using this code injection technique to hack a real app, here’s my next post on hacking PokemonGo App (
https://medium.com/@kennethpoon/hacking-the-pokemongo-ios-app-with-3-classes-4b81589a9f39#.kz2vey8ir)
So who is the evil one?
After going through the entire iOS Code injection process describe in this post, I personally feel that the ability to allow anyone to resign .ipa files is a serious security flaw. Once an ipa is signed, it should be immutable and any attempt to temper with its contents should result in it being considered damaged and iOS devices should not allow these .ipa to be launched.
iOS Dylib Injection Talk by Kenneth Poon in November 2016I hope readers find this post insightful. Feel free to comment or buzz me at de_poon@hotmail.com.
Video: November 2016 iOS Code Injection talk