diff --git a/idevice/src/services/mod.rs b/idevice/src/services/mod.rs index e5e3c91..a4d520d 100644 --- a/idevice/src/services/mod.rs +++ b/idevice/src/services/mod.rs @@ -47,3 +47,6 @@ pub mod screenshotr; pub mod springboardservices; #[cfg(feature = "syslog_relay")] pub mod syslog_relay; + +#[cfg(feature = "location_simulation")] +pub mod simulate_location; diff --git a/idevice/src/services/simulate_location.rs b/idevice/src/services/simulate_location.rs new file mode 100644 index 0000000..dd78f64 --- /dev/null +++ b/idevice/src/services/simulate_location.rs @@ -0,0 +1,38 @@ +use crate::{Idevice, IdeviceError, IdeviceService, obf}; + +pub struct LocationSimulationService { + idevice: Idevice, +} + +impl IdeviceService for LocationSimulationService { + fn service_name() -> std::borrow::Cow<'static, str> { + obf!("com.apple.dt.simulatelocation") + } + + async fn from_stream(idevice: Idevice) -> Result { + Ok(Self::new(idevice)) + } +} + +impl LocationSimulationService { + pub fn new(idevice: Idevice) -> Self { + Self { idevice } + } + + pub async fn clear(&mut self) -> Result<(), IdeviceError> { + let message: [u8; 4] = [0x00, 0x00, 0x00, 0x01]; + self.idevice.send_raw(&message).await?; + Ok(()) + } + + pub async fn set(&mut self, latitude: &str, longtiude: &str) -> Result<(), IdeviceError> { + let message: [u8; 4] = [0x00, 0x00, 0x00, 0x00]; + let latitude_len = latitude.len() as u32; + let longtiude_len = longtiude.len() as u32; + let latitude_bytes = [&latitude_len.to_be_bytes(), latitude.as_bytes()].concat(); + let longitude_bytes = [&longtiude_len.to_be_bytes(), longtiude.as_bytes()].concat(); + let data = [&message[..], &latitude_bytes[..], &longitude_bytes[..]].concat(); + self.idevice.send_raw(data.as_slice()).await?; + Ok(()) + } +} diff --git a/tools/src/location_simulation.rs b/tools/src/location_simulation.rs index c017fbb..2f0a128 100644 --- a/tools/src/location_simulation.rs +++ b/tools/src/location_simulation.rs @@ -4,6 +4,8 @@ use clap::{Arg, Command}; use idevice::{IdeviceService, RsdService, core_device_proxy::CoreDeviceProxy, rsd::RsdHandshake}; +use idevice::dvt::location_simulation::LocationSimulationClient; +use idevice::services::simulate_location::LocationSimulationService; mod common; #[tokio::main] @@ -63,65 +65,103 @@ async fn main() { return; } }; - let proxy = CoreDeviceProxy::connect(&*provider) + + if let Ok(proxy) = CoreDeviceProxy::connect(&*provider).await { + let rsd_port = proxy.handshake.server_rsd_port; + + let adapter = proxy.create_software_tunnel().expect("no software tunnel"); + let mut adapter = adapter.to_async_handle(); + let stream = adapter.connect(rsd_port).await.expect("no RSD connect"); + + // Make the connection to RemoteXPC + let mut handshake = RsdHandshake::new(stream).await.unwrap(); + + let mut ls_client = idevice::dvt::remote_server::RemoteServerClient::connect_rsd( + &mut adapter, + &mut handshake, + ) .await - .expect("no core proxy"); - let rsd_port = proxy.handshake.server_rsd_port; - - let adapter = proxy.create_software_tunnel().expect("no software tunnel"); - let mut adapter = adapter.to_async_handle(); - let stream = adapter.connect(rsd_port).await.expect("no RSD connect"); - - // Make the connection to RemoteXPC - let mut handshake = RsdHandshake::new(stream).await.unwrap(); - - let mut ls_client = - idevice::dvt::remote_server::RemoteServerClient::connect_rsd(&mut adapter, &mut handshake) - .await - .expect("Failed to connect"); - ls_client.read_message(0).await.expect("no read??"); - - let mut ls_client = - idevice::dvt::location_simulation::LocationSimulationClient::new(&mut ls_client) + .expect("Failed to connect"); + ls_client.read_message(0).await.expect("no read??"); + let mut ls_client = LocationSimulationClient::new(&mut ls_client) .await .expect("Unable to get channel for location simulation"); - - if matches.subcommand_matches("clear").is_some() { - ls_client.clear().await.expect("Unable to clear"); - println!("Location cleared!"); - } else if let Some(matches) = matches.subcommand_matches("set") { - let latitude: &String = match matches.get_one("latitude") { - Some(l) => l, - None => { - eprintln!("No latitude passed! Pass -h for help"); - return; - } - }; - let latitude: f64 = latitude.parse().expect("Failed to parse as float"); - let longitude: &String = match matches.get_one("longitude") { - Some(l) => l, - None => { - eprintln!("No longitude passed! Pass -h for help"); - return; - } - }; - let longitude: f64 = longitude.parse().expect("Failed to parse as float"); - ls_client - .set(latitude, longitude) - .await - .expect("Failed to set location"); - - println!("Location set!"); - println!("Press ctrl-c to stop"); - loop { + if matches.subcommand_matches("clear").is_some() { + ls_client.clear().await.expect("Unable to clear"); + println!("Location cleared!"); + } else if let Some(matches) = matches.subcommand_matches("set") { + let latitude: &String = match matches.get_one("latitude") { + Some(l) => l, + None => { + eprintln!("No latitude passed! Pass -h for help"); + return; + } + }; + let latitude: f64 = latitude.parse().expect("Failed to parse as float"); + let longitude: &String = match matches.get_one("longitude") { + Some(l) => l, + None => { + eprintln!("No longitude passed! Pass -h for help"); + return; + } + }; + let longitude: f64 = longitude.parse().expect("Failed to parse as float"); ls_client .set(latitude, longitude) .await .expect("Failed to set location"); - tokio::time::sleep(std::time::Duration::from_secs(5)).await; + + println!("Location set!"); + println!("Press ctrl-c to stop"); + loop { + ls_client + .set(latitude, longitude) + .await + .expect("Failed to set location"); + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + } + } else { + eprintln!("Invalid usage, pass -h for help"); } } else { - eprintln!("Invalid usage, pass -h for help"); - } + let mut location_client = match LocationSimulationService::connect(&*provider).await { + Ok(client) => client, + Err(e) => { + eprintln!( + "Unable to connect to simulate_location service: {e} Ensure Developer Disk Image is mounted." + ); + return; + } + }; + if matches.subcommand_matches("clear").is_some() { + location_client.clear().await.expect("Unable to clear"); + println!("Location cleared!"); + } else if let Some(matches) = matches.subcommand_matches("set") { + let latitude: &String = match matches.get_one("latitude") { + Some(l) => l, + None => { + eprintln!("No latitude passed! Pass -h for help"); + return; + } + }; + + let longitude: &String = match matches.get_one("longitude") { + Some(l) => l, + None => { + eprintln!("No longitude passed! Pass -h for help"); + return; + } + }; + location_client + .set(latitude, longitude) + .await + .expect("Failed to set location"); + + println!("Location set!"); + } else { + eprintln!("Invalid usage, pass -h for help"); + } + }; + return; }