了解usbmux和iOS锁定服务

如果您曾经对iTunes和Xcode与设备的通信方式以及对诸如libimobiledevice之类的非Apple代码如何能够控制它们感兴趣 ,那么您可以通过一些个人研究来掌握有关此问题的知识。

usbmux

usbmux是此事的第一位参与者,让我们看看iphonewiki.com对此有何评论:

Usbmux – iPhone Wiki

在正常运行期间,iTunes使用称为“ usbmux”的东西与iPhone通信–这是一个用于…的系统

www.theiphonewiki.com

在正常操作期间,iTunes使用称为“ usbmux”的东西与iPhone通信-这是一个用于通过一个USB管道多路复用多个“连接”的系统。 从概念上讲,它提供了一个类似TCP的系统-主机上的进程打开了与移动设备上特定编号端口的连接。

苹果已经为主机应用程序构建了一个“ usb复用器”,以便与iDevices进行通信。 显然,Apple已经为自己的应用程序开发了它,而不是为社区开发的。 Apple在OSX和Windows中提供usbmux以支持iTunes。 有一个开源项目可复制Mac / Linux / Windows的usbmux ,称为usbmuxd

iphonewiki.com提供有关原始usbmux程序在Mac平台中的位置以及如何启动的信息:

在Mac上,此操作由/System/Library/PrivateFrameworks/MobileDevice.framework/Resources/usbmuxd(启动时启动的守护程序)处理(请参阅/System/Library/LaunchDaemons/com.apple.usbmuxd.plist)

我们可以确认usbmuxd和守护进程plist在OS X 10.13.6中仍然存在:

usbmux守护程序plist的内容为:

请注意plist中有关Unix套接字的有趣信息。 usbmuxd守护程序在/ var / run / usbmuxd处打开Unix套接字。 更确切地说,它是进程间通信文件描述符,用于进程与iPhone连接和通信。

usbmuxd ..在/ var / run / usbmuxd创建一个侦听UNIX域套接字。 usbmuxd然后通过USB监视iPhone连接; 当它检测到以正常模式(而非恢复模式)运行的iPhone时,它将连接到它,然后开始中继通过/ var / run / usbmuxd接收到的请求-也就是说,usbmuxd是唯一实际通过USB与iPhone通话。 这意味着希望与iPhone通话的第三方应用程序必须通过usbmuxd进行通信,或者必须替换usbmuxd。

换句话说,iTunes和Xcode通过/ var / run / usbmuxd套接字与iDevices对话 。 我们可以确认套接字在那里:

到目前为止,我们知道该套接字存在并实现了TCP“ like”协议。 由于它仅适用于Apple,因此我们可以猜测它们不一定必须符合TCP,并且可能已经采用了“类似TCP”的方式来提高效率。

usbmuxd可执行文件的依赖关系不是很多。 看起来像是与设备进行通信的基础部分MobileDevice.framework。 我们稍后将了解该框架提供了什么。

您可以对usbmuxd.plist进行一些有趣的修改,以便在控制台中获取usbmuxd的调试日志。 添加值为7的简单DebugLevel项将设置启用调试日志。 本文介绍了如何执行此操作:

通过启用usbmuxd的调试日志来了解iOS设备如何通过USB同步

要了解iTunes和Xcode如何与iPhone同步,我在macOS的usbmuxd守护程序中启用了一个隐藏选项,该选项记录如何…

worthdoingbadly.com

usbmuxd项目

进一步深入研究usbmux,使我们进入“ libimobiledevice / usbmuxd ”,这在以下内容中有很好的解释:

usbmuxd

“ usbmuxd”代表“ USB多路复用守护程序”。 该守护程序负责通过USB将多路复用连接到一个…

cocoapods.org

libimobiledevice / usbmuxd是一个开放源代码项目,用于在Mac,Linux和Windows上模拟OS X usbmux系统。 除Linux外,安装iTunes / Xcode时Mac和Windows中都可以使用原始的Apple usbmux,因此您可能不需要使用开源项目。 但是,如果您不想在Windows上安装Apple的iTunes,则可以使用它。

