LaunchScreen Analysis
- tl;dr
- Environment
- Basics
- Start
- FrontBoard
- Continue Debugging
- Finally
- Temporarily Stop
- Write tweak
- Conclusion
- Code
- dyld_shared_cache
- Small Fragment
- Summary
tl;dr
After clicking App icon, iOS system’s desktop SpringBoard will first create LaunchScreen, then create App’s corresponding process. Then can think: LaunchScreen’s loading doesn’t occupy App process’s own perceived startup time. LaunchScreen is SpringBoard showing to users in advance before process startup for user experience.
Of course strictly speaking, LaunchScreen’s loading occupies system CPU and other resources, also has certain impact on App’s startup time.
Below is brief exploration process.
Environment
iOS 11.3.1 Jailbroken Jailbreak steps see: https://everettjf.github.io/2018/08/30/ios1131-jailbreak-tutorial/ Other jailbroken phones can also complete steps below.
Small ad here: To purchase jailbreakable phone can contact WeChat “467444”, I just bought an iPhone6S 11.3.1 from him, currently using everything normal.
Basics
Steps use basics below, can reference these three links when encountering problems:
- Using Xcode to debug target process on iOS11 http://iosre.com/t/ios-11-app/12838
- iOS Debugging Cheatsheet https://everettjf.github.io/2016/05/25/my-ios-debug-cheatsheet/
- chisel https://github.com/facebook/chisel
Start
Phone open to desktop, connect to computer, open an empty project, Xcode attach to SpringBoard, print ViewControllers and Views (chisel’s pvc and pviews commands).


Can see just a few key information: SBIconController SBHomeScreenViewController SBRootIconListView SBIconView
class-dump SpringBoard browse.
Through SBIconView can see this Delegate’s - (void)iconTapped:(SBIconView *)arg1;

Print delegate

Know SBIconController is delegate, indeed saw implementation in header file.

IDA open SpringBoard, look at iconTapped implementation:

Header file search prepareToLaunchTappedIcon:completionHandler:

IDA again

From sub_10017A874 above,

Look at _launchFromIconView

-[[FBWorkspaceEventQueue sharedInstance] executeOrAppendEvent:]
FrontBoard
Network search FBWorkspaceEventQueue can immediately know, now at FrontBoard.framework.
Find in this directory /Users/everettjf/Library/Developer/Xcode/iOS DeviceSupport/11.3.1 (15E302)/Symbols/System/Library/PrivateFrameworks

IDA separately analyze FrontBoard,

Many code can’t analyze. Then lldb debug.
Continue Debugging
First symbol breakpoint

Find those unrecognized BL instructions, address breakpoint:

Looks like arrayWithObjects, then pass to executeOrInsertEvents:atPosition:
Continue

Still many unrecognized, address breakpoint one by one, repeat po $x0 , p (char*)$x1 , po $x2

