Dynamic Frameworks

来源:互联网 发布:apache 开源框架 编辑:程序博客网 时间:2024/06/04 19:54

A dynamic framework

is a bundle of code loaded into an executable at runtime, instead of at compile time.

Examples in iOS include UIKit and the Foundation frameworks. Frameworks such as these contain a dynamic library and optionally assets, such as images.

The most obvious advantage is you can make updates to the framework without having to recompile the executable that depends on the framework.

Why dynamic frameworks?

Since you’ve the ability to load the framework at runtime, you can use LLDB to explore and execute code at runtime, which is great for spelunking in both public and private frameworks.

Statically inspecting an executable’s frameworks

The loading of these dynamic libraries into memory is done using a piece of code called the dynamic loader, or dyld

Open Xcode and create a new iOS project, Single View Application named DeleteMe. Yep, this project won’t hang around for long, so feel free to remove it once you’re done with this chapter.

Add the Social and CallKit framework. To the right of the CallKit framework, select Optional from the drop-down. Ensure that the Social framework has the Required value

Build the project on the simulator using Cmd + B. Do not run just yet. Once the project has been successfully built for the simulator, open the products directory in the Xcode project navigator.

Next, open up the DeleteMe IPA by right clicking the IPA and selecting Show Package Contents.
Next, open a new Terminal window and type the following but don’t press Enter:

 otool -L

Be sure to add a space at the end of the command. Next, drag the DeleteMe executable from the Finder window into the Terminal window. When finished, you should have a command that looks similar to the following:

devzkndeMacBook-Pro:.ssh devzkn$ otool -l /Users/devzkn/Library/Developer/Xcode/DerivedData/DeleteMe-ctwthypddlppxtdxhfdyydtqqytb/Build/Products/Debug-iphonesimulator/DeleteMe.app/DeleteMe 

Press Enter and observe the output. You’ll see something similar to the following:

    /System/Library/Frameworks/CallKit.framework/CallKit (compatibility version 1.0.0, current version 1.0.0)    /System/Library/Frameworks/Social.framework/Social (compatibility version 1.0.0, current version 87.0.0)    /System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1349.55.0)    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)    /usr/lib/libSystem.dylib (compatibility version 1.0.0, current version 1238.50.2)    /System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 3600.7.47)

You found the compiled binary DeleteMe and dumped out the list of dynamic frameworks it links to using the ever-so-awesome otool. Take note of the instructions to CallKit and the Social framework you manually added earlier. By default, the compiler automatically adds the “essential” frameworks to the iOS app, like UIKit and Foundation.
Take note of the directory path responsible for loading these frameworks;

 /System/Library/Frameworks//usr/lib/

Let’s go a tad bit deeper. Remember how you optionally required the CallKit framework, and required the Social framework? You can view the results of these decisions by using otool.

In Terminal, press the up arrow to recall the previous Terminal command. Next, change the capital L to a lowercase l and press Enter. You’ll get a longer list of output that shows all the load commands for the DeleteMe executable.

Load command 12          cmd LC_LOAD_DYLIB      cmdsize 80         name /System/Library/Frameworks/CallKit.framework/CallKit (offset 24)   time stamp 2 Thu Jan  1 08:00:02 1970      current version 1.0.0compatibility version 1.0.0Load command 13          cmd LC_LOAD_WEAK_DYLIB      cmdsize 80         name /System/Library/Frameworks/Social.framework/Social (offset 24)   time stamp 2 Thu Jan  1 08:00:02 1970      current version 87.0.0compatibility version 1.0.0

Compare the cmd in the load commands output. In Social, the load command is LC_LOAD_WEAK_DYLIB, which represents an optional framework, while the LC_LOAD_DYLIB of the CallKit load command indicates a required framework.

This is ideal for an application that supports multiple iOS versions. For example, if you supported iOS 9 and up, you would strongly link the Social framework and weak link the CallKit framework since it’s only available in iOS 10 and up.

