added support, for booting with custom bootargs from pwndfu

This commit is contained in:
tihmstar 2017-07-27 14:47:23 +02:00
parent f068ddb057
commit c90da707b1
4 changed files with 197 additions and 65 deletions

View file

@ -52,7 +52,7 @@ if [test -z "$LIBIPATCHER_FLAGS"]; then
else
AC_MSG_CHECKING([for futurerestore libipatcher])
if test "$build_libipatcher" = "true"; then
PKG_CHECK_MODULES(libipatcher, libipatcher >= 32)
PKG_CHECK_MODULES(libipatcher, libipatcher >= 38)
do_libipatcher=yes
else
do_libipatcher=no

View file

@ -125,9 +125,17 @@ int futurerestore::getDeviceMode(bool reRequest){
void futurerestore::putDeviceIntoRecovery(){
if (!_didInit) reterror(-1, "did not init\n");
#ifdef HAVE_LIBIPATCHER
_enterPwnRecoveryRequested = _isPwnDfu;
#endif
getDeviceMode(false);
info("Found device in %s mode\n", _client->mode->string);
if (_client->mode->index == MODE_NORMAL) {
if (_client->mode->index == MODE_NORMAL){
#ifdef HAVE_LIBIPATCHER
if (_isPwnDfu)
reterror(-501, "isPwnDfu enabled, but device was found in normal mode\n");
#endif
info("Entering recovery mode...\n");
if (normal_enter_recovery(_client) < 0) {
reterror(-2,"Unable to place device into recovery mode from %s mode\n", _client->mode->string);
@ -136,7 +144,7 @@ void futurerestore::putDeviceIntoRecovery(){
info("Device already in Recovery mode\n");
}else if (_client->mode->index == MODE_DFU && _isPwnDfu &&
#ifdef HAVE_LIBIPATCHER
(_enterPwnRecoveryRequested = true)
true
#else
false
#endif
@ -420,7 +428,7 @@ pair<ptr_smart<char*>, size_t> getIPSWComponent(struct idevicerestore_client_t*
}
void futurerestore::enterPwnRecovery(plist_t build_identity){
void futurerestore::enterPwnRecovery(plist_t build_identity, string bootargs){
#ifndef HAVE_LIBIPATCHER
reterror(-404, "compiled without libipatcher");
#else
@ -430,15 +438,8 @@ void futurerestore::enterPwnRecovery(plist_t build_identity){
if (dfu_client_new(_client) < 0)
reterror(-91,"Unable to connect to DFU device\n");
irecv_get_mode(_client->dfu->client, &mode);
if (mode != IRECV_K_DFU_MODE) {
info("NOTE: device is not in DFU mode, assuming recovery mode.\n");
_client->mode = &idevicerestore_modes[MODE_RECOVERY];
reterror(-91, "Device is in wrong mode\n");
}
try {
iBSSKeys = libipatcher::getFirmwareKey(_client->device->product_type, _client->build, "iBSS");
iBECKeys = libipatcher::getFirmwareKey(_client->device->product_type, _client->build, "iBEC");
@ -453,14 +454,24 @@ void futurerestore::enterPwnRecovery(plist_t build_identity){
auto iBEC = getIPSWComponent(_client, build_identity, "iBEC");
iBEC = move(libipatcher::patchiBEC((char*)iBEC.first, iBEC.second, iBECKeys));
iBEC = move(libipatcher::patchiBEC((char*)iBEC.first, iBEC.second, iBECKeys, bootargs));
info("Sending %s (%lu bytes)...\n", "iBSS", iBSS.second);
// FIXME: Did I do this right????
irecv_error_t err = irecv_send_buffer(_client->dfu->client, (unsigned char*)(char*)iBSS.first, (unsigned long)iBSS.second, 1);
if (err != IRECV_E_SUCCESS) {
reterror(-92,"ERROR: Unable to send %s component: %s\n", "iBSS", irecv_strerror(err));
bool modeIsRecovery = false;
if (mode != IRECV_K_DFU_MODE) {
info("NOTE: device is not in DFU mode, assuming pwn recovery mode.\n");
for (int i=IRECV_K_RECOVERY_MODE_1; i<=IRECV_K_RECOVERY_MODE_4; i++) {
if (mode == i)
modeIsRecovery = true;
}
if (!modeIsRecovery)
reterror(-505, "device not in recovery mode\n");
}else{
info("Sending %s (%lu bytes)...\n", "iBSS", iBSS.second);
// FIXME: Did I do this right????
irecv_error_t err = irecv_send_buffer(_client->dfu->client, (unsigned char*)(char*)iBSS.first, (unsigned long)iBSS.second, 1);
if (err != IRECV_E_SUCCESS) {
reterror(-92,"ERROR: Unable to send %s component: %s\n", "iBSS", irecv_strerror(err));
}
}
if (_client->build_major > 8) {
@ -480,6 +491,8 @@ void futurerestore::enterPwnRecovery(plist_t build_identity){
if (err != IRECV_E_SUCCESS) {
reterror(-92,"ERROR: Unable to send %s component: %s\n", "iBSS", irecv_strerror(err));
}
if (modeIsRecovery)
irecv_send_command(_client->dfu->client, "go");
}
dfu_client_free(_client);
@ -922,6 +935,106 @@ error:
return result ? abs(result) : err;
}
int futurerestore::doJustBoot(const char *ipsw, string bootargs){
int err = 0;
//some memory might not get freed if this function throws an exception, but you probably don't want to catch that anyway.
struct idevicerestore_client_t* client = _client;
int unused;
int result = 0;
plist_t buildmanifest = NULL;
plist_t build_identity = NULL;
client->ipsw = strdup(ipsw);
getDeviceMode(true);
info("Found device in %s mode\n", client->mode->string);
if (!(client->mode->index == MODE_DFU || client->mode->index == MODE_RECOVERY) || !_enterPwnRecoveryRequested)
reterror(-6, "device not in DFU/Recovery mode\n");
// discover the device type
if (check_hardware_model(client) == NULL || client->device == NULL) {
reterror(-2,"ERROR: Unable to discover device model\n");
}
info("Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type);
// verify if ipsw file exists
if (access(client->ipsw, F_OK) < 0) {
error("ERROR: Firmware file %s does not exist.\n", client->ipsw);
return -1;
}
info("Extracting BuildManifest from IPSW\n");
if (ipsw_extract_build_manifest(client->ipsw, &buildmanifest, &unused) < 0) {
reterror(-3,"ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw);
}
/* check if device type is supported by the given build manifest */
if (build_manifest_check_compatibility(buildmanifest, client->device->product_type) < 0) {
reterror(-4,"ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue.\n");
}
/* print iOS information from the manifest */
build_manifest_get_version_information(buildmanifest, client);
info("Product Version: %s\n", client->version);
info("Product Build: %s Major: %d\n", client->build, client->build_major);
client->image4supported = is_image4_supported(client);
info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false");
if (!(build_identity = getBuildidentityWithBoardconfig(buildmanifest, client->device->hardware_model, 0)))
reterror(-5,"ERROR: Unable to find any build identities for IPSW\n");
/* print information about current build identity */
build_identity_print_information(build_identity);
//check for enterpwnrecovery, because we could be in DFU mode
if (!_enterPwnRecoveryRequested)
reterror(-6, "enterPwnRecoveryRequested is not set, but required");
if (getDeviceMode(true) != MODE_DFU && getDeviceMode(false) != MODE_RECOVERY)
reterror(-6, "unexpected device mode");
enterPwnRecovery(build_identity, bootargs);
client->recovery_custom_component_function = get_custom_component;
for (int i=0;getDeviceMode(true) != MODE_RECOVERY && i<40; i++) putchar('.'),usleep(USEC_PER_SEC*0.5);
putchar('\n');
if (!check_mode(client))
reterror(-15, "failed to reconnect to device in recovery (iBEC) mode\n");
get_ecid(client, &client->ecid);
client->flags |= FLAG_BOOT;
if (client->mode->index == MODE_RECOVERY) {
if (client->srnm == NULL) {
reterror(-9,"ERROR: could not retrieve device serial number. Can't continue.\n");
}
if (irecv_send_command(client->recovery->client, "bgcolor 0 255 0") != IRECV_E_SUCCESS) {
error("ERROR: Unable to set bgcolor\n");
return -1;
}
info("[WARNING] Setting bgcolor to green! If you don't see a green screen, then your device didn't boot iBEC correctly\n");
sleep(2); //show the user a green screen!
client->image4supported = true; //dirty hack to not require apticket
if (recovery_enter_restore(client, build_identity) < 0) {
reterror(-10,"ERROR: Unable to place device into restore mode\n");
}
client->image4supported = false;
recovery_client_free(client);
}
info("Cleaning up...\n");
error:
safeFree(client->sepfwdata);
safePlistFree(buildmanifest);
if (!result && !err) info("DONE\n");
return result ? abs(result) : err;
}
futurerestore::~futurerestore(){
normal_client_free(_client);
recovery_client_free(_client);

View file

@ -62,7 +62,7 @@ class futurerestore {
bool _enterPwnRecoveryRequested = false;
bool _rerestoreiOS9 = false;
//methods
void enterPwnRecovery(plist_t build_identity);
void enterPwnRecovery(plist_t build_identity, std::string bootargs = "");
public:
@ -105,6 +105,7 @@ public:
uint64_t getBasebandGoldCertIDFromDevice();
int doRestore(const char *ipsw);
int doJustBoot(const char *ipsw, std::string bootargs = "");
~futurerestore();

View file

@ -35,7 +35,8 @@ static struct option longopts[] = {
{ "latest-baseband", no_argument, NULL, '1' },
{ "no-baseband", no_argument, NULL, '2' },
#ifdef HAVE_LIBIPATCHER
{ "use-pwndfu", no_argument, NULL, '3' },
{ "use-pwndfu", no_argument, NULL, '3' },
{ "just-boot", optional_argument, NULL, '4' },
#endif
{ NULL, 0, NULL, 0 }
};
@ -94,6 +95,7 @@ int main(int argc, const char * argv[]) {
const char *basebandManifestPath = NULL;
const char *sepPath = NULL;
const char *sepManifestPath = NULL;
const char *bootargs = NULL;
vector<const char*> apticketPaths;
@ -142,6 +144,10 @@ int main(int argc, const char * argv[]) {
case '3': // long option: "no-baseband";
flags |= FLAG_IS_PWN_DFU;
break;
case '4': // long option: "just-boot";
bootargs = (optarg) ? optarg : "";
break;
break;
#endif
case 'd': // long option: "debug"; can be called as short option
idevicerestore_debug = 1;
@ -172,13 +178,20 @@ int main(int argc, const char * argv[]) {
if (!client.init()) reterror(-3,"can't init, no device found\n");
printf("futurerestore init done\n");
if (bootargs && !(flags & FLAG_IS_PWN_DFU)) {
reterror(-2,"--just-boot required --use-pwndfu\n");
}
try {
if (apticketPaths.size()) client.loadAPTickets(apticketPaths);
if (!((apticketPaths.size() && ipsw)
&& ((basebandPath && basebandManifestPath) || ((flags & FLAG_LATEST_BASEBAND) || (flags & FLAG_NO_BASEBAND)))
&& ((sepPath && sepManifestPath) || (flags & FLAG_LATEST_SEP) || client.is32bit()) )) {
if (!(
((apticketPaths.size() && ipsw)
&& ((basebandPath && basebandManifestPath) || ((flags & FLAG_LATEST_BASEBAND) || (flags & FLAG_NO_BASEBAND)))
&& ((sepPath && sepManifestPath) || (flags & FLAG_LATEST_SEP) || client.is32bit())
) || (ipsw && bootargs && (flags & FLAG_IS_PWN_DFU))
)) {
if (!(flags & FLAG_WAIT) || ipsw){
error("missing argument\n");
cmd_help();
@ -190,53 +203,55 @@ int main(int argc, const char * argv[]) {
}
goto error;
}
devVals.deviceModel = (char*)client.getDeviceModelNoCopy();
devVals.deviceBoard = (char*)client.getDeviceBoardNoCopy();
if (flags & FLAG_LATEST_SEP){
info("user specified to use latest signed sep\n");
client.loadLatestSep();
}else if (!client.is32bit()){
client.loadSep(sepPath);
client.setSepManifestPath(sepManifestPath);
}
versVals.basebandMode = kBasebandModeWithoutBaseband;
if (!client.is32bit() && !(isSepManifestSigned = isManifestSignedForDevice(client.sepManifestPath(), &devVals, &versVals))){
reterror(-3,"sep firmware isn't signed\n");
}
if (flags & FLAG_NO_BASEBAND){
printf("\nWARNING: user specified not to flash a baseband. This can make the restore fail if the device needs a baseband!\n");
printf("if you added this flag by mistake you can press CTRL-C now to cancel\n");
int c = 5;
printf("continuing restore in ");
while (c) {
printf("%d ",c--);
fflush(stdout);
sleep(1);
}
printf("\n");
if (bootargs){
}else{
if (flags & FLAG_LATEST_BASEBAND){
info("user specified to use latest signed baseband (WARNING, THIS CAN CAUSE A NON-WORKING RESTORE)\n");
client.loadLatestBaseband();
}else{
client.setBasebandPath(basebandPath);
client.setBasebandManifestPath(basebandManifestPath);
printf("Did set sep+baseband path and firmware\n");
devVals.deviceModel = (char*)client.getDeviceModelNoCopy();
devVals.deviceBoard = (char*)client.getDeviceBoardNoCopy();
if (flags & FLAG_LATEST_SEP){
info("user specified to use latest signed sep\n");
client.loadLatestSep();
}else if (!client.is32bit()){
client.loadSep(sepPath);
client.setSepManifestPath(sepManifestPath);
}
versVals.basebandMode = kBasebandModeOnlyBaseband;
if (!(devVals.bbgcid = client.getBasebandGoldCertIDFromDevice())){
printf("[WARNING] using tsschecker's fallback to get BasebandGoldCertID. This might result in invalid baseband signing status information\n");
versVals.basebandMode = kBasebandModeWithoutBaseband;
if (!client.is32bit() && !(isSepManifestSigned = isManifestSignedForDevice(client.sepManifestPath(), &devVals, &versVals))){
reterror(-3,"sep firmware isn't signed\n");
}
if (!(isBasebandSigned = isManifestSignedForDevice(client.basebandManifestPath(), &devVals, &versVals))) {
reterror(-3,"baseband firmware isn't signed\n");
if (flags & FLAG_NO_BASEBAND){
printf("\nWARNING: user specified not to flash a baseband. This can make the restore fail if the device needs a baseband!\n");
printf("if you added this flag by mistake you can press CTRL-C now to cancel\n");
int c = 5;
printf("continuing restore in ");
while (c) {
printf("%d ",c--);
fflush(stdout);
sleep(1);
}
printf("\n");
}else{
if (flags & FLAG_LATEST_BASEBAND){
info("user specified to use latest signed baseband (WARNING, THIS CAN CAUSE A NON-WORKING RESTORE)\n");
client.loadLatestBaseband();
}else{
client.setBasebandPath(basebandPath);
client.setBasebandManifestPath(basebandManifestPath);
printf("Did set sep+baseband path and firmware\n");
}
versVals.basebandMode = kBasebandModeOnlyBaseband;
if (!(devVals.bbgcid = client.getBasebandGoldCertIDFromDevice())){
printf("[WARNING] using tsschecker's fallback to get BasebandGoldCertID. This might result in invalid baseband signing status information\n");
}
if (!(isBasebandSigned = isManifestSignedForDevice(client.basebandManifestPath(), &devVals, &versVals))) {
reterror(-3,"baseband firmware isn't signed\n");
}
}
}
client.putDeviceIntoRecovery();
if (flags & FLAG_WAIT){
client.waitForNonce();
@ -248,7 +263,10 @@ int main(int argc, const char * argv[]) {
}
try {
res = client.doRestore(ipsw);
if (bootargs)
res = client.doJustBoot(ipsw,bootargs);
else
res = client.doRestore(ipsw);
} catch (int error) {
if (error == -20) error("maybe you forgot -w ?\n");
err = error;