导语:作为iOS应用程序重打包和签名详尽指南的第二部分,本文将介绍的是使用App Extensions(应用扩展)和高级应用程序功能的应用程序以及绑定WatchKit的应用程序的重打包和签名。
作为iOS应用程序重打包和签名详尽指南的第二部分,本文将介绍的是使用App Extensions(应用扩展)和高级应用程序功能的应用程序以及绑定WatchKit的应用程序的重打包和签名。
3.使用App Extensions应用程序的重打包
一些iOS应用程序使用程序扩展来实现iOS提供的进程间通信(IPC)。其中一个例子是共享扩展(Share Extension),允许跨应用程序共享内容。这些扩展通常与IPA绑定作为单独的可执行文件。下面的代码片段展示了LinkedIn应用程序包中各种MachO二进制文件的布局:
Payload/ LinkedIn.app/ Frameworks/ lmdb.framework/ lmdb ... libswiftAVFoundation.dylib ... Plugins/ IntentsExtension.appex/ IntentsExtension IntentsUIExtension.appex/ IntentsUIExtension ... LinkedIn
应用程序扩展位于Plugins/目录下,如上面所示。每个应用程序都有绑定扩展名 .appex。
3.1解密MachO二进制文件
在处理绑定应用程序扩展名的应用程序时,除了解密应用程序二进制和框架之外,还必须解密应用程序扩展的二进制图像。为了解密应用程序扩展,首先设置debugserver来拦截并附加到启动的应用程序扩展。在下面的代码片段中,debugserver设置为附加到IntentsExtension:
amarekano-ipod:~/amarekano root# ./debugserver *:6666 -waitfor IntentsExtension &
设置好debugserver后,启动应用程序扩展。这一步可以手动执行,如下所示:
amarekano-ipod:~/amarekano root# /var/containers/Bundle/Application/AC8C5212-67D0-41AB-A01A-EEAF985AB824/LinkedIn.app/PlugIns/IntentsExtension.appex/IntentsExtension
debugserver附加了之后,就使用lldb进行连接,并从内存中转储解密后的图像。
(lldb) image list IntentsExtension [ 0] 2F48A100-110F-33F9-A376-B0475C46037A 0x00000001000f0000 /var/containers/Bundle/Application/AC8C5212-67D0-41AB-A01A-EEAF985AB824/LinkedIn.app/PlugIns/IntentsExtension.appex/IntentsExtension (0x00000001000f0000) (lldb) memory read --force --outfile ./decbins/intentsextension.bin --binary --count 114688 0x00000001000f0000+16384 114688 bytes written to './decbins/intentsextension.bin' (lldb) exit
一旦被解密,将被转储的二进制文件连接到原始的应用程序扩展二进制文件中,并使用同一方法将cryptid标志设置为0,就像对其他MachO二进制文件进行解密一样。
3.2给应用程序打补丁
修补应用程序二进制文件以加载FridaGadget的过程与前面示例演示的过程相同。
Amars-Mac:sandbox amarekano$ optool install -c load -p "@executable_path/FridaGadget.dylib" -t Payload/LinkedIn.app/LinkedIn Found FAT Header Found thin header... Found thin header... Inserting a LC_LOAD_DYLIB command for architecture: arm Successfully inserted a LC_LOAD_DYLIB command for arm Inserting a LC_LOAD_DYLIB command for architecture: arm64 Successfully inserted a LC_LOAD_DYLIB command for arm64 Writing executable to Payload/LinkedIn.app/LinkedIn...
3.3生成Provisioning Profile
一般来说,使用应用程序扩展名的应用程序几乎总是需要高级的应用程序功能。这些功能通常允许应用程序开发人员使用一些苹果技术,比如Siri、Apple Pay、iCloud等。示例中的LinkedIn应用程序使用了iCloud和Siri。这是通过审查应用程序的权限而发现的:
Amars-Mac:sandbox amarekano$ codesign -d --entitlements :- "Payload/LinkedIn.app/" Executable=/Users/amarekano/Desktop/sandbox/Payload/LinkedIn.app/LinkedIn <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> ... <truncated for brevity> ... <key>application-identifier</key> <string>8AXPVS6C36.com.linkedin.LinkedIn</string> ...<truncated for brevity>... <key>com.apple.developer.icloud-services</key> <array> <string>CloudDocuments</string> </array> <key>com.apple.developer.siri</key> <true/> ... <truncated for brevity>,,, </dict>
高级的应用程序功能只对使用付费开发者帐户的iOS开发人员可用。因此,为了在重新打包的应用程序中使用这些应用程序功能,必须使用付费开发者帐户创建一个合适的provisioning profile。这一操作可以通过创建一个虚拟的Xcode项目来实现,并指定一个付费的开发人员签署cert,如下面的截屏图所示:
创建了一个项目之后,就可以在Capabilities选项卡下启用应用程序所需的功能。下面的截屏图显示了在虚拟Xcode项目中启用的所需功能。
构建这个虚拟的Xcode项目将生成一个有效的Provisioning profile,该Provisioning profile具有重新打包LinkedIn应用程序所需的权限的权利。从生成的配置文件中提取这些权限如下所示:
Amars-Mac:sandbox amarekano$ security cms -D -i embedded.mobileprovision > profile.plist Amars-Mac:sandbox amarekano$ /usr/libexec/PlistBuddy -x -c 'Print :Entitlements' profile.plist > entitlements.plist Amars-Mac:sandbox amarekano$ cat entitlements.plist <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>application-identifier</key> <string>MS4K289Y4F.com.example.amarekano.advrepackdemo</string> ...<truncated for brevity>... <key>com.apple.developer.icloud-services</key> <string>*</string> <key>com.apple.developer.siri</key> <true/> <key>com.apple.developer.team-identifier</key> <string>MS4K289Y4F</string> ... <truncated for brevity>... <key>get-task-allow</key> <true/> <key>keychain-access-groups</key> <array> <string>MS4K289Y4F.*</string> </array> </dict> </plist>
3.4更新应用程序元数据
在成功生成Provisioning profile的过程中,将文件添加到应用程序包中,并更新应用程序和应用程序扩展的各种Info.plist文件如下所示:
Amars-Mac:sandbox amarekano$ /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.example.amarekano.advrepackdemo" Payload/LinkedIn.app/Info.plist Amars-Mac:sandbox amarekano$ /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.example.amarekano.advrepackdemo.IntentsExtension" Payload/LinkedIn.app/PlugIns/IntentsExtension.appex/Info.plist Amars-Mac:sandbox amarekano$ /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.example.amarekano.advrepackdemo.IntentsUIExtension" Payload/LinkedIn.app/PlugIns/IntentsUIExtension.appex/Info.plist Amars-Mac:sandbox amarekano$ /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.example.amarekano.advrepackdemo.MessagingNotificationContentExtension" Payload/LinkedIn.app/PlugIns/MessagingNotificationContentExtension.appex/Info.plist Amars-Mac:sandbox amarekano$ /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.example.amarekano.advrepackdemo.NewsModuleExtension" Payload/LinkedIn.app/PlugIns/NewsModuleExtension.appex/Info.plist Amars-Mac:sandbox amarekano$ /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.example.amarekano.advrepackdemo.ShareExtension" Payload/LinkedIn.app/PlugIns/ShareExtension.appex/Info.plist Amars-Mac:sandbox amarekano$ /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.example.amarekano.advrepackdemo.WVMPTodayExtension" Payload/LinkedIn.app/PlugIns/WVMPTodayExtension.appex/Info.plist Amars-Mac:sandbox amarekano$
请注意,通过权限生成Provisioning Profile 来使用高级应用程序功能,需要一个唯一的bundle标识符。在本例中,使用的bundle标识符是“com.example.amarekano.advrepackdemo”。
3.5MachO二进制文件重签名
当重签名应用程序二进制文件时,用多个可执行二进制文件重新打包应用程序时,重签名二进制文件的顺序非常重要。从重新签名应用程序扩展开始,如下所示:
Amars-Mac:sandbox amarekano$ codesign --force --sign "iPhone Developer: m***************" Payload/LinkedIn.app/PlugIns/IntentsExtension.appex/IntentsExtension Payload/LinkedIn.app/PlugIns/IntentsExtension.appex/IntentsExtension: replacing existing signature Amars-Mac:sandbox amarekano$ codesign --force --sign "iPhone Developer: m***************" Payload/LinkedIn.app/PlugIns/IntentsUIExtension.appex/IntentsUIExtension Payload/LinkedIn.app/PlugIns/IntentsUIExtension.appex/IntentsUIExtension: replacing existing signature ...
接下来是Framework和dylibs重签名:
Amars-Mac:sandbox amarekano$ codesign --force --sign "iPhone Developer: m***************" Payload/LinkedIn.app/Frameworks/lmdb.framework/lmdb Payload/LinkedIn.app/Frameworks/lmdb.framework/lmdb: replacing existing signature ... Amars-Mac:sandbox amarekano$ codesign --force --sign "iPhone Developer: m***************" Payload/LinkedIn.app/Frameworks/libswiftAVFoundation.dylib Payload/LinkedIn.app/Frameworks/libswiftAVFoundation.dylib: replacing existing signature ... Amars-Mac:sandbox amarekano$ codesign --force --sign "iPhone Developer: m***************" Payload/LinkedIn.app/FridaGadget.dylib Payload/LinkedIn.app/FridaGadget.dylib: replacing existing signature
最后,使用3.3节中生成的权限对LinkedIn应用程序进行重签名。
Amars-Mac:sandbox amarekano$ codesign --force --sign "iPhone Developer: m***************" --entitlements entitlements.plist Payload/LinkedIn.app/LinkedIn Payload/LinkedIn.app/LinkedIn: replacing existing signature
3.6归档和安装
应用程序被重签名后,将Payload目录归档到IPA中,并将重打包的 IPA安装到目标设备上。
Amars-Mac:sandbox amarekano$ zip -qr LinkedIn_resigned.ipa Payload/ Amars-Mac:sandbox amarekano$ ideviceinstaller -i LinkedIn_resigned.ipa WARNING: could not locate iTunesMetadata.plist in archive! Copying 'LinkedIn_resigned.ipa' to device... DONE. Installing 'com.example.amarekano.advrepackdemo' Install: CreatingStagingDirectory (5%) ...<truncated for brevity>... Install: GeneratingApplicationMap (90%) Install: Complete
3.7运行重新打包的应用程序
重新打包的应用程序成功安装到目标设备上后,使用idevicedebug启动它,然后连接到生成的Frida服务器。
Amars-Mac:sandbox amarekano$ idevicedebug -d run com.example.amarekano.advrepackdemo & Amars-Mac:sandbox amarekano$ frida -H 192.168.1.91:8080 -n Gadget ____ / _ | Frida 10.7.7 - A world-class dynamic instrumentation toolkit | (_| | > _ | Commands: /_/ |_| help -> Displays the help system . . . . object? -> Display information about 'object' . . . . exit/quit -> Exit . . . . . . . . More info at http://www.frida.re/docs/home/ [Remote::Gadget]-> %resume [Remote::Gadget]-> String(ObjC.classes.NSBundle.mainBundle().objectForInfoDictio naryKey_('CFBundleName')) "LinkedIn" [Remote::Gadget]-> String(ObjC.classes.NSBundle.mainBundle().objectForInfoDictio naryKey_('CFBundleIdentifier')) "com.example.amarekano.advrepackdemo"
4.重打包与WatchOS软件捆绑的应用程序
通常情况下,应用程序开发人员将在他们的移动应用程序中加一个配套的WatchOS应用程序。为了证明重新打包的iOS应用程序绑定了WatchOS应用程序,本指南使用Tube Map应用程序。IPA内的MachO二进制文件布局如下:
Payload/ TubeMap.app/ Frameworks/ AFNetworking.framework/ AFNetworking .... <truncated for brevity> ... Watch/ TubeMap WatchKit App.app/ Frameworks/ libswiftCore.dylib ... <truncated for brevity> ... Plugins/ TubeMap WatchKit Extension.appex/ TubeMap WatchKit Extension TubeMap WatchKit App TubeMap
4.1解密MachO二进制文件
当遇到解密二进制文件时,绑定WatchOS应用程序的重打包应用程序面临一个独特的挑战。到目前为止,示例应用程序中的所有可执行二进制文件都是为单个处理器体系结构编译的。因此,可以在调试器中启动这些加密的二进制文件,然后转储它们的解密部分。WatchOS二进制文件是为armv7k架构编译的。不幸的是,截至撰写本文,作者也没有破解的iWatch来解密WatchOS二进制文件。下面讨论一个解决这个挑战的方法。
如果不打算评估WatchOS应用程序,就可以简单地删除Watch/文件夹并重新打包应用程序,就像前面的示例演示的那样。然而,这种方法在运行应用程序时可能会导致稳定性问题,特别是在评估涉及WatchOS应用程序的功能时。
假设有一个破解的iWatch可用,那么必须在破解的watch上设置debugserver,并在调试器中启动WatchOS二进制文件。在调试器中运行应用程序之后,转储二进制文件解密部分的过程与前面示例中演示的转储常规iOS应用程序二进制文件相同。
4.2给应用程序打补丁
给解密应用程序打补丁同样再次需要将FridaGadget dylib添加到解压缩的IPA中,然后使用optool将加载命令插入应用程序二进制文件以加载Frida dylib。
4.3更新应用程序元数据
更新TubeMap应用程序的元数据包括更新应用程序的Info.plist文件以及应用程序扩展的Info.plist文件。需要将合适的provisioning profile添加到针对特定设备的解压缩IPA中。
4.4重签名MachO二进制文件
首先,将所有绑定的框架和dylib进行重签名,然后对应用程序二进制文件进行重签名。
Amars-Mac:Frameworks amarekano$ codesign --force --sign "iPhone Developer: m*******" AFNetworking.framework/AFNetworking AFNetworking.framework/AFNetworking: replacing existing signature ... Amars-Mac:Frameworks amarekano$ codesign --force --sign "iPhone Developer: m*******" libswiftCore.dylib libswiftCore.dylib: replacing existing signature ... Amars-Mac:TubeMap.app amarekano$ codesign --force --sign "iPhone Developer: m*******" --entitlements ../../entitlements.plist TubeMap
4.5归档和安装
应用程序被重签名后,将Payload目录归档到IPA中,并将重打包的 IPA安装到目标设备上。
Amars-Mac:sandbox amarekano$ zip -qr TubeMap_resigned.ipa Payload/ Amars-Mac:sandbox amarekano$ ideviceinstaller -i TubeMap_resigned.ipa WARNING: could not locate iTunesMetadata.plist in archive! Copying 'TubeMap_resigned.ipa' to device... DONE. Installing 'com.example.amarekano.repackdemo' Install: CreatingStagingDirectory (5%) ...<tuncated for brevity>... Install: GeneratingApplicationMap (90%) Install: Complete
4.6运行重新打包的应用程序
重新打包的应用程序成功安装到目标设备上之后,使用idevicedebug启动它,然后连接到生成的Frida服务器。
Amars-Mac:sandbox amarekano$ frida -H 192.168.1.67:8080 -n Gadget ____ / _ | Frida 10.7.7 - A world-class dynamic instrumentation toolkit | (_| | > _ | Commands: /_/ |_| help -> Displays the help system . . . . object? -> Display information about 'object' . . . . exit/quit -> Exit . . . . . . . . More info at http://www.frida.re/docs/home/ [Remote::Gadget]-> %resume [Remote::Gadget]-> String(ObjC.classes.NSBundle.mainBundle().objectForInfoDictio naryKey_('CFBundleName')) "Tube Map" [Remote::Gadget]-> String(ObjC.classes.NSBundle.mainBundle().objectForInfoDictio naryKey_('CFBundleIdentifier')) "com.example.amarekano.repackdemo" [Remote::Gadget]->
结束时的思考
重新打包应用程序并不总是可以顺利完成,在运行重新打包应用程序时,研究人员偶尔会遇到问题。这可能有几个原因。其中包括通过在运行时检查捆绑id、检测调试器等应用程序实现重新打包检测。为了在出现问题时进行调试,应该在运行重新打包的应用程序时扫描设备syslog和dmesg的错误/警告。这两个来源提供了关于运行过程的有价值的信息。
最后,本指南提供的信息是帮助安全研究人员评估iOS应用程序的安全漏洞。