https://ipa.rocks/
unzip myApp.ipa
otool -l foobar | grep -i LC_ENCRYPTION -B1 -A4
Load command 12
cmd LC_ENCRYPTION_INFO
cmdsize 20
cryptoff 16384
cryptsize 12910592
cryptid 1
--
--
Load command 12
cmd LC_ENCRYPTION_INFO_64
cmdsize 24
cryptoff 16384
cryptsize 14041088
cryptid 1
// download apps from the AppStore on Jailbroken device
// this script will extract and decrypt the IPA
https://github.com/AloneMonkey/frida-ios-dump
xcrun simctl spawn booted log stream --level=debug | grep App_Debug_String
xcrun simctl spawn booted log stream --predicate 'processImagePath endswith "MyAppName"'
idevicesyslog -u <Device ID> | myPipedProgram
find Payload -size +2M
find . -name '*.json' -or -name '*.txt'
find . -name main.jsbundle
find . -name '*.crt' -or -name '*.cer'
find Payload/ -name '*.plist'
find . -name '*.mobileprovision'
find . -name '*.framework'
find Payload -name '*.js'
find . -name '*.plist' | xargs grep "LSApplicationQueriesSchemes"
find . -name '*.plist' | xargs grep "NS"
grep "LSApplicationQueriesSchemes" . -R
grep "Requires" foobar.app -R
foobar.app/Info.plist: <key>UIRequiresFullScreen</key>
foobar.app/Info.plist: <key>LSRequiresIPhoneOS</key>
grep -i -B 10 'error'
lipo -info libprogressbar.a
jtool -arch arm64 -L <binary inside app bundle>
jtool -arch arm64 -l <binary inside app bundle>
rabin2 -H playground
objdump -macho -section-headers Payload/myApp.app/myApp
jtool -arch arm64 --ent <binary inside app bundle>
cat Payload/my.app/Info.plist | grep -i NS
https://gist.github.com/adamawolf/3048717
rabin2 -I -a arm_64 <binary inside app bundle> | grep -E 'stripped|canary'
rabin2 -I -a arm_64 <binary inside app bundle> | grep -E 'pic|bits
otool -l libprogressbar.a | grep __LLVM
otool -arch arm64 -l tinyDynamicFramework | grep __LLVM
// Remember this command won't work on a locally built Simulator / iPhone app. Bitcode happens after setting `Archive`
nm libprogressbar.a | less
rabin2 -s file
is~FUNC
strings <binary inside app bundle> | grep -E 'session|https'
strings <binary inside app bundle> | grep -E 'pinning'
rabin2 -qz <binary inside app bundle> // in Data Section
rabin2 -qzz <binary inside app bundle> // ALL strings in binary
jtool -dA __TEXT.__cstring c_playground
Dumping C-Strings from address 0x100000f7c (Segment: __TEXT.__cstring)..
Address : 0x100000f7c = Offset 0xf7c
0x100000f7c: and we have a winner @ %ld\r
0x100000f98: and that's a wrap folks!\r
Following Xcode/New/Project/Swift template app within xCode. Build
for Generic (ARM) Device not the simulator. You don’t need to run
the app unless you need to automagically add your device’s UUID to the Provisioning Profile. Now extract it from the built app bundle.
Read the Provisioning Profile to ensure your device is in the profile & it has not expired.
security cms -D -i embedded.mobileprovision
You want to make sure your Code Signing key is not revoked.
security find-identity -v -p codesigning
AAA.................FFFF
applesign -7 -i AAA.....FFFF --bundleid funky-chicken.resigned -m embedded.mobileprovision original.ipa
applesign -7 -i AAA.....FFFF myapp.ipa -o resigned.ipa
rm -v unsigned.ipa | rm -v ready.ipa | 7z a unsigned.ipa Payload
// Keep original Bundle ID
applesign -7 -i <CODE SIGNING ID> -m embedded.mobileprovision unsigned.ipa -o ready.ipa
// Set Bundle ID
// applesign -7 -i <CODE SIGNING ID> -b yd.com.rusty.repackaged -m embedded.mobileprovision unsigned.ipa -o ready.ipa
ios-deploy -b ready.ipa
Open Console.app
for macOS. Select your device and set process:mobile_installation_proxy
. This will give details behind the sideloaded IPA error message.
Title | Detail |
---|---|
Missing Device ID | Check Provisioning Profile (embedded.mobileprovision ) included device's UUID |
Wrong Code-Signing Key | check the Code Signing Key was NOT an iPhone Distribution key |
Code Signing Keys Match | check the Code Signing Key used when generating the Provisioning Profile matched the Key specified when repackaging and code signing. |
XCode check | When generating an app - to get hold of embedded.mobileprovision file - remember the Code signing options are different for each Project Target and ProjectTests. |
Delete Old Apps | check no old app is installed on the phone [ that was signed with a different key ] but has the same Bundle ID. |
Entitlements overload | You can have a Provisioning Profile (embedded.mobileprovision) that contained more Capabilities than the app you are re-signing. |
Clone Entitlements | When the app is complicated, with many entitlements, sometimes it is easier just to --clone-entitlements with Applesign . |
Wrong Bundle ID | When you add specific Entitlments you need a unique Bundle ID. Check whether you need to change Bundle ID when re-signing. |
frida-ls-devices // list available devices
frida-ps -Uai // list processes and bundle ID from USB connected device
frida-ps -U | grep -i myapp // get the target app's process ID from USB connected device
frida -U "My App" // Attach Frida to app over USB
frida -f objc_play // Open objc_play on macOS. %resume required to run.
ObjC.available
true
ObjC.classes.UIDevice.currentDevice().systemVersion().toString()
"11.1"
ObjC.classes.NSBundle.mainBundle().executablePath().UTF8String()
ObjC.classes.UIWindow.keyWindow().toString()
RET: <WKNavigation: 0x106e165c0>
var b = "hello frida"
console.log(b)
string text
c = Memory.allocUtf8String(b)
"0x105e5da00"
Memory.readUtf8String(c)
"hello frida"
// Attach to playground process ID
frida -p $(ps -ax | grep -i -m1 playground |awk '{print $1}')
// shows Static Methods and Instance Methods
ObjC.classes.NSString.$ownMethods
ObjC.classes.NSString.$ivars
var myDate = ObjC.classes.NSDate.alloc().init()
console.log(myDate)
2019-04-19 19:03:46 +0000
myDate.timeIntervalSince1970()
1555700626.021566
myDate.description().toString()
"2019-04-19 19:03:46 +0000"
var a = ObjC.classes.NSUUID.alloc().init()
console.log(a)
4645BFD2-94EE-413D-9CE5-8982D41ED6AE
a.UUIDString()
{
"handle": "0x7ff3b2403b20"
}
a.UUIDString().toString()
"4645BFD2-94EE-413D-9CE5-8982D41ED6AE"
// demoapp is the iOS app name
myapp=$(ps x | grep -i -m1 demoapp | awk '{print $1}')
frida-trace -i "getfsent*" -p $myapp
// Connect to process with Frida script
frida --codeshare mrmacete/objc-method-observer -p 85974
[iPhone]-> Process.enumerateModules()
// this will print all loaded Modules
[iPhone]-> Process.findModuleByName("libboringssl.dylib")
{
"base": "0x1861e2000",
"name": "libboringssl.dylib",
"path": "/usr/lib/libboringssl.dylib",
"size": 712704
}
[iPhone]-> Process.findModuleByName("Reachability")
{
"base": "0x102fa0000",
"name": "Reachability",
"path": "/private/var/containers/Bundle/Application/643949D8-1B45-4B98-9CAB-12AA59B9F078/Yolt.app/Frameworks/Reachability.framework/Reachability",
"size": 49152
}
a = Process.findModuleByName("Reachability")
a.enumerateExports()
....
{
"address": "0x102fab020",
"name": "ReachabilityVersionString",
"type": "variable"
},
{
"address": "0x102fab058",
"name": "ReachabilityVersionNumber",
"type": "variable"
}
....
....
....
Objective-C's Class Methods
used :
and @
. These characters were not used in the Frida Javascript API.
var b = ObjC.classes.NSString.stringWithString_("foo");
b.isKindOfClass_(ObjC.classes.NSString)
1
b.isKindOfClass_(ObjC.classes.NSUUID)
0
b.isEqualToString_("foo")
1
b.description().toString()
"foo"
b.isEqualToString_("foo")
1
var b = ObjC.classes.NSString.stringWithString_("foo");
var d = ObjC.classes.NSData
d = b.dataUsingEncoding_(1) // NSASCIIStringEncoding = 1, NSUTF8StringEncoding = 4,
console.log(d)
<666f6f> // This prints the Hex value "666f6f = foo"
d.$className
"NSConcreteMutableData"
var y = ObjC.classes.NSStringy.stringWithUTF8String_[d.bytes]
var x = d.CKHexString() // get you the Byte array as a Hex string
console.log(x)
666f6f
x.$className
"NSTaggedPointerString"
[objc_playground]-> var a = ObjC.classes.NSString.stringWithString_("foo");
[objc_playground]-> a.superclass().toString()
"NSString"
[objc_playground]-> a.class().toString()
"NSTaggedPointerString"
// PASTE THIS CODE INTO THE FRIDA INTERFACE...
Interceptor.attach(ObjC.classes.NSTaggedPointerString['- isEqualToString:'].implementation, {
onEnter: function (args) {
var str = new ObjC.Object(ptr(args[2])).toString()
console.log('[+] Hooked NSTaggedPointerString[- isEqualToString:] ->' , str);
}
});
// TRIGGER YOUR INTERCEPTOR
[objc_playground_2]-> a.isEqualToString_("foo")
[+] Hooked NSTaggedPointerString[- isEqualToString:] -> foo
1 // TRUE
[objc_playground_2]-> a.isEqualToString_("bar")
[+] Hooked NSTaggedPointerString[- isEqualToString:] -> bar
0 // FALSE
// frida -U -l open.js --no-pause -f com.yd.demoapp
// the below javascript code is the contents of open.js
var targetFunction = Module.findExportByName("libsystem_kernel.dylib", "open");
Interceptor.attach(targetFunction, {
onEnter: function (args) {
const path = Memory.readUtf8String(this.context.x0);
console.log("[+] " + path)
}
});
try {
var targetFunctPtr = Module.findExportByName("YDAppModule", "$s9YDAppModule17ConfigC33publicKeyVerifyCertsSayypGvpfi");
if (targetFunctPtr == null) {
throw "[*] Target function not found";
}
Interceptor.attach(targetFunctPtr, {
onLeave: function(retval) {
var array = new ObjC.Object(retval);
console.log('[*]ObjC Class Type:\t' + array.$className);
return retval;
}
});
console.log("[*] publicKeyVerifyCertificates called ");
}
catch(err){
console.log("[!] Exception: " + err.message);
}
frida-trace --v // check it works
frida-trace --help // excellent place to read about Flags
frida-trace -f objc_playground // spawn and NO trace
frida-trace -m "+[NSUUID UUID]" -U "Debug CrackMe" // trace ObjC UUID static Class Method
frida-trace -m "*[ComVendorDebugger* *]" -U -f com.robot.demo.app // ObjC wildcard trace on Classes
frida-trace -m "*[YDDummyApp.UserProfileMngr *]" -U -f com.robot.demo.app // Trace mangled Swift functions
Instrumenting functions...
/* TID 0x403 */
1128 ms -[YDDummyApp.UserProfileMngr init]
1130 ms -[YDDummyApp.UserProfileMngr .cxx_destruct]
frida-trace -i "getaddrinfo" -i "SSLSetSessionOption" -U -f com.robot.demo // trace C function on iOS
frida-trace -m "*[*URLProtection* *]" -U -f com.robot.demo // for https challenge information
frida-trace -m "*[NSURLSession* *didReceiveChallenge*]" -U -f com.robot.demo // check whether https check delegate used
frida-trace -U -f com.robot.demo.app -I libsystem_c.dylib // Trace entire Module. Bad idea!
frida-trace -p $myapp -I UIKit // Trace UIKit Module. Bad idea.
frida-trace -f objc_playground -I CoreFoundation // Trace CoreFoundation Module. Terrible idea.
frida-trace -I YDRustyKit -U -f com.yd.mobile // Trace my own module.
frida-trace -m "-[NSURLRequest initWithURL:]" -U -f com.robot.demo // Get app files and APIs
frida-trace -m "-[NSURL initWithString:]" -U -f com.robot.demo // find the API endpoints
frida-trace -m "*[NSURL absoluteString]" -U -f com.robot.demo // my favorite of these
Edit the Frida-Trace auto-generated, template file.
onEnter: function (log, args, state) {
log("-[NSURLRequest initWithURL:" + args[2] + "]");
var str = new ObjC.Object(ptr(args[2])).toString()
console.log('[*] ' , str);
},
// results
[*] https://secretserver.nl/SignIn
frida-trace -i "*strcpy" -f hitme aaaa bbbb
Instrumenting functions...
_platform_strcpy: Loaded handler at "/.../__handlers__/libSystem.B.dylib/_platform_strcpy.js"
Started tracing 1 function. Press Ctrl+C to stop.
Edit the auto-generated, template Javascript file.
-----------
onEnter: function (log, args, state) {
// strcpy() arg1 is the Source. arg0 is the Destination.
console.log('\n[+] _platform_strcpy()');
var src_ptr = args[1].toString()
var src_string = Memory.readCString(args[1]);
var src_byte_array = Memory.readByteArray(args[1],4);
var textDecoder = new TextDecoder("utf-8");
var decoded = textDecoder.decode(src_byte_array);
console.log('[+] src_ptr\t-> ' , src_ptr);
console.log('[+] src_string\t-> ' + src_string);
console.log('[+] src_byte_array\t-> ' + src_byte_array);
console.log('[+] src_byte_array size\t-> ' + src_byte_array.byteLength);
console.log('[+] src_byte_array decoded\t-> ' + decoded);
},
The results:
[+] _platform_strcpy()
[+] src_ptr -> 0x7ffeefbffaa6
[+] src_string -> aaaa
[+] src_byte_array -> [object ArrayBuffer]
[+] src_byte_array size -> 4
[+] decoded -> aaaa
[+] _platform_strcpy()
[+] src_ptr -> 0x7ffeefbffaab
[+] src_string -> bbbb
[+] src_byte_array -> [object ArrayBuffer]
[+] src_byte_array size -> 4
[+] decoded -> bbbb
frida-ps -Uai // get your bundle ID
frida --codeshare mrmacete/objc-method-observer -U -f funky-chicken.push-demo
[+] At the Frida prompt...
observeSomething('*[ABC* *]'); // any Class beginning with ABC, regardless of instance or static class
observeSomething('-[WKWebsiteDataStore httpCookieStore]');
observeSomething('-[WKWebAllowDenyPolicyListener *]');
observeSomething('-[WKWebView loadRequest:]'); // dump the URL to hit
observeSomething('-[WKWebView load*]'); // you get all HTML, js, css, etc
observeSomething('-[WKWebView loadHTMLString:baseURL:]') // really effective; see the entire request
observeSomething('-[WKWebView *Agent]'); // try to see if somebody set a custom UserAgent
observeSomething('*[* isEqualToString*]'); // watch string compares
cd /private/var/containers/Bundle/Application/<guid>/myapp.app
// Contains compiled code, statically linked files, compressed NIB files.
cd /private/var/mobile/Containers/Data/Application/
ls -lrt // Your freshly installed IPA is at the bottom of list
cd [app guid]/Documents/
cd [app guid]/Library/
#### /private/var/Keychains
TrustStore.sqlite3
keychain-2.db
pinningrules.sqlite3
// Extract IPA (whether App Store encrypted or not)
scp -r -P 2222 root@localhost:/var/containers/Bundle/Application/<app GUID>/hitme.app ~/hitme.app
// Different to SSH, the uppercase P for Port with SCP. Order important.
scp -P 2222 root@localhost:/var/root/overflow.c localfilename.c
// from Jailbroken device to local machine
// Caution:no space after the root@localhost: Otherwise you copy the entire filesystem!
scp -P 2222 root@localhost:/private/var/mobile/Containers/Data/Application/<App GUID>/Library/Caches/Snapshots/com.my.app
// from local machine to remote Jailbroken device
scp -P 2222 hello.txt root@localhost:/var/root/
/private/var/mobile/Containers/Data/Application/<app guid, given at install time>/Library/Cookies/Cookies.binarycookies
scp -P 2222 root@localhost:/private/var/mobile/Containers/Data/Application/<App GUID>/Library/Cookies/Cookies.binarycookies cookies.bin
BinaryCookieReader: Written By Satishb3 (http://www.securitylearn.net
python BinaryCookieReader.py Cookie.Binarycookies-FilePath
Cookie : s_fid=0BBD745EA9BCF67F-366EC6EDEFA2A0E6; domain=.apple.com; path=/; expires=Thu, 14 Dec 2023;
Cookie : s_pathLength=homepage%3D2%2C; domain=.apple.com; path=/; expires=Fri, 14 Dec 2018;
Cookie : s_vi=[CS]v1|2E09D702852E4ACE-60002D37A0008393[CE]; domain=.apple.com; path=/; expires=Sun, 13 Dec 2020;
............
............
$) ps -ax | grep -i WebKit.Networking
29163 ?? 0:00.21 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/WebKit.framework/XPCServices/com.apple.WebKit.Networking.xpc/com.apple.WebKit.Networking
$) frida --codeshare mrmacete/objc-method-observer -p 29163
[PID::29163]-> %resume
[PID::29163]-> observeSomething('*[* cookiesWithResponseHeaderFields:forURL:]');
Results:
+[NSHTTPCookie cookiesWithResponseHeaderFields:forURL:]
cookiesWithResponseHeaderFields: {
"Set-Cookie" = "EuConsent=<removed for brevity>; path=/; expires=Sat, 16 Nov 2019 14:51:01 GMT;";
} (__NSSingleEntryDictionaryI)
forURL: https://uk.yahoo.com/?p=us&guccounter=1 (NSURL)
RET: (
"<NSHTTPCookie
version:0
name:EuConsent
value:<removed for brevity>
expiresDate:'2019-11-16 14:51:01 +0000'
created:'2019-11-15 14:51:01 +0000'
sessionOnly:FALSE
domain:yahoo.com
partition:none
sameSite:none
path:/
isSecure:FALSE
path:"/" isSecure:FALSE>"
)
ios-deploy -b myapp-resigned.ipa // defaults to send over wifi
ios-deploy -b -W myapp-resigned.ipa // uses USB
ios-deploy -B | grep -i funky // list Bundle IDs
WARNING: only change the minimum iOS version of a specific app's plist and not for the entire device. Things start to break - like calls into C libraries - when you change the device's read-only iOS version.
ssh onto device
root# cd /System/Library/CoreServices/
root# cat SystemVersion.plist
root# nano SystemVersion.plist
EDIT THE VALUE. KEEP THE OLD VALUE!
https://developer.apple.com/library/archive/qa/qa1964/_index.html
otool -l -arch all my_framework | grep __llvm_prf
nm -m -arch all my_app | grep gcov