first commit

This commit is contained in:
uncor3
2025-07-27 04:00:39 +00:00
commit eb43f13077
83 changed files with 9604 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
// Detect AFC2 (Apple File Conduit 2) support
@@ -0,0 +1,35 @@
#include <libimobiledevice/afc.h>
#include <string>
#include <vector>
struct JailbreakDetectionResult {
bool is_jailbroken;
std::vector<std::string> found_folders;
};
// This is because afc_read_directory accepts "/var/mobile/Media" as "/"
std::string possible_root = "../../../../";
JailbreakDetectionResult detect_has_jailbroken_before(afc_client_t afc)
{
std::vector<std::string> jailbreak_folders = {".installed_palera1n",
".procursus_strapped"};
JailbreakDetectionResult result = {false, {}};
char **dirs = NULL;
if (afc_read_directory(afc, possible_root.c_str(), &dirs) ==
AFC_E_SUCCESS) {
for (char **dir = dirs; *dir != nullptr; ++dir) {
std::string dirname = *dir;
for (const auto &jb_folder : jailbreak_folders) {
if (dirname == jb_folder) {
result.found_folders.push_back(jb_folder);
result.is_jailbroken = true;
}
}
}
}
afc_dictionary_free(dirs);
return result;
}
@@ -0,0 +1,9 @@
// parse boot args from idevice info
// NonVolatileRAM: auto-boot: dHJ1ZQ==
// backlight-level: MTUyNg==
// boot-args:
// com.apple.System.tz0-size: MHg2MDAwMDA=
// oblit-begins:
// T2JsaXRUeXBlOiBPYmxpdGVyYXRlRGF0YVBhcnRpdGlvbi4gUmVhc29uOiB1bmtub3du
// obliteration: aGFuZGxlX21lc3NhZ2U6IE9ibGl0ZXJhdGlvbiBDb21wbGV0ZQo=
// PartitionType: GUID_partition_scheme
+27
View File
@@ -0,0 +1,27 @@
#include <libimobiledevice/afc.h>
// char *possible_jailbreak_paths[] = {
// "/Applications/Cydia.app",
// "/Library/MobileSubstrate/MobileSubstrate.dylib",
// "/bin/bash",
// "/usr/sbin/sshd",
// "/etc/apt",
// NULL
// };
#include <string>
// This is because afc_read_directory accepts "/var/mobile/Media" as "/"
std::string possible_root = "../../../../";
bool detect_jailbroken(afc_client_t afc)
{
char **dirs = NULL;
if (afc_read_directory(afc, (possible_root + "bin").c_str(), &dirs) ==
AFC_E_SUCCESS) {
// if we can loop through the directory, it means we have access to the
// file system
for (char **dir = dirs; *dir != nullptr; ++dir) {
afc_dictionary_free(dirs);
return true;
}
}
afc_dictionary_free(dirs);
return false;
}
+126
View File
@@ -0,0 +1,126 @@
// https://github.com/libimobiledevice/libimobiledevice/blob/master/tools/ideviceinfo.c
/*
* ideviceinfo.c
* Simple utility to show information about an attached device
*
* Copyright (c) 2010-2019 Nikias Bassen, All Rights Reserved.
* Copyright (c) 2009 Martin Szulecki All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <signal.h>
#endif
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <plist/plist.h>
#include <pugixml.hpp>
#define FORMAT_KEY_VALUE 1
#define FORMAT_XML 2
static const char *domains[] = {
"com.apple.disk_usage", "com.apple.disk_usage.factory",
"com.apple.mobile.battery",
/* FIXME: For some reason lockdownd segfaults on this, works sometimes
though "com.apple.mobile.debug",. */
"com.apple.iqagent", "com.apple.purplebuddy", "com.apple.PurpleBuddy",
"com.apple.mobile.chaperone", "com.apple.mobile.third_party_termination",
"com.apple.mobile.lockdownd", "com.apple.mobile.lockdown_cache",
"com.apple.xcode.developerdomain", "com.apple.international",
"com.apple.mobile.data_sync", "com.apple.mobile.tethered_sync",
"com.apple.mobile.mobile_application_usage", "com.apple.mobile.backup",
"com.apple.mobile.nikita", "com.apple.mobile.restriction",
"com.apple.mobile.user_preferences", "com.apple.mobile.sync_data_class",
"com.apple.mobile.software_behavior",
"com.apple.mobile.iTunes.SQLMusicLibraryPostProcessCommands",
"com.apple.mobile.iTunes.accessories",
"com.apple.mobile.internal", /**< iOS 4.0+ */
"com.apple.mobile.wireless_lockdown", /**< iOS 4.0+ */
"com.apple.fairplay", "com.apple.iTunes", "com.apple.mobile.iTunes.store",
"com.apple.mobile.iTunes", "com.apple.fmip", "com.apple.Accessibility",
NULL};
plist_t get_device_info(const char *udid, int use_network, int simple,
lockdownd_client_t client, idevice_t device)
{
lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
plist_t node = NULL;
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
// FIXME: network support does not properly work yet
// ret = idevice_new_with_options(&device, udid, (use_network) ?
// IDEVICE_LOOKUP_NETWORK : IDEVICE_LOOKUP_USBMUX);
ret = idevice_new_with_options(&device, udid, IDEVICE_LOOKUP_USBMUX);
if (ret != IDEVICE_E_SUCCESS) {
if (udid) {
fprintf(stderr, "ERROR: Device %s not found!\n", udid);
} else {
fprintf(stderr, "ERROR: No device found!\n");
}
return NULL;
}
if (LOCKDOWN_E_SUCCESS !=
(ldret = simple ? lockdownd_client_new(device, &client, "iDescriptor")
: lockdownd_client_new_with_handshake(device, &client,
"iDescriptor"))) {
fprintf(stderr, "ERROR: Could not connect to lockdownd: %s (%d)\n",
lockdownd_strerror(ldret), ldret);
return NULL;
}
/* run query and output information */
if (lockdownd_get_value(client, NULL, NULL, &node) != LOCKDOWN_E_SUCCESS) {
fprintf(stderr, "ERROR: Could not get value\n");
}
return node;
}
// Change return type to void
void get_device_info_xml(const char *udid, int use_network, int simple,
pugi::xml_document &infoXml, lockdownd_client_t client,
idevice_t device)
{
plist_t node = get_device_info(udid, use_network, simple, client, device);
if (!node)
return;
char *xml_string = nullptr;
uint32_t xml_length = 0;
plist_to_xml(node, &xml_string, &xml_length);
plist_free(node);
if (xml_string) {
infoXml.load_string(xml_string);
free(xml_string);
}
// No return statement needed
}
+65
View File
@@ -0,0 +1,65 @@
#include "./get-media.h"
#include "../../iDescriptor.h"
#include <iostream>
#include <libimobiledevice/afc.h>
#include <libimobiledevice/lockdown.h>
#include <string.h>
MediaFileTree getMediaFileTree(afc_client_t afcClient,
lockdownd_service_descriptor_t lockdownService,
const std::string &path = "/")
{
MediaFileTree result;
result.currentPath = path;
if (afcClient == nullptr) {
qDebug() << "AFC client is not initialized in getMediaFileTree";
}
if (lockdownService == nullptr) {
qDebug() << "Lockdown service is not initialized in getMediaFileTree";
}
char **dirs = NULL;
if (afc_read_directory(afcClient, path.c_str(), &dirs) != AFC_E_SUCCESS) {
// afc_client_free(afcClient);
// lockdownd_service_descriptor_free(lockdownService);
result.success = false;
return result;
}
for (int i = 0; dirs[i]; i++) {
std::string entryName = dirs[i];
if (entryName == "." || entryName == "..")
continue;
// Determine if entry is a directory
char **info = NULL;
std::string fullPath = path;
if (fullPath.back() != '/')
fullPath += "/";
fullPath += entryName;
bool isDir = false;
if (afc_get_file_info(afcClient, fullPath.c_str(), &info) ==
AFC_E_SUCCESS &&
info) {
for (int j = 0; info[j]; j += 2) {
if (strcmp(info[j], "st_ifmt") == 0) {
if (strcmp(info[j + 1], "S_IFDIR") == 0)
isDir = true;
break;
}
}
afc_dictionary_free(info);
}
result.entries.push_back({entryName, isDir});
}
// TODO : Freed when device is disconnected
// afc_client_free(afc);
// lockdownd_service_descriptor_free(service);
result.success = true;
return result;
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <string>
#include <vector>
struct MediaEntry {
std::string name;
bool isDir;
};
struct MediaFileTree {
std::vector<MediaEntry> entries;
bool success;
std::string currentPath;
};
+171
View File
@@ -0,0 +1,171 @@
#include "../../iDescriptor.h"
#include "../helpers/parse_product_type.cpp"
#include "./detect_jailbroken.cpp"
#include "./get-device-info.cpp"
#include "libirecovery.h"
#include <QDebug>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <pugixml.hpp>
DeviceInfo xmlToDeviceInfo(const pugi::xml_document &doc,
afc_client_t afcClient)
{
DeviceInfo d;
pugi::xml_node dict = doc.child("plist").child("dict");
auto safeGet = [&](const char *key) -> std::string {
for (pugi::xml_node child = dict.first_child(); child;
child = child.next_sibling()) {
if (strcmp(child.name(), "key") == 0 &&
strcmp(child.text().as_string(), key) == 0) {
pugi::xml_node value = child.next_sibling();
if (value)
return value.text().as_string();
}
}
return "";
};
d.deviceName = safeGet("DeviceName");
d.deviceClass = safeGet("DeviceClass");
d.deviceColor = safeGet("DeviceColor");
d.modelNumber = safeGet("ModelNumber");
d.cpuArchitecture = safeGet("CPUArchitecture");
d.buildVersion = safeGet("BuildVersion");
d.hardwareModel = safeGet("HardwareModel");
d.hardwarePlatform = safeGet("HardwarePlatform");
d.ethernetAddress = safeGet("EthernetAddress");
d.bluetoothAddress = safeGet("BluetoothAddress");
d.firmwareVersion = safeGet("FirmwareVersion");
d.productVersion = safeGet("ProductVersion");
std::string _activationState = safeGet("ActivationState");
if (_activationState == "Activated") {
d.activationState = DeviceInfo::ActivationState::Activated;
} else if (_activationState == "FactoryActivated") {
d.activationState = DeviceInfo::ActivationState::FactoryActivated;
} else if (_activationState == "Unactivated") {
d.activationState = DeviceInfo::ActivationState::Unactivated;
} else {
d.activationState =
DeviceInfo::ActivationState::Unactivated; // Default value
}
d.productType = parse_product_type(safeGet("ProductType"));
d.jailbroken = detect_jailbroken(
afcClient); // Default value, can be set later if needed
// d.udid = safeGet("UniqueDeviceID");
return d;
}
IDescriptorInitDeviceResult init_idescriptor_device(const char *udid)
{
qDebug() << "Initializing iDescriptor device with UDID: "
<< QString::fromUtf8(udid);
IDescriptorInitDeviceResult result = {};
lockdownd_client_t client;
lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
lockdownd_service_descriptor_t lockdownService = nullptr;
afc_client_t afcClient = nullptr;
try {
idevice_error_t ret = idevice_new_with_options(&result.device, udid,
IDEVICE_LOOKUP_USBMUX);
if (ret != IDEVICE_E_SUCCESS) {
qDebug() << "Failed to connect to device: " << ret;
return result;
}
if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(
result.device, &client, APP_LABEL))) {
result.error = ldret;
qDebug() << "Failed to create lockdown client: " << ldret;
idevice_free(result.device);
return result;
}
if (LOCKDOWN_E_SUCCESS !=
(ldret = lockdownd_start_service(client, "com.apple.afc",
&lockdownService))) {
lockdownd_client_free(client);
idevice_free(result.device);
qDebug() << "Failed to start AFC service: " << ldret;
return result;
}
if (lockdownService) {
qDebug() << "AFC service started successfully.";
} else {
qDebug() << "AFC service descriptor is null.";
// lockdownd_client_free(result.client);
// idevice_free(result.device);
// return result;
}
if (afc_client_new(result.device, lockdownService, &afcClient) !=
AFC_E_SUCCESS) {
lockdownd_service_descriptor_free(lockdownService);
lockdownd_client_free(client);
idevice_free(result.device);
qDebug() << "Failed to create AFC client: " << ldret;
return result;
}
pugi::xml_document infoXml;
get_device_info_xml(udid, 0, 0, infoXml, client, result.device);
if (infoXml.empty()) {
qDebug() << "Failed to retrieve device info XML for UDID: "
<< QString::fromUtf8(udid);
// Clean up resources before returning
// afc_client_free(result.afcClient);
// lockdownd_service_descriptor_free(result.lockdownService);
// lockdownd_client_free(result.client);
idevice_free(result.device);
return result;
}
// if (result.device) idevice_free(result.device);
result.deviceInfo = xmlToDeviceInfo(infoXml, afcClient);
result.success = true;
if (afcClient)
afc_client_free(afcClient);
if (lockdownService)
lockdownd_service_descriptor_free(lockdownService);
if (client)
lockdownd_client_free(client);
return result;
} catch (const std::exception &e) {
qDebug() << "Exception in init_idescriptor_device: " << e.what();
// Clean up any allocated resources
// if (result.afcClient) afc_client_free(result.afcClient);
// if (result.lockdownService)
// lockdownd_service_descriptor_free(result.lockdownService);
if (client)
lockdownd_client_free(client);
if (result.device)
idevice_free(result.device);
return result;
}
}
IDescriptorInitDeviceResultRecovery
init_idescriptor_recovery_device(irecv_device_info *info)
{
IDescriptorInitDeviceResultRecovery result;
result.deviceInfo = *info;
uint64_t ecid = info->ecid;
// irecv_client_t client = nullptr;
// Docs say that clients are not long-lived, so instead of storing, we
// create a new one each time we need it. irecv_error_t ret =
// irecv_open_with_ecid_and_attempts(&client, ecid,
// RECOVERY_CLIENT_CONNECTION_TRIES);
// if (ret != IRECV_E_SUCCESS)
// {
// return result;
// }
result.success = true;
return result;
}
+692
View File
@@ -0,0 +1,692 @@
/*
* ideviceimagemounter.c
* Mount developer/debug disk images on the device
*
* Copyright (C) 2010 Nikias Bassen <nikias@gmx.li>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
// TODO:
// we need to dynamically fetch dev imgs because every iOS version has a
// different one
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define TOOL_NAME "ideviceimagemounter"
#include <stdlib.h>
#define _GNU_SOURCE 1
#define __USE_GNU 1
#include <errno.h>
#include <getopt.h>
#include <inttypes.h>
#include <libgen.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#ifndef _WIN32
#include <signal.h>
#endif
#include <QDebug>
#include <libimobiledevice-glue/sha.h>
#include <libimobiledevice-glue/utils.h>
#include <libimobiledevice/afc.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/mobile_image_mounter.h>
#include <libimobiledevice/notification_proxy.h>
#include <libtatsu/tss.h>
#include <plist/plist.h>
#include <printf.h>
static int list_mode = 0;
static int use_network = 0;
static int xml_mode = 0;
static const char *udid = NULL;
static const char *imagetype = NULL;
static const char PKG_PATH[] = "PublicStaging";
static const char PATH_PREFIX[] = "/private/var/mobile/Media";
typedef enum {
DISK_IMAGE_UPLOAD_TYPE_AFC,
DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE
} disk_image_upload_type_t;
enum cmd_mode {
CMD_NONE = 0,
CMD_MOUNT,
CMD_UNMOUNT,
CMD_LIST,
CMD_DEVMODESTATUS
};
// int cmd = CMD_NONE;
#ifndef SOURCE_DIR
#define SOURCE_DIR "."
#endif
static ssize_t mim_upload_cb(void *buf, size_t size, void *userdata)
{
return fread(buf, 1, size, (FILE *)userdata);
}
// TODO: cleanup
bool mount_dev_image(char *udid)
{
mobile_image_mounter_client_t mim = NULL;
int res = -1;
size_t image_size = 0;
lockdownd_client_t lckd = NULL;
lockdownd_error_t ldret = LOCKDOWN_E_UNKNOWN_ERROR;
afc_client_t afc = NULL;
lockdownd_service_descriptor_t service = NULL;
idevice_t device = NULL;
if (IDEVICE_E_SUCCESS !=
idevice_new_with_options(&device, udid,
(use_network) ? IDEVICE_LOOKUP_NETWORK
: IDEVICE_LOOKUP_USBMUX)) {
qDebug() << "ERROR: Could not create idevice!";
return false;
}
if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(
device, &lckd, TOOL_NAME))) {
qDebug() << "ERROR: Could not connect to lockdownd service!";
return false;
// goto leave;
}
lockdownd_error_t lerr =
lockdownd_start_service(lckd, "com.apple.afc", &service);
if (lerr != LOCKDOWN_E_SUCCESS) {
qDebug() << "ERROR: Could not start AFC service!"
<< lockdownd_strerror(lerr) << "(" << lerr << ")";
lockdownd_client_free(lckd);
lckd = NULL;
idevice_free(device);
device = NULL;
return false;
}
afc_error_t rafc = afc_client_new(device, service, &afc);
if (rafc != AFC_E_SUCCESS) {
qDebug() << "ERROR: Could not connect to AFC!" << afc_strerror(rafc)
<< "(" << rafc << ")";
return false;
}
char *image_path = nullptr;
char *image_sig_path = nullptr;
if (asprintf(&image_path,
"%s/resources/dev-images/15/DeveloperDiskImage.dmg",
SOURCE_DIR) < 0) {
qDebug() << "Out of memory constructing image path!";
return false;
}
if (asprintf(&image_sig_path,
"%s/resources/dev-images/15/DeveloperDiskImage.dmg.signature",
SOURCE_DIR) < 0) {
qDebug() << "Out of memory constructing signature path!";
free(image_path);
return false;
}
// #ifndef _WIN32
// signal(SIGPIPE, SIG_IGN);
// #endif
unsigned int device_version = idevice_get_device_version(device);
disk_image_upload_type_t disk_image_upload_type =
DISK_IMAGE_UPLOAD_TYPE_AFC;
if (device_version >= IDEVICE_DEVICE_VERSION(7, 0, 0)) {
disk_image_upload_type = DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE;
}
if (device_version >= IDEVICE_DEVICE_VERSION(16, 0, 0)) {
uint8_t dev_mode_status = 0;
plist_t val = NULL;
ldret = lockdownd_get_value(lckd, "com.apple.security.mac.amfi",
"DeveloperModeStatus", &val);
if (ldret == LOCKDOWN_E_SUCCESS) {
plist_get_bool_val(val, &dev_mode_status);
plist_free(val);
}
if (!dev_mode_status) {
qDebug() << "ERROR: You have to enable Developer Mode on the given "
"device in order to allowing mounting a developer disk "
"image.";
return false;
}
}
lockdownd_start_service(lckd, "com.apple.mobile.mobile_image_mounter",
&service);
if (!service || service->port == 0) {
qDebug() << "ERROR: Could not start mobile_image_mounter service!";
return false;
}
if (mobile_image_mounter_new(device, service, &mim) !=
MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
qDebug() << "ERROR: Could not connect to mobile_image_mounter!";
return false;
}
// if (service)
// {
// lockdownd_service_descriptor_free(service);
// service = NULL;
// }
struct stat fst;
if (disk_image_upload_type == DISK_IMAGE_UPLOAD_TYPE_AFC) {
if (!service || !service->port) {
qDebug() << "Could not start com.apple.afc!";
return false;
}
if (!afc) {
qDebug() << "Could not connect to AFC!";
return false;
}
if (service) {
// lockdownd_service_descriptor_free(service);
service = NULL;
}
}
if (stat(image_path, &fst) != 0) {
qDebug() << "ERROR: stat:" << image_path << ":" << strerror(errno);
return false;
}
image_size = fst.st_size;
if (device_version < IDEVICE_DEVICE_VERSION(17, 0, 0) &&
stat(image_sig_path, &fst) != 0) {
qDebug() << "ERROR: stat:" << image_sig_path << ":" << strerror(errno);
return false;
}
// lockdownd_client_free(lckd);
// lckd = NULL;
mobile_image_mounter_error_t err = MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR;
plist_t result = NULL;
// if (cmd == CMD_LIST)
// {
// /* list mounts mode */
// if (!imagetype)
// {
// if (device_version < IDEVICE_DEVICE_VERSION(17, 0, 0))
// {
// imagetype = "Developer";
// }
// else
// {
// imagetype = "Personalized";
// }
// }
// err = mobile_image_mounter_lookup_image(mim, imagetype, &result);
// if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS)
// {
// res = 0;
// plist_write_to_stream(result, stdout, (xml_mode) ?
// PLIST_FORMAT_XML : PLIST_FORMAT_LIMD, 0);
// }
// else
// {
// printf("Error: lookup_image returned %d\n", err);
// }
// }
unsigned char *sig = NULL;
size_t sig_length = 0;
FILE *f;
// struct stat fst;
plist_t mount_options = NULL;
if (device_version < IDEVICE_DEVICE_VERSION(17, 0, 0)) {
f = fopen(image_sig_path, "rb");
if (!f) {
qDebug() << "Error opening signature file" << image_sig_path << ":"
<< strerror(errno);
return false;
}
if (fstat(fileno(f), &fst) != 0) {
qDebug() << "Error: fstat:" << strerror(errno);
return false;
}
sig = (unsigned char *)malloc(fst.st_size);
sig_length = fread(sig, 1, fst.st_size, f);
fclose(f);
if (sig_length == 0) {
qDebug() << "Could not read signature from file" << image_sig_path;
return false;
}
f = fopen(image_path, "rb");
if (!f) {
qDebug() << "Error opening image file" << image_path << ":"
<< strerror(errno);
return false;
}
} else {
if (stat(image_path, &fst) != 0) {
qDebug() << "Error: stat:" << image_path << ":" << strerror(errno);
return false;
}
if (!S_ISDIR(fst.st_mode)) {
qDebug() << "Error: Personalized Disk Image mount expects a "
"directory as image path.";
return false;
}
char *build_manifest_path =
string_build_path(image_path, "BuildManifest.plist", NULL);
plist_t build_manifest = NULL;
if (plist_read_from_file(build_manifest_path, &build_manifest, NULL) !=
0) {
free(build_manifest_path);
build_manifest_path = string_build_path(
image_path, "Restore", "BuildManifest.plist", NULL);
if (plist_read_from_file(build_manifest_path, &build_manifest,
NULL) == 0) {
char *image_path_new =
string_build_path(image_path, "Restore", NULL);
free(image_path);
image_path = image_path_new;
}
}
if (!build_manifest) {
qDebug() << "Error: Could not locate BuildManifest.plist inside "
"given disk image path!";
return false;
}
plist_t identifiers = NULL;
mobile_image_mounter_error_t merr =
mobile_image_mounter_query_personalization_identifiers(
mim, NULL, &identifiers);
if (merr != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
qDebug() << "Failed to query personalization identifiers:" << merr;
return false;
}
unsigned int board_id = plist_dict_get_uint(identifiers, "BoardId");
unsigned int chip_id = plist_dict_get_uint(identifiers, "ChipID");
plist_t build_identities =
plist_dict_get_item(build_manifest, "BuildIdentities");
plist_array_iter iter;
plist_array_new_iter(build_identities, &iter);
plist_t item = NULL;
plist_t build_identity = NULL;
do {
plist_array_next_item(build_identities, iter, &item);
if (!item) {
break;
}
unsigned int bi_board_id =
(unsigned int)plist_dict_get_uint(item, "ApBoardID");
unsigned int bi_chip_id =
(unsigned int)plist_dict_get_uint(item, "ApChipID");
if (bi_chip_id == chip_id && bi_board_id == board_id) {
build_identity = item;
break;
}
} while (item);
plist_mem_free(iter);
if (!build_identity) {
qDebug() << "Error: The given disk image is not compatible with "
"the current device.";
return false;
}
plist_t p_tc_path =
plist_access_path(build_identity, 4, "Manifest",
"LoadableTrustCache", "Info", "Path");
if (!p_tc_path) {
qDebug() << "Error: Could not determine path for trust cache!";
return false;
}
plist_t p_dmg_path = plist_access_path(
build_identity, 4, "Manifest", "PersonalizedDMG", "Info", "Path");
if (!p_dmg_path) {
qDebug() << "Error: Could not determine path for disk image!";
return false;
}
char *tc_path = string_build_path(
image_path, plist_get_string_ptr(p_tc_path, NULL), NULL);
unsigned char *trust_cache = NULL;
uint64_t trust_cache_size = 0;
if (!buffer_read_from_filename(tc_path, (char **)&trust_cache,
&trust_cache_size)) {
qDebug() << "Error: Trust cache does not exist at" << tc_path
<< "!";
return false;
}
mount_options = plist_new_dict();
plist_dict_set_item(
mount_options, "ImageTrustCache",
plist_new_data((char *)trust_cache, trust_cache_size));
free(trust_cache);
char *dmg_path = string_build_path(
image_path, plist_get_string_ptr(p_dmg_path, NULL), NULL);
free(image_path);
image_path = dmg_path;
f = fopen(image_path, "rb");
if (!f) {
qDebug() << "Error opening image file" << image_path << ":"
<< strerror(errno);
return false;
}
unsigned char buf[8192];
unsigned char sha384_digest[48];
sha384_context ctx;
sha384_init(&ctx);
fstat(fileno(f), &fst);
image_size = fst.st_size;
while (!feof(f)) {
ssize_t fr = fread(buf, 1, sizeof(buf), f);
if (fr <= 0) {
break;
}
sha384_update(&ctx, buf, fr);
}
rewind(f);
sha384_final(&ctx, sha384_digest);
unsigned char *manifest = NULL;
unsigned int manifest_size = 0;
/* check if the device already has a personalization manifest for this
* image */
if (mobile_image_mounter_query_personalization_manifest(
mim, "DeveloperDiskImage", sha384_digest, sizeof(sha384_digest),
&manifest, &manifest_size) == MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
qDebug() << "Using existing personalization manifest from device.";
} else {
/* we need to re-connect in this case */
mobile_image_mounter_free(mim);
mim = NULL;
if (mobile_image_mounter_start_service(device, &mim, TOOL_NAME) !=
MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
return false;
}
qDebug() << "No personalization manifest, requesting from TSS...";
unsigned char *nonce = NULL;
unsigned int nonce_size = 0;
/* create new TSS request and fill parameters */
plist_t request = tss_request_new(NULL);
plist_t params = plist_new_dict();
tss_parameters_add_from_manifest(params, build_identity, 1);
/* copy all `Ap,*` items from identifiers */
plist_dict_iter di = NULL;
plist_dict_new_iter(identifiers, &di);
plist_t node = NULL;
do {
char *key = NULL;
plist_dict_next_item(identifiers, di, &key, &node);
if (node) {
if (!strncmp(key, "Ap,", 3)) {
plist_dict_set_item(request, key, plist_copy(node));
}
}
free(key);
} while (node);
plist_mem_free(di);
plist_dict_copy_uint(params, identifiers, "ApECID", "UniqueChipID");
plist_dict_set_item(params, "ApProductionMode", plist_new_bool(1));
plist_dict_set_item(params, "ApSecurityMode", plist_new_bool(1));
plist_dict_set_item(params, "ApSupportsImg4", plist_new_bool(1));
/* query nonce from image mounter service */
merr = mobile_image_mounter_query_nonce(mim, "DeveloperDiskImage",
&nonce, &nonce_size);
if (merr == MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
plist_dict_set_item(params, "ApNonce",
plist_new_data((char *)nonce, nonce_size));
} else {
qDebug()
<< "ERROR: Failed to query nonce for developer disk image:"
<< merr;
return false;
}
mobile_image_mounter_free(mim);
mim = NULL;
plist_dict_set_item(
params, "ApSepNonce",
plist_new_data("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00",
20));
plist_dict_set_item(params, "UID_MODE", plist_new_bool(0));
tss_request_add_ap_tags(request, params, NULL);
tss_request_add_common_tags(request, params, NULL);
tss_request_add_ap_img4_tags(request, params);
plist_free(params);
/* request IM4M from TSS */
plist_t response = tss_request_send(request, NULL);
plist_free(request);
plist_t p_manifest = plist_dict_get_item(response, "ApImg4Ticket");
if (!PLIST_IS_DATA(p_manifest)) {
qDebug() << "Failed to get Img4Ticket";
return false;
}
uint64_t m4m_len = 0;
plist_get_data_val(p_manifest, (char **)&manifest, &m4m_len);
manifest_size = m4m_len;
plist_free(response);
qDebug() << "Done.";
}
sig = manifest;
sig_length = manifest_size;
imagetype = "Personalized";
}
char *targetname = NULL;
if (asprintf(&targetname, "%s/%s", PKG_PATH, "staging.dimage") < 0) {
qDebug() << "Out of memory!?";
return false;
}
char *mountname = NULL;
if (asprintf(&mountname, "%s/%s", PATH_PREFIX, targetname) < 0) {
qDebug() << "Out of memory!?";
return false;
}
if (!imagetype) {
imagetype = "Developer";
}
if (!mim) {
if (mobile_image_mounter_start_service(device, &mim, TOOL_NAME) !=
MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
return false;
}
}
switch (disk_image_upload_type) {
case DISK_IMAGE_UPLOAD_TYPE_UPLOAD_IMAGE:
qDebug() << "Uploading" << image_path;
err = mobile_image_mounter_upload_image(mim, imagetype, image_size, sig,
sig_length, mim_upload_cb, f);
break;
case DISK_IMAGE_UPLOAD_TYPE_AFC:
default:
qDebug() << "Uploading" << image_path << "--> afc:///" << targetname;
plist_t fileinfo = NULL;
if (afc_get_file_info_plist(afc, PKG_PATH, &fileinfo) !=
AFC_E_SUCCESS) {
if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) {
qDebug() << "WARNING: Could not create directory" << PKG_PATH
<< "on device!";
}
}
plist_free(fileinfo);
uint64_t af = 0;
if ((afc_file_open(afc, targetname, AFC_FOPEN_WRONLY, &af) !=
AFC_E_SUCCESS) ||
!af) {
fclose(f);
qDebug() << "afc_file_open on" << targetname << "failed!";
return false;
}
char buf[8192];
size_t amount = 0;
do {
amount = fread(buf, 1, sizeof(buf), f);
if (amount > 0) {
uint32_t written, total = 0;
while (total < amount) {
written = 0;
if (afc_file_write(afc, af, buf + total, amount - total,
&written) != AFC_E_SUCCESS) {
qDebug() << "AFC Write error!";
break;
}
total += written;
}
if (total != amount) {
qDebug() << "Error: wrote only" << total << "of"
<< (unsigned int)amount;
afc_file_close(afc, af);
fclose(f);
return false;
}
}
} while (amount > 0);
afc_file_close(afc, af);
break;
}
fclose(f);
if (err != MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
if (err == MOBILE_IMAGE_MOUNTER_E_DEVICE_LOCKED) {
qDebug() << "ERROR: Device is locked, can't mount. Unlock device "
"and try again.";
} else {
qDebug() << "ERROR: Unknown error occurred, can't mount.";
}
return false;
}
qDebug() << "done.";
qDebug() << "Mounting...";
err = mobile_image_mounter_mount_image_with_options(
mim, mountname, sig, sig_length, imagetype, mount_options, &result);
if (err == MOBILE_IMAGE_MOUNTER_E_SUCCESS) {
if (result) {
plist_t node = plist_dict_get_item(result, "Status");
if (node) {
char *status = NULL;
plist_get_string_val(node, &status);
if (status) {
if (!strcmp(status, "Complete")) {
qDebug() << "Done.";
res = 0;
} else {
qDebug() << "unexpected status value:";
plist_write_to_stream(result, stdout,
(xml_mode) ? PLIST_FORMAT_XML
: PLIST_FORMAT_LIMD,
(plist_write_options_t)0);
}
free(status);
} else {
qDebug() << "unexpected result:";
plist_write_to_stream(result, stdout,
(xml_mode) ? PLIST_FORMAT_XML
: PLIST_FORMAT_LIMD,
(plist_write_options_t)0);
}
}
node = plist_dict_get_item(result, "Error");
if (node) {
char *error = NULL;
plist_get_string_val(node, &error);
if (error) {
qDebug() << "Error:" << error;
free(error);
} else {
qDebug() << "unexpected result:";
plist_write_to_stream(result, stdout,
(xml_mode) ? PLIST_FORMAT_XML
: PLIST_FORMAT_LIMD,
(plist_write_options_t)0);
}
node = plist_dict_get_item(result, "DetailedError");
if (node) {
qDebug()
<< "DetailedError:" << plist_get_string_ptr(node, NULL);
}
} else {
plist_write_to_stream(result, stdout,
(xml_mode) ? PLIST_FORMAT_XML
: PLIST_FORMAT_LIMD,
(plist_write_options_t)0);
}
}
} else {
qDebug() << "Error: mount_image returned" << err;
}
if (result) {
plist_free(result);
}
// error_out:
// /* perform hangup command */
// mobile_image_mounter_hangup(mim);
// /* free client */
// mobile_image_mounter_free(mim);
// leave:
// if (afc)
// {
// afc_client_free(afc);
// }
// if (lckd)
// {
// lockdownd_client_free(lckd);
// }
// idevice_free(device);
// if (image_path)
// free(image_path);
// if (image_sig_path)
// free(image_sig_path);
// return res;
return true;
}
// int main(){return 0;}
+92
View File
@@ -0,0 +1,92 @@
/*
* idevicediagnostics.c
* Retrieves diagnostics information from device
*
* Copyright (c) 2012 Martin Szulecki All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define TOOL_NAME "idevicediagnostics"
#include <libimobiledevice/diagnostics_relay.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
// TODO:break all the client because device wont restart if any client is still
// connected we need to change the main device init function to not connect to
// any client
bool restart(idevice_t device)
{
lockdownd_client_t lockdown_client = NULL;
diagnostics_relay_client_t diagnostics_client = NULL;
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
lockdownd_service_descriptor_t service = NULL;
const char *udid = NULL;
int use_network = 0;
if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(
device, &lockdown_client, TOOL_NAME))) {
idevice_free(device);
printf("ERROR: Could not connect to lockdownd, error code %d\n", ret);
return false;
}
/* attempt to use newer diagnostics service available on iOS 5 and later */
ret = lockdownd_start_service(
lockdown_client, "com.apple.mobile.diagnostics_relay", &service);
if (ret == LOCKDOWN_E_INVALID_SERVICE) {
/* attempt to use older diagnostics service */
ret = lockdownd_start_service(
lockdown_client, "com.apple.iosdiagnostics.relay", &service);
}
lockdownd_client_free(lockdown_client);
if (ret != LOCKDOWN_E_SUCCESS) {
idevice_free(device);
printf("ERROR: Could not start diagnostics relay service: %s\n",
lockdownd_strerror(ret));
return false;
}
if ((ret == LOCKDOWN_E_SUCCESS) && service && (service->port > 0)) {
if (diagnostics_relay_client_new(device, service,
&diagnostics_client) !=
DIAGNOSTICS_RELAY_E_SUCCESS) {
printf("ERROR: Could not connect to diagnostics_relay!\n");
} else {
if (diagnostics_relay_restart(
diagnostics_client,
DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) ==
DIAGNOSTICS_RELAY_E_SUCCESS) {
printf("Restarting device.\n");
return true;
} else {
printf("ERROR: Failed to restart device.\n");
}
}
diagnostics_relay_goodbye(diagnostics_client);
diagnostics_relay_client_free(diagnostics_client);
}
if (service) {
lockdownd_service_descriptor_free(service);
service = NULL;
}
return false;
}
+124
View File
@@ -0,0 +1,124 @@
/*
* idevicesetlocation.c
* Simulate location on iOS device with mounted developer disk image
*
* Copyright (c) 2016-2020 Nikias Bassen, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define DT_SIMULATELOCATION_SERVICE "com.apple.dt.simulatelocation"
#define TOOL_NAME "idevicesetlocation"
#include <errno.h>
#include <getopt.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/service.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#include <machine/endian.h>
#define htobe32(x) OSSwapHostToBigInt32(x)
#else
#include <endian.h>
#endif
#include <QDebug>
// TODO: check for these
// if (device_version >= IDEVICE_DEVICE_VERSION(17,0,0)) {
// printf("Note: This tool is currently not supported on iOS 17+\n");
// } else {
// printf("Make sure a developer disk image is mounted!\n");
// }
enum { SET_LOCATION = 0, RESET_LOCATION = 1 };
bool set_location(idevice_t device, char *lat, char *lon)
{
uint32_t mode = 0;
lockdownd_client_t lockdown = NULL;
lockdownd_error_t lerr =
lockdownd_client_new_with_handshake(device, &lockdown, TOOL_NAME);
try {
/* code */
if (lerr != LOCKDOWN_E_SUCCESS) {
idevice_free(device);
printf("ERROR: Could not connect to lockdownd: %s (%d)\n",
lockdownd_strerror(lerr), lerr);
return false;
}
lockdownd_service_descriptor_t svc = NULL;
lerr = lockdownd_start_service(lockdown, DT_SIMULATELOCATION_SERVICE,
&svc);
if (lerr != LOCKDOWN_E_SUCCESS) {
unsigned int device_version = idevice_get_device_version(device);
lockdownd_client_free(lockdown);
idevice_free(device);
return false;
}
lockdownd_client_free(lockdown);
service_client_t service = NULL;
service_error_t serr = service_client_new(device, svc, &service);
lockdownd_service_descriptor_free(svc);
if (serr != SERVICE_E_SUCCESS) {
idevice_free(device);
return false;
}
uint32_t l;
uint32_t s = 0;
l = htobe32(mode);
service_send(service, (const char *)&l, 4, &s);
if (mode == SET_LOCATION) {
int len = 4 + strlen(lat) + 4 + strlen(lon);
char *buf = (char *)malloc(len);
uint32_t latlen;
latlen = strlen(lat);
l = htobe32(latlen);
memcpy(buf, &l, 4);
memcpy(buf + 4, lat, latlen);
uint32_t longlen = strlen(lon);
l = htobe32(longlen);
memcpy(buf + 4 + latlen, &l, 4);
memcpy(buf + 4 + latlen + 4, lon, longlen);
s = 0;
service_send(service, buf, len, &s);
free(buf); // <-- free the buffer after use
}
return true;
} catch (...) {
if (lockdown) {
lockdownd_client_free(lockdown);
}
if (device) {
idevice_free(device);
}
qDebug() << "Exception occurred while setting location.";
return false;
}
}
+92
View File
@@ -0,0 +1,92 @@
/*
* idevicediagnostics.c
* Retrieves diagnostics information from device
*
* Copyright (c) 2012 Martin Szulecki All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define TOOL_NAME "idevicediagnostics"
#include <libimobiledevice/diagnostics_relay.h>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
// TODO:break all the client because device wont restart if any client is still
// connected we need to change the main device init function to not connect to
// any client
bool shutdown(idevice_t device)
{
lockdownd_client_t lockdown_client = NULL;
diagnostics_relay_client_t diagnostics_client = NULL;
lockdownd_error_t ret = LOCKDOWN_E_UNKNOWN_ERROR;
lockdownd_service_descriptor_t service = NULL;
const char *udid = NULL;
int use_network = 0;
if (LOCKDOWN_E_SUCCESS != (ret = lockdownd_client_new_with_handshake(
device, &lockdown_client, TOOL_NAME))) {
idevice_free(device);
printf("ERROR: Could not connect to lockdownd, error code %d\n", ret);
return false;
}
/* attempt to use newer diagnostics service available on iOS 5 and later */
ret = lockdownd_start_service(
lockdown_client, "com.apple.mobile.diagnostics_relay", &service);
if (ret == LOCKDOWN_E_INVALID_SERVICE) {
/* attempt to use older diagnostics service */
ret = lockdownd_start_service(
lockdown_client, "com.apple.iosdiagnostics.relay", &service);
}
lockdownd_client_free(lockdown_client);
if (ret != LOCKDOWN_E_SUCCESS) {
idevice_free(device);
printf("ERROR: Could not start diagnostics relay service: %s\n",
lockdownd_strerror(ret));
return false;
}
if ((ret == LOCKDOWN_E_SUCCESS) && service && (service->port > 0)) {
if (diagnostics_relay_client_new(device, service,
&diagnostics_client) !=
DIAGNOSTICS_RELAY_E_SUCCESS) {
printf("ERROR: Could not connect to diagnostics_relay!\n");
} else {
if (diagnostics_relay_shutdown(
diagnostics_client,
DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) ==
DIAGNOSTICS_RELAY_E_SUCCESS) {
printf("Shutting down device.\n");
return true;
} else {
printf("ERROR: Failed to shut down device.\n");
}
}
diagnostics_relay_goodbye(diagnostics_client);
diagnostics_relay_client_free(diagnostics_client);
}
if (service) {
lockdownd_service_descriptor_free(service);
service = NULL;
}
return false;
}
+140
View File
@@ -0,0 +1,140 @@
/*
* idevicescreenshot.c
* Gets a screenshot from a device
*
* Copyright (C) 2010 Nikias Bassen <nikias@gmx.li>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define TOOL_NAME "idevicescreenshot"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#ifndef _WIN32
#include <signal.h>
#endif
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/screenshotr.h>
static void get_image_filename(char *imgdata, char **filename)
{
// If the provided filename already has an extension, use it as is.
if (*filename) {
char *last_dot = strrchr(*filename, '.');
if (last_dot && !strchr(last_dot, '/')) {
return;
}
}
// Find the appropriate file extension for the filename.
const char *fileext = NULL;
if (memcmp(imgdata, "\x89PNG", 4) == 0) {
fileext = ".png";
} else if (memcmp(imgdata, "MM\x00*", 4) == 0) {
fileext = ".tiff";
} else {
printf("WARNING: screenshot data has unexpected image format.\n");
fileext = ".dat";
}
// If a filename without an extension is provided, append the extension.
// Otherwise, generate a filename based on the current time.
char *basename = NULL;
if (*filename) {
basename = (char*)malloc(strlen(*filename) + 1);
strcpy(basename, *filename);
free(*filename);
*filename = NULL;
} else {
time_t now = time(NULL);
basename = (char*)malloc(32);
strftime(basename, 31, "screenshot-%Y-%m-%d-%H-%M-%S", gmtime(&now));
}
// Ensure the filename is unique on disk.
char *unique_filename = (char*)malloc(strlen(basename) + strlen(fileext) + 7);
sprintf(unique_filename, "%s%s", basename, fileext);
int i;
for (i = 2; i < (1 << 16); i++) {
if (access(unique_filename, F_OK) == -1) {
*filename = unique_filename;
break;
}
sprintf(unique_filename, "%s-%d%s", basename, i, fileext);
}
if (!*filename) {
free(unique_filename);
}
free(basename);
}
int take_screenshot(idevice_t device, lockdownd_service_descriptor_t service) {
screenshotr_client_t *shotr = nullptr;
char *filename = NULL;
int result=1;
try
{
/* code */
if (screenshotr_client_new(device, service, &shotr) != SCREENSHOTR_E_SUCCESS) {
printf("Could not connect to screenshotr!\n");
} else {
char *imgdata = NULL;
uint64_t imgsize = 0;
if (screenshotr_take_screenshot(*shotr, &imgdata, &imgsize) == SCREENSHOTR_E_SUCCESS) {
get_image_filename(imgdata, &filename);
if (!filename) {
printf("FATAL: Could not find a unique filename!\n");
} else {
FILE *f = fopen(filename, "wb");
if (f) {
if (fwrite(imgdata, 1, (size_t)imgsize, f) == (size_t)imgsize) {
printf("Screenshot saved to %s\n", filename);
result = 0;
} else {
printf("Could not save screenshot to file %s!\n", filename);
}
fclose(f);
} else {
printf("Could not open %s for writing: %s\n", filename, strerror(errno));
}
}
} else {
printf("Could not get screenshot!\n");
}
screenshotr_client_free(shotr);
}
return result;
}
catch(const std::exception& e)
{
return result;
std::cerr << e.what() << '\n';
}
}
+61
View File
@@ -0,0 +1,61 @@
/*
* idevicescreenshot.c
* Gets a screenshot from a device
*
* Copyright (C) 2010 Nikias Bassen <nikias@gmx.li>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "../../iDescriptor.h"
#include <QByteArray>
#include <QDate>
#include <QDebug>
#include <QImage>
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/screenshotr.h>
QImage get_image(const char *imgdata, uint64_t imgsize)
{
QByteArray byteArray(imgdata, static_cast<int>(imgsize));
QImage image;
image.loadFromData(byteArray);
return image;
}
TakeScreenshotResult take_screenshot(screenshotr_client_t shotr)
{
TakeScreenshotResult result;
try {
char *imgdata = NULL;
uint64_t imgsize = 0;
if (screenshotr_take_screenshot(shotr, &imgdata, &imgsize) ==
SCREENSHOTR_E_SUCCESS) {
QImage image = get_image(imgdata, imgsize);
if (image.isNull()) {
printf("Could not decode screenshot image!\n");
} else {
result.img = image;
result.success = true;
}
// Always free imgdata after use!
free(imgdata);
}
} catch (const std::exception &e) {
qDebug() << "Exception occurred while taking screenshot:" << e.what();
}
// Always return result!
return result;
}