diff --git a/idevice/src/lib.rs b/idevice/src/lib.rs index 8dd769d..cc8c4f7 100644 --- a/idevice/src/lib.rs +++ b/idevice/src/lib.rs @@ -509,6 +509,34 @@ pub enum IdeviceError { #[error("Unintialized stream ID")] UninitializedStreamId, + #[cfg(feature = "xpc")] + #[error("unknown XPC type")] + UnknownXpcType(u32), + + #[cfg(feature = "xpc")] + #[error("malformed XPC message")] + MalformedXpc, + + #[cfg(feature = "xpc")] + #[error("invalid XPC magic")] + InvalidXpcMagic, + + #[cfg(feature = "xpc")] + #[error("unexpected XPC version")] + UnexpectedXpcVersion, + + #[cfg(feature = "xpc")] + #[error("invalid C string")] + InvalidCString, + + #[cfg(feature = "xpc")] + #[error("stream reset")] + HttpStreamReset, + + #[cfg(feature = "xpc")] + #[error("go away packet received")] + HttpGoAway(String), + #[cfg(feature = "dvt")] #[error("NSKeyedArchive error")] NsKeyedArchiveError(#[from] ns_keyed_archive::ConverterError), diff --git a/idevice/src/services/xpc/format.rs b/idevice/src/services/xpc/format.rs new file mode 100644 index 0000000..025f02f --- /dev/null +++ b/idevice/src/services/xpc/format.rs @@ -0,0 +1,467 @@ +use std::{ + ffi::CString, + io::{BufRead, Cursor, Read}, + ops::{BitOr, BitOrAssign}, +}; + +use indexmap::IndexMap; +use log::warn; +use serde::{Deserialize, Serialize}; + +use crate::IdeviceError; + +#[derive(Clone, Copy, Debug)] +#[repr(u32)] +pub enum XPCFlag { + AlwaysSet, + DataFlag, + WantingReply, + InitHandshake, + + Custom(u32), +} + +impl From for u32 { + fn from(value: XPCFlag) -> Self { + match value { + XPCFlag::AlwaysSet => 0x00000001, + XPCFlag::DataFlag => 0x00000100, + XPCFlag::WantingReply => 0x00010000, + XPCFlag::InitHandshake => 0x00400000, + XPCFlag::Custom(inner) => inner, + } + } +} + +impl BitOr for XPCFlag { + fn bitor(self, rhs: Self) -> Self::Output { + XPCFlag::Custom(u32::from(self) | u32::from(rhs)) + } + + type Output = XPCFlag; +} + +impl BitOrAssign for XPCFlag { + fn bitor_assign(&mut self, rhs: Self) { + *self = self.bitor(rhs); + } +} + +impl PartialEq for XPCFlag { + fn eq(&self, other: &Self) -> bool { + u32::from(*self) == u32::from(*other) + } +} + +#[repr(u32)] +pub enum XPCType { + Bool = 0x00002000, + Dictionary = 0x0000f000, + Array = 0x0000e000, + + Int64 = 0x00003000, + UInt64 = 0x00004000, + + String = 0x00009000, + Data = 0x00008000, + Uuid = 0x0000a000, +} + +impl TryFrom for XPCType { + type Error = IdeviceError; + + fn try_from(value: u32) -> Result { + match value { + 0x00002000 => Ok(Self::Bool), + 0x0000f000 => Ok(Self::Dictionary), + 0x0000e000 => Ok(Self::Array), + 0x00003000 => Ok(Self::Int64), + 0x00004000 => Ok(Self::UInt64), + 0x00009000 => Ok(Self::String), + 0x00008000 => Ok(Self::Data), + 0x0000a000 => Ok(Self::Uuid), + _ => Err(IdeviceError::UnknownXpcType(value))?, + } + } +} + +pub type Dictionary = IndexMap; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum XPCObject { + Bool(bool), + Dictionary(Dictionary), + Array(Vec), + + Int64(i64), + UInt64(u64), + + String(String), + Data(Vec), + Uuid(uuid::Uuid), +} + +impl From for XPCObject { + fn from(value: plist::Value) -> Self { + match value { + plist::Value::Array(v) => { + XPCObject::Array(v.iter().map(|item| XPCObject::from(item.clone())).collect()) + } + plist::Value::Dictionary(v) => { + let mut dict = Dictionary::new(); + for (k, v) in v.into_iter() { + dict.insert(k.clone(), XPCObject::from(v)); + } + XPCObject::Dictionary(dict) + } + plist::Value::Boolean(v) => XPCObject::Bool(v), + plist::Value::Data(v) => XPCObject::Data(v), + plist::Value::Date(_) => todo!(), + plist::Value::Real(_) => todo!(), + plist::Value::Integer(v) => XPCObject::Int64(v.as_signed().unwrap()), + plist::Value::String(v) => XPCObject::String(v), + plist::Value::Uid(_) => todo!(), + _ => todo!(), + } + } +} + +impl XPCObject { + pub fn to_plist(&self) -> plist::Value { + match self { + Self::Bool(v) => plist::Value::Boolean(*v), + Self::Uuid(uuid) => plist::Value::String(uuid.to_string()), + Self::UInt64(v) => plist::Value::Integer({ *v }.into()), + Self::Int64(v) => plist::Value::Integer({ *v }.into()), + Self::String(v) => plist::Value::String(v.clone()), + Self::Data(v) => plist::Value::Data(v.clone()), + Self::Array(v) => plist::Value::Array(v.iter().map(|item| item.to_plist()).collect()), + Self::Dictionary(v) => { + let mut dict = plist::Dictionary::new(); + for (k, v) in v.into_iter() { + dict.insert(k.clone(), v.to_plist()); + } + plist::Value::Dictionary(dict) + } + } + } + + pub fn encode(&self) -> Result, IdeviceError> { + let mut buf = Vec::new(); + buf.extend_from_slice(&0x42133742_u32.to_le_bytes()); + buf.extend_from_slice(&0x00000005_u32.to_le_bytes()); + self.encode_object(&mut buf)?; + Ok(buf) + } + + fn encode_object(&self, buf: &mut Vec) -> Result<(), IdeviceError> { + match self { + XPCObject::Bool(val) => { + buf.extend_from_slice(&(XPCType::Bool as u32).to_le_bytes()); + buf.push(if *val { 0 } else { 1 }); + buf.extend_from_slice(&[0].repeat(3)); + } + XPCObject::Dictionary(dict) => { + buf.extend_from_slice(&(XPCType::Dictionary as u32).to_le_bytes()); + buf.extend_from_slice(&0_u32.to_le_bytes()); // represents l, no idea what this is. + buf.extend_from_slice(&(dict.len() as u32).to_le_bytes()); + for (k, v) in dict { + let padding = Self::calculate_padding(k.len() + 1); + buf.extend_from_slice(k.as_bytes()); + buf.push(0); + buf.extend_from_slice(&[0].repeat(padding)); + v.encode_object(buf)?; + } + } + XPCObject::Array(items) => { + buf.extend_from_slice(&(XPCType::Array as u32).to_le_bytes()); + buf.extend_from_slice(&0_u32.to_le_bytes()); // represents l, no idea what this is. + buf.extend_from_slice(&(items.len() as u32).to_le_bytes()); + for item in items { + item.encode_object(buf)?; + } + } + + XPCObject::Int64(num) => { + buf.extend_from_slice(&(XPCType::Int64 as u32).to_le_bytes()); + buf.extend_from_slice(&num.to_le_bytes()); + } + XPCObject::UInt64(num) => { + buf.extend_from_slice(&(XPCType::UInt64 as u32).to_le_bytes()); + buf.extend_from_slice(&num.to_le_bytes()); + } + XPCObject::String(item) => { + let l = item.len() + 1; + let padding = Self::calculate_padding(l); + buf.extend_from_slice(&(XPCType::String as u32).to_le_bytes()); + buf.extend_from_slice(&(l as u32).to_le_bytes()); + buf.extend_from_slice(item.as_bytes()); + buf.push(0); + buf.extend_from_slice(&[0].repeat(padding)); + } + XPCObject::Data(data) => { + let l = data.len(); + let padding = Self::calculate_padding(l); + buf.extend_from_slice(&(XPCType::Data as u32).to_le_bytes()); + buf.extend_from_slice(&(l as u32).to_le_bytes()); + buf.extend_from_slice(data); + buf.extend_from_slice(&[0].repeat(padding)); + } + XPCObject::Uuid(uuid) => { + buf.extend_from_slice(&(XPCType::Uuid as u32).to_le_bytes()); + buf.extend_from_slice(&16_u32.to_le_bytes()); + buf.extend_from_slice(uuid.as_bytes()); + } + } + Ok(()) + } + + pub fn decode(buf: &[u8]) -> Result { + if buf.len() < 8 { + return Err(IdeviceError::NotEnoughBytes(buf.len(), 8)); + } + let magic = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]); + if magic != 0x42133742 { + warn!("Invalid magic for XPCObject"); + return Err(IdeviceError::InvalidXpcMagic); + } + + let version = u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]); + if version != 0x00000005 { + warn!("Unexpected version for XPCObject"); + return Err(IdeviceError::UnexpectedXpcVersion); + } + + Self::decode_object(&mut Cursor::new(&buf[8..])) + } + + fn decode_object(mut cursor: &mut Cursor<&[u8]>) -> Result { + let mut buf_32: [u8; 4] = Default::default(); + cursor.read_exact(&mut buf_32)?; + let xpc_type = u32::from_le_bytes(buf_32); + let xpc_type: XPCType = xpc_type.try_into()?; + match xpc_type { + XPCType::Dictionary => { + let mut ret = IndexMap::new(); + + cursor.read_exact(&mut buf_32)?; + let _l = u32::from_le_bytes(buf_32); + cursor.read_exact(&mut buf_32)?; + let num_entries = u32::from_le_bytes(buf_32); + for _ in 0..num_entries { + let mut key_buf = Vec::new(); + BufRead::read_until(&mut cursor, 0, &mut key_buf)?; + let key = match CString::from_vec_with_nul(key_buf) + .ok() + .and_then(|x| x.to_str().ok().map(|x| x.to_string())) + { + Some(k) => k, + None => { + return Err(IdeviceError::InvalidCString); + } + }; + let padding = Self::calculate_padding(key.len() + 1); + + BufRead::consume(&mut cursor, padding); + ret.insert(key, Self::decode_object(cursor)?); + } + Ok(XPCObject::Dictionary(ret)) + } + XPCType::Array => { + cursor.read_exact(&mut buf_32)?; + let _l = u32::from_le_bytes(buf_32); + cursor.read_exact(&mut buf_32)?; + let num_entries = u32::from_le_bytes(buf_32); + + let mut ret = Vec::new(); + for _i in 0..num_entries { + ret.push(Self::decode_object(cursor)?); + } + Ok(XPCObject::Array(ret)) + } + XPCType::Int64 => { + let mut buf: [u8; 8] = Default::default(); + cursor.read_exact(&mut buf)?; + Ok(XPCObject::Int64(i64::from_le_bytes(buf))) + } + XPCType::UInt64 => { + let mut buf: [u8; 8] = Default::default(); + cursor.read_exact(&mut buf)?; + Ok(XPCObject::UInt64(u64::from_le_bytes(buf))) + } + XPCType::String => { + // 'l' includes utf8 '\0' character. + cursor.read_exact(&mut buf_32)?; + let l = u32::from_le_bytes(buf_32) as usize; + let padding = Self::calculate_padding(l); + + let mut key_buf = vec![0; l]; + cursor.read_exact(&mut key_buf)?; + let key = match CString::from_vec_with_nul(key_buf) + .ok() + .and_then(|x| x.to_str().ok().map(|x| x.to_string())) + { + Some(k) => k, + None => return Err(IdeviceError::InvalidCString), + }; + BufRead::consume(&mut cursor, padding); + Ok(XPCObject::String(key)) + } + XPCType::Bool => { + let mut buf: [u8; 4] = Default::default(); + cursor.read_exact(&mut buf)?; + Ok(XPCObject::Bool(buf[0] != 0)) + } + XPCType::Data => { + cursor.read_exact(&mut buf_32)?; + let l = u32::from_le_bytes(buf_32) as usize; + let padding = Self::calculate_padding(l); + + let mut data = vec![0; l]; + cursor.read_exact(&mut data)?; + BufRead::consume(&mut cursor, padding); + Ok(XPCObject::Data(data)) + } + XPCType::Uuid => { + let mut data: [u8; 16] = Default::default(); + cursor.read_exact(&mut data)?; + Ok(XPCObject::Uuid(uuid::Builder::from_bytes(data).into_uuid())) + } + } + } + + pub fn as_dictionary(&self) -> Option<&Dictionary> { + match self { + XPCObject::Dictionary(dict) => Some(dict), + _ => None, + } + } + + pub fn as_array(&self) -> Option<&Vec> { + match self { + XPCObject::Array(array) => Some(array), + _ => None, + } + } + + pub fn as_string(&self) -> Option<&str> { + match self { + XPCObject::String(s) => Some(s), + _ => None, + } + } + + pub fn as_bool(&self) -> Option<&bool> { + match self { + XPCObject::Bool(b) => Some(b), + _ => None, + } + } + + pub fn as_signed_integer(&self) -> Option { + match self { + XPCObject::String(s) => s.parse().ok(), + XPCObject::Int64(v) => Some(*v), + _ => None, + } + } + + pub fn as_unsigned_integer(&self) -> Option { + match self { + XPCObject::String(s) => s.parse().ok(), + XPCObject::UInt64(v) => Some(*v), + _ => None, + } + } + + fn calculate_padding(len: usize) -> usize { + let c = ((len as f64) / 4.0).ceil(); + (c * 4.0 - (len as f64)) as usize + } +} + +impl From for XPCObject { + fn from(value: Dictionary) -> Self { + XPCObject::Dictionary(value) + } +} + +#[derive(Debug)] +pub struct XPCMessage { + pub flags: u32, + pub message: Option, + pub message_id: Option, +} + +impl XPCMessage { + pub fn new( + flags: Option, + message: Option, + message_id: Option, + ) -> XPCMessage { + XPCMessage { + flags: flags.unwrap_or(XPCFlag::AlwaysSet).into(), + message, + message_id, + } + } + + pub fn decode(data: &[u8]) -> Result { + if data.len() < 24 { + Err(IdeviceError::NotEnoughBytes(data.len(), 24))? + } + + let magic = u32::from_le_bytes([data[0], data[1], data[2], data[3]]); + if magic != 0x29b00b92_u32 { + warn!("XPCMessage magic is invalid."); + Err(IdeviceError::MalformedXpc)? + } + + let flags = u32::from_le_bytes([data[4], data[5], data[6], data[7]]); + let body_len = u64::from_le_bytes([ + data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], + ]); + let message_id = u64::from_le_bytes([ + data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], + ]); + if body_len + 24 > data.len() as u64 { + warn!( + "Body length is {body_len}, but received bytes is {}", + data.len() + ); + println!("{}", String::from_utf8_lossy(data)); + Err(IdeviceError::PacketSizeMismatch)? + } + + if body_len == 0 { + return Ok(XPCMessage { + flags, + message: None, + message_id: Some(message_id), + }); + } + Ok(XPCMessage { + flags, + message: Some(XPCObject::decode(&data[24..24 + body_len as usize])?), + message_id: Some(message_id), + }) + } + + pub fn encode(self, message_id: u64) -> Result, IdeviceError> { + let mut out = 0x29b00b92_u32.to_le_bytes().to_vec(); + out.extend_from_slice(&self.flags.to_le_bytes()); + match self.message { + Some(message) => { + let body = message.encode()?; + out.extend_from_slice(&(body.len() as u64).to_le_bytes()); // body length + out.extend_from_slice(&message_id.to_le_bytes()); // messageId + out.extend_from_slice(&body); + } + _ => { + out.extend_from_slice(&0_u64.to_le_bytes()); + out.extend_from_slice(&message_id.to_le_bytes()); + } + } + Ok(out) + } +} diff --git a/idevice/src/services/xpc/http2/frame.rs b/idevice/src/services/xpc/http2/frame.rs index d3f1195..f083d41 100644 --- a/idevice/src/services/xpc/http2/frame.rs +++ b/idevice/src/services/xpc/http2/frame.rs @@ -7,6 +7,8 @@ pub trait HttpFrame { fn serialize(&self) -> Vec; } +#[derive(Debug)] +#[allow(dead_code)] // we don't care about frames from the device pub enum Frame { Settings(SettingsFrame), WindowUpdate(WindowUpdateFrame), @@ -15,10 +17,10 @@ pub enum Frame { } impl Frame { - pub async fn next(socket: &mut impl ReadWrite) -> Result { + pub async fn next(mut socket: &mut impl ReadWrite) -> Result { // Read the len of the frame let mut buf = [0u8; 3]; - socket.read_exact(&mut buf).await?; + tokio::io::AsyncReadExt::read_exact(&mut socket, &mut buf).await?; let frame_len = u32::from_be_bytes([0x00, buf[0], buf[1], buf[2]]); // Read the fields @@ -26,8 +28,8 @@ impl Frame { let flags = socket.read_u8().await?; let stream_id = socket.read_u32().await?; - let body = vec![0; frame_len as usize]; - socket.read_exact(&mut buf).await?; + let mut body = vec![0; frame_len as usize]; + socket.read_exact(&mut body).await?; Ok(match frame_type { 0x00 => { @@ -41,6 +43,7 @@ impl Frame { // headers Self::Headers(HeadersFrame { stream_id }) } + 0x03 => return Err(IdeviceError::HttpStreamReset), 0x04 => { // settings let mut body = std::io::Cursor::new(body); @@ -67,6 +70,14 @@ impl Frame { flags, }) } + 0x07 => { + let msg = if body.len() < 8 { + "".to_string() + } else { + String::from_utf8_lossy(&body[8..]).to_string() + }; + return Err(IdeviceError::HttpGoAway(msg)); + } 0x08 => { // window update if body.len() != 4 { @@ -86,23 +97,19 @@ impl Frame { } } +#[derive(Debug, Clone)] pub struct SettingsFrame { pub settings: Vec, pub stream_id: u32, pub flags: u8, } +#[derive(Debug, Clone)] pub enum Setting { MaxConcurrentStreams(u32), InitialWindowSize(u32), } -impl SettingsFrame { - pub fn ack(&mut self) { - self.flags = 1; // this seems to be the only http flag used - } -} - impl Setting { fn serialize(&self) -> Vec { match self { @@ -142,6 +149,7 @@ impl HttpFrame for SettingsFrame { } } +#[derive(Debug, Clone)] pub struct WindowUpdateFrame { pub increment_size: u32, pub stream_id: u32, @@ -156,6 +164,7 @@ impl HttpFrame for WindowUpdateFrame { } } +#[derive(Debug, Clone)] /// We don't actually care about this frame according to spec. This is just to open new channels. pub struct HeadersFrame { pub stream_id: u32, @@ -169,6 +178,7 @@ impl HttpFrame for HeadersFrame { } } +#[derive(Debug, Clone)] pub struct DataFrame { pub stream_id: u32, pub payload: Vec, diff --git a/idevice/src/services/xpc/http2/mod.rs b/idevice/src/services/xpc/http2/mod.rs index 361dc2f..ea0e473 100644 --- a/idevice/src/services/xpc/http2/mod.rs +++ b/idevice/src/services/xpc/http2/mod.rs @@ -1,13 +1,13 @@ // Jackson Coxson use frame::HttpFrame; -use log::warn; +use log::{debug, warn}; use std::collections::{HashMap, VecDeque}; use tokio::io::AsyncWriteExt; use crate::{IdeviceError, ReadWrite}; -mod frame; +pub mod frame; pub use frame::Setting; const HTTP2_MAGIC: &[u8] = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".as_bytes(); @@ -40,6 +40,7 @@ impl Http2Client { } .serialize(); self.inner.write_all(&frame).await?; + self.inner.flush().await?; Ok(()) } @@ -54,6 +55,7 @@ impl Http2Client { } .serialize(); self.inner.write_all(&frame).await?; + self.inner.flush().await?; Ok(()) } @@ -61,25 +63,34 @@ impl Http2Client { self.cache.insert(stream_id, VecDeque::new()); let frame = frame::HeadersFrame { stream_id }.serialize(); self.inner.write_all(&frame).await?; + self.inner.flush().await?; + Ok(()) + } + + pub async fn send(&mut self, payload: Vec, stream_id: u32) -> Result<(), IdeviceError> { + let frame = frame::DataFrame { stream_id, payload }.serialize(); + self.inner.write_all(&frame).await?; + self.inner.flush().await?; Ok(()) } pub async fn read(&mut self, stream_id: u32) -> Result, IdeviceError> { // See if we already have a cached message from another read - let c = match self.cache.get_mut(&stream_id) { - Some(c) => c, + match self.cache.get_mut(&stream_id) { + Some(c) => { + if let Some(d) = c.pop_front() { + return Ok(d); + } + } None => { - warn!("Requested stream ID is not in cache"); - return Err(IdeviceError::UninitializedStreamId); + self.cache.insert(stream_id, VecDeque::new()); } }; - if let Some(d) = c.pop_front() { - return Ok(d); - } // handle packets until we get what we want loop { let frame = frame::Frame::next(&mut self.inner).await?; + // debug!("Got frame: {frame:#?}"); match frame { frame::Frame::Settings(settings_frame) => { if settings_frame.flags != 1 { @@ -91,16 +102,25 @@ impl Http2Client { } .serialize(); self.inner.write_all(&frame).await?; + self.inner.flush().await?; } } frame::Frame::Data(data_frame) => { + debug!( + "Got data frame for {} with {} bytes", + data_frame.stream_id, + data_frame.payload.len() + ); if data_frame.stream_id == stream_id { return Ok(data_frame.payload); } else { let c = match self.cache.get_mut(&data_frame.stream_id) { Some(c) => c, None => { - warn!("Received message for stream ID not in cache"); + warn!( + "Received message for stream ID {} not in cache", + data_frame.stream_id + ); continue; } }; diff --git a/idevice/src/services/xpc/mod.rs b/idevice/src/services/xpc/mod.rs index b1141ec..6ef2b05 100644 --- a/idevice/src/services/xpc/mod.rs +++ b/idevice/src/services/xpc/mod.rs @@ -1,5 +1,118 @@ // Jackson Coxson +use http2::Setting; +use log::debug; + +use crate::{IdeviceError, ReadWrite}; + +mod format; mod http2; -pub trait XpcBackend {} +pub use format::XPCMessage; +use format::{XPCFlag, XPCObject}; + +const ROOT_CHANNEL: u32 = 1; +const REPLY_CHANNEL: u32 = 3; + +pub struct RemoteXpcClient { + h2_client: http2::Http2Client, + root_id: u64, + reply_id: u64, +} + +impl RemoteXpcClient { + pub async fn new(socket: R) -> Result { + Ok(Self { + h2_client: http2::Http2Client::new(socket).await?, + root_id: 1, + reply_id: 1, + }) + } + + pub async fn do_handshake(&mut self) -> Result { + self.h2_client + .set_settings( + vec![ + Setting::MaxConcurrentStreams(10), + Setting::InitialWindowSize(1048576), + ], + 0, + ) + .await?; + self.h2_client.window_update(983041, 0).await?; + self.h2_client.open_stream(1).await?; // root channel + + debug!("Sending empty dictionary"); + self.send_root(XPCMessage::new( + Some(XPCFlag::AlwaysSet), + Some(XPCObject::Dictionary(Default::default())), + None, + )) + .await?; + self.h2_client.read(ROOT_CHANNEL).await?; + self.h2_client.read(ROOT_CHANNEL).await?; + + debug!("Sending weird flags"); + self.send_root(XPCMessage::new(Some(XPCFlag::Custom(0x201)), None, None)) + .await?; + + debug!("Opening reply stream"); + self.h2_client.open_stream(REPLY_CHANNEL).await?; + self.send_reply(XPCMessage::new( + Some(XPCFlag::InitHandshake | XPCFlag::AlwaysSet), + None, + None, + )) + .await?; + + let mut total_msg = Vec::new(); + loop { + // We receive from the root channel for this message + total_msg.extend(self.h2_client.read(ROOT_CHANNEL).await?); + let msg = match XPCMessage::decode(&total_msg) { + Ok(m) => m, + Err(IdeviceError::PacketSizeMismatch) => { + continue; + } + Err(e) => { + return Err(e); + } + }; + + match msg.message { + Some(msg) => { + return Ok(msg.to_plist()); + } + None => { + return Err(IdeviceError::UnexpectedResponse); + } + }; + } + } + + pub async fn recv(&mut self) -> Result { + loop { + let msg = self.h2_client.read(REPLY_CHANNEL).await?; + + let msg = XPCMessage::decode(&msg)?; + if let Some(msg) = msg.message { + return Ok(msg.to_plist()); + } + self.reply_id += 1; + } + } + + async fn send_root(&mut self, msg: XPCMessage) -> Result<(), IdeviceError> { + self.h2_client + .send(msg.encode(self.root_id)?, ROOT_CHANNEL) + .await?; + Ok(()) + } + + async fn send_reply(&mut self, msg: XPCMessage) -> Result<(), IdeviceError> { + self.h2_client + .send(msg.encode(self.root_id)?, REPLY_CHANNEL) + .await?; + Ok(()) + } +} diff --git a/tools/src/core_device_proxy_tun.rs b/tools/src/core_device_proxy_tun.rs index 2f9b457..a6df7b1 100644 --- a/tools/src/core_device_proxy_tun.rs +++ b/tools/src/core_device_proxy_tun.rs @@ -96,7 +96,7 @@ async fn main() { println!("rsd port: {}", tun_proxy.handshake.server_rsd_port); println!("-----------------------------"); - let mut buf = vec![0; 1500]; + let mut buf = vec![0; 20_000]; // XPC is big lol loop { tokio::select! { Ok(len) = async_dev.recv(&mut buf) => { diff --git a/tools/src/remotexpc.rs b/tools/src/remotexpc.rs index 1b1be65..9aa5c4c 100644 --- a/tools/src/remotexpc.rs +++ b/tools/src/remotexpc.rs @@ -2,7 +2,7 @@ // Print out all the RemoteXPC services use clap::{Arg, Command}; -use idevice::{core_device_proxy::CoreDeviceProxy, xpc::XPCDevice, IdeviceService}; +use idevice::{core_device_proxy::CoreDeviceProxy, xpc::RemoteXpcClient, IdeviceService}; mod common; @@ -66,7 +66,7 @@ async fn main() { adapter.connect(rsd_port).await.expect("no RSD connect"); // Make the connection to RemoteXPC - let client = XPCDevice::new(Box::new(adapter)).await.unwrap(); + let mut client = RemoteXpcClient::new(Box::new(adapter)).await.unwrap(); - println!("{:#?}", client.services); + println!("{:#?}", client.do_handshake().await); }