commit 752d32600c338f067394d6b09ab2a7881cc4faa5 Author: Nick Chan Date: Mon Jan 16 16:17:41 2023 +0800 dfuhelper only diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c4ca332 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +dep_root/** +contrib/** +!dep_root/.keep +!contrib/.keep +contrib/ +*.o +.vscode +checkra1n* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b0cc49e --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +SRC = $(shell pwd) +DEP = $(SRC)/dep_root +CC = cc +CFLAGS = -mmacosx-version-min=12.0 -I$(DEP)/include -I/opt/procursus/include -I$(SRC)/include -g -O0 -Wall -Wextra +LIBS = $(DEP)/lib/libimobiledevice-1.0.a $(DEP)/lib/libirecovery-1.0.a $(DEP)/lib/libusbmuxd-2.0.a $(DEP)/lib/libplist-2.0.a $(DEP)/lib/libimobiledevice-glue-1.0.a -pthread +LIBS += $(DEP)/lib/libcrypto.35.tbd $(DEP)/lib/libssl.35.tbd +LIBS += -framework CoreFoundation -framework SystemConfiguration -framework IOKit +LDFLAGS = $(LIBS) + +export SRC DEP CC CFLAGS LDFLAGS + +all: palera1n + +palera1n: + $(MAKE) -C src + +clean: + $(MAKE) -C src clean + +.PHONY: all palera1n clean diff --git a/dep_root/.keep b/dep_root/.keep new file mode 100644 index 0000000..e69de29 diff --git a/include/ANSI-color-codes.h b/include/ANSI-color-codes.h new file mode 100644 index 0000000..538ab65 --- /dev/null +++ b/include/ANSI-color-codes.h @@ -0,0 +1,85 @@ +/* + * This is free and unencumbered software released into the public domain. + * + * For more information, please refer to + */ + +#ifndef ANSI_COLOR_CODES_H +#define ANSI_COLOR_CODES_H + +//Regular text +#define BLK "\e[0;30m" +#define RED "\e[0;31m" +#define GRN "\e[0;32m" +#define YEL "\e[0;33m" +#define BLU "\e[0;34m" +#define MAG "\e[0;35m" +#define CYN "\e[0;36m" +#define WHT "\e[0;37m" + +//Regular bold text +#define BBLK "\e[1;30m" +#define BRED "\e[1;31m" +#define BGRN "\e[1;32m" +#define BYEL "\e[1;33m" +#define BBLU "\e[1;34m" +#define BMAG "\e[1;35m" +#define BCYN "\e[1;36m" +#define BWHT "\e[1;37m" + +//Regular underline text +#define UBLK "\e[4;30m" +#define URED "\e[4;31m" +#define UGRN "\e[4;32m" +#define UYEL "\e[4;33m" +#define UBLU "\e[4;34m" +#define UMAG "\e[4;35m" +#define UCYN "\e[4;36m" +#define UWHT "\e[4;37m" + +//Regular background +#define BLKB "\e[40m" +#define REDB "\e[41m" +#define GRNB "\e[42m" +#define YELB "\e[43m" +#define BLUB "\e[44m" +#define MAGB "\e[45m" +#define CYNB "\e[46m" +#define WHTB "\e[47m" + +//High intensty background +#define BLKHB "\e[0;100m" +#define REDHB "\e[0;101m" +#define GRNHB "\e[0;102m" +#define YELHB "\e[0;103m" +#define BLUHB "\e[0;104m" +#define MAGHB "\e[0;105m" +#define CYNHB "\e[0;106m" +#define WHTHB "\e[0;107m" + +//High intensty text +#define HBLK "\e[0;90m" +#define HRED "\e[0;91m" +#define HGRN "\e[0;92m" +#define HYEL "\e[0;93m" +#define HBLU "\e[0;94m" +#define HMAG "\e[0;95m" +#define HCYN "\e[0;96m" +#define HWHT "\e[0;97m" + +//Bold high intensity text +#define BHBLK "\e[1;90m" +#define BHRED "\e[1;91m" +#define BHGRN "\e[1;92m" +#define BHYEL "\e[1;93m" +#define BHBLU "\e[1;94m" +#define BHMAG "\e[1;95m" +#define BHCYN "\e[1;96m" +#define BHWHT "\e[1;97m" + +//Reset +#define reset "\e[0m" +#define CRESET "\e[0m" +#define COLOR_RESET "\e[0m" + +#endif diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..404289d --- /dev/null +++ b/src/Makefile @@ -0,0 +1,14 @@ +all: palera1n + +OBJECTS = main.o dfuhelper.o lockdown_helper.o devhelper.o + +%.o: %.c + $(CC) -c $(CFLAGS) $< + +palera1n: $(OBJECTS) + $(CC) $(OBJECTS) $(CFLAGS) $(LDFLAGS) -o palera1n + +clean: + rm -f *.o palera1n + +.PHONY: all clean \ No newline at end of file diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..225819c --- /dev/null +++ b/src/common.h @@ -0,0 +1,60 @@ +#ifndef COMMON_H +#define COMMON_H + +#include "lockdown_helper.h" +#include +#include +#include +#include +#include +#include + +#define LOG(loglevel, ...) p1_log(loglevel, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define CLEAR() printf("\33[2K\r"); + +typedef enum { + LOG_FATAL = 0, + LOG_ERROR = 1, + LOG_WARNING = 2, + LOG_INFO = 3, + LOG_VERBOSE = 4, + LOG_DEBUG = 5 +} log_level_t; + +typedef struct { + uint64_t ecid; + char* productType; + char* productVersion; + char* buildVersion; + char* CPUArchitecture; + const char* displayName; +} devinfo_t; + +typedef struct { + int mode; + unsigned int cpid; + char product_type[0x20]; + char display_name[0x20]; + char iboot_ver[0x20]; +} recvinfo_t; + +// set this value to 0 gracefully exit +extern int spin; + +void* dfuhelper(void* ptr); +int p1_log(log_level_t loglevel, const char *fname, int lineno, const char *fxname, char* __restrict format, ...); +/* devhelper helpers */ +void devinfo_free(devinfo_t *dev); +bool cpid_is_arm64(unsigned int cpid); +/* devhelper commands */ +int subscribe_cmd(usbmuxd_event_cb_t device_event_cb, irecv_device_event_cb_t irecv_event_cb); +int unsubscribe_cmd(); +int devinfo_cmd(devinfo_t *dev, const char *udid); +int enter_recovery_cmd(const char* udid); +int reboot_cmd(const char* udid); +int passstat_cmd(char* status, const char* udid); +int recvinfo_cmd(recvinfo_t* info, const uint64_t ecid); +int autoboot_cmd(const uint64_t ecid); +int exitrecv_cmd(const uint64_t ecid); + +#endif \ No newline at end of file diff --git a/src/devhelper.c b/src/devhelper.c new file mode 100644 index 0000000..3509969 --- /dev/null +++ b/src/devhelper.c @@ -0,0 +1,399 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#include +#else +#include +#include +#include +#include +#include +#endif +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "lockdown_helper.h" + +#ifdef HAVE_LIB_TV_CONTROL +#include +#endif + +#include "common.h" + +irecv_device_event_context_t irecvctx = NULL; + +void devinfo_free(devinfo_t *dev) { + free(dev->buildVersion); + free(dev->productType); + free(dev->productVersion); + free(dev->CPUArchitecture); + return; +} + +bool cpid_is_arm64(unsigned int cpid) { + /* + * ========== 0x6000 =========== + * M1 Pro, M1 Max, etc. + * ========== 0x7000 =========== + * (ARM64) A8(X) + * ========== 0x7002 =========== + * S1 + * ========== 0x8000 =========== + * (ARM64) A9 (Samsung), A9X + * ========== 0x8002 =========== + * S1P, S2, T1 + * ========== 0x8003 =========== + * (ARM64) A9 (TSMC) + * ========== 0x8004 =========== + * S3 - S5 + * ========== 0x8010 =========== + * (ARM64) A10(X) - A11, T2 + * ========== 0x8020 =========== + * A12, M1, M2, etc + * ========== 0x8700 =========== + * iPod SoCs + * ========== 0x8747 =========== + * Haywire + * ========== 0x8900 =========== + * S5L8900 - A6(X) + * ========== 0x8960 =========== + * (ARM64) A7 + */ + if ( + cpid == 0x8960 || cpid == 0x7000 || cpid == 0x7001 + || cpid == 0x8000 || cpid == 0x8001 || cpid == 0x8003 + || cpid == 0x8010 || cpid == 0x8011 || cpid == 0x8012 + || cpid == 0x8015 + + ) return true; + return false; +} + +int subscribe_cmd(usbmuxd_event_cb_t device_event_cb, irecv_device_event_cb_t irecv_event_cb) +{ + usbmuxd_subscribe(device_event_cb, NULL); + irecv_device_event_subscribe(&irecvctx, irecv_event_cb, NULL); + return 0; +} + +int unsubscribe_cmd() +{ + usbmuxd_unsubscribe(); + irecv_device_event_unsubscribe(irecvctx); + irecvctx = NULL; + return 0; +} + +int devinfo_cmd(devinfo_t *dev, const char *udid) +{ + uint64_t this_ecid = 0; + char *productType = NULL; + char *productVersion = NULL; + char *buildVersion = NULL; + const char *displayName = NULL; + char *CPUArchitecture = NULL; + idevice_t device = NULL; + lockdownd_client_t lockdown = NULL; + if (idevice_new(&device, udid) != IDEVICE_E_SUCCESS) + { + LOG(LOG_ERROR, "Error connecting to device."); + return -1; + } + if (lockdownd_client_new(device, &lockdown, "devhelper") != LOCKDOWN_E_SUCCESS) + { + idevice_free(device); + LOG(LOG_ERROR, "Device is not in normal mode."); + return -1; + } + plist_t node = NULL; + if (lockdownd_get_value(lockdown, NULL, "UniqueChipID", &node) != LOCKDOWN_E_SUCCESS) + { + lockdownd_client_free(lockdown); + idevice_free(device); + LOG(LOG_ERROR, "Error getting ECID"); + return -1; + } + plist_get_uint_val(node, &this_ecid); + plist_free(node); + + node = NULL; + if (lockdownd_get_value(lockdown, NULL, "ProductType", &node) != LOCKDOWN_E_SUCCESS) + { + lockdownd_client_free(lockdown); + idevice_free(device); + LOG(LOG_ERROR, "Error getting product type"); + return -1; + } + plist_get_string_val(node, &productType); + plist_free(node); + + node = NULL; + if (lockdownd_get_value(lockdown, NULL, "CPUArchitecture", &node) != LOCKDOWN_E_SUCCESS) + { + lockdownd_client_free(lockdown); + idevice_free(device); + LOG(LOG_ERROR, "Error getting CPU type"); + return -1; + } + plist_get_string_val(node, &CPUArchitecture); + plist_free(node); + + node = NULL; + if (lockdownd_get_value(lockdown, NULL, "ProductVersion", &node) != LOCKDOWN_E_SUCCESS) + { + lockdownd_client_free(lockdown); + idevice_free(device); + LOG(LOG_ERROR, "Error getting product version"); + return -1; + } + plist_get_string_val(node, &productVersion); + plist_free(node); + + node = NULL; + if (lockdownd_get_value(lockdown, NULL, "BuildVersion", &node) != LOCKDOWN_E_SUCCESS) + { + lockdownd_client_free(lockdown); + idevice_free(device); + LOG(LOG_ERROR, "Error getting build version"); + return -1; + } + plist_get_string_val(node, &buildVersion); + plist_free(node); + lockdownd_client_free(lockdown); + idevice_free(device); + irecv_device_t rcvydev; + if (irecv_devices_get_device_by_product_type(productType, &rcvydev) == IRECV_E_SUCCESS) + { + displayName = rcvydev->display_name; + } + else + { + displayName = productType; + } + dev->buildVersion = buildVersion; + dev->ecid = this_ecid; + dev->CPUArchitecture = CPUArchitecture; + dev->displayName = displayName; + dev->productType = productType; + dev->productVersion = productVersion; + return 0; +} + +int enter_recovery_cmd(const char* udid) { + idevice_t device = NULL; + lockdownd_client_t lockdown = NULL; + if (idevice_new(&device, udid) != IDEVICE_E_SUCCESS) { + LOG(LOG_ERROR, "Could not connect to device"); + return -1; + } + lockdownd_error_t ldret = lockdownd_client_new(device, &lockdown, "devhelper"); + if (ldret != LOCKDOWN_E_SUCCESS) { + LOG(LOG_ERROR, "Could not connect to lockdownd: %s", lockdownd_strerror(ldret)); + return -1; + } + do { + ldret = lockdownd_enter_recovery(lockdown); + if (ldret == LOCKDOWN_E_SESSION_INACTIVE) { + lockdownd_client_free(lockdown); + lockdown = NULL; + if (LOCKDOWN_E_SUCCESS != (ldret = lockdownd_client_new_with_handshake(device, &lockdown, "devhelper"))) { + LOG(LOG_ERROR, "Could not connect to lockdownd: %s", lockdownd_strerror(ldret)); + return -1; + } + ldret = lockdownd_enter_recovery(lockdown); + } + if (ldret != LOCKDOWN_E_SUCCESS) { + LOG(LOG_ERROR, "Could not trigger entering recovery mode: %s", lockdownd_strerror(ldret)); + return -1; + } + lockdownd_client_free(lockdown); + } while (0); + idevice_free(device); + return 0; +} + +int reboot_cmd(const char* udid) { + idevice_t device = NULL; + lockdownd_client_t lockdown = NULL; + if (idevice_new(&device, udid) != IDEVICE_E_SUCCESS) { + LOG(LOG_ERROR, "Could not connect to device"); + return -1; + } else { + diagnostics_relay_client_t diag = NULL; + if (diagnostics_relay_client_start_service(device, &diag, "devhelper") == DIAGNOSTICS_RELAY_E_SUCCESS) { + if (diagnostics_relay_restart(diag, DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) != DIAGNOSTICS_RELAY_E_SUCCESS) { + LOG(LOG_ERROR, "Could not reboot device."); + } + diagnostics_relay_goodbye(diag); + diagnostics_relay_client_free(diag); + } else { + LOG(LOG_ERROR, "Could not connect to device."); + return -1; + } + idevice_free(device); + } + return 0; +} + +int passstat_cmd(char* status, const char* udid) { + lockdownd_error_t lerr = LOCKDOWN_E_SUCCESS; + diagnostics_relay_error_t derr = DIAGNOSTICS_RELAY_E_SUCCESS; + + idevice_t dev = NULL; + lockdownd_client_t lockdown = NULL; + lockdownd_service_descriptor_t service = NULL; + diagnostics_relay_client_t diagnostics_client = NULL; + plist_t node = NULL; + plist_t keys = NULL; + plist_t status_node = NULL; + plist_t value_node = NULL; + + if (idevice_new(&dev, udid) != IDEVICE_E_SUCCESS) + { + LOG(LOG_ERROR, "Error detecting device type\n"); + return -1; + } + lerr = lockdownd_client_new_with_handshake(dev, &lockdown, "idevicediagnostics"); + if ((lerr != LOCKDOWN_E_SUCCESS) || !lockdown) + { + idevice_free(dev); + LOG(LOG_ERROR, "Error connecting to lockdownd (lockdownd error %d)\n", lerr); + return -1; + } + lerr = lockdownd_start_service(lockdown, "com.apple.mobile.diagnostics_relay", &service); + if ((lerr != LOCKDOWN_E_SUCCESS) || !service) + lerr = lockdownd_start_service(lockdown, "com.apple.iosdiagnostics.relay", &service); + + lockdownd_client_free(lockdown); + if ((lerr != LOCKDOWN_E_SUCCESS) || !service) + { + idevice_free(dev); + LOG(LOG_ERROR, "Error starting diagnostics service (lockdownd error %d)\nUnlock the device and try again.\n", lerr); + return -1; + } + derr = diagnostics_relay_client_new(dev, service, &diagnostics_client); + if ((derr != DIAGNOSTICS_RELAY_E_SUCCESS) || !diagnostics_client) + { + lockdownd_service_descriptor_free(service); + idevice_free(dev); + LOG(LOG_ERROR, "Error starting diagnostics client (lockdownd error %d)\n", derr); + return -1; + } + keys = plist_new_array(); + plist_array_append_item(keys, plist_new_string("xsaMbRQ5rQ+eyKMKG+ZSSg")); + derr = diagnostics_relay_query_mobilegestalt(diagnostics_client, keys, &node); + + plist_free(keys); + diagnostics_relay_client_free(diagnostics_client); + lockdownd_service_descriptor_free(service); + idevice_free(dev); + + if (derr != DIAGNOSTICS_RELAY_E_SUCCESS || !node) + { + LOG(LOG_ERROR, "Error getting passcode state (lockdownd error %d)", lerr); + return -1; + } + status_node = plist_access_path(node, 2, "MobileGestalt", "Status"); + if (!status_node) + { + plist_free(node); + LOG(LOG_ERROR, "Error getting passcode state (invalid status node)\n"); + return -1; + } + plist_get_string_val(status_node, &status); + if (!status || strncmp(status, "Succ", 4)) + { + if (status) + free(status); + + plist_free(node); + LOG(LOG_ERROR, "Error getting passcode state (invalid status)"); + return -1; + } + + free(status); + value_node = plist_access_path(node, 2, "MobileGestalt", "xsaMbRQ5rQ+eyKMKG+ZSSg"); + if (!value_node) + { + plist_free(node); + LOG(LOG_ERROR, "Error getting passcode state (invalid value node)\n"); + return -1; + } + uint8_t passcode_state = 2; + plist_get_bool_val(value_node, &passcode_state); + plist_free(node); + *status = passcode_state; + return 0; +} + +int recvinfo_cmd(recvinfo_t* info, const uint64_t ecid) { + irecv_client_t client = NULL; + irecv_error_t err = irecv_open_with_ecid(&client, ecid); + if (err != IRECV_E_SUCCESS) { + LOG(LOG_ERROR, "libirecovery error: %d\n", err); + return -1; + } + int mode = 0; + irecv_get_mode(client, &mode); + char *ibootver = NULL; + irecv_getenv(client, "build-version", &ibootver); + irecv_device_t device; + err = irecv_devices_get_device_by_client(client, &device); + if (err != IRECV_E_SUCCESS) { + LOG(LOG_ERROR, "libirecovery error: %d\n", err); + return -1; + } + info->mode = mode; + info->cpid = device->chip_id; + strncpy(info->product_type, device->product_type, 0x20); + strncpy(info->display_name, device->display_name, 0x20); + strncpy(info->iboot_ver, (ibootver) ? ibootver : "", 0x20); + free(ibootver); + irecv_close(client); + return 0; +} + +int autoboot_cmd(const uint64_t ecid) { + irecv_client_t client = NULL; + irecv_error_t err = irecv_open_with_ecid(&client, ecid); + if (err == IRECV_E_SUCCESS) { + irecv_setenv(client, "auto-boot", "true"); + irecv_saveenv(client); + irecv_close(client); + return 0; + } else { + LOG(LOG_ERROR, "libirecovery error: %d\n", err); + return -1; + } +} + +int exitrecv_cmd(const uint64_t ecid) { + irecv_client_t client = NULL; + irecv_error_t err = irecv_open_with_ecid(&client, ecid); + if (err == IRECV_E_SUCCESS) { + irecv_setenv(client, "auto-boot", "true"); + irecv_saveenv(client); + irecv_reboot(client); + irecv_close(client); + return 0; + } else { + LOG(LOG_ERROR, "libirecovery error: %d\n", err); + return -1; + } +} diff --git a/src/dfuhelper.c b/src/dfuhelper.c new file mode 100644 index 0000000..fcecccb --- /dev/null +++ b/src/dfuhelper.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ANSI-color-codes.h" +#include "common.h" + +#define FORMAT_KEY_VALUE 1 +#define FORMAT_XML 2 + +#define NOHOME (info->cpid == 0x8015 || (info->cpid == 0x8010 && (info->bdid == 0x08 || info->bdid == 0x0a || info->bdid == 0x0c || info->bdid == 0x0e))) + +int spin = 1; +uint64_t ecid_wait_for_dfu = 0; + +void step(int time, int time2, char *text, bool (*cond)(uint64_t), uint64_t cond_arg) { + for (int i = time2; i < time; i++) { + printf(CYN "\r\e[K%s (%d)" CRESET, text, time - i + time2); + fflush(stdout); + sleep(1); + if (cond != NULL && cond(cond_arg)) return; + } + printf(CYN "\r%s (%d)" CRESET, text, time2); + if (time2 == 0) puts(""); +} + +int connected_normal_mode(const usbmuxd_device_info_t *usbmuxd_device) { + devinfo_t dev; + int ret; + ret = devinfo_cmd(&dev, usbmuxd_device->udid); + if (ret != 0) { + LOG(LOG_ERROR, "Unable to get device information"); + return 0; + } + if (strcmp(dev.CPUArchitecture, "arm64")) { + devinfo_free(&dev); + LOG(LOG_WARNING, "Ignoring non-arm64 device..."); + return -1; + } + if (strncmp(dev.productType, "iPhone10,", strlen("iPhone10,"))) { + char passcode_state = 0; + ret = passstat_cmd(&passcode_state, usbmuxd_device->udid); + if (ret != 0) { + LOG(LOG_ERROR, "Failed to get passcode state"); + devinfo_free(&dev); + return -1; + } + if (passcode_state) { + LOG(LOG_ERROR, "Passcode must be disabled on this device"); + devinfo_free(&dev); + return -1; + } + } + LOG(LOG_INFO, "Telling device with udid %s to enter recovery mode immediately", usbmuxd_device->udid); + enter_recovery_cmd(usbmuxd_device->udid); + devinfo_free(&dev); + return 0; +} + +static bool conditional(uint64_t ecid) { + return ecid_wait_for_dfu == ecid; +} + +void* connected_recovery_mode(struct irecv_device_info* info) { + int ret; + if (!cpid_is_arm64(info->cpid)) { + LOG(LOG_WARNING, "Ignoring non-arm64 device..."); + return NULL; + } + + ret = autoboot_cmd(info->ecid); + if (ret) { + LOG(LOG_ERROR, "Cannot set auto-boot back to true"); + return NULL; + } + LOG(LOG_INFO, "Press any key when ready for DFU mode"); + getchar(); + if (NOHOME) + step(4, 2, "Hold Volume Down + Side button", NULL, 0); + else + step(4, 2, "Hold Home + Power Button", NULL, 0); + + ret = exitrecv_cmd(info->ecid); + if (ret) { + LOG(LOG_ERROR, "Cannot exit recovery mode"); + return NULL; + } + printf("\r\e[K"); + ecid_wait_for_dfu = info->ecid; + bool nohome = NOHOME; + if (nohome) + step(2, 0, "Hold Volume Down + Side button", NULL, 0); + else + step(2, 0, "Hold Home + Power Button", NULL, 0); + if (nohome) + step(10, 0, "Hold Volume Down button", conditional, info->ecid); + else + step(10, 0, "Hold Home button", conditional, info->ecid); + if (ecid_wait_for_dfu != info->ecid) { + LOG(LOG_INFO, "Device entered DFU mode successfully"); + } else { + LOG(LOG_WARNING, "Whoops, device did not enter DFU mode"); + LOG(LOG_INFO, "Waiting for device to reconnect..."); + return NULL; + } + return NULL; +} + +void* connected_dfu_mode(struct irecv_device_info* info) { + + unsubscribe_cmd(); + if (ecid_wait_for_dfu == info->ecid) ecid_wait_for_dfu = 0; + spin = 0; + return NULL; +} + +void device_event_cb(const usbmuxd_event_t *event, void *userdata) { + switch (event->event) { + case UE_DEVICE_ADD: + LOG(LOG_VERBOSE, "Normal mode device connected"); + connected_normal_mode(&event->device); + break; + case UE_DEVICE_REMOVE: + LOG(LOG_VERBOSE, "Normal mode device disconnected"); + break; + } +} + +void irecv_device_event_cb(const irecv_device_event_t *event, void *userdata) { + pthread_t recovery_thread, dfu_thread; + switch(event->type) { + case IRECV_DEVICE_ADD: + if (event->mode == IRECV_K_RECOVERY_MODE_1 || event->mode == IRECV_K_RECOVERY_MODE_2 || event->mode == IRECV_K_RECOVERY_MODE_3 || event->mode == IRECV_K_RECOVERY_MODE_4) { + LOG(LOG_VERBOSE, "Recovery mode device %ld connected", event->device_info->ecid); + pthread_create(&recovery_thread, NULL, (void* (*)(void*))connected_recovery_mode, event->device_info); + } else if (event->mode == IRECV_K_DFU_MODE) { + LOG(LOG_VERBOSE, "DFU mode device %ld connected", event->device_info->ecid); + pthread_create(&dfu_thread, NULL, (void* (*)(void*))connected_dfu_mode, event->device_info); + } + break; + case IRECV_DEVICE_REMOVE: + if (event->mode == IRECV_K_RECOVERY_MODE_1 || event->mode == IRECV_K_RECOVERY_MODE_2 || event->mode == IRECV_K_RECOVERY_MODE_3 || event->mode == IRECV_K_RECOVERY_MODE_4) { + LOG(LOG_VERBOSE, "Recovery mode device %ld disconnected", event->device_info->serial_string); + } else if (event->mode == IRECV_K_DFU_MODE) { + LOG(LOG_VERBOSE, "DFU mode device %ld disconnected", event->device_info->ecid); + } + break; + } +} + +void *dfuhelper(void *ptr) { + // idevice_set_debug_level(1); + // irecv_set_debug_level(1); + subscribe_cmd(device_event_cb, irecv_device_event_cb); + while (spin) { + sleep(1); + }; + return 0; +} diff --git a/src/exec_checkra1n.c b/src/exec_checkra1n.c new file mode 100644 index 0000000..e69de29 diff --git a/src/lockdown_helper.c b/src/lockdown_helper.c new file mode 100644 index 0000000..91ac3f3 --- /dev/null +++ b/src/lockdown_helper.c @@ -0,0 +1,255 @@ +#ifndef HAVE_LIBIMOBILEDEVICE +#include "lockdown_helper.h" +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#define log_debug(...) fprintf(stderr, __VA_ARGS__); fputc('\n', stderr) +#else +#define log_debug(...) +#endif +#define log_error(...) fprintf(stderr, __VA_ARGS__); fputc('\n', stderr) + +int lockdown_connect_handle(uint32_t handle) +{ + int fd = usbmuxd_connect(handle, 62078); + if (fd < 0) { + log_debug("Can't connect to lockownd on device #%u", handle); + return fd; + } + return fd; +} + +int lockdown_connect_udid(const char* udid) +{ + usbmuxd_device_info_t device; + if (usbmuxd_get_device_by_udid(udid, &device) < 0) { + log_debug("Can't find device %s", udid); + return -ENOENT; + } + return lockdown_connect_handle(device.handle); +} + +void lockdown_disconnect(int fd) +{ + usbmuxd_disconnect(fd); +} + +int lockdown_check_type(int fd, const char* type_match); + +static const char QUERY_TYPE_REQUEST[] = "____Labelpalera1nRequestQueryType"; +static const char GET_VALUE_DOMAIN_REQUEST_FMT[] = "____Labelpalera1nDomain%sKey%sRequestGetValue"; +static const char GET_VALUE_REQUEST_FMT[] = "____Labelpalera1nKey%sRequestGetValue"; +static const char VALUE_KEY_NODE[] = "Value"; +static const char INTEGER_NODE[] = ""; +static const char STRING_NODE[] = ""; +static const char ENTER_RECOVERY_REQUEST[] = "____Labelpalera1nRequestEnterRecovery"; +static const char ERROR_KEY_NODE[] = "Error"; +static const char ENTER_RECOVERY_STRING_NODE[] = "EnterRecovery"; +static const int VALUE_KEY_NODE_SIZE = sizeof(VALUE_KEY_NODE)-1; +static const int INTEGER_NODE_SIZE = sizeof(INTEGER_NODE)-1; +static const int STRING_NODE_SIZE = sizeof(STRING_NODE)-1; +static const int ERROR_KEY_NODE_SIZE = sizeof(ERROR_KEY_NODE)-1; + +static void skip_ws(char** cur, char* end) +{ + char* p = *cur; + while (p < end && ((*p == ' ') || (*p == '\t') || (*p == '\r') || (*p == '\n'))) { + p++; + } + *cur = p; +} + +static char* _send_request_and_get_reply(int fd, const char* request, uint32_t len, uint32_t* received) +{ + uint32_t sent_bytes = 0; + usbmuxd_send(fd, request, len, &sent_bytes); + if (sent_bytes != len) { + usbmuxd_disconnect(fd); + log_error("Failed to send data payload"); + return NULL; + } + + uint32_t recv_bytes = 0; + uint32_t besize = 0; + int r = usbmuxd_recv(fd, (char*)&besize, sizeof(besize), &recv_bytes); + if (recv_bytes != sizeof(besize)) { + usbmuxd_disconnect(fd); + log_error("Failed to get size of packet (%d)", r); + return NULL; + } + + uint32_t resp_size = ntohl(besize); + char* resp = (char*)malloc(resp_size+1); + + recv_bytes = 0; + usbmuxd_recv(fd, resp, resp_size, &recv_bytes); + if (recv_bytes != resp_size) { + usbmuxd_disconnect(fd); + free(resp); + log_error("Failed to receive payload"); + return NULL; + } + resp[resp_size] = '\0'; + *received = resp_size; + return resp; +} + +int lockdown_check_type(int fd, const char* type_match) +{ + unsigned char tmp[512]; + uint32_t len = (uint32_t)sprintf((char*)tmp, QUERY_TYPE_REQUEST); + uint32_t belen = htonl(len-4); + *(uint32_t*)tmp = belen; + uint32_t resp_size = 0; + char* resp = _send_request_and_get_reply(fd, (char*)tmp, len, &resp_size); + if (!resp) { + log_error("Failed to get lockdown type"); + return -1; + } + + int result = (strstr(resp, type_match) == NULL) ? -1 : 0; + free(resp); + + return result; +} + +int lockdown_get_uint_value(int fd, const char* domain, const char* key, uint64_t* value) +{ + char tmp[1024]; + uint32_t len; + if (domain) { + len = sprintf(tmp, GET_VALUE_DOMAIN_REQUEST_FMT, domain, key); + } else { + len = sprintf(tmp, GET_VALUE_REQUEST_FMT, key); + } + *(uint32_t*)&tmp = htonl(len-4); + + uint32_t resp_size = 0; + char* resp = _send_request_and_get_reply(fd, tmp, len, &resp_size); + if (!resp) { + log_error("Failed to get value for key %s", key); + return -1; + } + + char* p = strstr(resp, VALUE_KEY_NODE); + if (!p) { + log_debug("Failed to get Value key node?!"); + return -1; + } + p += VALUE_KEY_NODE_SIZE; + skip_ws(&p, resp+resp_size); + if (p >= resp+resp_size) { + log_debug("Failed to get value node"); + return -1; + } + if (strncmp(p, INTEGER_NODE, INTEGER_NODE_SIZE) != 0) { + log_debug("Failed to parse value node"); + return -1; + } + p += INTEGER_NODE_SIZE; + *value = (uint64_t)strtoll(p, NULL, 10); + free(resp); + + return 0; +} + +int lockdown_get_string_value(int fd, const char* domain, const char* key, char** value) +{ + char tmp[1024]; + uint32_t len; + if (domain) { + len = sprintf(tmp, GET_VALUE_DOMAIN_REQUEST_FMT, domain, key); + } else { + len = sprintf(tmp, GET_VALUE_REQUEST_FMT, key); + } + *(uint32_t*)&tmp = htonl(len-4); + + uint32_t resp_size = 0; + char* resp = _send_request_and_get_reply(fd, tmp, len, &resp_size); + if (!resp) { + log_error("Failed to get value for key %s", key); + return -1; + } + + char* p = strstr(resp, VALUE_KEY_NODE); + if (!p) { + log_debug("Failed to get Value key node?!"); + free(resp); + return -1; + } + p += VALUE_KEY_NODE_SIZE; + skip_ws(&p, resp+resp_size); + if (p >= resp+resp_size) { + log_debug("Failed to get value node"); + free(resp); + return -1; + } + if (strncmp(p, STRING_NODE, STRING_NODE_SIZE) != 0) { + log_debug("Failed to parse value node"); + free(resp); + return -1; + } + p += STRING_NODE_SIZE; + char* str_start = p; + while (*p != '<' && *p != '\0') p++; + if (*p == '\0') { + log_debug("Failed to parse string value node"); + free(resp); + return -1; + } + size_t str_len = p - str_start; + *value = (char*)malloc(str_len + 1); + strncpy(*value, str_start, str_len); + (*value)[str_len] = '\0'; + free(resp); + + return 0; +} + +int lockdown_enter_recovery(int fd) +{ + char tmp[512]; + uint32_t len = (uint32_t)sprintf(tmp, ENTER_RECOVERY_REQUEST); + *(uint32_t*)&tmp = htonl(len-4); + uint32_t resp_size = 0; + char* resp = _send_request_and_get_reply(fd, tmp, len, &resp_size); + if (!resp) { + log_error("Failed to enter recover?"); + return -1; + } + + int result = -1; + char* p = strstr(resp, ERROR_KEY_NODE); + if (p) { + char* str_start = NULL; + size_t str_len = 0; + p += ERROR_KEY_NODE_SIZE; + skip_ws(&p, resp+resp_size); + if (*p && !strncmp(p, STRING_NODE, STRING_NODE_SIZE)) { + p += STRING_NODE_SIZE; + str_start = p; + while (*p != '<' && *p != '\0') p++; + if (*p == '<') { + str_len = p - str_start; + } + } + if (str_start && str_len > 0) { + log_error("ERROR: Failed to make device enter recovery mode: %.*s", (int)str_len, str_start); + } else { + log_error("ERROR: Failed to make device enter recovery mode: (unknown error)"); + } + result = -2; + } else { + result = (strstr(resp, ENTER_RECOVERY_STRING_NODE) == NULL) ? -1 : 0; + } + free(resp); + return result; +} + +#endif diff --git a/src/lockdown_helper.h b/src/lockdown_helper.h new file mode 100644 index 0000000..6c50ff8 --- /dev/null +++ b/src/lockdown_helper.h @@ -0,0 +1,30 @@ +#ifndef __LOCKDOWN_HELPER_H +#define __LOCKDOWN_HELPER_H + +#ifndef HAVE_LIBIMOBILEDEVICE + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int lockdown_connect_udid(const char* udid); +int lockdown_connect_handle(uint32_t handle); + +void lockdown_disconnect(int fd); + +int lockdown_check_type(int fd, const char* type_match); + +int lockdown_get_uint_value(int fd, const char* domain, const char* key, uint64_t* value); +int lockdown_get_string_value(int fd, const char* domain, const char* key, char** value); + +int lockdown_enter_recovery(int fd); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..a2dc13a --- /dev/null +++ b/src/main.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ANSI-color-codes.h" +#include "common.h" + +int p1_log(log_level_t loglevel, const char *fname, int lineno, const char *fxname, char* __restrict format, ...) { + va_list args; + va_start(args, format); + switch(loglevel) { + case LOG_FATAL: + printf(BRED "[!] " RED); + break; + case LOG_ERROR: + printf(BRED "[Error] " RED); + break; + case LOG_WARNING: + printf(BYEL "[Warning] " YEL); + break; + case LOG_INFO: + printf(BCYN "[Info] " CYN); + break; + case LOG_VERBOSE: + printf(BWHT "[Verbose] " WHT); + break; + case LOG_DEBUG: + printf(BLU "%s:%d: " BMAG "%s(): " WHT, fname, lineno, fxname); + break; + default: + assert(0); + break; + } + int ret = vprintf(format, args); + va_end(args); + printf(CRESET "\n"); + return ret; +} + +int main(int argc, char* argv[]) { + LOG(LOG_INFO, "Waiting for devices"); + pthread_t dfuhelper_thread; + pthread_create(&dfuhelper_thread, NULL, dfuhelper, NULL); + pthread_join(dfuhelper_thread, NULL); + return 0; +} diff --git a/src/palera1n b/src/palera1n new file mode 100755 index 0000000..4bdbe13 Binary files /dev/null and b/src/palera1n differ