Modifying the load commands

here’s a nice little command that lets you augment and add the framework load commands named install_name_tool.

n Xcode and build and run the application so the simulator is running DeleteMe. Once running in the LLDB Terminal, verify the CallKit framework is loaded into the DeleteMe address space. Pause the debugger, then type the following into LLDB:

image list CallKit

If the CallKit module is correctly loaded into the process space, you’ll get output similar to the following:

(lldb) image list CallKit[  0] 6558009B-6179-370D-ADD7-F9003764AFD3 0x0000000106e0e000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk//System/Library/Frameworks/CallKit.framework/CallKit 

Provided DeleteMe is running, this will give you the full path of DeleteMe under the simulator app. You’ll get output similar to the following:

devzkndeMacBook-Pro:.ssh devzkn$  pgrep -fl DeleteMe21401 /Users/devzkn/Library/Developer/CoreSimulator/Devices/03FD7AC9-0B1A-41C1-8790-9CF914D33B68/data/Containers/Bundle/Application/F0E41560-57C8-45F2-80E0-C0D04B4C6209/DeleteMe.app/DeleteMe

You’ll now modify this executable’s load commands to point to a different framework.
Grab the fullpath to the DeleteMe executable.
Stop the execution of the DeleteMe executable and temporarily close Xcode. If you were to accidentally build and run the DeleteMe application through Xcode at a later time, it would undo any tweaks you’re about to make.
In the same Terminal window, paste the full path you received from the output of your pgrep command along with the install_name_tool command as follows:

Usage: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/install_name_tool [-change old new] ... [-rpath old new] ... [-add_rpath new] ... [-delete_rpath old] ... [-id name] input
devzkndeMacBook-Pro:.ssh devzkn$ install_name_tool -change /System/Library/Frameworks/Social.framework/Social  /System/Library/Frameworks/NotificationCenter.framework/NotificationCenter /Users/devzkn/Library/Developer/CoreSimulator/Devices/03FD7AC9-0B1A-41C1-8790-9CF914D33B68/data/Containers/Bundle/Application/F0E41560-57C8-45F2-80E0-C0D04B4C6209/DeleteMe.app/DeleteMe

Verify if your changes were actually applied:

devzkndeMacBook-Pro:.ssh devzkn$ otool -L /Users/devzkn/Library/Developer/CoreSimulator/Devices/03FD7AC9-0B1A-41C1-8790-9CF914D33B68/data/Containers/Bundle/Application/F0E41560-57C8-45F2-80E0-C0D04B4C6209/DeleteMe.app/DeleteMe/Users/devzkn/Library/Developer/CoreSimulator/Devices/03FD7AC9-0B1A-41C1-8790-9CF914D33B68/data/Containers/Bundle/Application/F0E41560-57C8-45F2-80E0-C0D04B4C6209/DeleteMe.app/DeleteMe:    /System/Library/Frameworks/CallKit.framework/CallKit (compatibility version 1.0.0, current version 1.0.0)    /System/Library/Frameworks/NotificationCenter.framework/NotificationCenter (compatibility version 1.0.0, current version 87.0.0)    /System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 1349.55.0)    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)    /usr/lib/libSystem.dylib (compatibility version 1.0.0, current version 1238.50.2)    /System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 3600.7.47)

Verify these changes exist at runtime.

  lldb -n DeleteMe
