Use correct packets for mounting

This commit is contained in:
Jackson Coxson
2025-02-05 11:40:34 -07:00
parent 732940581e
commit 74e0f8e226
4 changed files with 58 additions and 11 deletions

View File

@@ -32,12 +32,14 @@ byteorder = { version = "1.5", optional = true }
reqwest = { version = "0.12", features = ["json"], optional = true } reqwest = { version = "0.12", features = ["json"], optional = true }
sha2 = { version = "0.10", optional = true }
[features] [features]
core_device_proxy = ["dep:serde_json", "dep:json", "dep:byteorder"] core_device_proxy = ["dep:serde_json", "dep:json", "dep:byteorder"]
heartbeat = [] heartbeat = []
installation_proxy = [] installation_proxy = []
mounter = [] mounter = ["dep:sha2"]
usbmuxd = [] usbmuxd = []
tcp = ["tokio/net"] tcp = ["tokio/net"]
tss = ["dep:uuid", "dep:reqwest"] tss = ["dep:uuid", "dep:reqwest"]

View File

@@ -86,7 +86,24 @@ impl Idevice {
/// Sends raw bytes to the socket /// Sends raw bytes to the socket
async fn send_raw(&mut self, message: &[u8]) -> Result<(), IdeviceError> { async fn send_raw(&mut self, message: &[u8]) -> Result<(), IdeviceError> {
if let Some(socket) = &mut self.socket { if let Some(socket) = &mut self.socket {
Ok(socket.write_all(message).await?) let mut trash = [0; 2048];
let _ = socket.read(&mut trash).await.ok();
let message_parts = message.chunks(2048);
let part_len = message_parts.len();
let mut err = 5;
for (i, part) in message_parts.enumerate() {
debug!("Writing {i}/{part_len}");
while let Err(e) = socket.write_all(part).await {
err -= 1;
if err == 0 {
return Err(e.into());
}
}
err = 5;
}
Ok(())
} else { } else {
Err(IdeviceError::NoEstablishedConnection) Err(IdeviceError::NoEstablishedConnection)
} }
@@ -210,6 +227,9 @@ pub enum IdeviceError {
#[error("device not found")] #[error("device not found")]
DeviceNotFound, DeviceNotFound,
#[error("device lockded")]
DeviceLocked,
#[error("device refused connection")] #[error("device refused connection")]
UsbConnectionRefused, UsbConnectionRefused,
#[error("bad command")] #[error("bad command")]
@@ -236,6 +256,7 @@ impl IdeviceError {
"GetProhibited" => Some(Self::GetProhibited), "GetProhibited" => Some(Self::GetProhibited),
"InvalidHostID" => Some(Self::InvalidHostID), "InvalidHostID" => Some(Self::InvalidHostID),
"SessionInactive" => Some(Self::SessionInactive), "SessionInactive" => Some(Self::SessionInactive),
"DeviceLocked" => Some(Self::DeviceLocked),
_ => None, _ => None,
} }
} }

View File

@@ -1,9 +1,9 @@
// Jackson Coxson // Jackson Coxson
use crate::{ use log::debug;
lockdownd::LockdowndClient, tss::TSSRequest, util::hashmap_to_dictionary, Idevice, use openssl::sha::Sha384;
IdeviceError, IdeviceService,
}; use crate::{lockdownd::LockdowndClient, tss::TSSRequest, Idevice, IdeviceError, IdeviceService};
pub struct ImageMounter { pub struct ImageMounter {
idevice: Idevice, idevice: Idevice,
@@ -81,11 +81,18 @@ impl ImageMounter {
signature: Vec<u8>, signature: Vec<u8>,
) -> Result<(), IdeviceError> { ) -> Result<(), IdeviceError> {
let image_type = image_type.into(); let image_type = image_type.into();
let image_size = match u64::try_from(image.len()) {
Ok(i) => i,
Err(e) => {
log::error!("Could not parse image size as u64: {e:?}");
return Err(IdeviceError::UnexpectedResponse);
}
};
let mut req = plist::Dictionary::new(); let mut req = plist::Dictionary::new();
req.insert("Command".into(), "ReceiveBytes".into()); req.insert("Command".into(), "ReceiveBytes".into());
req.insert("ImageType".into(), image_type.into()); req.insert("ImageType".into(), image_type.into());
req.insert("ImageSize".into(), (image.len() as u64).into()); req.insert("ImageSize".into(), image_size.into());
req.insert("ImageSignature".into(), plist::Value::Data(signature)); req.insert("ImageSignature".into(), plist::Value::Data(signature));
self.idevice self.idevice
.send_plist(plist::Value::Dictionary(req)) .send_plist(plist::Value::Dictionary(req))
@@ -102,7 +109,9 @@ impl ImageMounter {
_ => return Err(IdeviceError::UnexpectedResponse), _ => return Err(IdeviceError::UnexpectedResponse),
} }
debug!("Sending image bytes");
self.idevice.send_raw(image).await?; self.idevice.send_raw(image).await?;
debug!("Image bytes written");
let res = self.idevice.read_plist().await?; let res = self.idevice.read_plist().await?;
match res.get("Status") { match res.get("Status") {
@@ -278,7 +287,7 @@ impl ImageMounter {
image: &[u8], image: &[u8],
signature: Vec<u8>, signature: Vec<u8>,
) -> Result<(), IdeviceError> { ) -> Result<(), IdeviceError> {
self.upload_image("Developer", &image, signature.clone()) self.upload_image("Developer", image, signature.clone())
.await?; .await?;
self.mount_image( self.mount_image(
"Developer", "Developer",
@@ -291,8 +300,11 @@ impl ImageMounter {
Ok(()) Ok(())
} }
/// Calling this has the potential of closing the socket,
/// so a provider is required for this abstraction.
pub async fn mount_personalized( pub async fn mount_personalized(
&mut self, &mut self,
provider: &dyn crate::provider::IdeviceProvider,
image: Vec<u8>, image: Vec<u8>,
trust_cache: Vec<u8>, trust_cache: Vec<u8>,
build_manifest: &[u8], build_manifest: &[u8],
@@ -300,20 +312,28 @@ impl ImageMounter {
unique_chip_id: u64, unique_chip_id: u64,
) -> Result<(), IdeviceError> { ) -> Result<(), IdeviceError> {
// Try to fetch personalization manifest // Try to fetch personalization manifest
let mut hasher = Sha384::new();
hasher.update(&image);
let image_hash = hasher.finish();
let manifest = match self let manifest = match self
.query_personalization_manifest("DeveloperDiskImage", image.clone()) // TODO: .query_personalization_manifest("DeveloperDiskImage", image_hash.to_vec())
.await .await
{ {
Ok(manifest) => manifest, Ok(manifest) => manifest,
Err(IdeviceError::NotFound) => { Err(e) => {
debug!("Device didn't contain a manifest: {e:?}, fetching from TSS");
// On failure, the socket closes. Open a new one.
self.idevice = Self::connect(provider).await?.idevice;
// Get manifest from TSS // Get manifest from TSS
let manifest_dict: plist::Dictionary = plist::from_bytes(build_manifest)?; let manifest_dict: plist::Dictionary = plist::from_bytes(build_manifest)?;
self.get_manifest_from_tss(&manifest_dict, unique_chip_id) self.get_manifest_from_tss(&manifest_dict, unique_chip_id)
.await? .await?
} }
Err(e) => return Err(e),
}; };
debug!("Uploading imaage");
self.upload_image("Personalized", &image, manifest.clone()) self.upload_image("Personalized", &image, manifest.clone())
.await?; .await?;
@@ -326,6 +346,7 @@ impl ImageMounter {
plist::Value::Data(trust_cache.clone()), plist::Value::Data(trust_cache.clone()),
); );
debug!("Mounting image");
self.mount_image( self.mount_image(
"Personalized", "Personalized",
manifest, manifest,

View File

@@ -49,12 +49,15 @@ impl TSSRequest {
.await?; .await?;
debug!("Apple responeded with {res}"); debug!("Apple responeded with {res}");
let res = res.trim_start_matches("STATUS=0&");
let res = res.trim_start_matches("MESSAGE="); let res = res.trim_start_matches("MESSAGE=");
if !res.starts_with("SUCCESS") { if !res.starts_with("SUCCESS") {
warn!("TSS responded with non-success value");
return Err(IdeviceError::UnexpectedResponse); return Err(IdeviceError::UnexpectedResponse);
} }
let res = res.split("REQUEST_STRING=").collect::<Vec<&str>>(); let res = res.split("REQUEST_STRING=").collect::<Vec<&str>>();
if res.len() < 2 { if res.len() < 2 {
warn!("Response didn't contain a request string");
return Err(IdeviceError::UnexpectedResponse); return Err(IdeviceError::UnexpectedResponse);
} }
Ok(plist::from_bytes(res[1].as_bytes())?) Ok(plist::from_bytes(res[1].as_bytes())?)