mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 14:36:16 +01:00
Create new RSD service trait
This commit is contained in:
@@ -25,7 +25,7 @@ pub use services::*;
|
|||||||
pub use xpc::RemoteXpcClient;
|
pub use xpc::RemoteXpcClient;
|
||||||
|
|
||||||
use log::{debug, error, trace};
|
use log::{debug, error, trace};
|
||||||
use provider::IdeviceProvider;
|
use provider::{IdeviceProvider, RsdProvider};
|
||||||
use rustls::{crypto::CryptoProvider, pki_types::ServerName};
|
use rustls::{crypto::CryptoProvider, pki_types::ServerName};
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, BufWriter},
|
io::{self, BufWriter},
|
||||||
@@ -65,6 +65,25 @@ pub trait IdeviceService: Sized {
|
|||||||
) -> impl std::future::Future<Output = Result<Self, IdeviceError>> + Send;
|
) -> 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
|
/// Type alias for boxed device connection sockets
|
||||||
///
|
///
|
||||||
/// Used to enable dynamic dispatch of different connection types while maintaining
|
/// Used to enable dynamic dispatch of different connection types while maintaining
|
||||||
@@ -424,6 +443,8 @@ pub enum IdeviceError {
|
|||||||
HeartbeatTimeout,
|
HeartbeatTimeout,
|
||||||
#[error("not found")]
|
#[error("not found")]
|
||||||
NotFound,
|
NotFound,
|
||||||
|
#[error("service not found")]
|
||||||
|
ServiceNotFound,
|
||||||
#[error("CDTunnel packet too short")]
|
#[error("CDTunnel packet too short")]
|
||||||
CdtunnelPacketTooShort,
|
CdtunnelPacketTooShort,
|
||||||
#[error("CDTunnel packet invalid magic")]
|
#[error("CDTunnel packet invalid magic")]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::{future::Future, pin::Pin};
|
|||||||
#[cfg(feature = "tcp")]
|
#[cfg(feature = "tcp")]
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
use crate::{pairing_file::PairingFile, Idevice, IdeviceError};
|
use crate::{pairing_file::PairingFile, Idevice, IdeviceError, ReadWrite};
|
||||||
|
|
||||||
#[cfg(feature = "usbmuxd")]
|
#[cfg(feature = "usbmuxd")]
|
||||||
use crate::usbmuxd::UsbmuxdAddr;
|
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>>;
|
) -> 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
|
/// TCP-based device connection provider
|
||||||
#[cfg(feature = "tcp")]
|
#[cfg(feature = "tcp")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -8,10 +8,22 @@ use log::debug;
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
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
|
impl<R: ReadWrite> RsdService for DebugProxyClient<R> {
|
||||||
pub const SERVICE_NAME: &str = "com.apple.internal.dt.remote.debugproxy";
|
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
|
/// Client for interacting with the iOS debug proxy service
|
||||||
///
|
///
|
||||||
@@ -300,4 +312,3 @@ impl From<&str> for DebugserverCommand {
|
|||||||
s.to_string().into()
|
s.to_string().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
// Jackson Coxson
|
// Jackson Coxson
|
||||||
|
|
||||||
|
use crate::{IdeviceError, ReadWrite, RsdService};
|
||||||
|
|
||||||
#[cfg(feature = "location_simulation")]
|
#[cfg(feature = "location_simulation")]
|
||||||
pub mod location_simulation;
|
pub mod location_simulation;
|
||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod process_control;
|
pub mod process_control;
|
||||||
pub mod remote_server;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::collections::HashMap;
|
|||||||
use log::warn;
|
use log::warn;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{IdeviceError, ReadWrite, RemoteXpcClient};
|
use crate::{provider::RsdProvider, IdeviceError, ReadWrite, RemoteXpcClient};
|
||||||
|
|
||||||
/// Describes an available XPC service
|
/// Describes an available XPC service
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
@@ -23,21 +23,19 @@ pub struct RsdService {
|
|||||||
pub service_version: Option<i64>,
|
pub service_version: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RsdClient<R: ReadWrite> {
|
pub struct RsdHandshake {
|
||||||
inner: RemoteXpcClient<R>,
|
pub services: HashMap<String, RsdService>,
|
||||||
|
pub protocol_version: usize,
|
||||||
|
pub properties: HashMap<String, plist::Value>,
|
||||||
|
pub uuid: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: ReadWrite> RsdClient<R> {
|
impl RsdHandshake {
|
||||||
pub async fn new(socket: R) -> Result<Self, IdeviceError> {
|
pub async fn new(socket: impl ReadWrite) -> Result<Self, IdeviceError> {
|
||||||
Ok(Self {
|
let mut xpc_client = RemoteXpcClient::new(socket).await?;
|
||||||
inner: RemoteXpcClient::new(socket).await?,
|
let data = xpc_client.do_handshake().await?;
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_services(&mut self) -> Result<HashMap<String, RsdService>, IdeviceError> {
|
let services_dict = match data
|
||||||
let data = self.inner.do_handshake().await?;
|
|
||||||
|
|
||||||
let data = match data
|
|
||||||
.as_dictionary()
|
.as_dictionary()
|
||||||
.and_then(|x| x.get("Services"))
|
.and_then(|x| x.get("Services"))
|
||||||
.and_then(|x| x.as_dictionary())
|
.and_then(|x| x.as_dictionary())
|
||||||
@@ -47,8 +45,8 @@ impl<R: ReadWrite> RsdClient<R> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Parse available services
|
// Parse available services
|
||||||
let mut services = HashMap::new();
|
let mut services: HashMap<String, RsdService> = HashMap::new();
|
||||||
for (name, service) in data.into_iter() {
|
for (name, service) in services_dict.into_iter() {
|
||||||
match service.as_dictionary() {
|
match service.as_dictionary() {
|
||||||
Some(service) => {
|
Some(service) => {
|
||||||
let entitlement = match service.get("Entitlement").and_then(|x| x.as_string()) {
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,11 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
use stream::AdapterStream;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
|
use crate::provider::RsdProvider;
|
||||||
|
|
||||||
pub mod adapter;
|
pub mod adapter;
|
||||||
pub mod packets;
|
pub mod packets;
|
||||||
pub mod stream;
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{
|
use std::{
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ use std::io::Write;
|
|||||||
|
|
||||||
use clap::{Arg, Command};
|
use clap::{Arg, Command};
|
||||||
use idevice::{
|
use idevice::{
|
||||||
core_device_proxy::CoreDeviceProxy, debug_proxy::DebugProxyClient, rsd::RsdClient,
|
core_device_proxy::CoreDeviceProxy, debug_proxy::DebugProxyClient, rsd::RsdHandshake,
|
||||||
tcp::stream::AdapterStream, IdeviceService,
|
tcp::stream::AdapterStream, IdeviceService, RsdService,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
@@ -77,22 +77,12 @@ async fn main() {
|
|||||||
.expect("no RSD connect");
|
.expect("no RSD connect");
|
||||||
|
|
||||||
// Make the connection to RemoteXPC
|
// 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 mut dp = DebugProxyClient::connect_rsd(&mut adapter, &mut handshake)
|
||||||
let service = client
|
|
||||||
.get_services()
|
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.expect("no connect");
|
||||||
.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);
|
|
||||||
|
|
||||||
println!("Shell connected!");
|
println!("Shell connected!");
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
use clap::{Arg, Command};
|
use clap::{Arg, Command};
|
||||||
use idevice::{
|
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;
|
mod common;
|
||||||
@@ -76,22 +77,12 @@ async fn main() {
|
|||||||
.expect("no RSD connect");
|
.expect("no RSD connect");
|
||||||
|
|
||||||
// Make the connection to RemoteXPC
|
// 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 mut ls_client =
|
||||||
let service = client
|
idevice::dvt::remote_server::RemoteServerClient::connect_rsd(&mut adapter, &mut handshake)
|
||||||
.get_services()
|
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.expect("Failed to connect");
|
||||||
.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);
|
|
||||||
ls_client.read_message(0).await.expect("no read??");
|
ls_client.read_message(0).await.expect("no read??");
|
||||||
|
|
||||||
let mut ls_client =
|
let mut ls_client =
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
use clap::{Arg, Command};
|
use clap::{Arg, Command};
|
||||||
use idevice::{
|
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;
|
mod common;
|
||||||
@@ -84,22 +85,12 @@ async fn main() {
|
|||||||
.expect("no RSD connect");
|
.expect("no RSD connect");
|
||||||
|
|
||||||
// Make the connection to RemoteXPC
|
// 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 mut rs_client =
|
||||||
let service = client
|
idevice::dvt::remote_server::RemoteServerClient::connect_rsd(&mut adapter, &mut handshake)
|
||||||
.get_services()
|
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.expect("no connect");
|
||||||
.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);
|
|
||||||
rs_client.read_message(0).await.expect("no read??");
|
rs_client.read_message(0).await.expect("no read??");
|
||||||
let mut pc_client = idevice::dvt::process_control::ProcessControlClient::new(&mut rs_client)
|
let mut pc_client = idevice::dvt::process_control::ProcessControlClient::new(&mut rs_client)
|
||||||
.await
|
.await
|
||||||
|
|||||||
Reference in New Issue
Block a user