当usbmuxd运行时(通常由于“ udev”而启动或停止)
自动插入消息或通过systemd)它在以下位置提供套接字接口
设计为与套接字接口兼容的“ / var / run / usbmuxd”
在Mac OS X上提供。

此usbmuxd开源代码公开了您可能想要了解的有关usbmux TCP“ like”协议的所有信息。 您可以找到有关端口,端点,层,数据包大小,校验和,协商的所有信息……

我们可以在源文件main.c中确认有关Unix套接字/ var / run / usbmuxd的信息。 这是套接字创建的代码,带有“ chmod 0666”,表示所有用户都可以读写:

 静态const char * socket_path =“ / var / run / usbmuxd”; 
静态const char * lockfile =“ /var/run/usbmuxd.pid”;
..if(unlink(socket_path)== -1 && errno!= ENOENT){usbmuxd_log(LL_FATAL,“ unlink(%s)失败:%s”,socket_path,strerror(errno)); 返回-1; }
...
listenfd =套接字(AF_UNIX,SOCK_STREAM,0);
...
bzero(&bind_addr,sizeof(bind_addr));;
bind_addr.sun_family = AF_UNIX;
strcpy(bind_addr.sun_path,socket_path);
如果(bind(listenfd,(struct sockaddr *)&bind_addr,sizeof(bind_addr))!= 0){usbmuxd_log(LL_FATAL,“ bind()失败:%s”,strerror(errno));
返回-1;
}
//如果(listen(listenfd,5)!= 0){usbmuxd_log(LL_FATAL,“ listen()failed:%s”,strerror(errno)),开始收听。 返回-1;
}
chmod(socket_path,0666);

usbmux和设备配对

usbmux的另一个重要任务是检测设备连接并执行配对。 iOS方面的对应功能是锁定服务,我们将在稍后介绍。 配对不是一个透明的过程,它需要用户的批准,这就是为什么我们得到“信任”对话框的原因。 每个主机仅发生一次,直到iOS7才存在。

根据我在Mac上的测试,除非运行iTunes,Xcode或“照片”,否则“ 信任”对话框和配对不会发生。 usbmux守护程序本身不会启动Trust进程,它似乎设法建立了与设备的非完全信任的基本通信以收集基本信息。 主机中的应用程序要访问设备时,才会出现“信任”对话框并进行配对。 相反,在Linux上,usbmuxd确实会强制执行“信任”对话框。 这意味着Apple和开放源代码项目之间在何时执行配对方面存在一些差异。

在此过程中,配对记录集在iOS设备和计算机之间交换。 计算机使用配对机制与iPhone建立信任关系。 配对记录保存在/ var / db / lockdown文件夹中。 您可以通过列出目录来查看配对记录:

  $ sudo ls / var / db / lockdown 

删除其内容将使“信任”对话框出现在下一个连接中。

配对记录是一个以iDevice的UDID命名的文件,看起来像这样:

       DeviceCertificate   LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1akNDQWFLZ0F3SUJBZ0lCQURB… 该证书对于每个设备都是唯一的。   托管包  
hXUjlCIlve6v92…。=
EscrowBag的密钥包包含用于解密设备的类密钥。 HostCertificate LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1akNDQWFLZ0F3SUJBZ0lCQURB… 此证书适用于与iOS设备配对的主机(通常,您与所有文件在同一台计算机上)。 主机ID
5D9462DF-AB7D-486E-823F-B5C19BF3BF80
这是主机生成的ID。 HostPrivateKey LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVND .. 这是Mac上的私钥(应该在同一台计算机上)。 RootCertificate LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNyVENDQVpXZ0F3SUJBZ0lCQURB。 LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcw。 这是为该设备运行iTunes的计算机的私钥。 SystemBUID B0911AB5–84F7–436F-936E-DEA460F6EA3A 这是指运行iTunes的计算机的ID。 WiFiMACAddress e0:33:8e:b1:d7:d9 这是设备Wi-Fi接口的Mac地址,即与计算机配对。 如果您没有活动的Wi-Fi接口,则配对时仍会使用MAC。

在设备方面,配对记录保存在“ / var / root / Library / Lockdown / pair_records /”中 。 如果设备与多台计算机配对,则包含多个配对记录。 配对记录包含SystemBUID,HostID,RootDertificate,DeviceCertificate和HostCertificate。

利用设备和主机中的所有信息,配对过程可以确定设备和主机是否已经配对(可信)。 此信任关系授予特权访问权限,以在iOS设备上下载个人数据,安装应用程序或执行其他此类任务。

在设备端,配对记录旁边的另一种记录类型是scrow_records,位于“ / private / var / root / Library / Lockdown / escrow_records /”中。

在这里我们找到关于托管对的解释https://resources.infosecinstitute.com/ios-forensics/#gref

使用Escrow钥匙包,即使在锁定状态下,iTunes也可以备份并与iPhone同步。 它是类密钥和系统包的副本,用于IOS中的加密。 无需输入密码即可访问设备上所有类别的数据,这可以通过钥匙包实现。

根据密钥0x835计算出的新生成的密钥受托管密钥包保护,并保存在电话的托管记录中。 它也是plist文件,位于/ private / var / root / Library / Lockdown / escrow_records /

这些记录受NowFirstUserAuthentication保护类保护。 它进一步加密为用户的密码。 因此,在第一次将手机同步到iTunes时,需要输入设备密码。

嗅探usbmuxd Unix套接字

我们了解到,当主机上的某个进程想要与iPhone通讯时,它将打开与Unix套接字/ var / run / usbmuxd的连接 。 嗅闻怎么样? 我们实际上可以使用socat

  $ sudo mv / var / run / usbmuxd / var / run / usbmux_real 
$ sudo socat -t100 -x -v UNIX-LISTEN:/ var / run / usbmuxd,mode = 777,reuseaddr,fork UNIX-CONNECT:/ var / run / usbmux_real
完成后,请不要忘记:
$ sudo mv / var / run / usbmux_real / var / run / usbmuxd

Socat将在终端上打印完整的通信。要将日志转储到文件中,请执行以下操作:

  $ sudo socat -t100 -x -v UNIX-LISTEN:/ var / run / usbmuxd,mode = 777,reuseaddr,fork UNIX-CONNECT:/ var / run / usbmux_real > /tmp/usbmuxd.log 2>&1 

连接设备后,usbmuxd首先发送带有特定端口号的“连接”请求。 端口似乎总是32498 (正确的字节序为:62078):

   




ClientVersionString

usbmuxd-423.206.4

设备ID

4

MessageType

连接

端口号

32498 / * htonl 62078 * /

ProgName

usbmuxd


DeviceID始终是usbmuxd已分配给设备的整数。 在较早的交易中,usbmuxd已通知已连接的设备,其UDID和DeviceID。 该值稍后将用于此Connect命令。

如果已接受连接,则来自设备的响应将为“结果0”:

   

MessageType

结果
数字

0


一系列的请求和回答跟进:

  REQ :查询类型 
RESP :com.apple.mobile.lockdown REQ :ReadBUID
RESP :BUID REQ :ReadPairRecord PairRecorID“ a recordID”
RESP :PairRecordData与数据(PairRecord = {DeviceCertificate = xxxx,HostCertificate = xxxx,HostID = xxxx,RootCertificate = xxxx}) REQ :主机ID的StartSession
RESP :具有会话ID的EnableSessionSSL REQ :连接到端口号32498 / * htonl 62078 * /
RESP :如果确定,结果值为0 REQ :QueryType
RESP :com.apple.mobile.lockdown REQ :GetValue ProductVersion
RESP :iOS版本号,例如11.4.1 REQ :连接到端口号
RESP :如果确定,结果值为0 REQ :GetValue产品名称
RESP :“ iPhone OS”

请注意,StartSession需要稳定SSL协议。

我们已经了解到通信是基于plist(xml)记录的,并且已加密,这使得UNIX套接字嗅探对于获取信息进行反向工程协议无效。

这是已经配对的设备的输出,让我们看看未配对的设备的协议是什么。 就像我们说过的那样,我们可以通过删除/ var / db / lockdown中的配对记录来迫使主机忘记设备,方法是:

  $ sudo rm /var/db/lockdown/udid-of-the-device.plist 

仅当iTunes或Xcode运行时,连接过程才会到达配对请求,并且设备将使用PairingDialogResponsePending进行响应此时“ 信任”对话框将出现在屏幕上:

  REQ :GetValue DevicePublicKey 
RESP :公钥数据REQ :与参数配对:
RESP :错误PairingDialogResponsePending 设备屏幕上显示“信任”对话框。 接受。 RESP :命令RelayNotification com.apple.mobile.lockdown.request_pair REQ :连接到端口32498 / * 62078 * /
RESP :结果值0

usbmuxd和iPhone充电

至少可以说,usbmuxd和收费相关是有趣的。 停止usbmuxd守护进程将导致所连接的iPhone无法充电。

Apple必须确定任何不执行认可的连接和与设备配对的USB连接将不被接受,甚至不欢迎使用交流电。

您可能会自己经历。 要在Mac上停止usbmuxd守护程序:

  $    sudo launchctl卸载/System/Library/LaunchDaemons/com.apple.usbmuxd.plist 

重新启动usbmuxd:

  $    sudo launchctl加载-w /System/Library/LaunchDaemons/com.apple.usbmuxd.plist 

MobileDevice.framework和libusbmuxd

介绍完usbmux的基础知识之后,程序员的逻辑告诉我们,必须有一个API,以便应用程序可以通过usbmux进行通信。 iphonewiki.com再次提供了有关一个库的信息,该库似乎是我们正在寻找的API:

iTunes使用MobileDevice Library在iPhone和计算机之间通过USB和WiFi连接传输数据。

看一下MobileDevice的组成,我们发现它是一个由几个二进制文件组成的框架,带有一个主要的dylib和一些实用程序可执行文件。 这些应用程序中的某些实际上可以在终端中执行,但我们将重点介绍MobileDevice dylib。

我们可以在https://pewpewthespells.com/media/MobileDevice.h上找到反向生成的MobileDevice.h,它似乎包含iTunes与iDevice连接和通信所需的功能。 这里有一些功能:

  mach_error_t AMDeviceConnect (结构am_device * device); 

整型
AMDeviceIsPaired (struct am_device * device);

mach_error_t
AMDeviceValidatePairing (struct am_device * device);

mach_error_t
AMDeviceStartSession (struct am_device * device);

mach_error_t
AMDeviceStartService (struct am_device * device,CFStringRef service_name,service_conn_t * handle,unsigned int * unknown);

mach_error_t
AMDeviceStartHouseArrestService (struct am_device * device,CFStringRef identifier,void * unknown,service_conn_t * handle,unsigned int * what);

mach_error_t
AMDeviceStopSession (struct am_device * device); int socketForPort (struct am_restore_device * rdev,unsigned int portnum); int sendCommandToDevice (struct am_recovery_device * rdev,CFStringRef cfs,int block); int sendFileToDevice (struct am_recovery_device * rdev,CFStringRef filename);

实际上有一个开源项目,该项目使用MobileDevice.framework的未记录API来构建命令行工具以与设备进行通信,该项目称为mobiledevice

imkira /移动设备

命令行实用程序,用于与Apple的私有(封闭)移动设备框架进行交互– imkira / mobiledevice

github.com

该项目使用MobileDevice.framework,因此仅与Mac兼容。 libusbmuxd是这种开源的对等形式和交叉平台的解决方案:

libimobiledevice / libusbmuxd

客户端库,用于多路传输iOS设备之间的连接– libimobiledevice / libusbmuxd

github.com

到目前为止,我们已经看到了与iDevices进行通信的两个基本构件,即通过USB实现类似TCP协议的系统USB多路复用器守护程序(usbmuxd),以及用于构建将运行设备的主机应用程序(libusbmuxd)的API。 我们也知道该协议基于xml消息。