devzkndeMacBook-Pro:.ssh devzkn$   lldb -n DeleteMe(lldb) process attach --name "DeleteMe"Process 24703 stopped* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP    frame #0: 0x000000010e85834a libsystem_kernel.dylib` mach_msg_trap  + 10libsystem_kernel.dylib`mach_msg_trap:->  0x10e85834a <+10>: ret        0x10e85834b <+11>: nop    libsystem_kernel.dylib'mach_msg_overwrite_trap:    0x10e85834c <+0>: mov    r10, rcx    0x10e85834f <+3>:  mov    eax, 0x1000020    0x10e858354 <+8>:  syscall     0x10e858356 <+10>: ret        0x10e858357 <+11>: nop    libsystem_kernel.dylib'semaphore_signal_trap:    0x10e858358 <+0>: mov    r10, rcxExecutable module set to "/Users/devzkn/Library/Developer/CoreSimulator/Devices/03FD7AC9-0B1A-41C1-8790-9CF914D33B68/data/Containers/Bundle/Application/F0E41560-57C8-45F2-80E0-C0D04B4C6209/DeleteMe.app/DeleteMe".Architecture set to: x86_64h-apple-ios.

In LLDB, check if the CallKit framework is still loaded.

ou’re in a bit of a predicament here. If you build and run a new version of DeleteMe using Xcode, it will erase these changes. Instead, launch the DeleteMe application through the simulator and then attach to it in a new LLDB Terminal window. To do this, launch DeleteMe in the simulator. Next, type the following into Terminal:

lldb -n DeleteMe```

(lldb) image list NotificationCenter

(lldb) image list CallKit
[ 0] 6558009B-6179-370D-ADD7-F9003764AFD3 0x000000010a86c000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/CallKit.framework/CallKit
(lldb) image list NotificationCenter
[ 0] 6BD68E1B-EF6D-37F9-8CF2-705851074B36 0x000000010a90c000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/NotificationCenter.framework/NotificationCenter

27460 /Users/devzkn/Library/Developer/CoreSimulator/Devices/03FD7AC9-0B1A-41C1-8790-9CF914D33B68/data/Containers/Bundle/Application/CF4DB53B-949E-45E8-A362-CEB1AFA3290D/DeleteMe.app/DeleteMe
27584 /Applications/Xcode.app/Contents/Developer/usr/bin/lldb -n DeleteMe

Loading frameworks at runtime-----------------------------Start by adding the following to your ~/.lldbinit file:

command regex ls ‘s/(.+)/po @import Foundation; [[NSFileManager
defaultManager] contentsOfDirectoryAtPath:@”%1” error:nil]/’

This creates a command named ls, which will take the directory path you give it and dump out the contents. This command will work on the directory of the device that’s being debugged. For example, since you’re running on the simulator on your computer’s local drive it will dump that directory. If you were to run this on an attached iOS, tvOS or other appleOS device, it would dump the directory you give it on that device, with one minor caveat which you’ll learn about shortly.Since LLDB is already running and attached to DeleteMe, you’ll need to load this command into LLDB manually as well since LLDB has already read the ~/.lldbinit file. Type the following into your LLDB session:  (lldb) command source ~/.lldbinitNext, find the full path to the frameworks directory in the simulator by typing thefollowing:

(lldb) image list -d UIKit
[ 0] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/UIKit.framework

You actually want to go one level higher to the Frameworks directory. Copy that full directory path and use the new command ls that you just created, like so:

(lldb) ls /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk//System/Library/Frameworks/
<__NSArrayM 0x608000052b70>(
Accelerate.framework,
Accounts.framework,
AddressBook.framework,
AddressBookUI.framework,
AdSupport.framework,
AssetsLibrary.framework,

From the list of frameworks, load the Speech framework into the DeleteMe process space like so:

process load /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk//System/Library/Frameworks/Speech.framework/Speech
Loading “/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk//System/Library/Frameworks/Speech.framework/Speech”…ok
Image 0 loaded.

====================Exploring frameworks--------------------

Exploring frameworks

devzkndeMacBook-Pro:~ devzkn$ lldb -n DeleteMe

Add the following to your ~/.lldbinit file.

Load this command into the active LLDB session and then give it a go with the Social framework.

(lldb) command source ~/.lldbinit
(lldb) dump_stuff Social

Loading frameworks on an actual iOS device------------------------------------------if you’re running on an actual iOS device, the frameworks path will be located at:

/System/Library/Frameworks/
“`

原创粉丝点击