mirror of
https://github.com/tihmstar/futurerestore.git
synced 2025-04-20 14:31:41 +00:00
Add experimental --no-ibss flag for checkm8 pwned
This commit is contained in:
parent
0d90285e08
commit
16807fd344
|
@ -64,6 +64,7 @@ Usage: `futurerestore [OPTIONS] iPSW`
|
|||
| ` -d ` | ` --debug ` | Show all code, use to save a log for debug testing |
|
||||
| ` -e ` | ` --exit-recovery ` | Exit recovery mode and quit |
|
||||
| | ` --use-pwndfu ` | Restoring devices with Odysseus method. Device needs to be in pwned DFU mode already |
|
||||
| | ` --no-ibss ` | Restoring devices with Odysseus method. For checkm8 devices general, bootrom needs to be patched already. |
|
||||
| | ` --just-boot "-v" ` | Tethered booting the device from pwned DFU mode. You can optionally set ` boot-args ` |
|
||||
| | ` --latest-sep ` | Use latest signed SEP instead of manually specifying one (may cause bad restore) |
|
||||
| ` -s ` | ` --sep PATH ` | Manually specify SEP to be flashed |
|
||||
|
|
|
@ -100,10 +100,13 @@ extern "C"{
|
|||
int dfu_send_iboot_stage1_components(struct idevicerestore_client_t* client, plist_t build_identity);
|
||||
int dfu_send_command(struct idevicerestore_client_t* client, const char* command);
|
||||
int dfu_send_component_and_command(struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* command);
|
||||
irecv_error_t irecv_send_command(irecv_client_t client, const char* command);
|
||||
int recovery_send_component_and_command(struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* command);
|
||||
int recovery_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component);
|
||||
};
|
||||
|
||||
#pragma mark futurerestore
|
||||
futurerestore::futurerestore(bool isUpdateInstall, bool isPwnDfu) : _isUpdateInstall(isUpdateInstall), _isPwnDfu(isPwnDfu){
|
||||
futurerestore::futurerestore(bool isUpdateInstall, bool isPwnDfu, bool noIBSS) : _isUpdateInstall(isUpdateInstall), _isPwnDfu(isPwnDfu), _noIBSS(noIBSS){
|
||||
_client = idevicerestore_client_new();
|
||||
if (_client == NULL) throw std::string("could not create idevicerestore client\n");
|
||||
|
||||
|
@ -460,7 +463,7 @@ void futurerestore::enterPwnRecovery(plist_t build_identity, string bootargs){
|
|||
#ifndef HAVE_LIBIPATCHER
|
||||
reterror("compiled without libipatcher");
|
||||
#else
|
||||
bootargs = "rd=md0 -restore -v";
|
||||
bootargs = "rd=md0 -restore -v serial=3 debug=0x14e keepsyms=1 amfi=0xff amfi_unrestrict_task_for_pid=1 amfi_allow_any_signature=1 amfi_get_out_of_my_way=1";
|
||||
int mode = 0;
|
||||
libipatcher::fw_key iBSSKeys;
|
||||
libipatcher::fw_key iBECKeys;
|
||||
|
@ -485,6 +488,13 @@ void futurerestore::enterPwnRecovery(plist_t build_identity, string bootargs){
|
|||
auto iBEC = getIPSWComponent(_client, build_identity, "iBEC");
|
||||
iBEC = move(libipatcher::patchiBEC((char*)iBEC.first, iBEC.second, iBECKeys, bootargs));
|
||||
|
||||
if (_client->image4supported) {
|
||||
/* if this is 64-bit, we need to back IM4P to IMG4
|
||||
also due to the nature of iBoot64Patchers sigpatches we need to stich a valid signed im4m to it (but nonce is ignored) */
|
||||
iBSS = move(libipatcher::packIM4PToIMG4(iBSS.first, iBSS.second, _im4ms[0].first, _im4ms[0].second));
|
||||
iBEC = move(libipatcher::packIM4PToIMG4(iBEC.first, iBEC.second, _im4ms[0].first, _im4ms[0].second));
|
||||
}
|
||||
|
||||
/* send iBSS */
|
||||
info("Sending %s (%lu bytes)...\n", "iBSS", iBSS.second);
|
||||
mutex_lock(&_client->device_event_mutex);
|
||||
|
@ -637,6 +647,216 @@ void futurerestore::enterPwnRecovery(plist_t build_identity, string bootargs){
|
|||
info("Booting 2nd iBEC, Waiting for device to reconnect...\n");
|
||||
mutex_lock(&_client->device_event_mutex);
|
||||
cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000);
|
||||
info("mode: %s\n", (_client->mode == &idevicerestore_modes[MODE_RECOVERY]) ? "RECOVERY" : (_client->mode == &idevicerestore_modes[MODE_DFU]) ? "DFU" : (_client->mode == &idevicerestore_modes[MODE_UNKNOWN]) ? "UNKNOWN" : (_client->mode == &idevicerestore_modes[MODE_WTF]) ? "WTF" : "ERR");
|
||||
retassure((_client->mode == &idevicerestore_modes[MODE_RECOVERY] || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not reconnect after sending hax-iBEC in pwn-iBEC mode");
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
|
||||
retassure(!recovery_client_new(_client), "failed to reconnect to recovery after ApNonce hax");
|
||||
|
||||
printf("APnonce post-hax:\n");
|
||||
get_ap_nonce(_client, &_client->nonce, &_client->nonce_size);
|
||||
assure(!irecv_send_command(_client->recovery->client, "bgcolor 255 255 0"));
|
||||
retassure(memcmp(_client->nonce, nonceelem.payload(), _client->nonce_size) == 0, "ApNonce from device doesn't match IM4M nonce after applying ApNonce hax. Aborting!");
|
||||
}else{
|
||||
printf("APNonce from device already matches IM4M nonce, no need for extra hax...\n");
|
||||
}
|
||||
retassure(!irecv_setenv(_client->recovery->client, "com.apple.System.boot-nonce", generator.c_str()),"failed to write generator to nvram");
|
||||
retassure(!irecv_saveenv(_client->recovery->client), "failed to save nvram");
|
||||
|
||||
sleep(2); //yes, I like displaying colored screens to the user and making him wait for no reason :P
|
||||
}
|
||||
|
||||
#endif //HAVE_LIBIPATCHER
|
||||
}
|
||||
void futurerestore::enterPwnRecovery2(plist_t build_identity, string bootargs){
|
||||
#ifndef HAVE_LIBIPATCHER
|
||||
reterror("compiled without libipatcher");
|
||||
#else
|
||||
bootargs = "rd=md0 -restore -v serial=3 debug=0x14e keepsyms=1 amfi=0xff amfi_unrestrict_task_for_pid=1 amfi_allow_any_signature=1 amfi_get_out_of_my_way=1";
|
||||
int mode = 0;
|
||||
libipatcher::fw_key iBSSKeys;
|
||||
libipatcher::fw_key iBECKeys;
|
||||
|
||||
getDeviceMode(false);
|
||||
mutex_lock(&_client->device_event_mutex);
|
||||
cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 1000);
|
||||
retassure(((_client->mode->index == MODE_DFU) || (mutex_unlock(&_client->device_event_mutex),0)), "Device isn't in DFU mode!");
|
||||
retassure(((dfu_client_new(_client) == IRECV_E_SUCCESS) || (mutex_unlock(&_client->device_event_mutex),0)), "Failed to connect to device in DFU Mode!");
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
|
||||
try {
|
||||
iBSSKeys = libipatcher::getFirmwareKey(_client->device->product_type, _client->build, "iBSS");
|
||||
iBECKeys = libipatcher::getFirmwareKey(_client->device->product_type, _client->build, "iBEC");
|
||||
} catch (tihmstar::exception &e) {
|
||||
reterror("getting keys failed with error: %d (%s). Are keys publicly available?",e.code(),e.what());
|
||||
}
|
||||
|
||||
auto iBSS = getIPSWComponent(_client, build_identity, "iBSS");
|
||||
iBSS = move(libipatcher::patchiBSS((char*)iBSS.first, iBSS.second, iBSSKeys));
|
||||
|
||||
auto iBEC = getIPSWComponent(_client, build_identity, "iBEC");
|
||||
iBEC = move(libipatcher::patchiBEC((char*)iBEC.first, iBEC.second, iBECKeys, bootargs));
|
||||
|
||||
if (_client->image4supported) {
|
||||
/* if this is 64-bit, we need to back IM4P to IMG4
|
||||
also due to the nature of iBoot64Patchers sigpatches we need to stich a valid signed im4m to it (but nonce is ignored) */
|
||||
iBSS = move(libipatcher::packIM4PToIMG4(iBSS.first, iBSS.second, _im4ms[0].first, _im4ms[0].second));
|
||||
iBEC = move(libipatcher::packIM4PToIMG4(iBEC.first, iBEC.second, _im4ms[0].first, _im4ms[0].second));
|
||||
}
|
||||
|
||||
/* send iBSS */
|
||||
info("Sending %s (%lu bytes)...\n", "iBSS", iBSS.second);
|
||||
mutex_lock(&_client->device_event_mutex);
|
||||
irecv_error_t err = irecv_send_buffer(_client->dfu->client, (unsigned char*)(char*)iBSS.first, (unsigned long)iBSS.second, 1);
|
||||
retassure(err == IRECV_E_SUCCESS,"ERROR: Unable to send %s component: %s\n", "iBSS", irecv_strerror(err));
|
||||
getDeviceMode(true);
|
||||
info("Booting iBSS, waiting for device to disconnect...\n");
|
||||
cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000);
|
||||
retassure(((_client->mode == &idevicerestore_modes[MODE_UNKNOWN]) || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not disconnect. Possibly invalid iBSS. Reset device and try again");
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
info("Booting iBSS, waiting for device to reconnect...\n");
|
||||
mutex_lock(&_client->device_event_mutex);
|
||||
cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000);
|
||||
retassure(((_client->mode->index == MODE_RECOVERY) || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not reconnect. Possibly invalid iBSS. Reset device and try again");
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
retassure(((recovery_client_new(_client) == IRECV_E_SUCCESS) || (mutex_unlock(&_client->device_event_mutex),0)), "Failed to connect to device in Recovery Mode!");
|
||||
mutex_lock(&_client->device_event_mutex);
|
||||
|
||||
if (_client->build_major > 8) {
|
||||
retassure(irecv_usb_set_configuration(_client->recovery->client, 1) >= 0, "ERROR: set configuration failed\n");
|
||||
if (_client->build_major >= 20) {
|
||||
// Without this empty policy file & its special signature, iBEC won't start.
|
||||
if (recovery_send_component_and_command(_client, build_identity, "Ap,LocalPolicy", "lpolrestore") < 0) {
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
error("ERROR: Unable to send Ap,LocalPolicy to device\n");
|
||||
irecv_close(_client->recovery->client);
|
||||
_client->recovery->client = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// if (dfu_send_iboot_stage1_components(_client, build_identity) < 0) {
|
||||
// mutex_unlock(&_client->device_event_mutex);
|
||||
// error("ERROR: Unable to send iBoot stage 1 components to device\n");
|
||||
// irecv_close(_client->recovery->client);
|
||||
// _client->recovery->client = NULL;
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (irecv_send_command(_client->recovery->client, "setenv auto-boot false") < 0) {
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
error("ERROR: Unable to send command to device\n");
|
||||
irecv_close(_client->recovery->client);
|
||||
_client->recovery->client = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (irecv_send_command(_client->recovery->client, "saveenv") < 0) {
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
error("ERROR: Unable to send command to device\n");
|
||||
irecv_close(_client->recovery->client);
|
||||
_client->recovery->client = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (irecv_send_command(_client->recovery->client, "setenvnp boot-args rd=md0 nand-enable-reformat=1 -progress -restore -v") < 0) {
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
error("ERROR: Unable to send command to device\n");
|
||||
irecv_close(_client->recovery->client);
|
||||
_client->recovery->client = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (recovery_send_component(_client, build_identity, "RestoreLogo") < 0) {
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
error("ERROR: Unable to send RestoreDCP to device\n");
|
||||
irecv_close(_client->recovery->client);
|
||||
_client->recovery->client = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (irecv_send_command(_client->recovery->client, "setpicture 4") < 0) {
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
error("ERROR: Unable to send command to device\n");
|
||||
irecv_close(_client->recovery->client);
|
||||
_client->recovery->client = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (irecv_send_command(_client->recovery->client, "bgcolor 0 0 0") < 0) {
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
error("ERROR: Unable to send command to device\n");
|
||||
irecv_close(_client->recovery->client);
|
||||
_client->recovery->client = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* send iBEC */
|
||||
info("Sending %s (%lu bytes)...\n", "iBEC", iBEC.second);
|
||||
err = irecv_send_buffer(_client->recovery->client, (unsigned char*)(char*)iBEC.first, (unsigned long)iBEC.second, 1);
|
||||
retassure(err == IRECV_E_SUCCESS,"ERROR: Unable to send %s component: %s\n", "iBEC", irecv_strerror(err));
|
||||
info("Booting iBEC, waiting for device to disconnect...\n");
|
||||
if(_client->mode->index == MODE_RECOVERY)
|
||||
retassure(((irecv_send_command(_client->recovery->client, "go") == IRECV_E_SUCCESS) || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not disconnect/reconnect. Possibly invalid iBEC. Reset device and try again\n");
|
||||
getDeviceMode(true);
|
||||
cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000);
|
||||
retassure(((_client->mode == &idevicerestore_modes[MODE_UNKNOWN]) || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not disconnect. Possibly invalid iBEC. Reset device and try again");
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
info("Booting iBEC, waiting for device to reconnect...\n");
|
||||
}
|
||||
mutex_lock(&_client->device_event_mutex);
|
||||
cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000);
|
||||
retassure(((_client->mode->index == MODE_RECOVERY) || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not reconnect. Possibly invalid iBEC. Reset device and try again");
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
retassure(((recovery_client_new(_client) == IRECV_E_SUCCESS) || (mutex_unlock(&_client->device_event_mutex),0)), "Failed to connect to device in Recovery Mode! Reset device and try again.");
|
||||
retassure((_client->mode->index == MODE_RECOVERY), "Failed to connect to device in Recovery Mode! Reset device and try again.");
|
||||
if (_client->build_major < 20) {
|
||||
irecv_usb_control_transfer(_client->recovery->client, 0x21, 1, 0, 0, 0, 0, 5000);
|
||||
}
|
||||
|
||||
if (_client->image4supported) {
|
||||
char *deviceGen = NULL;
|
||||
cleanup([&]{
|
||||
safeFree(deviceGen);
|
||||
});
|
||||
/* IMG4 requires to have a generator set for the device to successfully boot after restore
|
||||
set generator now and make sure the nonce is the one we are trying to restore */
|
||||
|
||||
assure(!irecv_send_command(_client->recovery->client, "bgcolor 255 0 0"));
|
||||
sleep(2); //yes, I like displaying colored screens to the user and making him wait for no reason :P
|
||||
|
||||
auto nonceelem = img4tool::getValFromIM4M({_im4ms[0].first,_im4ms[0].second}, 'BNCH');
|
||||
|
||||
printf("ApNonce pre-hax:\n");
|
||||
get_ap_nonce(_client, &_client->nonce, &_client->nonce_size);
|
||||
std::string generator = getGeneratorFromSHSH2(_client->tss);
|
||||
|
||||
if (memcmp(_client->nonce, nonceelem.payload(), _client->nonce_size) != 0) {
|
||||
printf("ApNonce from device doesn't match IM4M nonce, applying hax...\n");
|
||||
|
||||
assure(_client->tss);
|
||||
printf("Writing generator=%s to nvram!\n",generator.c_str());
|
||||
|
||||
retassure(!irecv_setenv(_client->recovery->client, "com.apple.System.boot-nonce", generator.c_str()),"failed to write generator to nvram");
|
||||
retassure(!irecv_saveenv(_client->recovery->client), "failed to save nvram");
|
||||
|
||||
/* send iBEC */
|
||||
info("Sending %s (%lu bytes)...\n", "iBEC", iBEC.second);
|
||||
mutex_lock(&_client->device_event_mutex);
|
||||
irecv_error_t err = irecv_send_buffer(_client->recovery->client, (unsigned char*)(char*)iBEC.first, (unsigned long)iBEC.second, 1);
|
||||
retassure(err == IRECV_E_SUCCESS,"ERROR: Unable to send %s component: %s\n", "iBEC", irecv_strerror(err));
|
||||
printf("waiting for device to reconnect...\n");
|
||||
retassure(!irecv_send_command(_client->recovery->client, "go"),"failed to re-launch iBEC after ApNonce hax");
|
||||
getDeviceMode(true);
|
||||
|
||||
info("Booting 2nd iBEC, Waiting for device to disconnect...\n");
|
||||
cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000);
|
||||
retassure((_client->mode == &idevicerestore_modes[MODE_UNKNOWN] || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not disconnect after sending hax-iBEC in pwn-iBEC mode");
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
|
||||
info("Booting 2nd iBEC, Waiting for device to reconnect...\n");
|
||||
mutex_lock(&_client->device_event_mutex);
|
||||
cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000);
|
||||
info("mode: %s\n", (_client->mode == &idevicerestore_modes[MODE_RECOVERY]) ? "RECOVERY" : (_client->mode == &idevicerestore_modes[MODE_DFU]) ? "DFU" : (_client->mode == &idevicerestore_modes[MODE_UNKNOWN]) ? "UNKNOWN" : (_client->mode == &idevicerestore_modes[MODE_WTF]) ? "WTF" : "ERR");
|
||||
retassure((_client->mode == &idevicerestore_modes[MODE_RECOVERY] || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not reconnect after sending hax-iBEC in pwn-iBEC mode");
|
||||
mutex_unlock(&_client->device_event_mutex);
|
||||
|
||||
|
@ -899,7 +1119,10 @@ void futurerestore::doRestore(const char *ipsw){
|
|||
//check for enterpwnrecovery, because we could be in DFU mode
|
||||
if (_enterPwnRecoveryRequested){
|
||||
retassure(getDeviceMode(true) == MODE_DFU, "unexpected device mode\n");
|
||||
enterPwnRecovery(build_identity);
|
||||
if(_noIBSS)
|
||||
enterPwnRecovery2(build_identity);
|
||||
else
|
||||
enterPwnRecovery(build_identity);
|
||||
}
|
||||
|
||||
// Get filesystem name from build identity
|
||||
|
|
|
@ -57,6 +57,7 @@ class futurerestore {
|
|||
int _foundnonce = -1;
|
||||
bool _isUpdateInstall = false;
|
||||
bool _isPwnDfu = false;
|
||||
bool _noIBSS = false;
|
||||
|
||||
char *_firmwareJson = NULL;
|
||||
jssytok_t *_firmwareTokens = NULL;;
|
||||
|
@ -80,9 +81,10 @@ class futurerestore {
|
|||
bool _rerestoreiOS9 = false;
|
||||
//methods
|
||||
void enterPwnRecovery(plist_t build_identity, std::string bootargs = "");
|
||||
void enterPwnRecovery2(plist_t build_identity, std::string bootargs = "");
|
||||
|
||||
public:
|
||||
futurerestore(bool isUpdateInstall = false, bool isPwnDfu = false);
|
||||
futurerestore(bool isUpdateInstall = false, bool isPwnDfu = false, bool noIBSS = false);
|
||||
bool init();
|
||||
int getDeviceMode(bool reRequest);
|
||||
uint64_t getDeviceEcid();
|
||||
|
|
|
@ -49,6 +49,7 @@ static struct option longopts[] = {
|
|||
#ifdef HAVE_LIBIPATCHER
|
||||
{ "use-pwndfu", no_argument, NULL, '3' },
|
||||
{ "just-boot", optional_argument, NULL, '4' },
|
||||
{ "no-ibss", no_argument, NULL, '5' },
|
||||
#endif
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
@ -59,6 +60,7 @@ static struct option longopts[] = {
|
|||
#define FLAG_LATEST_BASEBAND 1 << 3
|
||||
#define FLAG_NO_BASEBAND 1 << 4
|
||||
#define FLAG_IS_PWN_DFU 1 << 5
|
||||
#define FLAG_NO_IBSS 1 << 6
|
||||
|
||||
void cmd_help(){
|
||||
printf("Usage: futurerestore [OPTIONS] iPSW\n");
|
||||
|
@ -75,6 +77,7 @@ void cmd_help(){
|
|||
printf("\nOptions for downgrading with Odysseus:\n");
|
||||
printf(" --use-pwndfu\t\tRestoring devices with Odysseus method. Device needs to be in pwned DFU mode already\n");
|
||||
printf(" --just-boot=\"-v\"\t\tTethered booting the device from pwned DFU mode. You can optionally set boot-args\n");
|
||||
printf(" --no-ibss\t\t\tRestoring devices with Odysseus method. For checkm8 devices general, bootrom needs to be patched already.\n");
|
||||
#endif
|
||||
|
||||
printf("\nOptions for SEP:\n");
|
||||
|
@ -174,6 +177,9 @@ int main_r(int argc, const char * argv[]) {
|
|||
case '4': // long option: "just-boot";
|
||||
bootargs = (optarg) ? optarg : "";
|
||||
break;
|
||||
case '5': // long option: "no-ibss";
|
||||
flags |= FLAG_NO_IBSS;
|
||||
break;
|
||||
break;
|
||||
#endif
|
||||
case 'e': // long option: "exit-recovery"; can be called as short option
|
||||
|
@ -207,11 +213,13 @@ int main_r(int argc, const char * argv[]) {
|
|||
return -5;
|
||||
}
|
||||
|
||||
futurerestore client(flags & FLAG_UPDATE, flags & FLAG_IS_PWN_DFU);
|
||||
futurerestore client(flags & FLAG_UPDATE, flags & FLAG_IS_PWN_DFU, flags & FLAG_NO_IBSS);
|
||||
retassure(client.init(),"can't init, no device found\n");
|
||||
|
||||
printf("futurerestore init done\n");
|
||||
retassure(!bootargs || (flags & FLAG_IS_PWN_DFU),"--just-boot requires --use-pwndfu\n");
|
||||
if(flags & FLAG_NO_IBSS)
|
||||
retassure((flags & FLAG_IS_PWN_DFU),"--no-ibss requires --use-pwndfu\n");
|
||||
|
||||
if (exitRecovery) {
|
||||
client.exitRecovery();
|
||||
|
|
Loading…
Reference in a new issue