<FBSynchronizedTransactionGroup: 0x1c0574c40>
Completed: NO
Milestones pending:
synchronizedCommit
Audit history:
TIME: 22:42:45.524; DESCRIPTION: Life assertion taken for reason: beginning
TIME: 22:42:45.524; DESCRIPTION: State changed from 'Initial' to 'Working'
TIME: 22:42:45.524; DESCRIPTION: Life assertion removed for reason: beginning
TIME: 22:42:45.627; DESCRIPTION: Commit preconditions satisfied.
TIME: 22:42:45.627; DESCRIPTION: Milestones added: synchronizedCommit
TIME: 22:42:45.627; DESCRIPTION: Using synchronization delegate: <SBSceneLayoutWorkspaceTransaction: 0x151d125d0>
Concurrent child transactions:
<SBApplicationSceneUpdateTransaction: 0x151c85a70>
Completed: NO
Application: <SBDeviceApplicationSceneEntity: 0x1c0c9a810; ID: com.meituan.imeituan; layoutRole: primary>
SceneID: com.meituan.imeituan
Display: Main
Launch Suspended: NO
Milestones pending:
synchronizedCommit
Audit history:
TIME: 22:42:45.524; DESCRIPTION: Life assertion taken for reason: beginning
TIME: 22:42:45.524; DESCRIPTION: State changed from 'Initial' to 'Working'
TIME: 22:42:45.524; DESCRIPTION: Life assertion removed for reason: beginning
TIME: 22:42:45.626; DESCRIPTION: Beginning scene updates.
TIME: 22:42:45.626; DESCRIPTION: Adding child transaction: <FBUpdateSceneTransaction: 0x1c41beae0>
TIME: 22:42:45.627; DESCRIPTION: Commit preconditions satisfied.
TIME: 22:42:45.627; DESCRIPTION: Milestones added: synchronizedCommit
TIME: 22:42:45.627; DESCRIPTION: Using synchronization delegate: <FBSynchronizedTransactionGroup: 0x1c0574c40>
Concurrent child transactions:
<FBApplicationProcessLaunchTransaction: 0x1c0388c90>
Completed: NO
Process: <FBApplicationProcess: 0x14f684580; imeituan (com.meituan.imeituan); pid: 1168>
Milestones pending:
processWillBeginLaunching
processDidFinishLaunching
Audit history:
TIME: 22:42:45.524; DESCRIPTION: Life assertion taken for reason: beginning
TIME: 22:42:45.524; DESCRIPTION: State changed from 'Initial' to 'Working'
TIME: 22:42:45.524; DESCRIPTION: Milestones added: processWillBeginLaunching
TIME: 22:42:45.524; DESCRIPTION: Life assertion removed for reason: beginning
TIME: 22:42:45.626; DESCRIPTION: Milestones added: processDidFinishLaunching
Concurrent child transactions: (none)
Serial child transactions: (none)
<FBUpdateSceneTransaction: 0x1c41beae0>
Completed: NO
SceneID: com.meituan.imeituan
Scene Visibility: Foreground
Wait for Commit: YES
Milestones pending:
synchronizedCommit
Audit history:
TIME: 22:42:45.626; DESCRIPTION: Life assertion taken for reason: beginning
TIME: 22:42:45.627; DESCRIPTION: State changed from 'Initial' to 'Working'
TIME: 22:42:45.627; DESCRIPTION: Milestones added: synchronizedCommit
Concurrent child transactions: (none)
Serial child transactions: (none)
Serial child transactions: (none)
Serial child transactions: (none)
graph-base64-encoded:



…. Omitted here ….
Finally
Finally found -[FBSynchronizedTransactionGroup _performSynchronizedCommit:] and -[FBApplicationUpdateScenesTransaction _performSynchronizedCommit:]
and +[FBSceneManager synchronizeChanges:]

Temporarily Stop
OK stop for now.
Write tweak
After various hooks, finally discovered, if we hook -[FBSynchronizedTransactionGroup _performSynchronizedCommit:], directly return.
Or -[FBSynchronizedTransactionGroup addSynchronizedTransaction:] directly return.
Can both achieve an effect:
- LaunchScreen started, but doesn’t disappear.
- App’s process doesn’t exist. (Can’t see App’s process in
ps ax)
Conclusion
Then we can think:
After clicking App icon, iOS system’s desktop SpringBoard will first create LaunchScreen, then create App’s corresponding process. Then can think: LaunchScreen’s loading doesn’t occupy App process’s own perceived startup time. LaunchScreen is SpringBoard showing to users in advance before process startup for user experience.
Code
dyld_shared_cache

Actually these BL IDA can normally recognize, just because I only analyzed FrontBoard one dynamic library. Actually can directly analyze /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64 , but rumor says analyzing this needs 30+ GB space. I also tried using IDA and Hopper to analyze, but because too large, various postures all can’t finish analyzing, either error, or stuck.
But currently OK, got this conclusion. Will continue exploring when there’s time.
Small Fragment
Still these unrecognized BL

step-in after is like this

step-in again is like this

Through two jumps, seems this is dyld_shared_cache’s characteristic, haven’t deeply searched materials. Looks like this can save dynamic binding process.
This is why fishhook can’t hook UIKit and other system libraries’ objc_msgSend.
Will continue researching when there’s time :)
Summary
Actually originally wanted to continue exploring to App process creation flow, how to notify launchd to start App process, but dyld_shared_cache always can’t finish analyzing, just temporarily like this, continue forward, will review when there’s time.
Interesting, but also quite time-consuming~
Welcome to follow subscription account “Client Technology Review”:
