Jump to content

如果你曾經將iPhone、iPad或iPod連接到Windows PC上,你可能會注意到,這些設備會根據你的操作顯示為不同類型的設備。例如,如果你正在給iPhone充電,它可能會顯示為“USB複合設備”,但如果你正在與iTunes同步音樂,它可能會顯示為“蘋果移動設備USB驅動程序”。你有沒有想過這是怎麼回事?事實證明,蘋果在Windows電腦上有一個USB低級過濾器,可以幫助他們控制操作系統使用哪些USB配置。

本文中,我們會首先介紹蘋果的USB低級過濾器是如何工作的,它是做什麼,以及無論是否安裝了蘋果軟件,它如何提供不同的體驗;其次,我們將研究為什麼當設備的WPD屬性WPD_DEVICE_PROTOCOL表明設備正在使用媒體傳輸協議(MTP)時,iphone的開箱操作如此有限。我們將深入研究諸如Windows便攜式設備(WPD),USB描述符和用戶模式驅動程序框架(UMDF)等話題。

初始化蘋果的USB低級過濾器蘋果設備將自己呈現為具有多個接口的複合設備,以確保它們的設備被正確識別,並加載所有必要的驅動程序。這是因為蘋果設備通常有多個接口,提供不同的功能,如音頻、視頻和控制。當我們將蘋果設備插入Windows設備時,總線適配器識別設備並向操作系統提供其hardwareid和compatibleid。這些id用於根據id的匹配質量在driver Store中搜索最佳驅動程序。

對於總線驅動器來說,要將該設備視為複合設備,必須滿足一定的要求。如果不滿足這些要求,操作系統將不會自動加載USB複合設備類驅動程序(usbccgp)。在這種情況下,我們需要提供一個INF來加載通用的父驅動程序,對於蘋果來說是文件AppleUSB.inf。

在iPhone的情況下,不滿足的要求是設備具有多個配置(bNumConfigurations==4)。

這個INF文件包含不同設備的各種設置配置(例如AppleUSB, AppleUsbHomePod和AppleUsbWatch)。對於iOS設備,HardwareId將完全匹配,因此操作系統將應用AppleUSB設置配置,這將復制AppleLowerFilter.sys,並將在設備特定的註冊表項下添加以下值:

1.png

OriginalConfigurationValue是一個可以在設備的硬件註冊表項中為Usbccgp.sys驅動程序設置的值。它確定複合設備的哪個配置應用作默認配置。首次插入複合設備時,系統讀取OriginalConfigurationValue並加載指定的配置。這對於具有多個配置的複合設備非常有用,其中一個配置可能是首選配置。

安裝驅動程序包後,微軟將詳細說明以下步驟。設備將重新啟動,重啟後,PnP管理器識別設備的功能驅動程序和任何可選的過濾器驅動程序,構建設備堆棧,在該樣本中,FDO是Usbccgp和LowerFiDO是AppleLowerFilter,並通過調用DriverEntry例程啟動設備,為任何尚未加載的所需驅動程序。然後為每個驅動程序調用AddDevice例程,從低過濾驅動程序開始,然後是函數驅動程序。如果需要,將分配資源,PnP管理器將IRP_MN_START_DEVICE發送給設備的驅動程序。

USB低級過濾器工作原理介紹了AppleLowerFilter的枚舉和安裝背後的理論之後,我們現在將仔細研究驅動程序是如何工作的,以及它在Windows設備上啟用Apple設備功能時所起的作用。

作為一個WDF驅動程序,PnP調用DriverEntry的第一步是初始化框架並綁定WDF版本(在本例中為WDF 1.15)。一旦完成,框架將調用我們的DriverEntry函數,在AppleLowerFilter的情況下,他們的驅動項將簡單地創建一個驅動對象,並在WDF_DRIVER_CONFIG中只設置一個AddDevice例程。 AppleLowerFilter的AddDevice例程將進行如下操作:

1.通過調用WdfFdoInitSetFilter將自己標識為FiDO;

2.為事件註冊PnP和電源管理回調:

EvtDevicePrepareHardware;

EvtDeviceReleaseHardware;

EvtDeviceD0Entry;

EvtDeviceD0Exit;

3.為IRP設置兩個IRP預處理回調:

IRP_MJ_PNP;

IRP_MJ_INTERNAL_DEVICE_CONTROL;

