Create new RSD service trait

This commit is contained in:
Jackson Coxson
2025-05-25 13:11:59 -06:00
parent 2a8a921951
commit a39cbd1d3d
9 changed files with 166 additions and 71 deletions

View File

@@ -25,7 +25,7 @@ pub use services::*;
pub use xpc::RemoteXpcClient;
use log::{debug, error, trace};
use provider::IdeviceProvider;
use provider::{IdeviceProvider, RsdProvider};
use rustls::{crypto::CryptoProvider, pki_types::ServerName};
use std::{
io::{self, BufWriter},
@@ -65,6 +65,25 @@ pub trait IdeviceService: Sized {
) -> impl std::future::Future<Output = Result<Self, IdeviceError>> + Send;
}
pub trait RsdService: Sized {
fn rsd_service_name() -> &'static str;
fn from_stream(
stream: Self::Stream,
) -> impl std::future::Future<Output = Result<Self, IdeviceError>> + Send;
fn connect_rsd<'a, S>(
provider: &'a mut impl RsdProvider<'a, Stream = S>,
handshake: &mut rsd::RsdHandshake,
) -> impl std::future::Future<Output = Result<Self, IdeviceError>>
where
Self: crate::RsdService<Stream = S>,
S: ReadWrite,
{
handshake.connect(provider)
}
type Stream: ReadWrite;
}
/// Type alias for boxed device connection sockets
///
/// Used to enable dynamic dispatch of different connection types while maintaining
@@ -424,6 +443,8 @@ pub enum IdeviceError {
HeartbeatTimeout,
#[error("not found")]
NotFound,
#[error("service not found")]
ServiceNotFound,
#[error("CDTunnel packet too short")]
CdtunnelPacketTooShort,
#[error("CDTunnel packet invalid magic")]

View File

@@ -8,7 +8,7 @@ use std::{future::Future, pin::Pin};
#[cfg(feature = "tcp")]
use tokio::net::TcpStream;
use crate::{pairing_file::PairingFile, Idevice, IdeviceError};
use crate::{pairing_file::PairingFile, Idevice, IdeviceError, ReadWrite};
#[cfg(feature = "usbmuxd")]
use crate::usbmuxd::UsbmuxdAddr;
@@ -42,6 +42,14 @@ pub trait IdeviceProvider: Unpin + Send + Sync + std::fmt::Debug {
) -> Pin<Box<dyn Future<Output = Result<PairingFile, IdeviceError>> + Send>>;
}
pub trait RsdProvider<'a>: Unpin + Send + Sync + std::fmt::Debug {
fn connect_to_service_port(
&'a mut self,
port: u16,
) -> impl std::future::Future<Output = Result<Self::Stream, IdeviceError>> + Send;
type Stream: ReadWrite;
}
/// TCP-based device connection provider
#[cfg(feature = "tcp")]
#[derive(Debug)]

View File

@@ -8,10 +8,22 @@ use log::debug;
use std::fmt::Write;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use crate::{IdeviceError, ReadWrite};
use crate::{IdeviceError, ReadWrite, RsdService};
/// The service name for the debug proxy as registered with lockdownd
pub const SERVICE_NAME: &str = "com.apple.internal.dt.remote.debugproxy";
impl<R: ReadWrite> RsdService for DebugProxyClient<R> {
fn rsd_service_name() -> &'static str {
"com.apple.internal.dt.remote.debugproxy"
}
async fn from_stream(stream: R) -> Result<Self, IdeviceError> {
Ok(Self {
socket: stream,
noack_mode: false,
})
}
type Stream = R;
}
/// Client for interacting with the iOS debug proxy service
///
@@ -300,4 +312,3 @@ impl From<&str> for DebugserverCommand {
s.to_string().into()
}
}

View File

@@ -1,9 +1,21 @@
// Jackson Coxson
use crate::{IdeviceError, ReadWrite, RsdService};
#[cfg(feature = "location_simulation")]
pub mod location_simulation;
pub mod message;
pub mod process_control;
pub mod remote_server;
pub const SERVICE_NAME: &str = "com.apple.instruments.dtservicehub";
impl<R: ReadWrite> RsdService for remote_server::RemoteServerClient<R> {
fn rsd_service_name() -> &'static str {
"com.apple.instruments.dtservicehub"
}
async fn from_stream(stream: R) -> Result<Self, IdeviceError> {
Ok(Self::new(stream))
}
type Stream = R;
}

