mirror of
https://github.com/palera1n/palera1n
synced 2025-08-29 13:27:58 +00:00
dfuhelper only
This commit is contained in:
commit
752d32600c
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
dep_root/**
|
||||||
|
contrib/**
|
||||||
|
!dep_root/.keep
|
||||||
|
!contrib/.keep
|
||||||
|
contrib/
|
||||||
|
*.o
|
||||||
|
.vscode
|
||||||
|
checkra1n*
|
20
Makefile
Normal file
20
Makefile
Normal file
@ -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
|
0
dep_root/.keep
Normal file
0
dep_root/.keep
Normal file
85
include/ANSI-color-codes.h
Normal file
85
include/ANSI-color-codes.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* This is free and unencumbered software released into the public domain.
|
||||||
|
*
|
||||||
|
* For more information, please refer to <https://unlicense.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
14
src/Makefile
Normal file
14
src/Makefile
Normal file
@ -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
|
60
src/common.h
Normal file
60
src/common.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
|
||||||
|
#include "lockdown_helper.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <usbmuxd.h>
|
||||||
|
#include <libirecovery.h>
|
||||||
|
|
||||||
|
#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
|
399
src/devhelper.c
Normal file
399
src/devhelper.c
Normal file
@ -0,0 +1,399 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#endif
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <libirecovery.h>
|
||||||
|
#include <usbmuxd.h>
|
||||||
|
|
||||||
|
#include <libimobiledevice/libimobiledevice.h>
|
||||||
|
#include <libimobiledevice/lockdown.h>
|
||||||
|
#include <libimobiledevice/diagnostics_relay.h>
|
||||||
|
#include <plist/plist.h>
|
||||||
|
|
||||||
|
#include "lockdown_helper.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIB_TV_CONTROL
|
||||||
|
#include <libtvcontrol.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
181
src/dfuhelper.c
Normal file
181
src/dfuhelper.c
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <libimobiledevice/libimobiledevice.h>
|
||||||
|
#include <libimobiledevice/lockdown.h>
|
||||||
|
#include <libimobiledevice/diagnostics_relay.h>
|
||||||
|
#include <plist/plist.h>
|
||||||
|
#include <libirecovery.h>
|
||||||
|
#include <usbmuxd.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
0
src/exec_checkra1n.c
Normal file
0
src/exec_checkra1n.c
Normal file
255
src/lockdown_helper.c
Normal file
255
src/lockdown_helper.c
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
#ifndef HAVE_LIBIMOBILEDEVICE
|
||||||
|
#include "lockdown_helper.h"
|
||||||
|
#include <usbmuxd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#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[] = "____<plist version=\"1.0\"><dict><key>Label</key><string>palera1n</string><key>Request</key><string>QueryType</string></dict></plist>";
|
||||||
|
static const char GET_VALUE_DOMAIN_REQUEST_FMT[] = "____<plist version=\"1.0\"><dict><key>Label</key><string>palera1n</string><key>Domain</key><string>%s</string><key>Key</key><string>%s</string><key>Request</key><string>GetValue</string></dict></plist>";
|
||||||
|
static const char GET_VALUE_REQUEST_FMT[] = "____<plist version=\"1.0\"><dict><key>Label</key><string>palera1n</string><key>Key</key><string>%s</string><key>Request</key><string>GetValue</string></dict></plist>";
|
||||||
|
static const char VALUE_KEY_NODE[] = "<key>Value</key>";
|
||||||
|
static const char INTEGER_NODE[] = "<integer>";
|
||||||
|
static const char STRING_NODE[] = "<string>";
|
||||||
|
static const char ENTER_RECOVERY_REQUEST[] = "____<plist version=\"1.0\"><dict><key>Label</key><string>palera1n</string><key>Request</key><string>EnterRecovery</string></dict></plist>";
|
||||||
|
static const char ERROR_KEY_NODE[] = "<key>Error</key>";
|
||||||
|
static const char ENTER_RECOVERY_STRING_NODE[] = "<string>EnterRecovery</string>";
|
||||||
|
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
|
30
src/lockdown_helper.h
Normal file
30
src/lockdown_helper.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef __LOCKDOWN_HELPER_H
|
||||||
|
#define __LOCKDOWN_HELPER_H
|
||||||
|
|
||||||
|
#ifndef HAVE_LIBIMOBILEDEVICE
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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
|
61
src/main.c
Normal file
61
src/main.c
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
BIN
src/palera1n
Executable file
BIN
src/palera1n
Executable file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user