4.使用名為FILTER_EXTENSION(sizeof==0x50)的上下文類型信息創建一個DO;

本文不深入討論WDF框架的所有細節,但鼓勵每個人都深入研究Github上的源代碼。它是一個設計良好的軟件,使編寫驅動程序變得更加容易和直觀,因此研究代碼是一個很好的練習。

在上電序列( power-up sequence)中,下一步是為上電準備硬件,這意味著調用過濾器註冊的EvtDevicePrepareHardware回調。這可能是AppleLowerFilter中最有趣的步驟。

Callback的第一步是檢索USB描述符,這是通過被稱為GetUsbDeviceDescriptor的函數完成的。此函數用於檢索USB設備的USB設備描述符。這是通過為URB (USB請求塊)分配內存並使用URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE類型完成的,這是一個從USB設備檢索描述符的請求。被請求的描述符是USB_DEVICE_DESCRIPTOR_TYPE,它提供有關USB設備的信息,如其供應商和產品id、設備類和協議。該函數同步提交URB以檢索描述符。

對於大多數與USB相關的操作,蘋果使用usbdlib,這有點令人不可思議,因為這是一個WDF驅動程序,他們可以使用wdfusb標頭,簡化事情。

然後,驅動程序將bNumConfigurations存儲到FILTER_EXTENSION上下文中,並繼續調用我認為是該驅動程序的主要函數GetPreferredConfig。在描述其內部結構之前,先看一下這個函數的簡單偽代碼:

2.png

該函數將首先檢查設備的配置數是否為1。如果是,則將首選配置設置為1;如果沒有,代碼將發送一個URB來檢索首選配置;如果URB請求失敗,則首選配置為3。然後代碼在FilterCtx結構中設置DeviceConfig字段。然後,它檢查QueryAppleSoftwarePresent函數是否返回false(表示未安裝AppleSoftware),如果是,則將首選配置設置為1。然後,代碼檢查首選配置是否大於或等於設備描述符中指定的配置數;如果是,則將首選配置設置為最大配置數。最後,如果首選配置大於或等於5,則代碼返回5。

在這個函數中有幾個關鍵點,首先突出的是getdeviceconfigure函數,該函數將為URB分配內存,設置URB以發出特定於供應商的控制請求,然後將URB同步提交給USB驅動程序堆棧。正在進行的特定供應商請求是請求類型為69的控制傳輸和包含一個字節數據的傳輸緩衝區。

3.png

選擇首選配置的下一個關鍵點是QueryAppleSoftwarePresent函數,這個函數起著很大的作用,因為它的返回值將決定我們是否總是被限制為只有一個首選配置。這個函數將做以下事情:

4.png

回到GetPreferredConfig函數,這個值起著很大的作用,因為這個函數返回的數字將用於覆蓋設備註冊表項中的OriginalConfigurationValue。

注意:GetPreferredConfig返回的值將被減去1,因為OriginalConfigurationValue描述的註冊表值對應於usb定義的配置索引,由配置描述符(USB_CONFIGURATION_DESCRIPTOR)的bConfigurationValue成員指示,而不是由設備配置描述符中報告的bConfigurationNum值表示。

我們剛剛看到的是為什麼即使INF在OriginalConfigurationValue中寫入值2,如果你將iPhone插入沒有安裝iTunes的PC,你會在註冊表中看到以下內容:

5.jpg

在註冊表中設置OriginalConfigurationValue之後,EvtDevicePrepareHardware函數將調用wdfusbtargetdevicecrecreate來創建USB目標設備對象。 USB目標設備對象表示底層USB設備,並為驅動程序與設備通信提供了一種方式。

為了定期檢查首選配置,該函數設置了一個WDFTIMER。計時器的回調函數將被定期調用,以檢查首選配置是否已更改。如果首選配置已更改,則函數將調用WdfUsbTargetDeviceCyclePortSynchronously,以便意外刪除並重新枚舉設備,從而使用新配置進行加載。

計時器的周期設置為0,因此框架不會調用計時器。另一方面,過濾器將在計時器的回調函數和D0Entry回調中調用WdfTimerStart, DueTime為5s(相對於當前系統時間)。

現在讓我們看看這兩個IRP預處理回調,以獲得驅動程序工作流的全貌。 IRP的預處理允許驅動程序在將IRP發送到默認處理程序或堆棧中的另一個驅動程序之前修改或重定向IRP。

