1

Please correct me if my reasoning is wrong (I assume it's correct ):

As I build an iOS app, it's output is a package MyApp.app, and among the other things it contains a Mach-O binary MyApp: MyApp.app/MyApp. We can detect which iOS public frameworks (e.g. UIKit, CoreData etc) MyApp uses by either running otool -L MyApp.app/MyApp, or searching for the particular symbols with some disassemlber tool e.g. Hopper. Now, if we meet some DYLD error for a private framework during an app's launch, e.g.

dyld[93664]: Symbol not found: _OBJC_CLASS_$_SomeClass
  Referenced from: /Applications/XcodeRC.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/FamilyCircleUI.framework/FamilyCircleUI

this means that FamilyCircleUI, which is a private framework, is referenced by some other public iOS framework. And we can't detect it with otool -L MyApp.app/MyApp, because public framework are not built into MyApp, just referenced from it!

So, the question is: in order to detect who's referencing FamilyCircleUI, do I need to run otool -L PublicIosFramework.framework/PublicIosFramework for each of the public frameworks used in the app, or is there much shorter way?

E.g.

  1. some documentation (Apple doesn't want to provide it, so maybe there're some reversed dumps I didn't found with Google)?
  2. some wild combination of otool+grep+find+ls ?
olha
  • 2,132
  • 1
  • 18
  • 39

1 Answers1

1

I would start with something fairly simple - set environmental variable DYLD_PRINT_LIBRARIES to 1 in your target scheme. enter image description here

That in Xcode console on your app startup should yield something like:

dyld: loaded: /System/Library/Frameworks/EventKitUI.framework/EventKitUI
dyld: loaded: /System/Library/PrivateFrameworks/iAdCore.framework/iAdCore
dyld: loaded: /System/Library/PrivateFrameworks/TransparencyDetailsView.framework/TransparencyDetailsView
dyld: loaded: /System/Library/PrivateFrameworks/AdAnalytics.framework/AdAnalytics
dyld: loaded: /System/Library/PrivateFrameworks/iAdServices.framework/iAdServices
dyld: loaded: /System/Library/PrivateFrameworks/CoreSuggestions.framework/CoreSuggestions

However if that's not enough or maybe you'd like to automate something in the long run here are actual scripts (intended to be run as Xcode script phase) to traverse the main app executable binary and its frameworks, then recursively their referenced frameworks etc.

Script looking up ASIdentifierManager symbol:

#/bin/sh
asIdentifierManagerTimesFound=0
nm ${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}|grep ASIdentifierManager
if [ $? -eq 0 ]; then
    asIdentifierManagerTimesFound=`expr "$asIdentifierManagerTimesFound" + 1`
fi
for d in ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/*/; do
    nm $d`echo $d|awk -F/ '{print $(NF-1)}'|awk -F. '{print $(NF-1)}'`|grep ASIdentifierManager
    if [ $? -eq 0 ]; then
        asIdentifierManagerTimesFound=`expr "$asIdentifierManagerTimesFound" + 1`
    fi
done
exit $asIdentifierManagerTimesFound

The script deliberately fails if at least one symbol occurance is found (you can change the logic by exiting with 0).

Here's a script if you're looking for particular framework (in my example AppTrackingTransparency framework) using the same strategy:

#/bin/sh
appTrackingTransparencyTimesFound=0
otool -l ${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}|grep AppTrackingTransparency
if [ $? -eq 0 ]; then
    appTrackingTransparencyTimesFound=`expr "$appTrackingTransparencyTimesFound" + 1`
fi
for d in ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/*/; do
    otool -l $d`echo $d|awk -F/ '{print $(NF-1)}'|awk -F. '{print $(NF-1)}'`|grep AppTrackingTransparency
    if [ $? -eq 0 ]; then
        appTrackingTransparencyTimesFound=`expr "$appTrackingTransparencyTimesFound" + 1`
    fi
done
exit $appTrackingTransparencyTimesFound

Both scripts are intended to be run as last Xcode build phases (so after the app has been built).

My original use case is for self inspecting for stuff rejected on Apple review.

A somewhat related operation but around verifying referenced frameworks vs actually embedded ones is covered in my answer here: https://stackoverflow.com/a/69560246/5329717

Kamil.S
  • 5,205
  • 2
  • 22
  • 51