View File

@@ -6,7 +6,7 @@ use std::collections::HashMap;
use log::warn;
use serde::Deserialize;
use crate::{IdeviceError, ReadWrite, RemoteXpcClient};
use crate::{provider::RsdProvider, IdeviceError, ReadWrite, RemoteXpcClient};
/// Describes an available XPC service
#[derive(Debug, Clone, Deserialize)]
@@ -23,21 +23,19 @@ pub struct RsdService {
pub service_version: Option<i64>,
}
pub struct RsdClient<R: ReadWrite> {
inner: RemoteXpcClient<R>,
pub struct RsdHandshake {
pub services: HashMap<String, RsdService>,
pub protocol_version: usize,
pub properties: HashMap<String, plist::Value>,
pub uuid: String,
}
impl<R: ReadWrite> RsdClient<R> {
pub async fn new(socket: R) -> Result<Self, IdeviceError> {
Ok(Self {
inner: RemoteXpcClient::new(socket).await?,
})
}
impl RsdHandshake {
pub async fn new(socket: impl ReadWrite) -> Result<Self, IdeviceError> {
let mut xpc_client = RemoteXpcClient::new(socket).await?;
let data = xpc_client.do_handshake().await?;
pub async fn get_services(&mut self) -> Result<HashMap<String, RsdService>, IdeviceError> {
let data = self.inner.do_handshake().await?;
let data = match data
let services_dict = match data
.as_dictionary()
.and_then(|x| x.get("Services"))
.and_then(|x| x.as_dictionary())
@@ -47,8 +45,8 @@ impl<R: ReadWrite> RsdClient<R> {
};
// Parse available services
let mut services = HashMap::new();
for (name, service) in data.into_iter() {
let mut services: HashMap<String, RsdService> = HashMap::new();
for (name, service) in services_dict.into_iter() {
match service.as_dictionary() {
Some(service) => {
let entitlement = match service.get("Entitlement").and_then(|x| x.as_string()) {
@@ -116,6 +114,64 @@ impl<R: ReadWrite> RsdClient<R> {
}
}
Ok(services)
let protocol_version = match data.as_dictionary().and_then(|x| {
x.get("MessagingProtocolVersion")
.and_then(|x| x.as_signed_integer())
}) {
Some(p) => p as usize,
None => {
return Err(IdeviceError::UnexpectedResponse);
}
};
let uuid = match data
.as_dictionary()
.and_then(|x| x.get("UUID").and_then(|x| x.as_string()))
{
Some(u) => u.to_string(),
None => {
return Err(IdeviceError::UnexpectedResponse);
}
};
let properties = match data
.as_dictionary()
.and_then(|x| x.get("Properties").and_then(|x| x.as_dictionary()))
{
Some(d) => d
.into_iter()
.map(|(name, prop)| (name.to_owned(), prop.to_owned()))
.collect::<HashMap<String, plist::Value>>(),
None => {
return Err(IdeviceError::UnexpectedResponse);
}
};
Ok(Self {
services,
protocol_version,
properties,
uuid,
})
}
pub async fn connect<'a, T, S>(
&mut self,
provider: &'a mut impl RsdProvider<'a, Stream = S>,
) -> Result<T, IdeviceError>
where
T: crate::RsdService<Stream = S>,
S: ReadWrite,
{
let service_name = T::rsd_service_name();
let service = match self.services.get(service_name) {
Some(s) => s,
None => {
return Err(IdeviceError::ServiceNotFound);
}
};
let stream = provider.connect_to_service_port(service.port).await?;
T::from_stream(stream).await
}
}

View File

@@ -6,8 +6,11 @@ use std::{
};
use log::debug;
use stream::AdapterStream;
use tokio::io::AsyncWriteExt;
use crate::provider::RsdProvider;
pub mod adapter;
pub mod packets;
pub mod stream;
@@ -36,6 +39,18 @@ pub(crate) fn log_packet(file: &Arc<tokio::sync::Mutex<tokio::fs::File>>, packet
});
}
impl<'a> RsdProvider<'a> for adapter::Adapter {
async fn connect_to_service_port(
&'a mut self,
port: u16,
) -> Result<stream::AdapterStream<'a>, crate::IdeviceError> {
let s = stream::AdapterStream::connect(self, port).await?;
Ok(s)
}
type Stream = AdapterStream<'a>;
}
#[cfg(test)]
mod tests {
use std::{

View File

@@ -4,8 +4,8 @@ use std::io::Write;
use clap::{Arg, Command};
use idevice::{
core_device_proxy::CoreDeviceProxy, debug_proxy::DebugProxyClient, rsd::RsdClient,
tcp::stream::AdapterStream, IdeviceService,
core_device_proxy::CoreDeviceProxy, debug_proxy::DebugProxyClient, rsd::RsdHandshake,
tcp::stream::AdapterStream, IdeviceService, RsdService,
};
mod common;
@@ -77,22 +77,12 @@ async fn main() {
.expect("no RSD connect");
// Make the connection to RemoteXPC
let mut client = RsdClient::new(stream).await.unwrap();
let mut handshake = RsdHandshake::new(stream).await.unwrap();
println!("{:?}", handshake.services);
// Get the debug proxy
let service = client
.get_services()
let mut dp = DebugProxyClient::connect_rsd(&mut adapter, &mut handshake)
.await
.unwrap()
.get(idevice::debug_proxy::SERVICE_NAME)
.expect("Client did not contain debug proxy service")
.to_owned();
let stream = AdapterStream::connect(&mut adapter, service.port)
.await
.unwrap();
let mut dp = DebugProxyClient::new(stream);
.expect("no connect");
println!("Shell connected!");
loop {

View File

@@ -3,7 +3,8 @@
use clap::{Arg, Command};
use idevice::{
core_device_proxy::CoreDeviceProxy, rsd::RsdClient, tcp::stream::AdapterStream, IdeviceService,
core_device_proxy::CoreDeviceProxy, rsd::RsdHandshake, tcp::stream::AdapterStream,
IdeviceService, RsdService,
};
mod common;
@@ -76,22 +77,12 @@ async fn main() {
.expect("no RSD connect");
// Make the connection to RemoteXPC
let mut client = RsdClient::new(stream).await.unwrap();
let mut handshake = RsdHandshake::new(stream).await.unwrap();
// Get the debug proxy
let service = client
.get_services()
let mut ls_client =
idevice::dvt::remote_server::RemoteServerClient::connect_rsd(&mut adapter, &mut handshake)
.await
.unwrap()
.get(idevice::dvt::SERVICE_NAME)
.expect("Client did not contain DVT service")
.to_owned();
let stream = AdapterStream::connect(&mut adapter, service.port)
.await
.unwrap();
let mut ls_client = idevice::dvt::remote_server::RemoteServerClient::new(stream);
.expect("Failed to connect");
ls_client.read_message(0).await.expect("no read??");
let mut ls_client =

View File

@@ -2,7 +2,8 @@
use clap::{Arg, Command};
use idevice::{
core_device_proxy::CoreDeviceProxy, rsd::RsdClient, tcp::stream::AdapterStream, IdeviceService,
core_device_proxy::CoreDeviceProxy, rsd::RsdHandshake, tcp::stream::AdapterStream,
IdeviceService, RsdService,
};
mod common;
@@ -84,22 +85,12 @@ async fn main() {
.expect("no RSD connect");
// Make the connection to RemoteXPC
let mut client = RsdClient::new(stream).await.unwrap();
let mut handshake = RsdHandshake::new(stream).await.unwrap();
// Get the debug proxy
let service = client
.get_services()
let mut rs_client =
idevice::dvt::remote_server::RemoteServerClient::connect_rsd(&mut adapter, &mut handshake)
.await
.unwrap()
.get(idevice::dvt::SERVICE_NAME)
.expect("Client did not contain DVT service")
.to_owned();
let stream = AdapterStream::connect(&mut adapter, service.port)
.await
.unwrap();
let mut rs_client = idevice::dvt::remote_server::RemoteServerClient::new(stream);
.expect("no connect");
rs_client.read_message(0).await.expect("no read??");
let mut pc_client = idevice::dvt::process_control::ProcessControlClient::new(&mut rs_client)
.await