mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 14:36:16 +01:00
Implement openstdiosocket
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
use log::warn;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{IdeviceError, ReadWrite, RsdService, obf};
|
||||
use crate::{IdeviceError, ReadWrite, RsdService, obf, xpc::XPCObject};
|
||||
|
||||
use super::CoreDeviceServiceClient;
|
||||
|
||||
@@ -152,7 +152,7 @@ impl<R: ReadWrite> AppServiceClient<R> {
|
||||
});
|
||||
let res = self
|
||||
.inner
|
||||
.invoke("com.apple.coredevice.feature.listapps", Some(options))
|
||||
.invoke_with_plist("com.apple.coredevice.feature.listapps", options)
|
||||
.await?;
|
||||
|
||||
let res = match res.as_array() {
|
||||
@@ -178,6 +178,16 @@ impl<R: ReadWrite> AppServiceClient<R> {
|
||||
Ok(desd)
|
||||
}
|
||||
|
||||
/// Launches an application by a bundle ID.
|
||||
///
|
||||
/// # Notes
|
||||
/// * `start_suspended` - If set to true, you will need to attach a debugger using
|
||||
/// `DebugServer` to continue.
|
||||
///
|
||||
/// * `stdio_uuid` - Create a new ``OpenStdioSocketClient``, read the UUID, and pass it to this
|
||||
/// function. Note that if the process already has another stdio UUID, this parameter is ignored by
|
||||
/// iOS. Either make sure the proccess isn't running, or pass ``kill_existing: true``
|
||||
#[allow(clippy::too_many_arguments)] // still didn't ask
|
||||
pub async fn launch_application(
|
||||
&mut self,
|
||||
bundle_id: impl Into<String>,
|
||||
@@ -186,6 +196,7 @@ impl<R: ReadWrite> AppServiceClient<R> {
|
||||
start_suspended: bool,
|
||||
environment: Option<plist::Dictionary>,
|
||||
platform_options: Option<plist::Dictionary>,
|
||||
stdio_uuid: Option<uuid::Uuid>,
|
||||
) -> Result<LaunchResponse, IdeviceError> {
|
||||
let bundle_id = bundle_id.into();
|
||||
|
||||
@@ -196,20 +207,34 @@ impl<R: ReadWrite> AppServiceClient<R> {
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"arguments": arguments, // Now this will work directly
|
||||
"arguments": arguments,
|
||||
"environmentVariables": environment.unwrap_or_default(),
|
||||
"standardIOUsesPseudoterminals": true,
|
||||
"startStopped": start_suspended,
|
||||
"terminateExisting": kill_existing,
|
||||
"user": {
|
||||
"shortName": "mobile"
|
||||
"active": true,
|
||||
},
|
||||
"platformSpecificOptions": plist::Value::Data(crate::util::plist_to_xml_bytes(&platform_options.unwrap_or_default())),
|
||||
},
|
||||
"standardIOIdentifiers": {}
|
||||
})
|
||||
.into_dictionary()
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
let req: XPCObject = req.into();
|
||||
let mut req = req.to_dictionary().unwrap();
|
||||
req.insert(
|
||||
"standardIOIdentifiers".into(),
|
||||
match stdio_uuid {
|
||||
Some(u) => {
|
||||
let u = XPCObject::Uuid(u);
|
||||
let mut d = crate::xpc::Dictionary::new();
|
||||
d.insert("standardInput".into(), u.clone());
|
||||
d.insert("standardOutput".into(), u.clone());
|
||||
d.insert("standardError".into(), u.clone());
|
||||
d.into()
|
||||
}
|
||||
None => crate::xpc::Dictionary::new().into(),
|
||||
},
|
||||
);
|
||||
|
||||
let res = self
|
||||
.inner
|
||||
@@ -259,13 +284,11 @@ impl<R: ReadWrite> AppServiceClient<R> {
|
||||
) -> Result<(), IdeviceError> {
|
||||
let bundle_id = bundle_id.into();
|
||||
self.inner
|
||||
.invoke(
|
||||
.invoke_with_plist(
|
||||
"com.apple.coredevice.feature.uninstallapp",
|
||||
Some(
|
||||
crate::plist!({"bundleIdentifier": bundle_id})
|
||||
.into_dictionary()
|
||||
.unwrap(),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -279,16 +302,14 @@ impl<R: ReadWrite> AppServiceClient<R> {
|
||||
) -> Result<SignalResponse, IdeviceError> {
|
||||
let res = self
|
||||
.inner
|
||||
.invoke(
|
||||
.invoke_with_plist(
|
||||
"com.apple.coredevice.feature.sendsignaltoprocess",
|
||||
Some(
|
||||
crate::plist!({
|
||||
"process": { "processIdentifier": pid as i64},
|
||||
"signal": signal as i64,
|
||||
})
|
||||
.into_dictionary()
|
||||
.unwrap(),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -314,9 +335,8 @@ impl<R: ReadWrite> AppServiceClient<R> {
|
||||
let bundle_id = bundle_id.into();
|
||||
let res = self
|
||||
.inner
|
||||
.invoke(
|
||||
.invoke_with_plist(
|
||||
"com.apple.coredevice.feature.fetchappicons",
|
||||
Some(
|
||||
crate::plist!({
|
||||
"width": width,
|
||||
"height": height,
|
||||
@@ -326,7 +346,6 @@ impl<R: ReadWrite> AppServiceClient<R> {
|
||||
})
|
||||
.into_dictionary()
|
||||
.unwrap(),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ impl<R: ReadWrite> DiagnostisServiceClient<R> {
|
||||
|
||||
let res = self
|
||||
.inner
|
||||
.invoke("com.apple.coredevice.feature.capturesysdiagnose", Some(req))
|
||||
.invoke_with_plist("com.apple.coredevice.feature.capturesysdiagnose", req)
|
||||
.await?;
|
||||
|
||||
if let Some(len) = res
|
||||
|
||||
@@ -10,8 +10,10 @@ use crate::{
|
||||
|
||||
mod app_service;
|
||||
mod diagnosticsservice;
|
||||
mod openstdiosocket;
|
||||
pub use app_service::*;
|
||||
pub use diagnosticsservice::*;
|
||||
pub use openstdiosocket::*;
|
||||
|
||||
const CORE_SERVICE_VERSION: &str = "443.18";
|
||||
|
||||
@@ -26,13 +28,26 @@ impl<R: ReadWrite> CoreDeviceServiceClient<R> {
|
||||
Ok(Self { inner: client })
|
||||
}
|
||||
|
||||
pub async fn invoke_with_plist(
|
||||
&mut self,
|
||||
feature: impl Into<String>,
|
||||
input: plist::Dictionary,
|
||||
) -> Result<plist::Value, IdeviceError> {
|
||||
let input: XPCObject = plist::Value::Dictionary(input).into();
|
||||
let input = input.to_dictionary().unwrap();
|
||||
self.invoke(feature, Some(input)).await
|
||||
}
|
||||
|
||||
pub async fn invoke(
|
||||
&mut self,
|
||||
feature: impl Into<String>,
|
||||
input: Option<plist::Dictionary>,
|
||||
input: Option<crate::xpc::Dictionary>,
|
||||
) -> Result<plist::Value, IdeviceError> {
|
||||
let feature = feature.into();
|
||||
let input = input.unwrap_or_default();
|
||||
let input: crate::xpc::XPCObject = match input {
|
||||
Some(i) => i.into(),
|
||||
None => crate::xpc::Dictionary::new().into(),
|
||||
};
|
||||
|
||||
let mut req = xpc::Dictionary::new();
|
||||
req.insert(
|
||||
@@ -52,10 +67,7 @@ impl<R: ReadWrite> CoreDeviceServiceClient<R> {
|
||||
"CoreDevice.featureIdentifier".into(),
|
||||
XPCObject::String(feature),
|
||||
);
|
||||
req.insert(
|
||||
"CoreDevice.input".into(),
|
||||
plist::Value::Dictionary(input).into(),
|
||||
);
|
||||
req.insert("CoreDevice.input".into(), input);
|
||||
req.insert(
|
||||
"CoreDevice.invocationIdentifier".into(),
|
||||
XPCObject::String(uuid::Uuid::new_v4().to_string()),
|
||||
|
||||
33
idevice/src/services/core_device/openstdiosocket.rs
Normal file
33
idevice/src/services/core_device/openstdiosocket.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
// Jackson Coxson
|
||||
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
use crate::{IdeviceError, ReadWrite, RsdService, obf};
|
||||
|
||||
impl RsdService for OpenStdioSocketClient {
|
||||
fn rsd_service_name() -> std::borrow::Cow<'static, str> {
|
||||
obf!("com.apple.coredevice.openstdiosocket")
|
||||
}
|
||||
|
||||
async fn from_stream(stream: Box<dyn ReadWrite>) -> Result<Self, IdeviceError> {
|
||||
Ok(Self { inner: stream })
|
||||
}
|
||||
}
|
||||
|
||||
/// Call ``read_uuid`` to get the UUID. Pass that to app service launch to connect to the stream of
|
||||
/// the launched app. Inner is exposed to read and write to, using Tokio's AsyncReadExt/AsyncWriteExt
|
||||
pub struct OpenStdioSocketClient {
|
||||
pub inner: Box<dyn ReadWrite>,
|
||||
}
|
||||
|
||||
impl OpenStdioSocketClient {
|
||||
/// iOS assigns a UUID to a newly opened stream. That UUID is then passed to the launch
|
||||
/// parameters of app service to start a stream.
|
||||
pub async fn read_uuid(&mut self) -> Result<uuid::Uuid, IdeviceError> {
|
||||
let mut buf = [0u8; 16];
|
||||
self.inner.read_exact(&mut buf).await?;
|
||||
|
||||
let res = uuid::Uuid::from_bytes(buf);
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user