mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 06:26:15 +01:00
Add cpp bindings for image mounter
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -1825,9 +1825,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "plist_ffi"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a5ca928241bc2e8c5fd28b81772962389efdbfcb71dfc9ec694369e063cb3a"
|
||||
checksum = "35ed070b06d9f2fdd7e816ef784fb07b09672f2acf37527f810dbedf450b7769"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"cc",
|
||||
|
||||
230
cpp/examples/mounter.cpp
Normal file
230
cpp/examples/mounter.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Idevice++ library headers
|
||||
#include <idevice++/lockdown.hpp>
|
||||
#include <idevice++/mobile_image_mounter.hpp>
|
||||
#include <idevice++/provider.hpp>
|
||||
#include <idevice++/usbmuxd.hpp>
|
||||
#include <plist/plist++.h>
|
||||
|
||||
// --- Helper Functions ---
|
||||
|
||||
/**
|
||||
* @brief Reads an entire file into a byte vector.
|
||||
* @param path The path to the file.
|
||||
* @return A vector containing the file's data.
|
||||
*/
|
||||
std::vector<uint8_t> read_file(const std::string& path) {
|
||||
std::ifstream file(path, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
throw std::runtime_error("Failed to open file: " + path);
|
||||
}
|
||||
std::streamsize size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
std::vector<uint8_t> buffer(size);
|
||||
if (!file.read(reinterpret_cast<char*>(buffer.data()), size)) {
|
||||
throw std::runtime_error("Failed to read file: " + path);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prints the command usage instructions.
|
||||
*/
|
||||
void print_usage(const char* prog_name) {
|
||||
std::cerr << "Usage: " << prog_name << " [options] <subcommand>\n\n"
|
||||
<< "A tool to manage developer images on a device.\n\n"
|
||||
<< "Options:\n"
|
||||
<< " --udid <UDID> Target a specific device by its UDID.\n\n"
|
||||
<< "Subcommands:\n"
|
||||
<< " list List mounted images.\n"
|
||||
<< " unmount Unmount the developer image.\n"
|
||||
<< " mount [mount_options] Mount a developer image.\n\n"
|
||||
<< "Mount Options:\n"
|
||||
<< " --image <path> (Required) Path to the DeveloperDiskImage.dmg.\n"
|
||||
<< " --signature <path> (Required for iOS < 17) Path to the .signature file.\n"
|
||||
<< " --manifest <path> (Required for iOS 17+) Path to the BuildManifest.plist.\n"
|
||||
<< " --trustcache <path> (Required for iOS 17+) Path to the trust cache file.\n"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// --- Main Logic ---
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
idevice_init_logger(Debug, Disabled, NULL);
|
||||
// --- 1. Argument Parsing ---
|
||||
if (argc < 2) {
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string udid_arg;
|
||||
std::string subcommand;
|
||||
std::string image_path;
|
||||
std::string signature_path;
|
||||
std::string manifest_path;
|
||||
std::string trustcache_path;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string arg = argv[i];
|
||||
if (arg == "--udid" && i + 1 < argc) {
|
||||
udid_arg = argv[++i];
|
||||
} else if (arg == "--image" && i + 1 < argc) {
|
||||
image_path = argv[++i];
|
||||
} else if (arg == "--signature" && i + 1 < argc) {
|
||||
signature_path = argv[++i];
|
||||
} else if (arg == "--manifest" && i + 1 < argc) {
|
||||
manifest_path = argv[++i];
|
||||
} else if (arg == "--trustcache" && i + 1 < argc) {
|
||||
trustcache_path = argv[++i];
|
||||
} else if (arg == "list" || arg == "mount" || arg == "unmount") {
|
||||
subcommand = arg;
|
||||
} else if (arg == "--help" || arg == "-h") {
|
||||
print_usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (subcommand.empty()) {
|
||||
std::cerr << "Error: No subcommand specified. Use 'list', 'mount', or 'unmount'."
|
||||
<< std::endl;
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
// --- 2. Device Connection ---
|
||||
auto u =
|
||||
IdeviceFFI::UsbmuxdConnection::default_new(0).expect("Failed to connect to usbmuxd");
|
||||
auto devices = u.get_devices().expect("Failed to get devices from usbmuxd");
|
||||
if (devices.empty()) {
|
||||
throw std::runtime_error("No devices connected.");
|
||||
}
|
||||
|
||||
IdeviceFFI::UsbmuxdDevice* target_dev = nullptr;
|
||||
if (!udid_arg.empty()) {
|
||||
for (auto& dev : devices) {
|
||||
if (dev.get_udid().unwrap_or("") == udid_arg) {
|
||||
target_dev = &dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!target_dev) {
|
||||
throw std::runtime_error("Device with UDID " + udid_arg + " not found.");
|
||||
}
|
||||
} else {
|
||||
target_dev = &devices[0]; // Default to the first device
|
||||
}
|
||||
|
||||
auto udid = target_dev->get_udid().expect("Device has no UDID");
|
||||
auto id = target_dev->get_id().expect("Device has no ID");
|
||||
|
||||
IdeviceFFI::UsbmuxdAddr addr = IdeviceFFI::UsbmuxdAddr::default_new();
|
||||
auto prov = IdeviceFFI::Provider::usbmuxd_new(std::move(addr), 0, udid, id, "mounter-tool")
|
||||
.expect("Failed to create provider");
|
||||
|
||||
// --- 3. Connect to Lockdown & Get iOS Version ---
|
||||
auto lockdown_client =
|
||||
IdeviceFFI::Lockdown::connect(prov).expect("Lockdown connect failed");
|
||||
|
||||
auto pairing_file = prov.get_pairing_file().expect("Failed to get pairing file");
|
||||
lockdown_client.start_session(pairing_file).expect("Failed to start session");
|
||||
|
||||
auto version_plist = lockdown_client.get_value("ProductVersion", NULL)
|
||||
.expect("Failed to get ProductVersion");
|
||||
PList::String version_node(version_plist);
|
||||
std::string version_str = version_node.GetValue();
|
||||
std::cout << "Version string: " << version_str << std::endl;
|
||||
|
||||
if (version_str.empty()) {
|
||||
throw std::runtime_error(
|
||||
"Failed to get a valid ProductVersion string from the device.");
|
||||
}
|
||||
int major_version = std::stoi(version_str);
|
||||
|
||||
// --- 4. Connect to MobileImageMounter ---
|
||||
auto mounter_client = IdeviceFFI::MobileImageMounter::connect(prov).expect(
|
||||
"Failed to connect to image mounter");
|
||||
|
||||
// --- 5. Execute Subcommand ---
|
||||
if (subcommand == "list") {
|
||||
auto images = mounter_client.copy_devices().expect("Failed to get images");
|
||||
std::cout << "Mounted Images:\n";
|
||||
for (plist_t p : images) {
|
||||
PList::Dictionary dict(p);
|
||||
std::cout << dict.ToXml() << std::endl;
|
||||
}
|
||||
|
||||
} else if (subcommand == "unmount") {
|
||||
const char* unmount_path = (major_version < 17) ? "/Developer" : "/System/Developer";
|
||||
mounter_client.unmount_image(unmount_path).expect("Failed to unmount image");
|
||||
std::cout << "Successfully unmounted image from " << unmount_path << std::endl;
|
||||
|
||||
} else if (subcommand == "mount") {
|
||||
if (image_path.empty()) {
|
||||
throw std::runtime_error("Mount command requires --image <path>");
|
||||
}
|
||||
auto image_data = read_file(image_path);
|
||||
|
||||
if (major_version < 17) {
|
||||
if (signature_path.empty()) {
|
||||
throw std::runtime_error("iOS < 17 requires --signature <path>");
|
||||
}
|
||||
auto signature_data = read_file(signature_path);
|
||||
mounter_client
|
||||
.mount_developer(image_data.data(),
|
||||
image_data.size(),
|
||||
signature_data.data(),
|
||||
signature_data.size())
|
||||
.expect("Failed to mount developer image");
|
||||
} else { // iOS 17+
|
||||
if (manifest_path.empty() || trustcache_path.empty()) {
|
||||
throw std::runtime_error("iOS 17+ requires --manifest and --trustcache paths");
|
||||
}
|
||||
auto manifest_data = read_file(manifest_path);
|
||||
auto trustcache_data = read_file(trustcache_path);
|
||||
|
||||
auto chip_id_plist = lockdown_client.get_value(nullptr, "UniqueChipID")
|
||||
.expect("Failed to get UniqueChipID");
|
||||
PList::Integer chip_id_node(chip_id_plist);
|
||||
uint64_t unique_chip_id = chip_id_node.GetValue();
|
||||
|
||||
std::function<void(size_t, size_t)> progress_callback = [](size_t n, size_t d) {
|
||||
if (d == 0) {
|
||||
return;
|
||||
}
|
||||
double percent = (static_cast<double>(n) / d) * 100.0;
|
||||
std::cout << "\rProgress: " << std::fixed << std::setprecision(2) << percent
|
||||
<< "%" << std::flush;
|
||||
if (n == d) {
|
||||
std::cout << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
mounter_client
|
||||
.mount_personalized_with_callback(prov,
|
||||
image_data.data(),
|
||||
image_data.size(),
|
||||
trustcache_data.data(),
|
||||
trustcache_data.size(),
|
||||
manifest_data.data(),
|
||||
manifest_data.size(),
|
||||
nullptr, // info_plist
|
||||
unique_chip_id,
|
||||
progress_callback)
|
||||
.expect("Failed to mount personalized image");
|
||||
}
|
||||
std::cout << "Successfully mounted image." << std::endl;
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <idevice++/bindings.hpp>
|
||||
|
||||
87
cpp/include/idevice++/mobile_image_mounter.hpp
Normal file
87
cpp/include/idevice++/mobile_image_mounter.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <idevice++/bindings.hpp>
|
||||
#include <idevice++/ffi.hpp>
|
||||
#include <idevice++/provider.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
|
||||
using MobileImageMounterPtr =
|
||||
std::unique_ptr<ImageMounterHandle, FnDeleter<ImageMounterHandle, image_mounter_free>>;
|
||||
|
||||
class MobileImageMounter {
|
||||
public:
|
||||
// Factory: connect via Provider
|
||||
static Result<MobileImageMounter, FfiError> connect(Provider& provider);
|
||||
|
||||
// Factory: wrap an existing Idevice socket (consumes it on success)
|
||||
static Result<MobileImageMounter, FfiError> from_socket(Idevice&& socket);
|
||||
|
||||
// Ops
|
||||
Result<std::vector<plist_t>, FfiError> copy_devices();
|
||||
Result<std::vector<uint8_t>, FfiError> lookup_image(std::string image_type);
|
||||
Result<void, FfiError> upload_image(std::string image_type,
|
||||
const uint8_t* image_data,
|
||||
size_t image_size,
|
||||
const uint8_t* signature_data,
|
||||
size_t signature_size);
|
||||
Result<void, FfiError> mount_image(std::string image_type,
|
||||
const uint8_t* signature_data,
|
||||
size_t signature_size,
|
||||
const uint8_t* trust_cache_data,
|
||||
size_t trust_cache_size,
|
||||
plist_t info_plist);
|
||||
Result<void, FfiError> unmount_image(std::string mount_path);
|
||||
Result<bool, FfiError> query_developer_mode_status();
|
||||
Result<void, FfiError> mount_developer(const uint8_t* image_data,
|
||||
size_t image_size,
|
||||
const uint8_t* signature_data,
|
||||
size_t signature_size);
|
||||
Result<std::vector<uint8_t>, FfiError> query_personalization_manifest(
|
||||
std::string image_type, const uint8_t* signature_data, size_t signature_size);
|
||||
Result<std::vector<uint8_t>, FfiError> query_nonce(std::string personalized_image_type);
|
||||
Result<plist_t, FfiError> query_personalization_identifiers(std::string image_type);
|
||||
Result<void, FfiError> roll_personalization_nonce();
|
||||
Result<void, FfiError> roll_cryptex_nonce();
|
||||
Result<void, FfiError> mount_personalized(Provider& provider,
|
||||
const uint8_t* image_data,
|
||||
size_t image_size,
|
||||
const uint8_t* trust_cache_data,
|
||||
size_t trust_cache_size,
|
||||
const uint8_t* build_manifest_data,
|
||||
size_t build_manifest_size,
|
||||
plist_t info_plist,
|
||||
uint64_t unique_chip_id);
|
||||
Result<void, FfiError>
|
||||
mount_personalized_with_callback(Provider& provider,
|
||||
const uint8_t* image_data,
|
||||
size_t image_size,
|
||||
const uint8_t* trust_cache_data,
|
||||
size_t trust_cache_size,
|
||||
const uint8_t* build_manifest_data,
|
||||
size_t build_manifest_size,
|
||||
plist_t info_plist,
|
||||
uint64_t unique_chip_id,
|
||||
std::function<void(size_t, size_t)>& lambda);
|
||||
|
||||
// RAII / moves
|
||||
~MobileImageMounter() noexcept = default;
|
||||
MobileImageMounter(MobileImageMounter&&) noexcept = default;
|
||||
MobileImageMounter& operator=(MobileImageMounter&&) noexcept = default;
|
||||
MobileImageMounter(const MobileImageMounter&) = delete;
|
||||
MobileImageMounter& operator=(const MobileImageMounter&) = delete;
|
||||
|
||||
ImageMounterHandle* raw() const noexcept { return handle_.get(); }
|
||||
static MobileImageMounter adopt(ImageMounterHandle* h) noexcept {
|
||||
return MobileImageMounter(h);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit MobileImageMounter(ImageMounterHandle* h) noexcept : handle_(h) {}
|
||||
MobileImageMounterPtr handle_{};
|
||||
};
|
||||
|
||||
} // namespace IdeviceFFI
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -115,6 +116,34 @@ template <typename T> class Option {
|
||||
return has_ ? std::move(*ptr()) : static_cast<T>(f());
|
||||
}
|
||||
|
||||
T expect(const char* message) && {
|
||||
if (is_none()) {
|
||||
std::fprintf(stderr, "Fatal (expect) error: %s\n", message);
|
||||
std::terminate();
|
||||
}
|
||||
T tmp = std::move(*ptr());
|
||||
reset();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// Returns a mutable reference from an lvalue Result
|
||||
T& expect(const char* message) & {
|
||||
if (is_none()) {
|
||||
std::fprintf(stderr, "Fatal (expect) error: %s\n", message);
|
||||
std::terminate();
|
||||
}
|
||||
return *ptr();
|
||||
}
|
||||
|
||||
// Returns a const reference from a const lvalue Result
|
||||
const T& expect(const char* message) const& {
|
||||
if (is_none()) {
|
||||
std::fprintf(stderr, "Fatal (expect) error: %s\n", message);
|
||||
std::terminate();
|
||||
}
|
||||
return *ptr();
|
||||
}
|
||||
|
||||
// map
|
||||
template <typename F>
|
||||
auto map(F&& f) const& -> Option<typename std::decay<decltype(f(*ptr()))>::type> {
|
||||
|
||||
246
cpp/src/mobile_image_mounter.cpp
Normal file
246
cpp/src/mobile_image_mounter.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
// Jackson Coxson
|
||||
|
||||
#include <idevice++/mobile_image_mounter.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace IdeviceFFI {
|
||||
|
||||
// -------- Anonymous Namespace for Helpers --------
|
||||
namespace {
|
||||
/**
|
||||
* @brief A C-style trampoline function to call back into a C++ std::function.
|
||||
*
|
||||
* This function is passed to the Rust FFI layer. It receives a void* context,
|
||||
* which it casts back to the original std::function object to invoke it.
|
||||
*/
|
||||
extern "C" void progress_trampoline(size_t progress, size_t total, void* context) {
|
||||
if (context) {
|
||||
auto& callback_fn = *static_cast<std::function<void(size_t, size_t)>*>(context);
|
||||
callback_fn(progress, total);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// -------- Factory Methods --------
|
||||
|
||||
Result<MobileImageMounter, FfiError> MobileImageMounter::connect(Provider& provider) {
|
||||
ImageMounterHandle* handle = nullptr;
|
||||
FfiError e(::image_mounter_connect(provider.raw(), &handle));
|
||||
if (e) {
|
||||
return Err(e);
|
||||
}
|
||||
return Ok(MobileImageMounter::adopt(handle));
|
||||
}
|
||||
|
||||
Result<MobileImageMounter, FfiError> MobileImageMounter::from_socket(Idevice&& socket) {
|
||||
ImageMounterHandle* handle = nullptr;
|
||||
// The Rust FFI function consumes the socket, so we must release it from the
|
||||
// C++ RAII wrapper's control. An `Idevice::release()` method is assumed here.
|
||||
FfiError e(::image_mounter_new(socket.release(), &handle));
|
||||
if (e) {
|
||||
return Err(e);
|
||||
}
|
||||
return Ok(MobileImageMounter::adopt(handle));
|
||||
}
|
||||
|
||||
// -------- Ops --------
|
||||
|
||||
Result<std::vector<plist_t>, FfiError> MobileImageMounter::copy_devices() {
|
||||
plist_t* devices_raw = nullptr;
|
||||
size_t devices_len = 0;
|
||||
|
||||
FfiError e(::image_mounter_copy_devices(this->raw(), &devices_raw, &devices_len));
|
||||
if (e) {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
std::vector<plist_t> devices;
|
||||
if (devices_raw) {
|
||||
devices.assign(devices_raw, devices_raw + devices_len);
|
||||
}
|
||||
|
||||
return Ok(std::move(devices));
|
||||
}
|
||||
|
||||
Result<std::vector<uint8_t>, FfiError> MobileImageMounter::lookup_image(std::string image_type) {
|
||||
uint8_t* signature_raw = nullptr;
|
||||
size_t signature_len = 0;
|
||||
|
||||
FfiError e(::image_mounter_lookup_image(
|
||||
this->raw(), image_type.c_str(), &signature_raw, &signature_len));
|
||||
if (e) {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> signature(signature_len);
|
||||
std::memcpy(signature.data(), signature_raw, signature_len);
|
||||
idevice_data_free(signature_raw, signature_len);
|
||||
|
||||
return Ok(std::move(signature));
|
||||
}
|
||||
|
||||
Result<void, FfiError> MobileImageMounter::upload_image(std::string image_type,
|
||||
const uint8_t* image_data,
|
||||
size_t image_size,
|
||||
const uint8_t* signature_data,
|
||||
size_t signature_size) {
|
||||
FfiError e(::image_mounter_upload_image(
|
||||
this->raw(), image_type.c_str(), image_data, image_size, signature_data, signature_size));
|
||||
return e ? Result<void, FfiError>(Err(e)) : Result<void, FfiError>(Ok());
|
||||
}
|
||||
|
||||
Result<void, FfiError> MobileImageMounter::mount_image(std::string image_type,
|
||||
const uint8_t* signature_data,
|
||||
size_t signature_size,
|
||||
const uint8_t* trust_cache_data,
|
||||
size_t trust_cache_size,
|
||||
plist_t info_plist) {
|
||||
FfiError e(::image_mounter_mount_image(this->raw(),
|
||||
image_type.c_str(),
|
||||
signature_data,
|
||||
signature_size,
|
||||
trust_cache_data,
|
||||
trust_cache_size,
|
||||
info_plist));
|
||||
return e ? Result<void, FfiError>(Err(e)) : Result<void, FfiError>(Ok());
|
||||
}
|
||||
|
||||
Result<void, FfiError> MobileImageMounter::unmount_image(std::string mount_path) {
|
||||
FfiError e(::image_mounter_unmount_image(this->raw(), mount_path.c_str()));
|
||||
return e ? Result<void, FfiError>(Err(e)) : Result<void, FfiError>(Ok());
|
||||
}
|
||||
|
||||
Result<bool, FfiError> MobileImageMounter::query_developer_mode_status() {
|
||||
int status_c = 0;
|
||||
FfiError e(::image_mounter_query_developer_mode_status(this->raw(), &status_c));
|
||||
if (e) {
|
||||
return Err(e);
|
||||
}
|
||||
return Ok(status_c != 0);
|
||||
}
|
||||
|
||||
Result<void, FfiError> MobileImageMounter::mount_developer(const uint8_t* image_data,
|
||||
size_t image_size,
|
||||
const uint8_t* signature_data,
|
||||
size_t signature_size) {
|
||||
FfiError e(::image_mounter_mount_developer(
|
||||
this->raw(), image_data, image_size, signature_data, signature_size));
|
||||
return e ? Result<void, FfiError>(Err(e)) : Result<void, FfiError>(Ok());
|
||||
}
|
||||
|
||||
Result<std::vector<uint8_t>, FfiError> MobileImageMounter::query_personalization_manifest(
|
||||
std::string image_type, const uint8_t* signature_data, size_t signature_size) {
|
||||
uint8_t* manifest_raw = nullptr;
|
||||
size_t manifest_len = 0;
|
||||
FfiError e(::image_mounter_query_personalization_manifest(this->raw(),
|
||||
image_type.c_str(),
|
||||
signature_data,
|
||||
signature_size,
|
||||
&manifest_raw,
|
||||
&manifest_len));
|
||||
if (e) {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> manifest(manifest_len);
|
||||
std::memcpy(manifest.data(), manifest_raw, manifest_len);
|
||||
idevice_data_free(manifest_raw, manifest_len);
|
||||
|
||||
return Ok(std::move(manifest));
|
||||
}
|
||||
|
||||
Result<std::vector<uint8_t>, FfiError>
|
||||
MobileImageMounter::query_nonce(std::string personalized_image_type) {
|
||||
uint8_t* nonce_raw = nullptr;
|
||||
size_t nonce_len = 0;
|
||||
const char* image_type_c =
|
||||
personalized_image_type.empty() ? nullptr : personalized_image_type.c_str();
|
||||
|
||||
FfiError e(::image_mounter_query_nonce(this->raw(), image_type_c, &nonce_raw, &nonce_len));
|
||||
if (e) {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> nonce(nonce_len);
|
||||
std::memcpy(nonce.data(), nonce_raw, nonce_len);
|
||||
idevice_data_free(nonce_raw, nonce_len);
|
||||
|
||||
return Ok(std::move(nonce));
|
||||
}
|
||||
|
||||
Result<plist_t, FfiError>
|
||||
MobileImageMounter::query_personalization_identifiers(std::string image_type) {
|
||||
plist_t identifiers = nullptr;
|
||||
const char* image_type_c = image_type.empty() ? nullptr : image_type.c_str();
|
||||
|
||||
FfiError e(
|
||||
::image_mounter_query_personalization_identifiers(this->raw(), image_type_c, &identifiers));
|
||||
if (e) {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
// The caller now owns the returned `plist_t` and is responsible for freeing it.
|
||||
return Ok(identifiers);
|
||||
}
|
||||
|
||||
Result<void, FfiError> MobileImageMounter::roll_personalization_nonce() {
|
||||
FfiError e(::image_mounter_roll_personalization_nonce(this->raw()));
|
||||
return e ? Result<void, FfiError>(Err(e)) : Result<void, FfiError>(Ok());
|
||||
}
|
||||
|
||||
Result<void, FfiError> MobileImageMounter::roll_cryptex_nonce() {
|
||||
FfiError e(::image_mounter_roll_cryptex_nonce(this->raw()));
|
||||
return e ? Result<void, FfiError>(Err(e)) : Result<void, FfiError>(Ok());
|
||||
}
|
||||
|
||||
Result<void, FfiError> MobileImageMounter::mount_personalized(Provider& provider,
|
||||
const uint8_t* image_data,
|
||||
size_t image_size,
|
||||
const uint8_t* trust_cache_data,
|
||||
size_t trust_cache_size,
|
||||
const uint8_t* build_manifest_data,
|
||||
size_t build_manifest_size,
|
||||
plist_t info_plist,
|
||||
uint64_t unique_chip_id) {
|
||||
FfiError e(::image_mounter_mount_personalized(this->raw(),
|
||||
provider.raw(),
|
||||
image_data,
|
||||
image_size,
|
||||
trust_cache_data,
|
||||
trust_cache_size,
|
||||
build_manifest_data,
|
||||
build_manifest_size,
|
||||
info_plist,
|
||||
unique_chip_id));
|
||||
return e ? Result<void, FfiError>(Err(e)) : Result<void, FfiError>(Ok());
|
||||
}
|
||||
|
||||
Result<void, FfiError>
|
||||
MobileImageMounter::mount_personalized_with_callback(Provider& provider,
|
||||
const uint8_t* image_data,
|
||||
size_t image_size,
|
||||
const uint8_t* trust_cache_data,
|
||||
size_t trust_cache_size,
|
||||
const uint8_t* build_manifest_data,
|
||||
size_t build_manifest_size,
|
||||
plist_t info_plist,
|
||||
uint64_t unique_chip_id,
|
||||
std::function<void(size_t, size_t)>& lambda) {
|
||||
|
||||
FfiError e(::image_mounter_mount_personalized_with_callback(this->raw(),
|
||||
provider.raw(),
|
||||
image_data,
|
||||
image_size,
|
||||
trust_cache_data,
|
||||
trust_cache_size,
|
||||
build_manifest_data,
|
||||
build_manifest_size,
|
||||
info_plist,
|
||||
unique_chip_id,
|
||||
progress_trampoline,
|
||||
&lambda /* context */));
|
||||
|
||||
return e ? Result<void, FfiError>(Err(e)) : Result<void, FfiError>(Ok());
|
||||
}
|
||||
|
||||
} // namespace IdeviceFFI
|
||||
@@ -13,7 +13,7 @@ once_cell = "1.21.1"
|
||||
tokio = { version = "1.44.1", features = ["full"] }
|
||||
libc = "0.2.171"
|
||||
plist = "1.7.1"
|
||||
plist_ffi = { version = "0.1.5" }
|
||||
plist_ffi = { version = "0.1.6" }
|
||||
uuid = { version = "1.12", features = ["v4"], optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
||||
Reference in New Issue
Block a user