首先看一下內部設備控制請求的處理程序。該函數將檢查IRP是否為IOCTL_INTERNAL_USB_SUBMIT_URB請求,以選擇USB配置。如果是,函數將獲得設備的句柄,轉發IRP,然後檢索USB接口的管道句柄。 Interrupt、BulkIn和BulkOut的管道句柄將存儲在設備上下文中。

現在讓我們看一下PnP IRPs預處理的處理程序。在本文的示例中,句柄將處理兩種情況:IRP_MN_QUERY_DEVICE_RELATIONS 和IRP_MN_QUERY_ID。

QueryID IRP的情況非常簡單,函數將檢查FilterCtx-DeviceConfig(記住這個值是通過供應商特定的URB獲得的)是否被設置為1,如果是,函數將字符串RESTORE_MODE附加到BusQueryHardwareIDs和BusQueryDeviceID請求返回的信息中。

另一方面,querydevicerrelation更有趣一些。首先,這個處理程序只會在某個計時器沒有運行並且設備上安裝了Apple Software的情況下執行。它將只處理BusRelations IRP,它將同步轉發請求並檢查狀態是否成功。如果返回任何信息,它將在返回的設備對象列表中查找其CompatibleId包含USB\Class_06的設備。如果找到了,它會取消對這個DO的引用,然後將其從列表中刪除並更新設備計數,這樣即使usbccgp為WPD設備創建了PDO, PnP也不會看到這個DO,因為返回的列表中沒有它。不久,我們將看到低級過濾器如何處理這一點。

如果找到了類6的設備,那麼該函數將根據DbgPrints設置另一個WDF定時器,我們將其稱為PtpTimer,它在5秒後被觸發。當觸發回調時,將在deviceContext中設置一個標誌,因此QueryDeviceRelations處理程序不再處理請求,將檢查iTunes是否存在,如果存在,它將發送以下一組PTP/MTP操作請求包到USB設備。

OpenSession - OperationCode:0x1002;

vendoreextensionoperationcode:0x9008;

CloseSession - OperationCode:0x1003;

下面的USB數據包捕獲說明了這些操作的執行,注意它們是如何在該端口上捕獲大約5秒後發生的。

6.jpg

儘管嘗試了所有的手段來獲得操作0x9008的更多信息,但似乎沒有任何關於它的蘋果設備的信息。所能得到的最好結果是ChatGPT說“PTP/MTP數據包中的操作命令0x9008通常對應於“Apple Device Info”命令”。不幸的是,當要求提供證明這一點的文檔/引用時,而聊天給到的每個鏈接要么是無效的,要么是不可用的/廢棄的蘋果文檔。給定名稱“蘋果設備信息”,筆者認為它類似於PTP/MTP命令“GetDeviceInfo”,但在設備命令0x9008上嘗試的每個測試似乎都沒有數據階段,所以最好的猜測是,要么不是“設備信息”命令,要么蘋果設備不再響應該命令。

7.jpg

最後,在發送PTP/MTP請求後,PtpTimer將調用IoInvalidateDeviceRelations,其關係類型為BusRelation,這將觸發一個新的IRP QueryDeviceRelations,但由於這次計時器已經執行,處理程序不會從設備列表中刪除WPD設備。這次PnP管理器我們會看到WPD設備的PDO並開始為它構建堆棧。下圖顯示了通過將LowerFilter添加到堆棧中並跟踪Pre和Post捕獲的這種行為,IRP由AppleLowerFilter處理。

8.jpg

目前猜測是帶有operationCode0x9008的PTP包以某種方式,通知設備iTunes存在於主機上或這些行周圍的東西。除此之外,沒有註意到WPD設備在安裝iTunes或沒有安裝iTunes的情況下有任何不同的行為,除了WPD設備實際顯示需要5秒鐘。從設備的LowerFilters列表中刪除AppleLowerFilter似乎對WPD設備的行為沒有任何重大影響。

這幾乎就是AppleLowerFilter的行為方式,可以看到它主要在設備初始化期間工作,除了檢查活動配置的計時器每5秒在後台運行一次之外,查看端口時必須重新舉例。

0 Comments

Recommended Comments

There are no comments to display.

Guest
Add a comment...