From 3dc130f3049e250b2d5c0b48af1995fda2fad3d4 Mon Sep 17 00:00:00 2001 From: Matt Colyer Date: Tue, 29 Jul 2008 10:13:37 -0700 Subject: Autotooled the project with very basic versioning support. --- AFC.c | 381 -------------------------------------------------------- AFC.h | 80 ------------ Makefile.am | 2 + autogen.sh | 4 + configure.ac | 35 ++++++ iphone.c | 156 ----------------------- iphone.h | 29 ----- lockdown.c | 372 ------------------------------------------------------ lockdown.h | 36 ------ main.c | 105 ---------------- main.h | 1 - plist.c | 91 -------------- plist.h | 17 --- src/AFC.c | 381 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/AFC.h | 80 ++++++++++++ src/Makefile.am | 5 + src/iphone.c | 156 +++++++++++++++++++++++ src/iphone.h | 29 +++++ src/lockdown.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lockdown.h | 36 ++++++ src/main.c | 104 ++++++++++++++++ src/main.h | 1 + src/plist.c | 91 ++++++++++++++ src/plist.h | 17 +++ src/usbmux.c | 198 +++++++++++++++++++++++++++++ src/usbmux.h | 39 ++++++ usbmux.c | 198 ----------------------------- usbmux.h | 39 ------ 28 files changed, 1550 insertions(+), 1505 deletions(-) delete mode 100644 AFC.c delete mode 100644 AFC.h create mode 100644 Makefile.am create mode 100755 autogen.sh create mode 100644 configure.ac delete mode 100644 iphone.c delete mode 100644 iphone.h delete mode 100644 lockdown.c delete mode 100644 lockdown.h delete mode 100644 main.c delete mode 100644 main.h delete mode 100644 plist.c delete mode 100644 plist.h create mode 100644 src/AFC.c create mode 100644 src/AFC.h create mode 100644 src/Makefile.am create mode 100644 src/iphone.c create mode 100644 src/iphone.h create mode 100644 src/lockdown.c create mode 100644 src/lockdown.h create mode 100644 src/main.c create mode 100644 src/main.h create mode 100644 src/plist.c create mode 100644 src/plist.h create mode 100644 src/usbmux.c create mode 100644 src/usbmux.h delete mode 100644 usbmux.c delete mode 100644 usbmux.h diff --git a/AFC.c b/AFC.c deleted file mode 100644 index f3d538e..0000000 --- a/AFC.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * AFC.c -- contains functions for the built-in AFC client. - * Written by FxChiP - */ - -#include "AFC.h" - -extern int debug; - -AFClient *afc_connect(iPhone *phone, int s_port, int d_port) { - if (!phone) return NULL; - AFClient *client = (AFClient*)malloc(sizeof(AFClient)); - client->connection = mux_connect(phone, s_port, d_port); - if (!client->connection) { free(client); return NULL; } - else { - client->afc_packet = (AFCPacket*)malloc(sizeof(AFCPacket)); - if (client->afc_packet) { - client->phone = phone; - client->afc_packet->packet_num = 0; - client->afc_packet->unknown1 = client->afc_packet->unknown2 = client->afc_packet->unknown3 = client->afc_packet->unknown4 = client->afc_packet->entire_length = client->afc_packet->this_length = 0; - client->afc_packet->header1 = 0x36414643; - client->afc_packet->header2 = 0x4141504C; - client->file_handle = 0; - return client; - } else { - mux_close_connection(client->phone, client->connection); - free(client); - return NULL; - } - } - - return NULL; // should never get to this point -} - -void afc_disconnect(AFClient *client) { - // client and its members should never be NULL is assumed here. - if (!client || !client->connection || !client->phone || !client->afc_packet) return; - mux_close_connection(client->phone, client->connection); - free(client->afc_packet); - free(client); -} - -int count_nullspaces(char *string, int number) { - int i = 0, nulls = 0; - for (i = 0; i < number; i++) { - if (string[i] == '\0') nulls++; - } - return nulls; -} - -int dispatch_AFC_packet(AFClient *client, char *data, int length) { - char *buffer; - int bytes = 0, offset = 0; - if (!client || !client->connection || !client->phone || !client->afc_packet) return 0; - if (!data || !length) length = 0; - - client->afc_packet->packet_num++; - if (!client->afc_packet->entire_length) client->afc_packet->entire_length = client->afc_packet->this_length = (length) ? sizeof(AFCPacket) + length + 1 : sizeof(AFCPacket); - if (!client->afc_packet->this_length) client->afc_packet->this_length = sizeof(AFCPacket); - - if (client->afc_packet->this_length != client->afc_packet->entire_length) { - // We want to send two segments; buffer+sizeof(AFCPacket) to this_length is the parameters - // And everything beyond that is the next packet. (for writing) - char *buffer = (char*)malloc(client->afc_packet->this_length); - memcpy(buffer, (char*)client->afc_packet, sizeof(AFCPacket)); - offset = client->afc_packet->this_length - sizeof(AFCPacket); - if (debug) printf("dispatch_AFC_packet: Offset: %i\n", offset); - if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { - if (debug) printf("dispatch_AFC_packet: Length did not resemble what it was supposed to based on the packet.\nlength minus offset: %i\nrest of packet: %i\n", length-offset, client->afc_packet->entire_length - client->afc_packet->this_length); - free(buffer); - return 0; - } - if (debug) printf("dispatch_AFC_packet: fucked-up packet method (probably a write)\n"); - memcpy(buffer+sizeof(AFCPacket), data, offset); - bytes = mux_send(client->phone, client->connection, buffer, client->afc_packet->this_length); - free(buffer); - if (bytes <= 0) { return 0; } - if (debug) { - printf("dispatch_AFC_packet: sent the first now go with the second\n"); - printf("Length: %i\n", length-offset); - printf("Buffer: \n"); - fwrite(data+offset, 1, length-offset, stdout); - } - - - bytes = mux_send(client->phone, client->connection, data+offset, length-offset); - if (bytes <= 0) { return 0; } - else { return bytes; } - } else { - if (debug) printf("dispatch_AFC_packet doin things the old way\n"); - char *buffer = (char*)malloc(sizeof(char) * client->afc_packet->this_length); - if (debug) printf("dispatch_AFC_packet packet length = %i\n", client->afc_packet->this_length); - memcpy(buffer, (char*)client->afc_packet, sizeof(AFCPacket)); - if (debug) printf("dispatch_AFC_packet packet data follows\n"); - if (length > 0) { memcpy(buffer+sizeof(AFCPacket), data, length); buffer[sizeof(AFCPacket)+length] = '\0'; } - if (debug) fwrite(buffer, 1, client->afc_packet->this_length, stdout); - if (debug) printf("\n"); - bytes = mux_send(client->phone, client->connection, buffer, client->afc_packet->this_length); - if (bytes <= 0) return 0; - else return bytes; - } - return 0; -} - -int receive_AFC_data(AFClient *client, char **dump_here) { - AFCPacket *r_packet; - char *buffer = (char*)malloc(sizeof(AFCPacket) * 4); - int bytes = 0, recv_len = 0; - - bytes = mux_recv(client->phone, client->connection, buffer, sizeof(AFCPacket) * 4); - if (bytes <= 0) { - free(buffer); - printf("Just didn't get enough.\n"); - *dump_here = NULL; - return 0; - } - - r_packet = (AFCPacket*)malloc(sizeof(AFCPacket)); - memcpy(r_packet, buffer, sizeof(AFCPacket)); - - if (r_packet->entire_length == r_packet->this_length && r_packet->entire_length > sizeof(AFCPacket) && r_packet->operation != AFC_ERROR) { - *dump_here = (char*)malloc(sizeof(char) * (r_packet->entire_length-sizeof(AFCPacket))); - memcpy(*dump_here, buffer+sizeof(AFCPacket), r_packet->entire_length-sizeof(AFCPacket)); - free(buffer); - free(r_packet); - return r_packet->entire_length - sizeof(AFCPacket); - } - - uint32 param1 = buffer[sizeof(AFCPacket)]; - free(buffer); - - if (r_packet->operation == 0x01 && !((client->afc_packet->operation == AFC_DELETE && param1 == 7))) { - if (debug) printf("Oops? Bad operation code received.\n"); - if (param1 == 0) { - if (debug) printf("... false alarm, but still\n"); - return 1; - } - else { if (debug) printf("Errno %i\n", param1); } - free(r_packet); - *dump_here = NULL; - return 0; - } else { - if (debug) printf("Operation code %x\nFull length %i and this length %i\n", r_packet->operation, r_packet->entire_length, r_packet->this_length); - } - - recv_len = r_packet->entire_length - r_packet->this_length; - free(r_packet); - if (!recv_len) return bytes; - buffer = (char*)malloc(sizeof(char) * recv_len); - bytes = mux_recv(client->phone, client->connection, buffer, recv_len); - if (bytes <= 0) { - free(buffer); - printf("Didn't get it at the second pass.\n"); - *dump_here = NULL; - return 0; - } - - *dump_here = buffer; // what they do beyond this point = not my problem - return bytes; -} - -char **afc_get_dir_list(AFClient *client, char *dir) { - client->afc_packet->operation = AFC_LIST_DIR; - int bytes = 0; - char *blah = NULL, **list = NULL; - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - bytes = dispatch_AFC_packet(client, dir, strlen(dir)); - if (!bytes) return NULL; - - bytes = receive_AFC_data(client, &blah); - if (!bytes && !blah) return NULL; - - list = make_strings_list(blah, bytes); - free(blah); - return list; -} - -char **make_strings_list(char *tokens, int true_length) { - if (!tokens || !true_length) return NULL; - int nulls = 0, i = 0, j = 0; - char **list = NULL; - - nulls = count_nullspaces(tokens, true_length); - list = (char**)malloc(sizeof(char*) * (nulls + 1)); - for (i = 0; i < nulls; i++) { - list[i] = strdup(tokens+j); - j += strlen(list[i]) + 1; - } - list[i] = strdup(""); - return list; -} - -int afc_delete_file(AFClient *client, const char *path) { - if (!client || !path || !client->afc_packet || !client->phone ||!client->connection) return 0; - - char *receive = NULL; - client->afc_packet->this_length = client->afc_packet->entire_length = 0; - client->afc_packet->operation = AFC_DELETE; - int bytes; - bytes = dispatch_AFC_packet(client, path, strlen(path)); - if (bytes <= 0) return 0; - - bytes = receive_AFC_data(client, &receive); - free(receive); - if (bytes <= 0) return 0; - else return 1; -} - -int afc_rename_file(AFClient *client, const char *from, const char *to) { - if (!client || !from || !to || !client->afc_packet || !client->phone || !client->connection) return 0; - - char *receive = NULL; - char *send = (char*)malloc(sizeof(char) * (strlen(from) + strlen(to) + 1 + sizeof(uint32))); - int bytes = 0; - - memcpy(send, from, strlen(from)+1); - memcpy(send+strlen(from)+1, to, strlen(to)); - fwrite(send, 1, strlen(from)+1+strlen(to), stdout); - printf("\n"); - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - client->afc_packet->operation = AFC_RENAME; - bytes = dispatch_AFC_packet(client, send, strlen(to) + strlen(from) + 2); - if (bytes <= 0) return 0; - - bytes = receive_AFC_data(client, &receive); - free(receive); - if (bytes <= 0) return 0; - else return 1; -} - - - -AFCFile *afc_get_file_info(AFClient *client, char *path) { - client->afc_packet->operation = AFC_GET_INFO; - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - dispatch_AFC_packet(client, path, strlen(path)); - - char *received, **list; - AFCFile *my_file; - int length, i = 0; - - length = receive_AFC_data(client, &received); - list = make_strings_list(received, length); - free(received); - if (list) { - my_file = (AFCFile *)malloc(sizeof(AFCFile)); - for (i = 0; strcmp(list[i], ""); i++) { - if (!strcmp(list[i], "st_size")) { - my_file->size = atoi(list[i+1]); - } - - - if (!strcmp(list[i], "st_blocks")) { - my_file->blocks = atoi(list[i+1]); - } - - if (!strcmp(list[i], "st_ifmt")) { - if (!strcmp(list[i+1], "S_IFREG")) { - my_file->type = S_IFREG; - } else if (!strcmp(list[i+1], "S_IFDIR")) { - my_file->type = S_IFDIR; - } - } - } - free_dictionary(list); - return my_file; - } else { - return NULL; - } -} - -AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode) { - if (file_mode != AFC_FILE_READ && file_mode != AFC_FILE_WRITE) return NULL; - if (!client ||!client->connection || !client->phone ||!client->afc_packet) return NULL; - char *further_data = (char*)malloc(sizeof(char) * (8 + strlen(filename) + 1)); - AFCFile *file_infos = NULL; - memcpy(further_data, &file_mode, 4); - uint32 ag = 0; - memcpy(further_data+4, &ag, 4); - memcpy(further_data+8, filename, strlen(filename)); - further_data[8+strlen(filename)] = '\0'; - int bytes = 0, length_thing = 0; - client->afc_packet->operation = AFC_FILE_OPEN; - - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - bytes = dispatch_AFC_packet(client, further_data, 8+strlen(filename)); - free(further_data); - if (bytes <= 0) { - if (debug) printf("didn't read enough\n"); - return NULL; - } else { - length_thing = receive_AFC_data(client, &further_data); - if (length_thing && further_data) { - file_infos = afc_get_file_info(client, filename); - memcpy(&file_infos->filehandle, further_data, 4); - return file_infos; - } else { - if (debug) printf("didn't get further data or something\n"); - return NULL; - } - } - if (debug) printf("what the fuck\n"); - return NULL; -} - -int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) { - if (!client || !client->afc_packet || !client->phone || !client->connection || !file) return -1; - AFCFilePacket *packet = (AFCFilePacket*)malloc(sizeof(AFCFilePacket)); - char *input = NULL; - packet->unknown1 = packet->unknown2 = 0; - packet->filehandle = file->filehandle; - packet->size = length; - int bytes = 0; - - client->afc_packet->operation = AFC_READ; - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - bytes = dispatch_AFC_packet(client, (char*)packet, sizeof(AFCFilePacket)); - - if (bytes > 0) { - bytes = receive_AFC_data(client, &input); - if (bytes <= 0) { - if (input) free(input); - return -1; - } else { - memcpy(data, input, (bytes > length) ? length : bytes); - free(input); - return (bytes > length) ? length : bytes; - } - } else { - return -1; - } - return 0; -} - -int afc_write_file(AFClient *client, AFCFile *file, char *data, int length) { - char *acknowledgement = NULL; - if (!client ||!client->afc_packet ||!client->phone || !client->connection || !file) return -1; - client->afc_packet->this_length = sizeof(AFCPacket) + 8; - client->afc_packet->entire_length = client->afc_packet->this_length + length; - client->afc_packet->operation = AFC_WRITE; - if (debug) printf("afc_write_file: Write length: %i\n", length); - uint32 zero = 0, bytes = 0; - - char *out_buffer = NULL; - out_buffer = (char*)malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); - memcpy(out_buffer, (char*)&file->filehandle, sizeof(uint32)); - memcpy(out_buffer+4, (char*)&zero, sizeof(uint32)); - memcpy(out_buffer+8, data, length); - - bytes = dispatch_AFC_packet(client, out_buffer, length + 8); - if (!bytes) return -1; - - zero = bytes; - bytes = receive_AFC_data(client, &acknowledgement); - if (bytes <= 0) { - if (debug) printf("afc_write_file: uh oh?\n"); - } - - return zero; -} - -void afc_close_file(AFClient *client, AFCFile *file) { - char *buffer = malloc(sizeof(char) * 8); - uint32 zero = 0; - if (debug) printf("File handle %i\n", file->filehandle); - memcpy(buffer, &file->filehandle, sizeof(uint32)); - memcpy(buffer+sizeof(uint32), &zero, sizeof(zero)); - client->afc_packet->operation = AFC_FILE_CLOSE; - int bytes = 0; - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - bytes = dispatch_AFC_packet(client, buffer, sizeof(char) * 8); - - free(buffer); - client->afc_packet->entire_length = client->afc_packet->this_length = 0; - if (!bytes) return; - - bytes = receive_AFC_data(client, &buffer); - return; - if (buffer) free(buffer); // we're *SUPPOSED* to get an "error" here. -} - diff --git a/AFC.h b/AFC.h deleted file mode 100644 index 787b9fe..0000000 --- a/AFC.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * AFC.h - * Defines and structs and the like for the built-in AFC client - * Written by FxChiP - */ - -#include "usbmux.h" -#include "iphone.h" - -#include -#include -#include - -typedef struct { - //const uint32 header1 = 0x36414643; // '6AFC' or 'CFA6' when sent ;) - uint32 header1, header2; - //const uint32 header2 = 0x4141504C; // 'AAPL' or 'LPAA' when sent ;) - uint32 entire_length, unknown1, this_length, unknown2, packet_num, unknown3, operation, unknown4; -} AFCPacket; - -typedef struct { - usbmux_tcp_header *connection; - iPhone *phone; - AFCPacket *afc_packet; - int file_handle; -} AFClient; - -typedef struct { - uint32 filehandle, unknown1, size, unknown2; -} AFCFilePacket; - -typedef struct { - uint32 filehandle, blocks, size, type; -} AFCFile; - -typedef struct __AFCToken { - struct __AFCToken *last, *next; - char *token; -} AFCToken; - -enum { - S_IFREG = 0, - S_IFDIR = 1 -}; - -enum { - AFC_FILE_READ = 0x00000002, - AFC_FILE_WRITE = 0x00000003 -}; - -enum { - AFC_ERROR = 0x00000001, - AFC_GET_INFO = 0x0000000a, - AFC_GET_DEVINFO = 0x0000000b, - AFC_LIST_DIR = 0x00000003, - AFC_DELETE = 0x00000008, - AFC_RENAME = 0x00000018, - AFC_SUCCESS_RESPONSE = 0x00000002, - AFC_FILE_OPEN = 0x0000000d, - AFC_FILE_CLOSE = 0x00000014, - AFC_FILE_HANDLE = 0x0000000e, - AFC_READ = 0x0000000f, - AFC_WRITE = 0x00000010 -}; - -AFClient *afc_connect(iPhone *phone, int s_port, int d_port); -void afc_disconnect(AFClient *client); -int count_nullspaces(char *string, int number); -char **make_strings_list(char *tokens, int true_length); -int dispatch_AFC_packet(AFClient *client, char *data, int length); -int receive_AFC_data(AFClient *client, char **dump_here); - -char **afc_get_dir_list(AFClient *client, char *dir); -AFCFile *afc_get_file_info(AFClient *client, char *path); -AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode); -void afc_close_file(AFClient *client, AFCFile *file); -int afc_read_file(AFClient *client, AFCFile *file, char *data, int length); -int afc_write_file(AFClient *client, AFCFile *file, char *data, int length); -int afc_delete_file(AFClient *client, const char *path); -int afc_rename_file(AFClient *client, const char *from, const char *to); diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..4103ac3 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,2 @@ +AUTOMAKE_OPTIONS = foreign +SUBDIRS = src diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..06b6899 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,4 @@ +#!/bin/sh +aclocal +automake --add-missing +autoconf diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..fcc20ff --- /dev/null +++ b/configure.ac @@ -0,0 +1,35 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.61) +AC_INIT(libiphone, 0.1.0, nospam@nowhere.com) +AM_INIT_AUTOMAKE(libiphone, 0.1.0) +AC_CONFIG_SRCDIR([src/lockdown.c]) +AC_CONFIG_HEADER([config.h]) + +# Checks for programs. +AC_PROG_CC + +# Checks for libraries. +AC_CHECK_LIB(xml2,xmlFree,,[AC_MSG_ERROR([libxml2 library missing])]) +AC_CHECK_LIB(usb,usb_bulk_write,,[AC_MSG_ERROR([libusb library missing])]) +AC_CHECK_LIB(gnutls,gnutls_record_send,,[AC_MSG_ERROR([libgnutls library missing])]) + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([arpa/inet.h stdint.h stdlib.h string.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_CHECK_FUNCS([strcasecmp strdup strerror strndup]) + +AC_OUTPUT(Makefile src/Makefile) diff --git a/iphone.c b/iphone.c deleted file mode 100644 index 4ddb571..0000000 --- a/iphone.c +++ /dev/null @@ -1,156 +0,0 @@ -/* iPhone.c - * Functions for creating and initializing iPhone structures - */ - -#include "usbmux.h" -#include "iphone.h" -#include -#include -#include -#include - -/* get_iPhone() - * - * Returns a structure with data on the first iPhone it finds. - * (Or NULL, on error) - */ -extern int debug; - -iPhone *get_iPhone() { - iPhone *phone = (iPhone*)malloc(sizeof(iPhone)); - usbmux_version_header *version = version_header(); - - // initialize the struct - phone->device = NULL; - phone->__device = NULL; - - // Initialize libusb. - usb_init(); - usb_find_busses(); - usb_find_devices(); - struct usb_bus *busses = usb_get_busses(), *bus; - struct usb_device *dev; - - for (bus = busses; bus; bus = bus->next) { - for (dev = bus->devices; dev; dev = dev->next) { - if (dev->descriptor.idVendor == 0x05ac && (dev->descriptor.idProduct == 0x1290 || dev->descriptor.idProduct == 0x1291)) { - phone->__device = dev; - phone->device = usb_open(phone->__device); - usb_reset(phone->device); - } - } - } - - phone->device = NULL; // :( sorry Daniel - phone->__device = NULL; // :( sorry Daniel - - for (bus = busses; bus; bus = bus->next) { // do it again as per libusb documentation - for (dev = bus->devices; dev; dev = dev->next) { - if (dev->descriptor.idVendor == 0x05ac && (dev->descriptor.idProduct == 0x1290 || dev->descriptor.idProduct == 0x1291)) { - phone->__device = dev; - phone->device = usb_open(phone->__device); - usb_set_configuration(phone->device, 3); - usb_claim_interface(phone->device, 1); - break; - } - } - if (phone->__device && phone->device) break; - } - - if (!phone->device || !phone->__device) { // nothing connected - free_iPhone(phone); - if (debug) printf("get_iPhone(): iPhone not found\n"); - return NULL; - } - - // Okay, initialize the phone now. - int bytes = 0; - bytes = usb_bulk_write(phone->device, BULKOUT, (char*)version, sizeof(*version), 800); - if (bytes < 20 && debug) { - printf("get_iPhone(): libusb did NOT send enough!\n"); - if (bytes < 0) { - printf("get_iPhone(): libusb gave me the error: %s\n", usb_strerror()); - } - } - bytes = usb_bulk_read(phone->device, BULKIN, (char*)version, sizeof(*version), 800); - if (bytes < 20) { - free_iPhone(phone); - if (debug) printf("get_iPhone(): Invalid version message -- header too short.\n"); - if (debug && bytes < 0) printf("get_iPhone(): libusb error message: %s\n", usb_strerror()); - return NULL; - } else { - if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) { - // We're all ready to roll. - printf("get_iPhone() success\n"); - return phone; - } else { // BAD HEADER - free_iPhone(phone); - if (debug) printf("get_iPhone(): Received a bad header/invalid version number."); - return NULL; - } - } - - if (debug) printf("get_iPhone(): Unknown error.\n"); - return NULL; // if it got to this point it's gotta be bad -} - -/* free_iPhone(victim) - * This is a library-level function; deals directly with the iPhone to tear down relations, - * but otherwise is mostly internal. - * - * victim: a pointer to an iPhone structure - * Cleans up an iPhone structure, then frees the structure itself. - */ - -void free_iPhone(iPhone *victim) { - if (victim->buffer) free(victim->buffer); - if (victim->device) { - usb_release_interface(victim->device, 1); - usb_reset(victim->device); - usb_close(victim->device); - } - free(victim); -} - -/* send_to_phone(phone, data, datalen) - * This is a low-level (i.e. directly to phone) function. - * - * phone: the iPhone to send data to - * data: the data to send to the iPhone - * datalen: the length of the data - * - * Returns the number of bytes sent, or -1 on error or something. - */ -int send_to_phone(iPhone *phone, char *data, int datalen) { - if (!phone) return -1; - int bytes = 0; - // it may die here - if (debug) printf("dying here?\ndatalen = %i\ndata = %x\n", datalen, data); - - bytes = usb_bulk_write(phone->device, BULKOUT, data, datalen, 800); - if (debug) printf("noooo...?\n"); - if (bytes < datalen) { - return -1; - } else { - return bytes; - } - - return -1; -} - -/* recv_from_phone(phone, data, datalen): - * This function is a low-level (i.e. direct to iPhone) function. - * - * phone: the iPhone to receive data from - * data: where to put data read - * datalen: how much data to read in - * - * Returns: how many bytes were read in, or -1 on error. - */ -int recv_from_phone(iPhone *phone, char *data, int datalen) { - if (!phone) return -1; - int bytes = 0; - bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, 3500); - return bytes; -} - diff --git a/iphone.h b/iphone.h deleted file mode 100644 index a49b7ef..0000000 --- a/iphone.h +++ /dev/null @@ -1,29 +0,0 @@ -/* iphone.h - * iPhone struct - * Written by FxChiP */ - -#ifndef IPHONE_H -#define IPHONE_H - -#ifndef USBMUX_H -#include "usbmux.h" -#warning usbmux not included? -#endif - -#include - -#define BULKIN 0x85 -#define BULKOUT 0x04 - -typedef struct { - char *buffer; - struct usb_dev_handle *device; - struct usb_device *__device; -} iPhone; - -// Function definitions -void free_iPhone(iPhone *victim); -iPhone *get_iPhone(); -int send_to_phone(iPhone *phone, char *data, int datalen); -int recv_from_phone(iPhone *phone, char *data, int datalen); -#endif diff --git a/lockdown.c b/lockdown.c deleted file mode 100644 index 34a98f7..0000000 --- a/lockdown.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * lockdown.c -- libiphone built-in lockdownd client - * Written by FxChiP - */ - -#include "usbmux.h" -#include "iphone.h" -#include "lockdown.h" -#include -#include - -extern int debug; - -lockdownd_client *new_lockdownd_client(iPhone *phone) { - if (!phone) return NULL; - lockdownd_client *control = (lockdownd_client*)malloc(sizeof(lockdownd_client)); - control->connection = mux_connect(phone, 0x0a00, 0xf27e); - if (!control->connection) { - free(control); - return NULL; - } - - control->ssl_session = (gnutls_session_t*)malloc(sizeof(gnutls_session_t)); - control->in_SSL = 0; - control->iphone = phone; - control->gtls_buffer_hack_len = 0; - return control; -} - -void lockdown_close(lockdownd_client *control) { - if (!control) return; - if (control->connection) { - mux_close_connection(control->iphone, control->connection); - } - - if (control->ssl_session) free(control->ssl_session); - free(control); -} - - -int lockdownd_recv(lockdownd_client *control, char **dump_data) { - char *receive; - uint32 datalen = 0, bytes = 0; - - if (!control->in_SSL) bytes = mux_recv(control->iphone, control->connection, &datalen, sizeof(datalen)); - else bytes = gnutls_record_recv(*control->ssl_session, &datalen, sizeof(datalen)); - datalen = ntohl(datalen); - - receive = (char*)malloc(sizeof(char) * datalen); - if (!control->in_SSL) bytes = mux_recv(control->iphone, control->connection, receive, datalen); - else bytes = gnutls_record_recv(*control->ssl_session, receive, datalen); - *dump_data = receive; - return bytes; -} - -int lockdownd_send(lockdownd_client *control, char *raw_data, uint32 length) { - char *real_query; - int bytes; - - real_query = (char*)malloc(sizeof(char) * (length+4)); - length = htonl(length); - memcpy(real_query, &length, sizeof(length)); - memcpy(real_query+4, raw_data, ntohl(length)); - if (!control->in_SSL) bytes = mux_send(control->iphone, control->connection, real_query, ntohl(length)+sizeof(length)); - else gnutls_record_send(*control->ssl_session, real_query, ntohl(length)+sizeof(length)); - return bytes; -} - -int lockdownd_hello(lockdownd_client *control) { - xmlDocPtr plist = new_plist(); - xmlNode *dict, *key; - char **dictionary; - int bytes = 0, i = 0; - - dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); - key = add_key_str_dict_element(plist, dict, "Request", "QueryType", 1); - char *XML_content; - uint32 length; - - xmlDocDumpMemory(plist, &XML_content, &length); - - bytes = lockdownd_send(control, XML_content, length); - - xmlFree(XML_content); - xmlFreeDoc(plist); plist = NULL; - - bytes = lockdownd_recv(control, &XML_content); - - plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); - if (!plist) return 0; - dict = xmlDocGetRootElement(plist); - for (dict = dict->children; dict; dict = dict->next) { - if (!xmlStrcmp(dict->name, "dict")) break; - } - if (!dict) return 0; - - dictionary = read_dict_element_strings(dict); - xmlFreeDoc(plist); - free(XML_content); - - for (i = 0; strcmp(dictionary[i], ""); i+=2) { - if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i+1], "Success")) { - free_dictionary(dictionary); - return 1; - } - } - - free_dictionary(dictionary); - return 0; -} - -int lockdownd_start_SSL_session(lockdownd_client *control, const char *HostID) { - xmlDocPtr plist = new_plist(); - xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); - xmlNode *key; - char *what2send = NULL, **dictionary = NULL; - uint32 len = 0, bytes = 0, return_me = 0, i = 0; - // end variables - - key = add_key_str_dict_element(plist, dict, "HostID", HostID, 1); - if (!key) { - if (debug) printf("Couldn't add a key.\n"); - xmlFreeDoc(plist); - return 0; - } - key = add_key_str_dict_element(plist, dict, "Request", "StartSession", 1); - if (!key) { - if (debug) printf("Couldn't add a key.\n"); - xmlFreeDoc(plist); - return 0; - } - - xmlDocDumpMemory(plist, &what2send, &len); - bytes = lockdownd_send(control, what2send, len); - - xmlFree(what2send); - xmlFreeDoc(plist); - - if (bytes > 0) { - len = lockdownd_recv(control, &what2send); - plist = xmlReadMemory(what2send, len, NULL, NULL, 0); - dict = xmlDocGetRootElement(plist); - for (dict = dict->children; dict; dict = dict->next) { - if (!xmlStrcmp(dict->name, "dict")) break; - } - dictionary = read_dict_element_strings(dict); - xmlFreeDoc(plist); - free(what2send); - for (i = 0; strcmp(dictionary[i], ""); i+=2) { - if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i+1], "Success")) { - // Set up GnuTLS... - //gnutls_anon_client_credentials_t anoncred; - gnutls_certificate_credentials_t xcred; - if (debug) printf("We started the session OK, now trying GnuTLS\n"); - errno = 0; - gnutls_global_init(); - //gnutls_anon_allocate_client_credentials(&anoncred); - gnutls_certificate_allocate_credentials(&xcred); - gnutls_certificate_set_x509_trust_file(xcred, "hostcert.pem", GNUTLS_X509_FMT_PEM); - gnutls_init(control->ssl_session, GNUTLS_CLIENT); - { - int protocol_priority[16] = {GNUTLS_SSL3, 0 }; - int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 }; - int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 }; - int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 }; - int comp_priority[16] = { GNUTLS_COMP_NULL, 0 }; - - gnutls_cipher_set_priority(*control->ssl_session, cipher_priority); - gnutls_compression_set_priority(*control->ssl_session, comp_priority); - gnutls_kx_set_priority(*control->ssl_session, kx_priority); - gnutls_protocol_set_priority( *control->ssl_session, protocol_priority); - gnutls_mac_set_priority(*control->ssl_session, mac_priority); - - } - gnutls_credentials_set(*control->ssl_session, GNUTLS_CRD_CERTIFICATE, xcred); // this part is killing me. - - if (debug) printf("GnuTLS step 1...\n"); - gnutls_transport_set_ptr(*control->ssl_session, (gnutls_transport_ptr_t) control); - if (debug) printf("GnuTLS step 2...\n"); - gnutls_transport_set_push_function(*control->ssl_session, (gnutls_push_func)&lockdownd_secuwrite); - if (debug) printf("GnuTLS step 3...\n"); - gnutls_transport_set_pull_function(*control->ssl_session, (gnutls_pull_func)&lockdownd_securead); - if (debug) printf("GnuTLS step 4 -- now handshaking...\n"); - - if (errno && debug) printf("WARN: errno says %s before handshake!\n", strerror(errno)); - return_me = gnutls_handshake(*control->ssl_session); - if (debug) printf("GnuTLS handshake done...\n"); - - free_dictionary(dictionary); - - if (return_me != GNUTLS_E_SUCCESS) { - if (debug) printf("GnuTLS reported something wrong.\n"); - gnutls_perror(return_me); - if (debug) printf("oh.. errno says %s\n", strerror(errno)); - return 0; - } else { - control->in_SSL = 1; - return 1; - } - } - } - - if (debug) { - printf("Apparently failed negotiating with lockdownd.\n"); - printf("Responding dictionary: \n"); - for (i = 0; strcmp(dictionary[i], ""); i+=2) { - printf("\t%s: %s\n", dictionary[i], dictionary[i+1]); - } - } - - free_dictionary(dictionary); - return 0; - } else { - if (debug) printf("Didn't get enough bytes.\n"); - return 0; - } -} - -ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length) { - int bytes = 0; - lockdownd_client *control; - control = (lockdownd_client*)transport; - if (debug) printf("lockdownd_secuwrite() called\n"); - if (debug) printf("pre-send\nlength = %i\n", length); - bytes = mux_send(control->iphone, control->connection, buffer, length); - if (debug) printf("post-send\nsent %i bytes\n", bytes); - if (debug) { - FILE *my_ssl_packet = fopen("sslpacketwrite.out", "w+"); - fwrite(buffer, 1, length, my_ssl_packet); - fflush(my_ssl_packet); - printf("Wrote SSL packet to drive, too.\n"); - fclose(my_ssl_packet); - } - - return bytes; -} - -ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length) { - int bytes = 0, pos_start_fill = 0; - char *hackhackhack = NULL; - lockdownd_client *control; - control = (lockdownd_client*)transport; - if (debug) printf("lockdownd_securead() called\nlength = %i\n", length); - // Buffering hack! Throw what we've got in our "buffer" into the stream first, then get more. - if (control->gtls_buffer_hack_len > 0) { - if (length > control->gtls_buffer_hack_len) { // If it's asking for more than we got - length -= control->gtls_buffer_hack_len; // Subtract what we have from their requested length - pos_start_fill = control->gtls_buffer_hack_len; // set the pos to start filling at - memcpy(buffer, control->gtls_buffer_hack, control->gtls_buffer_hack_len); // Fill their buffer partially - free(control->gtls_buffer_hack); // free our memory, it's not chained anymore - control->gtls_buffer_hack_len = 0; // we don't have a hack buffer anymore - if (debug) printf("Did a partial fill to help quench thirst for data\n"); - } else if (length < control->gtls_buffer_hack_len) { // If it's asking for less... - control->gtls_buffer_hack_len -= length; // subtract what they're asking for - memcpy(buffer, control->gtls_buffer_hack, length); // fill their buffer - hackhackhack = (char*)malloc(sizeof(char) * control->gtls_buffer_hack_len); // strndup is NOT a good solution -- concatenates \0!!!! Anyway, make a new "hack" buffer. - memcpy(hackhackhack, control->gtls_buffer_hack+length, control->gtls_buffer_hack_len); // Move what's left into the new one - free(control->gtls_buffer_hack); // Free the old one - control->gtls_buffer_hack = hackhackhack; // And make it the new one. - hackhackhack = NULL; - if (debug) printf("Quenched the thirst for data; new hack length is %i\n", control->gtls_buffer_hack_len); - return length; // hand it over. - } else { // length == hack length - memcpy(buffer, control->gtls_buffer_hack, length); // copy our buffer into theirs - free(control->gtls_buffer_hack); // free our "obligation" - control->gtls_buffer_hack_len = 0; // free our "obligation" - if (debug) printf("Satiated the thirst for data; now we have to eventually receive again.\n"); - return length; // hand it over - } - } - // End buffering hack! - char *recv_buffer = (char*)malloc(sizeof(char) * (length * 1000)); // ensuring nothing stupid happens - - if (debug) printf("pre-read\nclient wants %i bytes\n", length); - bytes = mux_recv(control->iphone, control->connection, recv_buffer, (length * 1000)); - if (debug) printf("post-read\nwe got %i bytes\n", bytes); - if (debug && bytes < 0) { - printf("lockdownd_securead(): uh oh\n"); - printf("I believe what we have here is a failure to communicate... libusb says %s but strerror says %s\n", usb_strerror(), strerror(errno)); - return bytes + 28; // an errno - } - if (bytes >= length) { - if (bytes > length) { - if (debug) printf("lockdownd_securead: Client deliberately read less data than was there; resorting to GnuTLS buffering hack.\n"); - if (!control->gtls_buffer_hack_len) { // if there's no hack buffer yet - //control->gtls_buffer_hack = strndup(recv_buffer+length, bytes-length); // strndup is NOT a good solution! - control->gtls_buffer_hack_len += bytes-length; - control->gtls_buffer_hack = (char*)malloc(sizeof(char) * control->gtls_buffer_hack_len); - memcpy(control->gtls_buffer_hack, recv_buffer+length, control->gtls_buffer_hack_len); - } else { // if there is. - control->gtls_buffer_hack = realloc(control->gtls_buffer_hack, control->gtls_buffer_hack_len + (bytes - length)); - memcpy(control->gtls_buffer_hack+control->gtls_buffer_hack_len, recv_buffer+length, bytes-length); - control->gtls_buffer_hack_len += bytes - length; - } - } - memcpy(buffer+pos_start_fill, recv_buffer, length); - free(recv_buffer); - if (bytes == length) { if (debug) printf("Returning how much we received.\n"); return bytes; } - else { if (debug) printf("Returning what they want to hear.\nHack length: %i\n", control->gtls_buffer_hack_len); return length; } - } - return bytes; -} - -int lockdownd_start_service(lockdownd_client *control, const char *service) { - if (!control) return 0; - if (!control->in_SSL && !lockdownd_start_SSL_session(control, "29942970-207913891623273984")) return 0; - - char *XML_query, **dictionary; - uint32 length, i = 0, port = 0; - uint8 result = 0; - - xmlDocPtr plist = new_plist(); - xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); - xmlNode *key; - key = add_key_str_dict_element(plist, dict, "Request", "StartService", 1); - if (!key) { xmlFreeDoc(plist); return 0; } - key = add_key_str_dict_element(plist, dict, "Service", service, 1); - if (!key) { xmlFreeDoc(plist); return 0; } - - xmlDocDumpMemory(plist, &XML_query, &length); - - lockdownd_send(control, XML_query, length); - free(XML_query); - - length = lockdownd_recv(control, &XML_query); - - xmlFreeDoc(plist); - - if (length <= 0) return 0; - else { - plist = xmlReadMemory(XML_query, length, NULL, NULL, 0); - if (!plist) return 0; - dict = xmlDocGetRootElement(plist); - if (!dict) return 0; - for (dict = dict->children; dict; dict = dict->next) { - if (!xmlStrcmp(dict->name, "dict")) break; - } - - if (!dict) return 0; - dictionary = read_dict_element_strings(dict); - - for (i = 0; strcmp(dictionary[i], ""); i+=2) { - if (debug) printf("lockdownd_start_service() dictionary %s: %s\n", dictionary[i], dictionary[i+1]); - - if (!xmlStrcmp(dictionary[i], "Port")) { - port = atoi(dictionary[i+1]); - if (debug) printf("lockdownd_start_service() atoi'd port: %i\n", port); - } - - if (!xmlStrcmp(dictionary[i], "Result")) { - if (!xmlStrcmp(dictionary[i+1], "Success")) { - result = 1; - } - } - } - - if (debug) { - printf("lockdownd_start_service(): DATA RECEIVED:\n\n"); - fwrite(XML_query, 1, length, stdout); - printf("end data received by lockdownd_start_service()\n"); - } - - free(XML_query); - xmlFreeDoc(plist); - free_dictionary(dictionary); - if (port && result) return port; - else return 0; - } - - return 0; -} - diff --git a/lockdown.h b/lockdown.h deleted file mode 100644 index 0acd624..0000000 --- a/lockdown.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * lockdown.h - * Defines lockdown stuff, like the client struct. - */ - -#ifndef LOCKDOWND_H -#define LOCKDOWND_H - -#include "plist.h" - -#include -#include - -typedef struct { - usbmux_tcp_header *connection; - gnutls_session_t *ssl_session; - iPhone *iphone; - int in_SSL; - char *gtls_buffer_hack; - int gtls_buffer_hack_len; -} lockdownd_client; - -lockdownd_client *new_lockdownd_client(iPhone *phone); -int lockdownd_hello(lockdownd_client *control); -int lockdownd_recv(lockdownd_client *control, char **dump_data); -int lockdownd_send(lockdownd_client *control, char *raw_data, uint32 length); -void lockdownd_close(lockdownd_client *control); - -// SSL functions -int lockdownd_start_SSL_session(lockdownd_client *control, const char *HostID); -ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length); -ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length); - -// Higher-level lockdownd stuff -int lockdownd_start_service(lockdownd_client *control, const char *service); -#endif diff --git a/main.c b/main.c deleted file mode 100644 index d5c2dfa..0000000 --- a/main.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * libiphone main.c written by FxChiP - * With much help from Daniel Brownlees - */ - -#include -#include -#include -#include - -#include "usbmux.h" -#include "iphone.h" - -#include -#include -#include "plist.h" -#include "lockdown.h" -#include "AFC.h" - -int debug = 1; - -int main(int argc, char *argv[]) { - iPhone *phone = get_iPhone(); - if (argc > 1 && !strcasecmp(argv[1], "--debug")) debug = 1; - else debug = 0; - char *response = (char*)malloc(sizeof(char) * 2048); - int bytes = 0, port = 0, i = 0; - if (phone) printf("I got a phone.\n"); - else { printf("oops\n"); return -1; } - - lockdownd_client *control = new_lockdownd_client(phone); - if (!lockdownd_hello(control)) { - printf("Something went wrong in the lockdownd client, go take a look.\n"); - } else { - printf("We said hello. :)\n"); - } - - printf("Now starting SSL.\n"); -// if (!lockdownd_start_SSL_session(control, "29942970-207913891623273984")) { - if (!lockdownd_start_SSL_session(control, "2994593482385678618538736")) { - printf("Error happened in GnuTLS...\n"); - } else { - printf("... we're in SSL with the phone... !?\n"); - port = lockdownd_start_service(control, "com.apple.afc"); - } - if (port) { - printf("Start Service successful -- connect on port %i\n", port); - AFClient *afc = afc_connect(phone, 3432, port); - if (afc) { - char **dirs; - dirs = afc_get_dir_list(afc, "/eafaedf"); - if (!dirs) dirs = afc_get_dir_list(afc, "/"); - printf("Directory time.\n"); - for (i = 0; strcmp(dirs[i], ""); i++) { - printf("/%s\n", dirs[i]); - } - - free_dictionary(dirs); - AFCFile *my_file = afc_open_file(afc, "/iTunesOnTheGoPlaylist.plist", AFC_FILE_READ); - if (my_file) { - printf("A file size: %i\n", my_file->size); - char *file_data = (char*)malloc(sizeof(char) * my_file->size); - bytes = afc_read_file(afc, my_file, file_data, my_file->size); - if (bytes >= 0) { - printf("The file's data:\n"); - fwrite(file_data, 1, bytes, stdout); - } - printf("\nClosing my file.\n"); - afc_close_file(afc, my_file); - free(my_file); - free(file_data); - } else printf("couldn't open a file\n"); - - my_file = afc_open_file(afc, "/readme.libiphone.fx", AFC_FILE_WRITE); - if (my_file) { - char *outdatafile = strdup("this is a bitchin text file\n"); - bytes = afc_write_file(afc, my_file, outdatafile, strlen(outdatafile)); - free(outdatafile); - if (bytes > 0) printf("Wrote a surprise. ;)\n"); - else printf("I wanted to write a surprise, but... :(\n"); - afc_close_file(afc, my_file); - free(my_file); - } - printf("Deleting a file...\n"); - bytes = afc_delete_file(afc, "/delme"); - if (bytes) printf("Success.\n"); - else printf("Failure.\n"); - - printf("Renaming a file...\n"); - bytes = afc_rename_file(afc, "/renme", "/renme2"); - if (bytes > 0) printf("Success.\n"); - else printf("Failure.\n"); - } - afc_disconnect(afc); - } else { - printf("Start service failure.\n"); - } - - printf("All done.\n"); - - free_iPhone(phone); - - return 0; -} - diff --git a/main.h b/main.h deleted file mode 100644 index 8b13789..0000000 --- a/main.h +++ /dev/null @@ -1 +0,0 @@ - diff --git a/plist.c b/plist.c deleted file mode 100644 index cbd6302..0000000 --- a/plist.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * plist.c - * Builds plist XML structures. - * Written by FxChiP - */ - -#include -#include -#include -#include "plist.h" - -const char *plist_base = "\n\ -\n\ -\n\ -\0"; - -xmlDocPtr new_plist() { - char *plist = strdup(plist_base); - xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0); - if (!plist_xml) return NULL; - free(plist); - return plist_xml; -} - -void free_plist(xmlDocPtr plist) { - if (!plist) return; - xmlFreeDoc(plist); -} - -xmlNode *add_child_to_plist(xmlDocPtr plist, const char *name, const char *content, xmlNode *to_node, int depth) { - if (!plist) return NULL; - int i = 0; - xmlNode *child; - if (!to_node) to_node = xmlDocGetRootElement(plist); - for (i = 0; i < depth; i++) { - xmlNodeAddContent(to_node, "\t"); - } - child = xmlNewChild(to_node, NULL, name, content); - xmlNodeAddContent(to_node, "\n"); - return child; -} - -xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth) { - xmlNode *keyPtr; - keyPtr = add_child_to_plist(plist, "key", key, dict, depth); - add_child_to_plist(plist, "string", value, dict, depth); - return keyPtr; -} - -char **read_dict_element_strings(xmlNode *dict) { - // reads a set of keys and strings into an array where each even number is a key and odd numbers are values. - // if the odd number is \0, that's the end of the list. - char **return_me = NULL, **old = NULL; - int current_length = 0; - int current_pos = 0; - xmlNode *dict_walker; - - for (dict_walker = dict->children; dict_walker; dict_walker = dict_walker->next) { - if (!xmlStrcmp(dict_walker->name, "key")) { - current_length += 2; - old = return_me; - return_me = realloc(return_me, sizeof(char*) * current_length); - if (!return_me) { - free(old); - return NULL; - } - return_me[current_pos++] = xmlNodeGetContent(dict_walker); - return_me[current_pos++] = xmlNodeGetContent(dict_walker->next->next); - } - } - - // one last thing... - old = return_me; - return_me = realloc(return_me, sizeof(char*) * current_length+1); - return_me[current_pos] = strdup(""); - - return return_me; -} - -void free_dictionary(char **dictionary) { - if (!dictionary) return; - int i = 0; - - for (i = 0; strcmp(dictionary[i], ""); i++) { - free(dictionary[i]); - } - - free(dictionary[i]); - free(dictionary); -} - diff --git a/plist.h b/plist.h deleted file mode 100644 index 1f18eb4..0000000 --- a/plist.h +++ /dev/null @@ -1,17 +0,0 @@ -/* plist.h - * contains structures and the like for plists - * written by fxchip - */ - -#ifndef PLIST_H -#define PLIST_H - -#include -#include - -xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth); -xmlNode *add_child_to_plist(xmlDocPtr plist, const char *name, const char *content, xmlNode *to_node, int depth); -void free_plist(xmlDocPtr plist); -xmlDocPtr new_plist(); -void free_dictionary(char **dictionary); -#endif diff --git a/src/AFC.c b/src/AFC.c new file mode 100644 index 0000000..f3d538e --- /dev/null +++ b/src/AFC.c @@ -0,0 +1,381 @@ +/* + * AFC.c -- contains functions for the built-in AFC client. + * Written by FxChiP + */ + +#include "AFC.h" + +extern int debug; + +AFClient *afc_connect(iPhone *phone, int s_port, int d_port) { + if (!phone) return NULL; + AFClient *client = (AFClient*)malloc(sizeof(AFClient)); + client->connection = mux_connect(phone, s_port, d_port); + if (!client->connection) { free(client); return NULL; } + else { + client->afc_packet = (AFCPacket*)malloc(sizeof(AFCPacket)); + if (client->afc_packet) { + client->phone = phone; + client->afc_packet->packet_num = 0; + client->afc_packet->unknown1 = client->afc_packet->unknown2 = client->afc_packet->unknown3 = client->afc_packet->unknown4 = client->afc_packet->entire_length = client->afc_packet->this_length = 0; + client->afc_packet->header1 = 0x36414643; + client->afc_packet->header2 = 0x4141504C; + client->file_handle = 0; + return client; + } else { + mux_close_connection(client->phone, client->connection); + free(client); + return NULL; + } + } + + return NULL; // should never get to this point +} + +void afc_disconnect(AFClient *client) { + // client and its members should never be NULL is assumed here. + if (!client || !client->connection || !client->phone || !client->afc_packet) return; + mux_close_connection(client->phone, client->connection); + free(client->afc_packet); + free(client); +} + +int count_nullspaces(char *string, int number) { + int i = 0, nulls = 0; + for (i = 0; i < number; i++) { + if (string[i] == '\0') nulls++; + } + return nulls; +} + +int dispatch_AFC_packet(AFClient *client, char *data, int length) { + char *buffer; + int bytes = 0, offset = 0; + if (!client || !client->connection || !client->phone || !client->afc_packet) return 0; + if (!data || !length) length = 0; + + client->afc_packet->packet_num++; + if (!client->afc_packet->entire_length) client->afc_packet->entire_length = client->afc_packet->this_length = (length) ? sizeof(AFCPacket) + length + 1 : sizeof(AFCPacket); + if (!client->afc_packet->this_length) client->afc_packet->this_length = sizeof(AFCPacket); + + if (client->afc_packet->this_length != client->afc_packet->entire_length) { + // We want to send two segments; buffer+sizeof(AFCPacket) to this_length is the parameters + // And everything beyond that is the next packet. (for writing) + char *buffer = (char*)malloc(client->afc_packet->this_length); + memcpy(buffer, (char*)client->afc_packet, sizeof(AFCPacket)); + offset = client->afc_packet->this_length - sizeof(AFCPacket); + if (debug) printf("dispatch_AFC_packet: Offset: %i\n", offset); + if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { + if (debug) printf("dispatch_AFC_packet: Length did not resemble what it was supposed to based on the packet.\nlength minus offset: %i\nrest of packet: %i\n", length-offset, client->afc_packet->entire_length - client->afc_packet->this_length); + free(buffer); + return 0; + } + if (debug) printf("dispatch_AFC_packet: fucked-up packet method (probably a write)\n"); + memcpy(buffer+sizeof(AFCPacket), data, offset); + bytes = mux_send(client->phone, client->connection, buffer, client->afc_packet->this_length); + free(buffer); + if (bytes <= 0) { return 0; } + if (debug) { + printf("dispatch_AFC_packet: sent the first now go with the second\n"); + printf("Length: %i\n", length-offset); + printf("Buffer: \n"); + fwrite(data+offset, 1, length-offset, stdout); + } + + + bytes = mux_send(client->phone, client->connection, data+offset, length-offset); + if (bytes <= 0) { return 0; } + else { return bytes; } + } else { + if (debug) printf("dispatch_AFC_packet doin things the old way\n"); + char *buffer = (char*)malloc(sizeof(char) * client->afc_packet->this_length); + if (debug) printf("dispatch_AFC_packet packet length = %i\n", client->afc_packet->this_length); + memcpy(buffer, (char*)client->afc_packet, sizeof(AFCPacket)); + if (debug) printf("dispatch_AFC_packet packet data follows\n"); + if (length > 0) { memcpy(buffer+sizeof(AFCPacket), data, length); buffer[sizeof(AFCPacket)+length] = '\0'; } + if (debug) fwrite(buffer, 1, client->afc_packet->this_length, stdout); + if (debug) printf("\n"); + bytes = mux_send(client->phone, client->connection, buffer, client->afc_packet->this_length); + if (bytes <= 0) return 0; + else return bytes; + } + return 0; +} + +int receive_AFC_data(AFClient *client, char **dump_here) { + AFCPacket *r_packet; + char *buffer = (char*)malloc(sizeof(AFCPacket) * 4); + int bytes = 0, recv_len = 0; + + bytes = mux_recv(client->phone, client->connection, buffer, sizeof(AFCPacket) * 4); + if (bytes <= 0) { + free(buffer); + printf("Just didn't get enough.\n"); + *dump_here = NULL; + return 0; + } + + r_packet = (AFCPacket*)malloc(sizeof(AFCPacket)); + memcpy(r_packet, buffer, sizeof(AFCPacket)); + + if (r_packet->entire_length == r_packet->this_length && r_packet->entire_length > sizeof(AFCPacket) && r_packet->operation != AFC_ERROR) { + *dump_here = (char*)malloc(sizeof(char) * (r_packet->entire_length-sizeof(AFCPacket))); + memcpy(*dump_here, buffer+sizeof(AFCPacket), r_packet->entire_length-sizeof(AFCPacket)); + free(buffer); + free(r_packet); + return r_packet->entire_length - sizeof(AFCPacket); + } + + uint32 param1 = buffer[sizeof(AFCPacket)]; + free(buffer); + + if (r_packet->operation == 0x01 && !((client->afc_packet->operation == AFC_DELETE && param1 == 7))) { + if (debug) printf("Oops? Bad operation code received.\n"); + if (param1 == 0) { + if (debug) printf("... false alarm, but still\n"); + return 1; + } + else { if (debug) printf("Errno %i\n", param1); } + free(r_packet); + *dump_here = NULL; + return 0; + } else { + if (debug) printf("Operation code %x\nFull length %i and this length %i\n", r_packet->operation, r_packet->entire_length, r_packet->this_length); + } + + recv_len = r_packet->entire_length - r_packet->this_length; + free(r_packet); + if (!recv_len) return bytes; + buffer = (char*)malloc(sizeof(char) * recv_len); + bytes = mux_recv(client->phone, client->connection, buffer, recv_len); + if (bytes <= 0) { + free(buffer); + printf("Didn't get it at the second pass.\n"); + *dump_here = NULL; + return 0; + } + + *dump_here = buffer; // what they do beyond this point = not my problem + return bytes; +} + +char **afc_get_dir_list(AFClient *client, char *dir) { + client->afc_packet->operation = AFC_LIST_DIR; + int bytes = 0; + char *blah = NULL, **list = NULL; + client->afc_packet->entire_length = client->afc_packet->this_length = 0; + bytes = dispatch_AFC_packet(client, dir, strlen(dir)); + if (!bytes) return NULL; + + bytes = receive_AFC_data(client, &blah); + if (!bytes && !blah) return NULL; + + list = make_strings_list(blah, bytes); + free(blah); + return list; +} + +char **make_strings_list(char *tokens, int true_length) { + if (!tokens || !true_length) return NULL; + int nulls = 0, i = 0, j = 0; + char **list = NULL; + + nulls = count_nullspaces(tokens, true_length); + list = (char**)malloc(sizeof(char*) * (nulls + 1)); + for (i = 0; i < nulls; i++) { + list[i] = strdup(tokens+j); + j += strlen(list[i]) + 1; + } + list[i] = strdup(""); + return list; +} + +int afc_delete_file(AFClient *client, const char *path) { + if (!client || !path || !client->afc_packet || !client->phone ||!client->connection) return 0; + + char *receive = NULL; + client->afc_packet->this_length = client->afc_packet->entire_length = 0; + client->afc_packet->operation = AFC_DELETE; + int bytes; + bytes = dispatch_AFC_packet(client, path, strlen(path)); + if (bytes <= 0) return 0; + + bytes = receive_AFC_data(client, &receive); + free(receive); + if (bytes <= 0) return 0; + else return 1; +} + +int afc_rename_file(AFClient *client, const char *from, const char *to) { + if (!client || !from || !to || !client->afc_packet || !client->phone || !client->connection) return 0; + + char *receive = NULL; + char *send = (char*)malloc(sizeof(char) * (strlen(from) + strlen(to) + 1 + sizeof(uint32))); + int bytes = 0; + + memcpy(send, from, strlen(from)+1); + memcpy(send+strlen(from)+1, to, strlen(to)); + fwrite(send, 1, strlen(from)+1+strlen(to), stdout); + printf("\n"); + client->afc_packet->entire_length = client->afc_packet->this_length = 0; + client->afc_packet->operation = AFC_RENAME; + bytes = dispatch_AFC_packet(client, send, strlen(to) + strlen(from) + 2); + if (bytes <= 0) return 0; + + bytes = receive_AFC_data(client, &receive); + free(receive); + if (bytes <= 0) return 0; + else return 1; +} + + + +AFCFile *afc_get_file_info(AFClient *client, char *path) { + client->afc_packet->operation = AFC_GET_INFO; + client->afc_packet->entire_length = client->afc_packet->this_length = 0; + dispatch_AFC_packet(client, path, strlen(path)); + + char *received, **list; + AFCFile *my_file; + int length, i = 0; + + length = receive_AFC_data(client, &received); + list = make_strings_list(received, length); + free(received); + if (list) { + my_file = (AFCFile *)malloc(sizeof(AFCFile)); + for (i = 0; strcmp(list[i], ""); i++) { + if (!strcmp(list[i], "st_size")) { + my_file->size = atoi(list[i+1]); + } + + + if (!strcmp(list[i], "st_blocks")) { + my_file->blocks = atoi(list[i+1]); + } + + if (!strcmp(list[i], "st_ifmt")) { + if (!strcmp(list[i+1], "S_IFREG")) { + my_file->type = S_IFREG; + } else if (!strcmp(list[i+1], "S_IFDIR")) { + my_file->type = S_IFDIR; + } + } + } + free_dictionary(list); + return my_file; + } else { + return NULL; + } +} + +AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode) { + if (file_mode != AFC_FILE_READ && file_mode != AFC_FILE_WRITE) return NULL; + if (!client ||!client->connection || !client->phone ||!client->afc_packet) return NULL; + char *further_data = (char*)malloc(sizeof(char) * (8 + strlen(filename) + 1)); + AFCFile *file_infos = NULL; + memcpy(further_data, &file_mode, 4); + uint32 ag = 0; + memcpy(further_data+4, &ag, 4); + memcpy(further_data+8, filename, strlen(filename)); + further_data[8+strlen(filename)] = '\0'; + int bytes = 0, length_thing = 0; + client->afc_packet->operation = AFC_FILE_OPEN; + + client->afc_packet->entire_length = client->afc_packet->this_length = 0; + bytes = dispatch_AFC_packet(client, further_data, 8+strlen(filename)); + free(further_data); + if (bytes <= 0) { + if (debug) printf("didn't read enough\n"); + return NULL; + } else { + length_thing = receive_AFC_data(client, &further_data); + if (length_thing && further_data) { + file_infos = afc_get_file_info(client, filename); + memcpy(&file_infos->filehandle, further_data, 4); + return file_infos; + } else { + if (debug) printf("didn't get further data or something\n"); + return NULL; + } + } + if (debug) printf("what the fuck\n"); + return NULL; +} + +int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) { + if (!client || !client->afc_packet || !client->phone || !client->connection || !file) return -1; + AFCFilePacket *packet = (AFCFilePacket*)malloc(sizeof(AFCFilePacket)); + char *input = NULL; + packet->unknown1 = packet->unknown2 = 0; + packet->filehandle = file->filehandle; + packet->size = length; + int bytes = 0; + + client->afc_packet->operation = AFC_READ; + client->afc_packet->entire_length = client->afc_packet->this_length = 0; + bytes = dispatch_AFC_packet(client, (char*)packet, sizeof(AFCFilePacket)); + + if (bytes > 0) { + bytes = receive_AFC_data(client, &input); + if (bytes <= 0) { + if (input) free(input); + return -1; + } else { + memcpy(data, input, (bytes > length) ? length : bytes); + free(input); + return (bytes > length) ? length : bytes; + } + } else { + return -1; + } + return 0; +} + +int afc_write_file(AFClient *client, AFCFile *file, char *data, int length) { + char *acknowledgement = NULL; + if (!client ||!client->afc_packet ||!client->phone || !client->connection || !file) return -1; + client->afc_packet->this_length = sizeof(AFCPacket) + 8; + client->afc_packet->entire_length = client->afc_packet->this_length + length; + client->afc_packet->operation = AFC_WRITE; + if (debug) printf("afc_write_file: Write length: %i\n", length); + uint32 zero = 0, bytes = 0; + + char *out_buffer = NULL; + out_buffer = (char*)malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); + memcpy(out_buffer, (char*)&file->filehandle, sizeof(uint32)); + memcpy(out_buffer+4, (char*)&zero, sizeof(uint32)); + memcpy(out_buffer+8, data, length); + + bytes = dispatch_AFC_packet(client, out_buffer, length + 8); + if (!bytes) return -1; + + zero = bytes; + bytes = receive_AFC_data(client, &acknowledgement); + if (bytes <= 0) { + if (debug) printf("afc_write_file: uh oh?\n"); + } + + return zero; +} + +void afc_close_file(AFClient *client, AFCFile *file) { + char *buffer = malloc(sizeof(char) * 8); + uint32 zero = 0; + if (debug) printf("File handle %i\n", file->filehandle); + memcpy(buffer, &file->filehandle, sizeof(uint32)); + memcpy(buffer+sizeof(uint32), &zero, sizeof(zero)); + client->afc_packet->operation = AFC_FILE_CLOSE; + int bytes = 0; + client->afc_packet->entire_length = client->afc_packet->this_length = 0; + bytes = dispatch_AFC_packet(client, buffer, sizeof(char) * 8); + + free(buffer); + client->afc_packet->entire_length = client->afc_packet->this_length = 0; + if (!bytes) return; + + bytes = receive_AFC_data(client, &buffer); + return; + if (buffer) free(buffer); // we're *SUPPOSED* to get an "error" here. +} + diff --git a/src/AFC.h b/src/AFC.h new file mode 100644 index 0000000..787b9fe --- /dev/null +++ b/src/AFC.h @@ -0,0 +1,80 @@ +/* + * AFC.h + * Defines and structs and the like for the built-in AFC client + * Written by FxChiP + */ + +#include "usbmux.h" +#include "iphone.h" + +#include +#include +#include + +typedef struct { + //const uint32 header1 = 0x36414643; // '6AFC' or 'CFA6' when sent ;) + uint32 header1, header2; + //const uint32 header2 = 0x4141504C; // 'AAPL' or 'LPAA' when sent ;) + uint32 entire_length, unknown1, this_length, unknown2, packet_num, unknown3, operation, unknown4; +} AFCPacket; + +typedef struct { + usbmux_tcp_header *connection; + iPhone *phone; + AFCPacket *afc_packet; + int file_handle; +} AFClient; + +typedef struct { + uint32 filehandle, unknown1, size, unknown2; +} AFCFilePacket; + +typedef struct { + uint32 filehandle, blocks, size, type; +} AFCFile; + +typedef struct __AFCToken { + struct __AFCToken *last, *next; + char *token; +} AFCToken; + +enum { + S_IFREG = 0, + S_IFDIR = 1 +}; + +enum { + AFC_FILE_READ = 0x00000002, + AFC_FILE_WRITE = 0x00000003 +}; + +enum { + AFC_ERROR = 0x00000001, + AFC_GET_INFO = 0x0000000a, + AFC_GET_DEVINFO = 0x0000000b, + AFC_LIST_DIR = 0x00000003, + AFC_DELETE = 0x00000008, + AFC_RENAME = 0x00000018, + AFC_SUCCESS_RESPONSE = 0x00000002, + AFC_FILE_OPEN = 0x0000000d, + AFC_FILE_CLOSE = 0x00000014, + AFC_FILE_HANDLE = 0x0000000e, + AFC_READ = 0x0000000f, + AFC_WRITE = 0x00000010 +}; + +AFClient *afc_connect(iPhone *phone, int s_port, int d_port); +void afc_disconnect(AFClient *client); +int count_nullspaces(char *string, int number); +char **make_strings_list(char *tokens, int true_length); +int dispatch_AFC_packet(AFClient *client, char *data, int length); +int receive_AFC_data(AFClient *client, char **dump_here); + +char **afc_get_dir_list(AFClient *client, char *dir); +AFCFile *afc_get_file_info(AFClient *client, char *path); +AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode); +void afc_close_file(AFClient *client, AFCFile *file); +int afc_read_file(AFClient *client, AFCFile *file, char *data, int length); +int afc_write_file(AFClient *client, AFCFile *file, char *data, int length); +int afc_delete_file(AFClient *client, const char *path); +int afc_rename_file(AFClient *client, const char *from, const char *to); diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..cb05d95 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,5 @@ +AM_CFLAGS = `xml2-config --cflags` +AM_LDFLAGS = `xml2-config --libs` -lusb -lgnutls + +bin_PROGRAMS = iphoneclient +iphoneclient_SOURCES = usbmux.c main.c iphone.c plist.c lockdown.c AFC.c diff --git a/src/iphone.c b/src/iphone.c new file mode 100644 index 0000000..4ddb571 --- /dev/null +++ b/src/iphone.c @@ -0,0 +1,156 @@ +/* iPhone.c + * Functions for creating and initializing iPhone structures + */ + +#include "usbmux.h" +#include "iphone.h" +#include +#include +#include +#include + +/* get_iPhone() + * + * Returns a structure with data on the first iPhone it finds. + * (Or NULL, on error) + */ +extern int debug; + +iPhone *get_iPhone() { + iPhone *phone = (iPhone*)malloc(sizeof(iPhone)); + usbmux_version_header *version = version_header(); + + // initialize the struct + phone->device = NULL; + phone->__device = NULL; + + // Initialize libusb. + usb_init(); + usb_find_busses(); + usb_find_devices(); + struct usb_bus *busses = usb_get_busses(), *bus; + struct usb_device *dev; + + for (bus = busses; bus; bus = bus->next) { + for (dev = bus->devices; dev; dev = dev->next) { + if (dev->descriptor.idVendor == 0x05ac && (dev->descriptor.idProduct == 0x1290 || dev->descriptor.idProduct == 0x1291)) { + phone->__device = dev; + phone->device = usb_open(phone->__device); + usb_reset(phone->device); + } + } + } + + phone->device = NULL; // :( sorry Daniel + phone->__device = NULL; // :( sorry Daniel + + for (bus = busses; bus; bus = bus->next) { // do it again as per libusb documentation + for (dev = bus->devices; dev; dev = dev->next) { + if (dev->descriptor.idVendor == 0x05ac && (dev->descriptor.idProduct == 0x1290 || dev->descriptor.idProduct == 0x1291)) { + phone->__device = dev; + phone->device = usb_open(phone->__device); + usb_set_configuration(phone->device, 3); + usb_claim_interface(phone->device, 1); + break; + } + } + if (phone->__device && phone->device) break; + } + + if (!phone->device || !phone->__device) { // nothing connected + free_iPhone(phone); + if (debug) printf("get_iPhone(): iPhone not found\n"); + return NULL; + } + + // Okay, initialize the phone now. + int bytes = 0; + bytes = usb_bulk_write(phone->device, BULKOUT, (char*)version, sizeof(*version), 800); + if (bytes < 20 && debug) { + printf("get_iPhone(): libusb did NOT send enough!\n"); + if (bytes < 0) { + printf("get_iPhone(): libusb gave me the error: %s\n", usb_strerror()); + } + } + bytes = usb_bulk_read(phone->device, BULKIN, (char*)version, sizeof(*version), 800); + if (bytes < 20) { + free_iPhone(phone); + if (debug) printf("get_iPhone(): Invalid version message -- header too short.\n"); + if (debug && bytes < 0) printf("get_iPhone(): libusb error message: %s\n", usb_strerror()); + return NULL; + } else { + if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) { + // We're all ready to roll. + printf("get_iPhone() success\n"); + return phone; + } else { // BAD HEADER + free_iPhone(phone); + if (debug) printf("get_iPhone(): Received a bad header/invalid version number."); + return NULL; + } + } + + if (debug) printf("get_iPhone(): Unknown error.\n"); + return NULL; // if it got to this point it's gotta be bad +} + +/* free_iPhone(victim) + * This is a library-level function; deals directly with the iPhone to tear down relations, + * but otherwise is mostly internal. + * + * victim: a pointer to an iPhone structure + * Cleans up an iPhone structure, then frees the structure itself. + */ + +void free_iPhone(iPhone *victim) { + if (victim->buffer) free(victim->buffer); + if (victim->device) { + usb_release_interface(victim->device, 1); + usb_reset(victim->device); + usb_close(victim->device); + } + free(victim); +} + +/* send_to_phone(phone, data, datalen) + * This is a low-level (i.e. directly to phone) function. + * + * phone: the iPhone to send data to + * data: the data to send to the iPhone + * datalen: the length of the data + * + * Returns the number of bytes sent, or -1 on error or something. + */ +int send_to_phone(iPhone *phone, char *data, int datalen) { + if (!phone) return -1; + int bytes = 0; + // it may die here + if (debug) printf("dying here?\ndatalen = %i\ndata = %x\n", datalen, data); + + bytes = usb_bulk_write(phone->device, BULKOUT, data, datalen, 800); + if (debug) printf("noooo...?\n"); + if (bytes < datalen) { + return -1; + } else { + return bytes; + } + + return -1; +} + +/* recv_from_phone(phone, data, datalen): + * This function is a low-level (i.e. direct to iPhone) function. + * + * phone: the iPhone to receive data from + * data: where to put data read + * datalen: how much data to read in + * + * Returns: how many bytes were read in, or -1 on error. + */ +int recv_from_phone(iPhone *phone, char *data, int datalen) { + if (!phone) return -1; + int bytes = 0; + bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, 3500); + return bytes; +} + diff --git a/src/iphone.h b/src/iphone.h new file mode 100644 index 0000000..a49b7ef --- /dev/null +++ b/src/iphone.h @@ -0,0 +1,29 @@ +/* iphone.h + * iPhone struct + * Written by FxChiP */ + +#ifndef IPHONE_H +#define IPHONE_H + +#ifndef USBMUX_H +#include "usbmux.h" +#warning usbmux not included? +#endif + +#include + +#define BULKIN 0x85 +#define BULKOUT 0x04 + +typedef struct { + char *buffer; + struct usb_dev_handle *device; + struct usb_device *__device; +} iPhone; + +// Function definitions +void free_iPhone(iPhone *victim); +iPhone *get_iPhone(); +int send_to_phone(iPhone *phone, char *data, int datalen); +int recv_from_phone(iPhone *phone, char *data, int datalen); +#endif diff --git a/src/lockdown.c b/src/lockdown.c new file mode 100644 index 0000000..34a98f7 --- /dev/null +++ b/src/lockdown.c @@ -0,0 +1,372 @@ +/* + * lockdown.c -- libiphone built-in lockdownd client + * Written by FxChiP + */ + +#include "usbmux.h" +#include "iphone.h" +#include "lockdown.h" +#include +#include + +extern int debug; + +lockdownd_client *new_lockdownd_client(iPhone *phone) { + if (!phone) return NULL; + lockdownd_client *control = (lockdownd_client*)malloc(sizeof(lockdownd_client)); + control->connection = mux_connect(phone, 0x0a00, 0xf27e); + if (!control->connection) { + free(control); + return NULL; + } + + control->ssl_session = (gnutls_session_t*)malloc(sizeof(gnutls_session_t)); + control->in_SSL = 0; + control->iphone = phone; + control->gtls_buffer_hack_len = 0; + return control; +} + +void lockdown_close(lockdownd_client *control) { + if (!control) return; + if (control->connection) { + mux_close_connection(control->iphone, control->connection); + } + + if (control->ssl_session) free(control->ssl_session); + free(control); +} + + +int lockdownd_recv(lockdownd_client *control, char **dump_data) { + char *receive; + uint32 datalen = 0, bytes = 0; + + if (!control->in_SSL) bytes = mux_recv(control->iphone, control->connection, &datalen, sizeof(datalen)); + else bytes = gnutls_record_recv(*control->ssl_session, &datalen, sizeof(datalen)); + datalen = ntohl(datalen); + + receive = (char*)malloc(sizeof(char) * datalen); + if (!control->in_SSL) bytes = mux_recv(control->iphone, control->connection, receive, datalen); + else bytes = gnutls_record_recv(*control->ssl_session, receive, datalen); + *dump_data = receive; + return bytes; +} + +int lockdownd_send(lockdownd_client *control, char *raw_data, uint32 length) { + char *real_query; + int bytes; + + real_query = (char*)malloc(sizeof(char) * (length+4)); + length = htonl(length); + memcpy(real_query, &length, sizeof(length)); + memcpy(real_query+4, raw_data, ntohl(length)); + if (!control->in_SSL) bytes = mux_send(control->iphone, control->connection, real_query, ntohl(length)+sizeof(length)); + else gnutls_record_send(*control->ssl_session, real_query, ntohl(length)+sizeof(length)); + return bytes; +} + +int lockdownd_hello(lockdownd_client *control) { + xmlDocPtr plist = new_plist(); + xmlNode *dict, *key; + char **dictionary; + int bytes = 0, i = 0; + + dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); + key = add_key_str_dict_element(plist, dict, "Request", "QueryType", 1); + char *XML_content; + uint32 length; + + xmlDocDumpMemory(plist, &XML_content, &length); + + bytes = lockdownd_send(control, XML_content, length); + + xmlFree(XML_content); + xmlFreeDoc(plist); plist = NULL; + + bytes = lockdownd_recv(control, &XML_content); + + plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); + if (!plist) return 0; + dict = xmlDocGetRootElement(plist); + for (dict = dict->children; dict; dict = dict->next) { + if (!xmlStrcmp(dict->name, "dict")) break; + } + if (!dict) return 0; + + dictionary = read_dict_element_strings(dict); + xmlFreeDoc(plist); + free(XML_content); + + for (i = 0; strcmp(dictionary[i], ""); i+=2) { + if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i+1], "Success")) { + free_dictionary(dictionary); + return 1; + } + } + + free_dictionary(dictionary); + return 0; +} + +int lockdownd_start_SSL_session(lockdownd_client *control, const char *HostID) { + xmlDocPtr plist = new_plist(); + xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); + xmlNode *key; + char *what2send = NULL, **dictionary = NULL; + uint32 len = 0, bytes = 0, return_me = 0, i = 0; + // end variables + + key = add_key_str_dict_element(plist, dict, "HostID", HostID, 1); + if (!key) { + if (debug) printf("Couldn't add a key.\n"); + xmlFreeDoc(plist); + return 0; + } + key = add_key_str_dict_element(plist, dict, "Request", "StartSession", 1); + if (!key) { + if (debug) printf("Couldn't add a key.\n"); + xmlFreeDoc(plist); + return 0; + } + + xmlDocDumpMemory(plist, &what2send, &len); + bytes = lockdownd_send(control, what2send, len); + + xmlFree(what2send); + xmlFreeDoc(plist); + + if (bytes > 0) { + len = lockdownd_recv(control, &what2send); + plist = xmlReadMemory(what2send, len, NULL, NULL, 0); + dict = xmlDocGetRootElement(plist); + for (dict = dict->children; dict; dict = dict->next) { + if (!xmlStrcmp(dict->name, "dict")) break; + } + dictionary = read_dict_element_strings(dict); + xmlFreeDoc(plist); + free(what2send); + for (i = 0; strcmp(dictionary[i], ""); i+=2) { + if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i+1], "Success")) { + // Set up GnuTLS... + //gnutls_anon_client_credentials_t anoncred; + gnutls_certificate_credentials_t xcred; + if (debug) printf("We started the session OK, now trying GnuTLS\n"); + errno = 0; + gnutls_global_init(); + //gnutls_anon_allocate_client_credentials(&anoncred); + gnutls_certificate_allocate_credentials(&xcred); + gnutls_certificate_set_x509_trust_file(xcred, "hostcert.pem", GNUTLS_X509_FMT_PEM); + gnutls_init(control->ssl_session, GNUTLS_CLIENT); + { + int protocol_priority[16] = {GNUTLS_SSL3, 0 }; + int kx_priority[16] = { GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA, 0 }; + int cipher_priority[16] = { GNUTLS_CIPHER_AES_128_CBC, GNUTLS_CIPHER_AES_256_CBC, 0 }; + int mac_priority[16] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_MD5, 0 }; + int comp_priority[16] = { GNUTLS_COMP_NULL, 0 }; + + gnutls_cipher_set_priority(*control->ssl_session, cipher_priority); + gnutls_compression_set_priority(*control->ssl_session, comp_priority); + gnutls_kx_set_priority(*control->ssl_session, kx_priority); + gnutls_protocol_set_priority( *control->ssl_session, protocol_priority); + gnutls_mac_set_priority(*control->ssl_session, mac_priority); + + } + gnutls_credentials_set(*control->ssl_session, GNUTLS_CRD_CERTIFICATE, xcred); // this part is killing me. + + if (debug) printf("GnuTLS step 1...\n"); + gnutls_transport_set_ptr(*control->ssl_session, (gnutls_transport_ptr_t) control); + if (debug) printf("GnuTLS step 2...\n"); + gnutls_transport_set_push_function(*control->ssl_session, (gnutls_push_func)&lockdownd_secuwrite); + if (debug) printf("GnuTLS step 3...\n"); + gnutls_transport_set_pull_function(*control->ssl_session, (gnutls_pull_func)&lockdownd_securead); + if (debug) printf("GnuTLS step 4 -- now handshaking...\n"); + + if (errno && debug) printf("WARN: errno says %s before handshake!\n", strerror(errno)); + return_me = gnutls_handshake(*control->ssl_session); + if (debug) printf("GnuTLS handshake done...\n"); + + free_dictionary(dictionary); + + if (return_me != GNUTLS_E_SUCCESS) { + if (debug) printf("GnuTLS reported something wrong.\n"); + gnutls_perror(return_me); + if (debug) printf("oh.. errno says %s\n", strerror(errno)); + return 0; + } else { + control->in_SSL = 1; + return 1; + } + } + } + + if (debug) { + printf("Apparently failed negotiating with lockdownd.\n"); + printf("Responding dictionary: \n"); + for (i = 0; strcmp(dictionary[i], ""); i+=2) { + printf("\t%s: %s\n", dictionary[i], dictionary[i+1]); + } + } + + free_dictionary(dictionary); + return 0; + } else { + if (debug) printf("Didn't get enough bytes.\n"); + return 0; + } +} + +ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length) { + int bytes = 0; + lockdownd_client *control; + control = (lockdownd_client*)transport; + if (debug) printf("lockdownd_secuwrite() called\n"); + if (debug) printf("pre-send\nlength = %i\n", length); + bytes = mux_send(control->iphone, control->connection, buffer, length); + if (debug) printf("post-send\nsent %i bytes\n", bytes); + if (debug) { + FILE *my_ssl_packet = fopen("sslpacketwrite.out", "w+"); + fwrite(buffer, 1, length, my_ssl_packet); + fflush(my_ssl_packet); + printf("Wrote SSL packet to drive, too.\n"); + fclose(my_ssl_packet); + } + + return bytes; +} + +ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length) { + int bytes = 0, pos_start_fill = 0; + char *hackhackhack = NULL; + lockdownd_client *control; + control = (lockdownd_client*)transport; + if (debug) printf("lockdownd_securead() called\nlength = %i\n", length); + // Buffering hack! Throw what we've got in our "buffer" into the stream first, then get more. + if (control->gtls_buffer_hack_len > 0) { + if (length > control->gtls_buffer_hack_len) { // If it's asking for more than we got + length -= control->gtls_buffer_hack_len; // Subtract what we have from their requested length + pos_start_fill = control->gtls_buffer_hack_len; // set the pos to start filling at + memcpy(buffer, control->gtls_buffer_hack, control->gtls_buffer_hack_len); // Fill their buffer partially + free(control->gtls_buffer_hack); // free our memory, it's not chained anymore + control->gtls_buffer_hack_len = 0; // we don't have a hack buffer anymore + if (debug) printf("Did a partial fill to help quench thirst for data\n"); + } else if (length < control->gtls_buffer_hack_len) { // If it's asking for less... + control->gtls_buffer_hack_len -= length; // subtract what they're asking for + memcpy(buffer, control->gtls_buffer_hack, length); // fill their buffer + hackhackhack = (char*)malloc(sizeof(char) * control->gtls_buffer_hack_len); // strndup is NOT a good solution -- concatenates \0!!!! Anyway, make a new "hack" buffer. + memcpy(hackhackhack, control->gtls_buffer_hack+length, control->gtls_buffer_hack_len); // Move what's left into the new one + free(control->gtls_buffer_hack); // Free the old one + control->gtls_buffer_hack = hackhackhack; // And make it the new one. + hackhackhack = NULL; + if (debug) printf("Quenched the thirst for data; new hack length is %i\n", control->gtls_buffer_hack_len); + return length; // hand it over. + } else { // length == hack length + memcpy(buffer, control->gtls_buffer_hack, length); // copy our buffer into theirs + free(control->gtls_buffer_hack); // free our "obligation" + control->gtls_buffer_hack_len = 0; // free our "obligation" + if (debug) printf("Satiated the thirst for data; now we have to eventually receive again.\n"); + return length; // hand it over + } + } + // End buffering hack! + char *recv_buffer = (char*)malloc(sizeof(char) * (length * 1000)); // ensuring nothing stupid happens + + if (debug) printf("pre-read\nclient wants %i bytes\n", length); + bytes = mux_recv(control->iphone, control->connection, recv_buffer, (length * 1000)); + if (debug) printf("post-read\nwe got %i bytes\n", bytes); + if (debug && bytes < 0) { + printf("lockdownd_securead(): uh oh\n"); + printf("I believe what we have here is a failure to communicate... libusb says %s but strerror says %s\n", usb_strerror(), strerror(errno)); + return bytes + 28; // an errno + } + if (bytes >= length) { + if (bytes > length) { + if (debug) printf("lockdownd_securead: Client deliberately read less data than was there; resorting to GnuTLS buffering hack.\n"); + if (!control->gtls_buffer_hack_len) { // if there's no hack buffer yet + //control->gtls_buffer_hack = strndup(recv_buffer+length, bytes-length); // strndup is NOT a good solution! + control->gtls_buffer_hack_len += bytes-length; + control->gtls_buffer_hack = (char*)malloc(sizeof(char) * control->gtls_buffer_hack_len); + memcpy(control->gtls_buffer_hack, recv_buffer+length, control->gtls_buffer_hack_len); + } else { // if there is. + control->gtls_buffer_hack = realloc(control->gtls_buffer_hack, control->gtls_buffer_hack_len + (bytes - length)); + memcpy(control->gtls_buffer_hack+control->gtls_buffer_hack_len, recv_buffer+length, bytes-length); + control->gtls_buffer_hack_len += bytes - length; + } + } + memcpy(buffer+pos_start_fill, recv_buffer, length); + free(recv_buffer); + if (bytes == length) { if (debug) printf("Returning how much we received.\n"); return bytes; } + else { if (debug) printf("Returning what they want to hear.\nHack length: %i\n", control->gtls_buffer_hack_len); return length; } + } + return bytes; +} + +int lockdownd_start_service(lockdownd_client *control, const char *service) { + if (!control) return 0; + if (!control->in_SSL && !lockdownd_start_SSL_session(control, "29942970-207913891623273984")) return 0; + + char *XML_query, **dictionary; + uint32 length, i = 0, port = 0; + uint8 result = 0; + + xmlDocPtr plist = new_plist(); + xmlNode *dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); + xmlNode *key; + key = add_key_str_dict_element(plist, dict, "Request", "StartService", 1); + if (!key) { xmlFreeDoc(plist); return 0; } + key = add_key_str_dict_element(plist, dict, "Service", service, 1); + if (!key) { xmlFreeDoc(plist); return 0; } + + xmlDocDumpMemory(plist, &XML_query, &length); + + lockdownd_send(control, XML_query, length); + free(XML_query); + + length = lockdownd_recv(control, &XML_query); + + xmlFreeDoc(plist); + + if (length <= 0) return 0; + else { + plist = xmlReadMemory(XML_query, length, NULL, NULL, 0); + if (!plist) return 0; + dict = xmlDocGetRootElement(plist); + if (!dict) return 0; + for (dict = dict->children; dict; dict = dict->next) { + if (!xmlStrcmp(dict->name, "dict")) break; + } + + if (!dict) return 0; + dictionary = read_dict_element_strings(dict); + + for (i = 0; strcmp(dictionary[i], ""); i+=2) { + if (debug) printf("lockdownd_start_service() dictionary %s: %s\n", dictionary[i], dictionary[i+1]); + + if (!xmlStrcmp(dictionary[i], "Port")) { + port = atoi(dictionary[i+1]); + if (debug) printf("lockdownd_start_service() atoi'd port: %i\n", port); + } + + if (!xmlStrcmp(dictionary[i], "Result")) { + if (!xmlStrcmp(dictionary[i+1], "Success")) { + result = 1; + } + } + } + + if (debug) { + printf("lockdownd_start_service(): DATA RECEIVED:\n\n"); + fwrite(XML_query, 1, length, stdout); + printf("end data received by lockdownd_start_service()\n"); + } + + free(XML_query); + xmlFreeDoc(plist); + free_dictionary(dictionary); + if (port && result) return port; + else return 0; + } + + return 0; +} + diff --git a/src/lockdown.h b/src/lockdown.h new file mode 100644 index 0000000..0acd624 --- /dev/null +++ b/src/lockdown.h @@ -0,0 +1,36 @@ +/* + * lockdown.h + * Defines lockdown stuff, like the client struct. + */ + +#ifndef LOCKDOWND_H +#define LOCKDOWND_H + +#include "plist.h" + +#include +#include + +typedef struct { + usbmux_tcp_header *connection; + gnutls_session_t *ssl_session; + iPhone *iphone; + int in_SSL; + char *gtls_buffer_hack; + int gtls_buffer_hack_len; +} lockdownd_client; + +lockdownd_client *new_lockdownd_client(iPhone *phone); +int lockdownd_hello(lockdownd_client *control); +int lockdownd_recv(lockdownd_client *control, char **dump_data); +int lockdownd_send(lockdownd_client *control, char *raw_data, uint32 length); +void lockdownd_close(lockdownd_client *control); + +// SSL functions +int lockdownd_start_SSL_session(lockdownd_client *control, const char *HostID); +ssize_t lockdownd_securead(gnutls_transport_ptr_t transport, char *buffer, size_t length); +ssize_t lockdownd_secuwrite(gnutls_transport_ptr_t transport, char *buffer, size_t length); + +// Higher-level lockdownd stuff +int lockdownd_start_service(lockdownd_client *control, const char *service); +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e4007e9 --- /dev/null +++ b/src/main.c @@ -0,0 +1,104 @@ +/* + * libiphone main.c written by FxChiP + * With much help from Daniel Brownlees + */ + +#include +#include +#include +#include + +#include "usbmux.h" +#include "iphone.h" + +#include +#include +#include "plist.h" +#include "lockdown.h" +#include "AFC.h" + +int debug = 1; + +int main(int argc, char *argv[]) { + iPhone *phone = get_iPhone(); + if (argc > 1 && !strcasecmp(argv[1], "--debug")) debug = 1; + else debug = 0; + char *response = (char*)malloc(sizeof(char) * 2048); + int bytes = 0, port = 0, i = 0; + if (phone) printf("I got a phone.\n"); + else { printf("oops\n"); return -1; } + + lockdownd_client *control = new_lockdownd_client(phone); + if (!lockdownd_hello(control)) { + printf("Something went wrong in the lockdownd client, go take a look.\n"); + } else { + printf("We said hello. :)\n"); + } + + printf("Now starting SSL.\n"); +// if (!lockdownd_start_SSL_session(control, "29942970-207913891623273984")) { + printf("Error happened in GnuTLS...\n"); + } else { + printf("... we're in SSL with the phone... !?\n"); + port = lockdownd_start_service(control, "com.apple.afc"); + } + if (port) { + printf("Start Service successful -- connect on port %i\n", port); + AFClient *afc = afc_connect(phone, 3432, port); + if (afc) { + char **dirs; + dirs = afc_get_dir_list(afc, "/eafaedf"); + if (!dirs) dirs = afc_get_dir_list(afc, "/"); + printf("Directory time.\n"); + for (i = 0; strcmp(dirs[i], ""); i++) { + printf("/%s\n", dirs[i]); + } + + free_dictionary(dirs); + AFCFile *my_file = afc_open_file(afc, "/iTunesOnTheGoPlaylist.plist", AFC_FILE_READ); + if (my_file) { + printf("A file size: %i\n", my_file->size); + char *file_data = (char*)malloc(sizeof(char) * my_file->size); + bytes = afc_read_file(afc, my_file, file_data, my_file->size); + if (bytes >= 0) { + printf("The file's data:\n"); + fwrite(file_data, 1, bytes, stdout); + } + printf("\nClosing my file.\n"); + afc_close_file(afc, my_file); + free(my_file); + free(file_data); + } else printf("couldn't open a file\n"); + + my_file = afc_open_file(afc, "/readme.libiphone.fx", AFC_FILE_WRITE); + if (my_file) { + char *outdatafile = strdup("this is a bitchin text file\n"); + bytes = afc_write_file(afc, my_file, outdatafile, strlen(outdatafile)); + free(outdatafile); + if (bytes > 0) printf("Wrote a surprise. ;)\n"); + else printf("I wanted to write a surprise, but... :(\n"); + afc_close_file(afc, my_file); + free(my_file); + } + printf("Deleting a file...\n"); + bytes = afc_delete_file(afc, "/delme"); + if (bytes) printf("Success.\n"); + else printf("Failure.\n"); + + printf("Renaming a file...\n"); + bytes = afc_rename_file(afc, "/renme", "/renme2"); + if (bytes > 0) printf("Success.\n"); + else printf("Failure.\n"); + } + afc_disconnect(afc); + } else { + printf("Start service failure.\n"); + } + + printf("All done.\n"); + + free_iPhone(phone); + + return 0; +} + diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/main.h @@ -0,0 +1 @@ + diff --git a/src/plist.c b/src/plist.c new file mode 100644 index 0000000..cbd6302 --- /dev/null +++ b/src/plist.c @@ -0,0 +1,91 @@ +/* + * plist.c + * Builds plist XML structures. + * Written by FxChiP + */ + +#include +#include +#include +#include "plist.h" + +const char *plist_base = "\n\ +\n\ +\n\ +\0"; + +xmlDocPtr new_plist() { + char *plist = strdup(plist_base); + xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0); + if (!plist_xml) return NULL; + free(plist); + return plist_xml; +} + +void free_plist(xmlDocPtr plist) { + if (!plist) return; + xmlFreeDoc(plist); +} + +xmlNode *add_child_to_plist(xmlDocPtr plist, const char *name, const char *content, xmlNode *to_node, int depth) { + if (!plist) return NULL; + int i = 0; + xmlNode *child; + if (!to_node) to_node = xmlDocGetRootElement(plist); + for (i = 0; i < depth; i++) { + xmlNodeAddContent(to_node, "\t"); + } + child = xmlNewChild(to_node, NULL, name, content); + xmlNodeAddContent(to_node, "\n"); + return child; +} + +xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth) { + xmlNode *keyPtr; + keyPtr = add_child_to_plist(plist, "key", key, dict, depth); + add_child_to_plist(plist, "string", value, dict, depth); + return keyPtr; +} + +char **read_dict_element_strings(xmlNode *dict) { + // reads a set of keys and strings into an array where each even number is a key and odd numbers are values. + // if the odd number is \0, that's the end of the list. + char **return_me = NULL, **old = NULL; + int current_length = 0; + int current_pos = 0; + xmlNode *dict_walker; + + for (dict_walker = dict->children; dict_walker; dict_walker = dict_walker->next) { + if (!xmlStrcmp(dict_walker->name, "key")) { + current_length += 2; + old = return_me; + return_me = realloc(return_me, sizeof(char*) * current_length); + if (!return_me) { + free(old); + return NULL; + } + return_me[current_pos++] = xmlNodeGetContent(dict_walker); + return_me[current_pos++] = xmlNodeGetContent(dict_walker->next->next); + } + } + + // one last thing... + old = return_me; + return_me = realloc(return_me, sizeof(char*) * current_length+1); + return_me[current_pos] = strdup(""); + + return return_me; +} + +void free_dictionary(char **dictionary) { + if (!dictionary) return; + int i = 0; + + for (i = 0; strcmp(dictionary[i], ""); i++) { + free(dictionary[i]); + } + + free(dictionary[i]); + free(dictionary); +} + diff --git a/src/plist.h b/src/plist.h new file mode 100644 index 0000000..1f18eb4 --- /dev/null +++ b/src/plist.h @@ -0,0 +1,17 @@ +/* plist.h + * contains structures and the like for plists + * written by fxchip + */ + +#ifndef PLIST_H +#define PLIST_H + +#include +#include + +xmlNode *add_key_str_dict_element(xmlDocPtr plist, xmlNode *dict, const char *key, const char *value, int depth); +xmlNode *add_child_to_plist(xmlDocPtr plist, const char *name, const char *content, xmlNode *to_node, int depth); +void free_plist(xmlDocPtr plist); +xmlDocPtr new_plist(); +void free_dictionary(char **dictionary); +#endif diff --git a/src/usbmux.c b/src/usbmux.c new file mode 100644 index 0000000..8c5fc34 --- /dev/null +++ b/src/usbmux.c @@ -0,0 +1,198 @@ + +#include +#include +#include +#include +#include + +#include "usbmux.h" + +extern int debug; + +usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port) { + usbmux_tcp_header *conn = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header)); + conn->type = htonl(6); + conn->length = 28; + conn->sport = htons(s_port); + conn->dport = htons(d_port); + conn->scnt = 0; + conn->ocnt = 0; + conn->offset = 0x50; + conn->window = htons(0x0200); + conn->nullnull = 0x0000; + conn->length16 = 28; + return conn; +} + +usbmux_version_header *version_header() { + usbmux_version_header *version = (usbmux_version_header*)malloc(sizeof(usbmux_version_header)); + version->type = 0; + version->length = htonl(20); + version->major = htonl(1); + version->minor = 0; + version->allnull = 0; + return version; +} + +/* mux_connect(phone, s_port, d_port) + * This is a higher-level USBMuxTCP-type function. + * phone: the iPhone to initialize a connection on. + * s_port: the source port + * d_port: the destination port -- 0xf27e for lockdownd. + * Initializes a connection on phone, with source port s_port and destination port d_port + * + * Returns a mux TCP header for the connection which is used for tracking and data transfer. + */ + +usbmux_tcp_header *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port) { + if (!phone || !s_port || !d_port) return NULL; + int bytes = 0; + // Initialize connection stuff + usbmux_tcp_header *new_connection; + new_connection = new_mux_packet(s_port, d_port); + usbmux_tcp_header *response; + response = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header)); + // blargg + if (new_connection) { + new_connection->tcp_flags = 0x02; + new_connection->length = htonl(new_connection->length); + new_connection->length16 = htons(new_connection->length16); + + if (send_to_phone(phone, (char*)new_connection, sizeof(*new_connection)) >= 0) { + bytes = recv_from_phone(phone, (char*)response, sizeof(*response)); + if (response->tcp_flags != 0x12) return NULL; + else { + new_connection->tcp_flags = 0x10; + new_connection->scnt = 1; + new_connection->ocnt = 1; + return new_connection; + } + } else { + return NULL; + } + } + + // if we get to this point it's probably bad + return NULL; +} + +/* mux_close_connection(phone, connection) + * This is a higher-level USBmuxTCP-type function. + * phone: the iPhone to close a connection with. + * connection: the connection to close. + * + * Doesn't return anything; WILL FREE THE CONNECTION'S MEMORY!!! + */ +void mux_close_connection(iPhone *phone, usbmux_tcp_header *connection) { + if (!phone || !connection) return; + + connection->tcp_flags = 0x04; + connection->scnt = htonl(connection->scnt); + connection->ocnt = htonl(connection->ocnt); + int bytes = 0; + + bytes = usb_bulk_write(phone->device, BULKOUT, (char*)connection, sizeof(*connection), 800); + bytes = usb_bulk_read(phone->device, BULKIN, (char*)connection, sizeof(*connection), 800); + + free(connection); +} + +/* mux_send(phone, connection, data, datalen) + * This is a higher-level USBMuxTCP-like function. + * phone: the iPhone to send to. + * connection: the connection we're sending data on. + * data: a pointer to the data to send. + * datalen: how much data we're sending. + * + * Returns number of bytes sent, minus the header (28), or -1 on error. + */ +int mux_send(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) { + if (!phone || !connection || !data || datalen == 0) return -1; + // connection->scnt and connection->ocnt should already be in host notation... + // we don't need to change them juuuust yet. + int bytes = 0; + if (debug) printf("mux_send(): client wants to send %i bytes\n", datalen); + char *buffer = (char*)malloc(sizeof(*connection) + datalen + 2); // allow 2 bytes of safety padding + // Set the length and pre-emptively htonl/htons it + connection->length = htonl(sizeof(*connection) + datalen); + connection->length16 = htons(sizeof(*connection) + datalen); + + // Put scnt and ocnt into big-endian notation + connection->scnt = htonl(connection->scnt); + connection->ocnt = htonl(connection->ocnt); + // Concatenation of stuff in the buffer. + memcpy(buffer, connection, sizeof(*connection)); + memcpy(buffer+sizeof(*connection)/*+sizeof(datalen)*/, data, datalen); + + // We have a buffer full of data, we should now send it to the phone. + if (debug) printf("actually sending %i bytes of data at %x\n", sizeof(*connection)+datalen, buffer); + + + bytes = send_to_phone(phone, buffer, sizeof(*connection)+datalen); + + // Now that we've sent it off, we can clean up after our sloppy selves. + free(buffer); + + // Re-calculate scnt and ocnt + connection->scnt = ntohl(connection->scnt) + datalen; + connection->ocnt = ntohl(connection->ocnt); + + // Revert lengths + connection->length = ntohl(connection->length); + connection->length16 = ntohs(connection->length16); + + // Now return the bytes. + if (bytes < sizeof(*connection)+datalen) { + return -1; // blah + } else { + return bytes - 28; // actual length sent. :/ + } + + return bytes; // or something +} + +/* mux_recv(phone, connection, data, datalen) + * This is a higher-level USBMuxTCP-like function + * phone: the phone to receive data from. + * connection: the connection to receive data on. + * data: where to put the data we receive. + * datalen: how much data to read. + * + * Returns: how many bytes were read, or -1 if something bad happens. + */ + +int mux_recv(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) { + char *buffer = (char*)malloc(sizeof(*connection) + sizeof(datalen) + datalen); + int bytes = 0, my_datalen = 0; + if (debug) printf("mux_recv: datalen == %i\n", datalen); + bytes = recv_from_phone(phone, buffer, sizeof(*connection) + datalen); + if (debug) printf("mux_recv: bytes == %i\n", bytes); + if (bytes < datalen) { + if (bytes < 28) { + // if they didn't do that annoying thing, something else mighta happened. + if (debug) printf("mux_recv: bytes too low anyway!\n"); + free(buffer); + return -1; + } else if (bytes == 28) { // no data... + free(buffer); + return 0; + } else { // bytes > 28 + my_datalen = ntohl(buffer[4]) - 28; + connection->ocnt += my_datalen; + memcpy(data, buffer+28, bytes - 28); + free(buffer); + if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28); + return bytes - 28; + } + } else {// all's good, they didn't do anything bonky. + my_datalen = ntohl(buffer[4]) - 28; + connection->ocnt += my_datalen; + memcpy(data, buffer+28, datalen); + free(buffer); + if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28); + return bytes - 28; + } + + return bytes; +} + diff --git a/src/usbmux.h b/src/usbmux.h new file mode 100644 index 0000000..921f4b7 --- /dev/null +++ b/src/usbmux.h @@ -0,0 +1,39 @@ + +#include +#include +#include + + +#ifndef USBMUX_H +#define USBMUX_H + +#ifndef IPHONE_H +#include "iphone.h" +#endif + +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint8_t uint8; + + +typedef struct { + uint32 type, length; + uint16 sport, dport; + uint32 scnt, ocnt; + uint8 offset, tcp_flags; + uint16 window, nullnull, length16; +} usbmux_tcp_header; + +usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port); + +typedef struct { + uint32 type, length, major, minor, allnull; +} usbmux_version_header; + +usbmux_version_header *version_header(); + +usbmux_tcp_header *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port); +void mux_close_connection(iPhone *phone, usbmux_tcp_header *connection); +int mux_send(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen); +int mux_recv(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen); +#endif diff --git a/usbmux.c b/usbmux.c deleted file mode 100644 index 8c5fc34..0000000 --- a/usbmux.c +++ /dev/null @@ -1,198 +0,0 @@ - -#include -#include -#include -#include -#include - -#include "usbmux.h" - -extern int debug; - -usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port) { - usbmux_tcp_header *conn = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header)); - conn->type = htonl(6); - conn->length = 28; - conn->sport = htons(s_port); - conn->dport = htons(d_port); - conn->scnt = 0; - conn->ocnt = 0; - conn->offset = 0x50; - conn->window = htons(0x0200); - conn->nullnull = 0x0000; - conn->length16 = 28; - return conn; -} - -usbmux_version_header *version_header() { - usbmux_version_header *version = (usbmux_version_header*)malloc(sizeof(usbmux_version_header)); - version->type = 0; - version->length = htonl(20); - version->major = htonl(1); - version->minor = 0; - version->allnull = 0; - return version; -} - -/* mux_connect(phone, s_port, d_port) - * This is a higher-level USBMuxTCP-type function. - * phone: the iPhone to initialize a connection on. - * s_port: the source port - * d_port: the destination port -- 0xf27e for lockdownd. - * Initializes a connection on phone, with source port s_port and destination port d_port - * - * Returns a mux TCP header for the connection which is used for tracking and data transfer. - */ - -usbmux_tcp_header *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port) { - if (!phone || !s_port || !d_port) return NULL; - int bytes = 0; - // Initialize connection stuff - usbmux_tcp_header *new_connection; - new_connection = new_mux_packet(s_port, d_port); - usbmux_tcp_header *response; - response = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header)); - // blargg - if (new_connection) { - new_connection->tcp_flags = 0x02; - new_connection->length = htonl(new_connection->length); - new_connection->length16 = htons(new_connection->length16); - - if (send_to_phone(phone, (char*)new_connection, sizeof(*new_connection)) >= 0) { - bytes = recv_from_phone(phone, (char*)response, sizeof(*response)); - if (response->tcp_flags != 0x12) return NULL; - else { - new_connection->tcp_flags = 0x10; - new_connection->scnt = 1; - new_connection->ocnt = 1; - return new_connection; - } - } else { - return NULL; - } - } - - // if we get to this point it's probably bad - return NULL; -} - -/* mux_close_connection(phone, connection) - * This is a higher-level USBmuxTCP-type function. - * phone: the iPhone to close a connection with. - * connection: the connection to close. - * - * Doesn't return anything; WILL FREE THE CONNECTION'S MEMORY!!! - */ -void mux_close_connection(iPhone *phone, usbmux_tcp_header *connection) { - if (!phone || !connection) return; - - connection->tcp_flags = 0x04; - connection->scnt = htonl(connection->scnt); - connection->ocnt = htonl(connection->ocnt); - int bytes = 0; - - bytes = usb_bulk_write(phone->device, BULKOUT, (char*)connection, sizeof(*connection), 800); - bytes = usb_bulk_read(phone->device, BULKIN, (char*)connection, sizeof(*connection), 800); - - free(connection); -} - -/* mux_send(phone, connection, data, datalen) - * This is a higher-level USBMuxTCP-like function. - * phone: the iPhone to send to. - * connection: the connection we're sending data on. - * data: a pointer to the data to send. - * datalen: how much data we're sending. - * - * Returns number of bytes sent, minus the header (28), or -1 on error. - */ -int mux_send(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) { - if (!phone || !connection || !data || datalen == 0) return -1; - // connection->scnt and connection->ocnt should already be in host notation... - // we don't need to change them juuuust yet. - int bytes = 0; - if (debug) printf("mux_send(): client wants to send %i bytes\n", datalen); - char *buffer = (char*)malloc(sizeof(*connection) + datalen + 2); // allow 2 bytes of safety padding - // Set the length and pre-emptively htonl/htons it - connection->length = htonl(sizeof(*connection) + datalen); - connection->length16 = htons(sizeof(*connection) + datalen); - - // Put scnt and ocnt into big-endian notation - connection->scnt = htonl(connection->scnt); - connection->ocnt = htonl(connection->ocnt); - // Concatenation of stuff in the buffer. - memcpy(buffer, connection, sizeof(*connection)); - memcpy(buffer+sizeof(*connection)/*+sizeof(datalen)*/, data, datalen); - - // We have a buffer full of data, we should now send it to the phone. - if (debug) printf("actually sending %i bytes of data at %x\n", sizeof(*connection)+datalen, buffer); - - - bytes = send_to_phone(phone, buffer, sizeof(*connection)+datalen); - - // Now that we've sent it off, we can clean up after our sloppy selves. - free(buffer); - - // Re-calculate scnt and ocnt - connection->scnt = ntohl(connection->scnt) + datalen; - connection->ocnt = ntohl(connection->ocnt); - - // Revert lengths - connection->length = ntohl(connection->length); - connection->length16 = ntohs(connection->length16); - - // Now return the bytes. - if (bytes < sizeof(*connection)+datalen) { - return -1; // blah - } else { - return bytes - 28; // actual length sent. :/ - } - - return bytes; // or something -} - -/* mux_recv(phone, connection, data, datalen) - * This is a higher-level USBMuxTCP-like function - * phone: the phone to receive data from. - * connection: the connection to receive data on. - * data: where to put the data we receive. - * datalen: how much data to read. - * - * Returns: how many bytes were read, or -1 if something bad happens. - */ - -int mux_recv(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) { - char *buffer = (char*)malloc(sizeof(*connection) + sizeof(datalen) + datalen); - int bytes = 0, my_datalen = 0; - if (debug) printf("mux_recv: datalen == %i\n", datalen); - bytes = recv_from_phone(phone, buffer, sizeof(*connection) + datalen); - if (debug) printf("mux_recv: bytes == %i\n", bytes); - if (bytes < datalen) { - if (bytes < 28) { - // if they didn't do that annoying thing, something else mighta happened. - if (debug) printf("mux_recv: bytes too low anyway!\n"); - free(buffer); - return -1; - } else if (bytes == 28) { // no data... - free(buffer); - return 0; - } else { // bytes > 28 - my_datalen = ntohl(buffer[4]) - 28; - connection->ocnt += my_datalen; - memcpy(data, buffer+28, bytes - 28); - free(buffer); - if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28); - return bytes - 28; - } - } else {// all's good, they didn't do anything bonky. - my_datalen = ntohl(buffer[4]) - 28; - connection->ocnt += my_datalen; - memcpy(data, buffer+28, datalen); - free(buffer); - if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28); - return bytes - 28; - } - - return bytes; -} - diff --git a/usbmux.h b/usbmux.h deleted file mode 100644 index 921f4b7..0000000 --- a/usbmux.h +++ /dev/null @@ -1,39 +0,0 @@ - -#include -#include -#include - - -#ifndef USBMUX_H -#define USBMUX_H - -#ifndef IPHONE_H -#include "iphone.h" -#endif - -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint8_t uint8; - - -typedef struct { - uint32 type, length; - uint16 sport, dport; - uint32 scnt, ocnt; - uint8 offset, tcp_flags; - uint16 window, nullnull, length16; -} usbmux_tcp_header; - -usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port); - -typedef struct { - uint32 type, length, major, minor, allnull; -} usbmux_version_header; - -usbmux_version_header *version_header(); - -usbmux_tcp_header *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port); -void mux_close_connection(iPhone *phone, usbmux_tcp_header *connection); -int mux_send(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen); -int mux_recv(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen); -#endif -- cgit v1.1-32-gdbae