// Jackson Coxson #include #include #include 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*>(context); callback_fn(progress, total); } } } // namespace // -------- Factory Methods -------- Result 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::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, 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 devices; if (devices_raw) { devices.assign(devices_raw, devices_raw + devices_len); } return Ok(std::move(devices)); } Result, 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 signature(signature_len); std::memcpy(signature.data(), signature_raw, signature_len); idevice_data_free(signature_raw, signature_len); return Ok(std::move(signature)); } Result 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(Err(e)) : Result(Ok()); } Result 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(Err(e)) : Result(Ok()); } Result MobileImageMounter::unmount_image(std::string mount_path) { FfiError e(::image_mounter_unmount_image(this->raw(), mount_path.c_str())); return e ? Result(Err(e)) : Result(Ok()); } Result 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 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(Err(e)) : Result(Ok()); } Result, 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 manifest(manifest_len); std::memcpy(manifest.data(), manifest_raw, manifest_len); idevice_data_free(manifest_raw, manifest_len); return Ok(std::move(manifest)); } Result, 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 nonce(nonce_len); std::memcpy(nonce.data(), nonce_raw, nonce_len); idevice_data_free(nonce_raw, nonce_len); return Ok(std::move(nonce)); } Result 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 MobileImageMounter::roll_personalization_nonce() { FfiError e(::image_mounter_roll_personalization_nonce(this->raw())); return e ? Result(Err(e)) : Result(Ok()); } Result MobileImageMounter::roll_cryptex_nonce() { FfiError e(::image_mounter_roll_cryptex_nonce(this->raw())); return e ? Result(Err(e)) : Result(Ok()); } Result 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(Err(e)) : Result(Ok()); } Result 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& 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(Err(e)) : Result(Ok()); } } // namespace IdeviceFFI