此时,只要我们知道要发送什么消息,就可以开始编写可以与设备通信的应用程序。

锁定服务

现在我们知道了主机端的内容,是时候找出设备端的内容了。

lockdownd是一个iOS守护进程,负责提供iOS系统信息和对服务的访问。 它以root特权运行。

我们可以在/ System / Library / LaunchDaemons中找到守护程序声明 plist是:

这是它的内容:

根据这些信息,我们可以推断出它在localhost:62078中打开了一个TCP套接字,在/var/run/lockdown.sock中打开了UNIX套接字。 这些是客户端进程与锁定服务进行通信的端口。 二进制文件是/ usr / libexec / lockdown。

实际上,现在我们可以理解为什么我们之前看到的Connect阶段连接到端口62078。Connect命令请求打开给定DeviceID中的锁定62078的连接。 授予连接后,我们可以继续与设备通信。

在plist中查看,似乎已使用特权511创建了UNIX套接字,这意味着只有root才能对其进行写入。

我们可以确认端口62078已打开:

如前所述, 锁定服务是其他iOS服务的网关。 /System/Library/Lockdown/Services.plist文件中描述了它提供的服务列表。 这些是服务:

挂载开发人员映像时,还添加了其他服务:

连接到iOS服务

锁定提供的iOS服务是iTunes或Xcode之类的应用程序需要执行其操作的服务。 完成设备配对后,程序会请求锁定访问不同的服务以与其进行通信。

这里有一些服务示例:

  com.apple.mobile.house_arrest 
iTunes使用house_arrest在支持此功能的应用程序的iOS设备之间来回传送文件。 Xcode也使用它来协助在开发应用程序时将测试数据传输到设备。 com.apple.mobile.installation_proxy在设备上安装所有应用程序。
com.apple.debugserver以调试模式启动iOS应用。
com.apple.mobile.screenshotr
服务请求截图。 com.apple.mobilesync由iTunes用来传输通讯录,Safari书签,便笺和用户已选择与台式机同步的其他信息。
com.apple.afc此服务通常用于访问用户的相机卷轴,相册,音乐以及存储在设备上的/ var / mobile / Media文件夹中的其他内容。
您可以在精彩的文章中详细了解其他内容:https://www.zdziarski.com/blog/wp-content/uploads/2014/08/Zdziarski-iOS-DI-2014.pdf

让我们看一个有关Xcode如何请求与安装代理服务的连接的示例:

   
<!DOCTYPE plist PUBLIC“-// Apple // DTD PLIST 1.0 // EN”“ http://
www.apple.com/DTDs/PropertyList-1.0.dtd”>


标签
xcodebuild
ProtocolVersion
2

请求

StartService

服务 com.apple.mobile.installation_proxy


波纹管是来自锁定服务的响应,该服务已启动并且其打开的套接字端口为50261(= 21956) 对installation_proxy的后续请求必须在该端口中执行。

   
<!DOCTYPE plist PUBLIC“-// Apple // DTD PLIST 1.0 // EN”“ http://
www.apple.com/DTDs/PropertyList-1.0.dtd”>



端口

50261 / * 21956 * /

请求

StartService
服务
com.apple.mobile.installation_proxy


50261(= 21956 实际上是在iOS设备中创建的TCP端口。 我们可以从外部计算机发送与我们之前看到的Connect命令建立该端口的通信,并指定端口和设备ID。

通过usbmuxd连接到我们自己的iOS应用

如果我们将“连接”命令视为连接到任何iOS端口的通用工具,则可能会带来一些有趣的可能性。

实际上,可以在iOS应用程序的免费端口中创建套接字服务器,并通过/ var / run / usbmuxd Unix套接字(文件描述符)发送以下命令,从主机连接到它:

   




ClientVersionString

usbmuxd-423.206.4

设备ID

4

MessageType

连接

端口号

我的端口 <---端口号(使用endian转换htonl)

ProgName

usbmuxd


谢谢 !

如果喜欢,可以给Organismo-iOS-Driver Github存储库和本文加注星标。 🙂