Ejemplo n.º 1
0
Archivo: main.c Proyecto: 1butler1/xpwn
int main(int argc, char* argv[]) {
	printf("---------------------------PLEASE READ THIS---------------------------\n");
	printf("Please make certain that all iTunes related processes are not running\n");
	printf("at this time (use Task Manager, etc. to end them). Your iPhone/iPod\n");
	printf("must be placed into DFU mode AFTER iTunes had been turned off. This\n");
	printf(" will allow me to talk to it without iTunes getting in beforehand.\n");
	printf("USB Product ID of iPhone ought to be 0x1222\n");
	printf("---------------------------PLEASE READ THIS---------------------------\n");

	if(argc < 3) {
		printf("usage: %s <custom.ipsw> <n82ap|m68ap|n45ap>\n", argv[0]);
		printf("advanced usage: %s -f <file>\n", argv[0]);
		printf("n82ap = 3G iPhone, m68ap = First-generation iPhone, n45ap = iPod touch\n");
		return 0;
	}

	if(strcmp(argv[1], "-f") == 0) {
		download(createAbstractFileFromFile(fopen(argv[2], "rb")), 2048, 1);
		return 0;
	}

	char ibssName[100];
	sprintf(ibssName, "Firmware/dfu/iBSS.%s.RELEASE.dfu", argv[2]);

	OutputState* data = NULL;
	loadZipFile(argv[1], &data, "Firmware/dfu/WTF.s5l8900xall.RELEASE.dfu");
	loadZipFile(argv[1], &data, ibssName);

	download(getFileFromOutputState(&data, "Firmware/dfu/WTF.s5l8900xall.RELEASE.dfu"), 2048, 1);
	sleep(5);
	download(getFileFromOutputState(&data, ibssName), 2048, 1);

	releaseOutput(&data);

	return 0;
}
Ejemplo n.º 2
0
Archivo: main.c Proyecto: OPK/xpwn
int main(int argc, char* argv[]) {
    init_libxpwn();

    Dictionary* info;
    Dictionary* firmwarePatches;
    Dictionary* patchDict;
    ArrayValue* patchArray;

    void* buffer;

    StringValue* actionValue;
    StringValue* pathValue;

    StringValue* fileValue;

    StringValue* patchValue;
    char* patchPath;

    char* rootFSPathInIPSW;
    io_func* rootFS;
    Volume* rootVolume;
    size_t rootSize;
    size_t preferredRootSize = 0;
    size_t minimumRootSize = 0;

    char* ramdiskFSPathInIPSW;
    unsigned int ramdiskKey[16];
    unsigned int ramdiskIV[16];
    unsigned int* pRamdiskKey = NULL;
    unsigned int* pRamdiskIV = NULL;
    io_func* ramdiskFS;
    Volume* ramdiskVolume;

    char* updateRamdiskFSPathInIPSW = NULL;

    int i;

    OutputState* outputState;

    char* bundlePath;
    char* bundleRoot = "FirmwareBundles/";

    int mergePaths;
    char* outputIPSW;

    void* imageBuffer;
    size_t imageSize;

    AbstractFile* bootloader39 = NULL;
    AbstractFile* bootloader46 = NULL;
    AbstractFile* applelogo = NULL;
    AbstractFile* recoverymode = NULL;

    char noWipe = FALSE;

    char unlockBaseband = FALSE;
    char selfDestruct = FALSE;
    char use39 = FALSE;
    char use46 = FALSE;
    char doBootNeuter = FALSE;
    char updateBB = FALSE;
    char useMemory = FALSE;

    unsigned int key[16];
    unsigned int iv[16];

    unsigned int* pKey = NULL;
    unsigned int* pIV = NULL;

    if(argc < 3) {
        XLOG(0, "usage %s <input.ipsw> <target.ipsw> [-b <bootimage.png>] [-r <recoveryimage.png>] [-s <system partition size>] [-memory] [-bbupdate] [-nowipe] [-e \"<action to exclude>\"] [[-unlock] [-use39] [-use46] [-cleanup] -3 <bootloader 3.9 file> -4 <bootloader 4.6 file>] <package1.tar> <package2.tar>...\n", argv[0]);
        return 0;
    }

    outputIPSW = argv[2];

    int* toRemove = NULL;
    int numToRemove = 0;

    for(i = 3; i < argc; i++) {
        if(argv[i][0] != '-') {
            break;
        }

        if(strcmp(argv[i], "-memory") == 0) {
            useMemory = TRUE;
            continue;
        }

        if(strcmp(argv[i], "-s") == 0) {
            int size;
            sscanf(argv[i + 1], "%d", &size);
            preferredRootSize = size;
            i++;
            continue;
        }

        if(strcmp(argv[i], "-nowipe") == 0) {
            noWipe = TRUE;
            continue;
        }

        if(strcmp(argv[i], "-bbupdate") == 0) {
            updateBB = TRUE;
            continue;
        }

        if(strcmp(argv[i], "-e") == 0) {
            numToRemove++;
            toRemove = realloc(toRemove, numToRemove * sizeof(int));
            toRemove[numToRemove - 1] = i + 1;
            i++;
            continue;
        }

        if(strcmp(argv[i], "-unlock") == 0) {
            unlockBaseband = TRUE;
            continue;
        }

        if(strcmp(argv[i], "-cleanup") == 0) {
            selfDestruct = TRUE;
            continue;
        }

        if(strcmp(argv[i], "-use39") == 0) {
            if(use46) {
                XLOG(0, "error: select only one of -use39 and -use46\n");
                exit(1);
            }
            use39 = TRUE;
            continue;
        }

        if(strcmp(argv[i], "-use46") == 0) {
            if(use39) {
                XLOG(0, "error: select only one of -use39 and -use46\n");
                exit(1);
            }
            use46 = TRUE;
            continue;
        }

        if(strcmp(argv[i], "-b") == 0) {
            applelogo = createAbstractFileFromFile(fopen(argv[i + 1], "rb"));
            if(!applelogo) {
                XLOG(0, "cannot open %s\n", argv[i + 1]);
                exit(1);
            }
            i++;
            continue;
        }

        if(strcmp(argv[i], "-r") == 0) {
            recoverymode = createAbstractFileFromFile(fopen(argv[i + 1], "rb"));
            if(!recoverymode) {
                XLOG(0, "cannot open %s\n", argv[i + 1]);
                exit(1);
            }
            i++;
            continue;
        }

        if(strcmp(argv[i], "-3") == 0) {
            bootloader39 = createAbstractFileFromFile(fopen(argv[i + 1], "rb"));
            if(!bootloader39) {
                XLOG(0, "cannot open %s\n", argv[i + 1]);
                exit(1);
            }
            i++;
            continue;
        }

        if(strcmp(argv[i], "-4") == 0) {
            bootloader46 = createAbstractFileFromFile(fopen(argv[i + 1], "rb"));
            if(!bootloader46) {
                XLOG(0, "cannot open %s\n", argv[i + 1]);
                exit(1);
            }
            i++;
            continue;
        }
    }

    mergePaths = i;

    if(use39 || use46 || unlockBaseband || selfDestruct || bootloader39 || bootloader46) {
        if(!(bootloader39) || !(bootloader46)) {
            XLOG(0, "error: you must specify both bootloader files.\n");
            exit(1);
        } else {
            doBootNeuter = TRUE;
        }
    }

    info = parseIPSW2(argv[1], bundleRoot, &bundlePath, &outputState, useMemory);
    if(info == NULL) {
        XLOG(0, "error: Could not load IPSW\n");
        exit(1);
    }

    firmwarePatches = (Dictionary*)getValueByKey(info, "FilesystemPatches");

    int j;
    for(j = 0; j < numToRemove; j++) {
        removeKey(firmwarePatches, argv[toRemove[j]]);
    }
    free(toRemove);

    firmwarePatches = (Dictionary*)getValueByKey(info, "FirmwarePatches");
    patchDict = (Dictionary*) firmwarePatches->values;
    while(patchDict != NULL) {
        fileValue = (StringValue*) getValueByKey(patchDict, "File");

        StringValue* keyValue = (StringValue*) getValueByKey(patchDict, "Key");
        StringValue* ivValue = (StringValue*) getValueByKey(patchDict, "IV");
        pKey = NULL;
        pIV = NULL;

        if(keyValue) {
            sscanf(keyValue->value, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
                   &key[0], &key[1], &key[2], &key[3], &key[4], &key[5], &key[6], &key[7], &key[8],
                   &key[9], &key[10], &key[11], &key[12], &key[13], &key[14], &key[15]);

            pKey = key;
        }

        if(ivValue) {
            sscanf(ivValue->value, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
                   &iv[0], &iv[1], &iv[2], &iv[3], &iv[4], &iv[5], &iv[6], &iv[7], &iv[8],
                   &iv[9], &iv[10], &iv[11], &iv[12], &iv[13], &iv[14], &iv[15]);
            pIV = iv;
        }

        if(strcmp(patchDict->dValue.key, "Restore Ramdisk") == 0) {
            ramdiskFSPathInIPSW = fileValue->value;
            if(pKey) {
                memcpy(ramdiskKey, key, sizeof(key));
                memcpy(ramdiskIV, iv, sizeof(iv));
                pRamdiskKey = ramdiskKey;
                pRamdiskIV = ramdiskIV;
            } else {
                pRamdiskKey = NULL;
                pRamdiskIV = NULL;
            }
        }

        if(strcmp(patchDict->dValue.key, "Update Ramdisk") == 0) {
            updateRamdiskFSPathInIPSW = fileValue->value;
        }

        patchValue = (StringValue*) getValueByKey(patchDict, "Patch2");
        if(patchValue) {
            if(noWipe) {
                XLOG(0, "%s: ", patchDict->dValue.key);
                fflush(stdout);
                doPatch(patchValue, fileValue, bundlePath, &outputState, pKey, pIV, useMemory);
                patchDict = (Dictionary*) patchDict->dValue.next;
                continue; /* skip over the normal Patch */
            }
        }

        patchValue = (StringValue*) getValueByKey(patchDict, "Patch");
        if(patchValue) {
            XLOG(0, "%s: ", patchDict->dValue.key);
            fflush(stdout);
            doPatch(patchValue, fileValue, bundlePath, &outputState, pKey, pIV, useMemory);
        }

        if(strcmp(patchDict->dValue.key, "AppleLogo") == 0 && applelogo) {
            XLOG(0, "replacing %s\n", fileValue->value);
            fflush(stdout);
            ASSERT((imageBuffer = replaceBootImage(getFileFromOutputState(&outputState, fileValue->value), pKey, pIV, applelogo, &imageSize)) != NULL, "failed to use new image");
            addToOutput(&outputState, fileValue->value, imageBuffer, imageSize);
        }

        if(strcmp(patchDict->dValue.key, "RecoveryMode") == 0 && recoverymode) {
            XLOG(0, "replacing %s\n", fileValue->value);
            fflush(stdout);
            ASSERT((imageBuffer = replaceBootImage(getFileFromOutputState(&outputState, fileValue->value), pKey, pIV, recoverymode, &imageSize)) != NULL, "failed to use new image");
            addToOutput(&outputState, fileValue->value, imageBuffer, imageSize);
        }

        patchDict = (Dictionary*) patchDict->dValue.next;
    }

    fileValue = (StringValue*) getValueByKey(info, "RootFilesystem");
    rootFSPathInIPSW = fileValue->value;

    size_t defaultRootSize = ((IntegerValue*) getValueByKey(info, "RootFilesystemSize"))->value;
    minimumRootSize = defaultRootSize * 1000 * 1000;
    minimumRootSize -= minimumRootSize % 512;

    if(preferredRootSize == 0) {
        preferredRootSize = defaultRootSize;
    }

    rootSize =  preferredRootSize * 1000 * 1000;
    rootSize -= rootSize % 512;

    if(useMemory) {
        buffer = malloc(rootSize);
    } else {
        buffer = NULL;
    }

    if(buffer == NULL) {
        XLOG(2, "using filesystem backed temporary storage\n");
    }

    extractDmg(
        createAbstractFileFromFileVault(getFileFromOutputState(&outputState, rootFSPathInIPSW), ((StringValue*)getValueByKey(info, "RootFilesystemKey"))->value),
        openRoot((void**)&buffer, &rootSize), -1);


    rootFS = IOFuncFromAbstractFile(openRoot((void**)&buffer, &rootSize));
    rootVolume = openVolume(rootFS);
    XLOG(0, "Growing root to minimum: %ld\n", (long) defaultRootSize);
    fflush(stdout);
    grow_hfs(rootVolume, minimumRootSize);
    if(rootSize > minimumRootSize) {
        XLOG(0, "Growing root: %ld\n", (long) preferredRootSize);
        fflush(stdout);
        grow_hfs(rootVolume, rootSize);
    }

    firmwarePatches = (Dictionary*)getValueByKey(info, "FilesystemPatches");
    patchArray = (ArrayValue*) firmwarePatches->values;
    while(patchArray != NULL) {
        for(i = 0; i < patchArray->size; i++) {
            patchDict = (Dictionary*) patchArray->values[i];
            fileValue = (StringValue*) getValueByKey(patchDict, "File");

            actionValue = (StringValue*) getValueByKey(patchDict, "Action");
            if(strcmp(actionValue->value, "ReplaceKernel") == 0) {
                pathValue = (StringValue*) getValueByKey(patchDict, "Path");
                XLOG(0, "replacing kernel... %s -> %s\n", fileValue->value, pathValue->value);
                fflush(stdout);
                add_hfs(rootVolume, getFileFromOutputState(&outputState, fileValue->value), pathValue->value);
            }
            if(strcmp(actionValue->value, "Patch") == 0) {
                patchValue = (StringValue*) getValueByKey(patchDict, "Patch");
                patchPath = (char*) malloc(sizeof(char) * (strlen(bundlePath) + strlen(patchValue->value) + 2));
                strcpy(patchPath, bundlePath);
                strcat(patchPath, "/");
                strcat(patchPath, patchValue->value);

                XLOG(0, "patching %s (%s)... ", fileValue->value, patchPath);
                doPatchInPlace(rootVolume, fileValue->value, patchPath);
                free(patchPath);
            }
        }

        patchArray = (ArrayValue*) patchArray->dValue.next;
    }

    for(; mergePaths < argc; mergePaths++) {
        XLOG(0, "merging %s\n", argv[mergePaths]);
        AbstractFile* tarFile = createAbstractFileFromFile(fopen(argv[mergePaths], "rb"));
        if(tarFile == NULL) {
            XLOG(1, "cannot find %s, make sure your slashes are in the right direction\n", argv[mergePaths]);
            releaseOutput(&outputState);
            closeRoot(buffer);
            exit(0);
        }
        hfs_untar(rootVolume, tarFile);
        tarFile->close(tarFile);
    }

    if(pRamdiskKey) {
        ramdiskFS = IOFuncFromAbstractFile(openAbstractFile2(getFileFromOutputStateForOverwrite(&outputState, ramdiskFSPathInIPSW), pRamdiskKey, pRamdiskIV));
    } else {
        XLOG(0, "unencrypted ramdisk\n");
        ramdiskFS = IOFuncFromAbstractFile(openAbstractFile(getFileFromOutputStateForOverwrite(&outputState, ramdiskFSPathInIPSW)));
    }
    ramdiskVolume = openVolume(ramdiskFS);
    XLOG(0, "growing ramdisk: %d -> %d\n", ramdiskVolume->volumeHeader->totalBlocks * ramdiskVolume->volumeHeader->blockSize, (ramdiskVolume->volumeHeader->totalBlocks + 4) * ramdiskVolume->volumeHeader->blockSize);
    grow_hfs(ramdiskVolume, (ramdiskVolume->volumeHeader->totalBlocks + 4) * ramdiskVolume->volumeHeader->blockSize);

    if(doBootNeuter) {
        firmwarePatches = (Dictionary*)getValueByKey(info, "BasebandPatches");
        if(firmwarePatches != NULL) {
            patchDict = (Dictionary*) firmwarePatches->values;
            while(patchDict != NULL) {
                pathValue = (StringValue*) getValueByKey(patchDict, "Path");

                fileValue = (StringValue*) getValueByKey(patchDict, "File");
                if(fileValue) {
                    XLOG(0, "copying %s -> %s... ", fileValue->value, pathValue->value);
                    fflush(stdout);
                    if(copyAcrossVolumes(ramdiskVolume, rootVolume, fileValue->value, pathValue->value)) {
                        patchValue = (StringValue*) getValueByKey(patchDict, "Patch");
                        if(patchValue) {
                            patchPath = malloc(sizeof(char) * (strlen(bundlePath) + strlen(patchValue->value) + 2));
                            strcpy(patchPath, bundlePath);
                            strcat(patchPath, "/");
                            strcat(patchPath, patchValue->value);
                            XLOG(0, "patching %s (%s)... ", pathValue->value, patchPath);
                            fflush(stdout);
                            doPatchInPlace(rootVolume, pathValue->value, patchPath);
                            free(patchPath);
                        }
                    }
                }

                if(strcmp(patchDict->dValue.key, "Bootloader 3.9") == 0 && bootloader39 != NULL) {
                    add_hfs(rootVolume, bootloader39, pathValue->value);
                }

                if(strcmp(patchDict->dValue.key, "Bootloader 4.6") == 0 && bootloader46 != NULL) {
                    add_hfs(rootVolume, bootloader46, pathValue->value);
                }

                patchDict = (Dictionary*) patchDict->dValue.next;
            }
        }

        fixupBootNeuterArgs(rootVolume, unlockBaseband, selfDestruct, use39, use46);
    }

    createRestoreOptions(ramdiskVolume, preferredRootSize, updateBB);
    closeVolume(ramdiskVolume);
    CLOSE(ramdiskFS);

    if(updateRamdiskFSPathInIPSW)
        removeFileFromOutputState(&outputState, updateRamdiskFSPathInIPSW);

    closeVolume(rootVolume);
    CLOSE(rootFS);

    buildDmg(openRoot((void**)&buffer, &rootSize), getFileFromOutputStateForReplace(&outputState, rootFSPathInIPSW));

    closeRoot(buffer);

    writeOutput(&outputState, outputIPSW);

    releaseDictionary(info);

    free(bundlePath);

    return 0;
}
Ejemplo n.º 3
0
int doDecrypt(StringValue* decryptValue, StringValue* fileValue, const char* bundlePath, OutputState** state, unsigned int* key, unsigned int* iv, int useMemory) {
	size_t bufferSize;
	void* buffer;
	
	AbstractFile* file;
	AbstractFile* out;
	AbstractFile* outRaw;

	char* tmpFileName;

	if(useMemory) {
		bufferSize = 0;
		buffer = malloc(1);
		outRaw = createAbstractFileFromMemoryFile((void**)&buffer, &bufferSize);
	} else {
		tmpFileName = createTempFile();
		outRaw = createAbstractFileFromFile(fopen(tmpFileName, "wb"));
	}

	out = duplicateAbstractFile(getFileFromOutputState(state, fileValue->value), outRaw);
	file = openAbstractFile3(getFileFromOutputState(state, fileValue->value), key, iv, 0);
	
	if(!file || !out) {
		XLOG(0, "file error\n");
		exit(0);
	}

	char *buf = malloc(1024 * 1024);
	off_t inDataSize = file->getLength(file);
	while (inDataSize > 0) {
		off_t avail, chunk = 1024 * 1024;
		if (chunk > inDataSize) {
			chunk = inDataSize;
		}
		if (chunk < 0) {
			XLOG(0, "decrypt failed\n");
			exit(0);
		}
		avail = file->read(file, buf, chunk);
		out->write(out, buf, avail);
		if (avail < chunk) {
			break;
		}
		inDataSize -= chunk;
	}
	out->close(out);
	file->close(file);
	free(buf);

	XLOG(0, "writing... "); fflush(stdout);
	
	if (decryptValue) {
		fileValue = decryptValue;
	}
	if(useMemory) {
		addToOutput(state, fileValue->value, buffer, bufferSize);
	} else {
		outRaw = createAbstractFileFromFile(fopen(tmpFileName, "rb"));
		size_t length = outRaw->getLength(outRaw);
		outRaw->close(outRaw);
		addToOutput2(state, fileValue->value, NULL, length, tmpFileName);
	}

	XLOG(0, "success\n"); fflush(stdout);

	return 0;
}
Ejemplo n.º 4
0
int doPatch(StringValue* patchValue, StringValue* fileValue, const char* bundlePath, OutputState** state, unsigned int* key, unsigned int* iv, int useMemory, int isPlain) {
	char* patchPath;
	size_t bufferSize;
	void* buffer;
	
	AbstractFile* patchFile;
	AbstractFile* file;
	AbstractFile* out;
	AbstractFile* outRaw;

	char* tmpFileName;

	if(useMemory) {
		bufferSize = 0;
		buffer = malloc(1);
		outRaw = createAbstractFileFromMemoryFile((void**)&buffer, &bufferSize);
	} else {
		tmpFileName = createTempFile();
		outRaw = createAbstractFileFromFile(fopen(tmpFileName, "wb"));
	}
			
	patchPath = malloc(sizeof(char) * (strlen(bundlePath) + strlen(patchValue->value) + 2));
	strcpy(patchPath, bundlePath);
	strcat(patchPath, "/");
	strcat(patchPath, patchValue->value);
	
	XLOG(0, "%s (%s)... ", fileValue->value, patchPath); fflush(stdout);
	
	patchFile = createAbstractFileFromFile(fopen(patchPath, "rb"));

	if (isPlain) {
		out = outRaw;
		file = getFileFromOutputState(state, fileValue->value);
	} else {
		if(key != NULL) {
			XLOG(0, "encrypted input... ");
			out = duplicateAbstractFile2(getFileFromOutputState(state, fileValue->value), outRaw, key, iv, NULL);
		} else {
			out = duplicateAbstractFile(getFileFromOutputState(state, fileValue->value), outRaw);
		}

		if(key != NULL) {
			XLOG(0, "encrypted output... ");
			file = openAbstractFile2(getFileFromOutputState(state, fileValue->value), key, iv);
		} else {
			file = openAbstractFile(getFileFromOutputState(state, fileValue->value));
		}
	}
	
	if(!patchFile || !file || !out) {
		XLOG(0, "file error\n");
		exit(0);
	}

	if(patch(file, out, patchFile) != 0) {
		XLOG(0, "patch failed\n");
		exit(0);
	}

	if(strstr(fileValue->value, "WTF.s5l8900xall.RELEASE")) {
		XLOG(0, "Exploiting 8900 vulnerability... ;)\n");
		AbstractFile* exploited;
		if(useMemory) {
			exploited = createAbstractFileFrom8900(createAbstractFileFromMemoryFile((void**)&buffer, &bufferSize));
		} else {
			exploited = createAbstractFileFrom8900(createAbstractFileFromFile(fopen(tmpFileName, "r+b")));
		}
		exploit8900(exploited);
		exploited->close(exploited);
	}
	
	XLOG(0, "writing... "); fflush(stdout);
	
	if(useMemory) {
		addToOutput(state, fileValue->value, buffer, bufferSize);
	} else {
		outRaw = createAbstractFileFromFile(fopen(tmpFileName, "rb"));
		size_t length = outRaw->getLength(outRaw);
		outRaw->close(outRaw);
		addToOutput2(state, fileValue->value, NULL, length, tmpFileName);
	}

	XLOG(0, "success\n"); fflush(stdout);

	free(patchPath);

	return 0;
}
Ejemplo n.º 5
0
int main(int argc, char* argv[])
{
	struct stat st;

	init_libxpwn(&argc, argv);
	libxpwn_log(logCB);
	libxpwn_loglevel(2);

	printf("---------------------------PLEASE READ THIS---------------------------\n");
	printf("Please make certain that all iTunes related processes are not running\n");
	printf("at this time (use Task Manager, etc. to end them).\n");
	printf("---------------------------PLEASE READ THIS---------------------------\n\n\n");

	if(argc < 3) {
		printf("usage: %s <custom.ipsw> <n82ap|m68ap|n45ap> [loglevel]\n", argv[0]);
		printf("n82ap = 3G iPhone, m68ap = First-generation iPhone, n45ap = iPod touch\n");
		return 0;
	}

	if(argc >= 4) {
		int logLevel;
		sscanf(argv[3], "%d", &logLevel);
		libxpwn_loglevel(logLevel);
	}

	if(stat("restore.img3", &st) < 0) {
		fprintf(stderr, "missing restore.img3\n");
		return 1;
	}

	Stage = 0;
	Status = Disconnected;

	char ibssName[100];
	char wtfName[100];
	sprintf(ibssName, "Firmware/dfu/iBSS.%s.RELEASE.dfu", argv[2]);
	sprintf(wtfName, "Firmware/dfu/WTF.%s.RELEASE.dfu", argv[2]);

	data = NULL;
	loadZipFile(argv[1], &data, "Firmware/dfu/WTF.s5l8900xall.RELEASE.dfu");
	loadZipFile(argv[1], &data, ibssName);
	loadZipFile(argv[1], &data, wtfName);
	loadZipFile(argv[1], &data, "Restore.plist");

	AbstractFile* xallFile = getFileFromOutputState(&data, "Firmware/dfu/WTF.s5l8900xall.RELEASE.dfu");
	AbstractFile* wtfFile = getFileFromOutputState(&data, wtfName);
	AbstractFile* ibssFile = getFileFromOutputState(&data, ibssName);
	AbstractFile* restoreFile = getFileFromOutputState(&data, "Restore.plist");

	GetTempPath(MAX_PATH, tmpFilePath);

	strcat(tmpFilePath, "/restore");
	if(stat(tmpFilePath, &st) < 0) {
		mkdir(tmpFilePath, 0755);
	}

	strcpy(tmpFirmwarePath, tmpFilePath);
	strcat(tmpFirmwarePath, "/Firmware");
	if(stat(tmpFirmwarePath, &st) < 0) {
		mkdir(tmpFirmwarePath, 0755);
	}

	strcpy(tmpDFUPath, tmpFirmwarePath);
	strcat(tmpDFUPath, "/dfu");
	if(stat(tmpDFUPath, &st) < 0) {
		mkdir(tmpDFUPath, 0755);
	}

	strcpy(tmpXALLPath, tmpFilePath);
	strcat(tmpXALLPath, "/");
	strcat(tmpXALLPath, "Firmware/dfu/WTF.s5l8900xall.RELEASE.dfu");

	strcpy(tmpWTFPath, tmpFilePath);
	strcat(tmpWTFPath, "/");
	strcat(tmpWTFPath, wtfName);

	strcpy(tmpIBSSPath, tmpFilePath);
	strcat(tmpIBSSPath, "/");
	strcat(tmpIBSSPath, ibssName);

	strcpy(tmpRestorePath, tmpFilePath);
	strcat(tmpRestorePath, "/");
	strcat(tmpRestorePath, "Restore.plist");

	FILE* file;
	void* buffer;
	size_t length;

	length = xallFile->getLength(xallFile);
	buffer = malloc(length);
	xallFile->read(xallFile, buffer, length);
       	file = fopen(tmpXALLPath, "wb");
	fwrite(buffer, 1, length, file);
	fclose(file);
	free(buffer);
	xallFile->close(xallFile);

	length = wtfFile->getLength(wtfFile);
	buffer = malloc(length);
	wtfFile->read(wtfFile, buffer, length);
       	file = fopen(tmpWTFPath, "wb");
	fwrite(buffer, 1, length, file);
	fclose(file);
	free(buffer);
	wtfFile->close(wtfFile);

	length = ibssFile->getLength(ibssFile);
	buffer = malloc(length);
	ibssFile->read(ibssFile, buffer, length);
       	file = fopen(tmpIBSSPath, "wb");
	fwrite(buffer, 1, length, file);
	fclose(file);
	free(buffer);
	ibssFile->close(ibssFile);

	extractedIPSWPath = argv[1];
	length = restoreFile->getLength(restoreFile);
	buffer = malloc(length);
	restoreFile->read(restoreFile, buffer, length);
       	file = fopen(tmpRestorePath, "wb");
	fwrite(buffer, 1, length, file);
	fclose(file);
	free(buffer);
	restoreFile->close(restoreFile);

	extractedIPSWPath = tmpFilePath;
	bootImagePath = "restore.img3";

	fprintf(stdout, "\nGetting iPhone/iPod status...\n");
	fflush(stdout);

	if(LoadWindowsDLL() < 0) {
		printf("Failed to load iTunes Mobile Device driver!\n");
		cleanup_and_exit();
	}
	
	mach_error_t ret;
	struct am_device_notification *notif; 
	
	ret = AMDeviceNotificationSubscribe(notification, 0, 0, 0, &notif);
	if(ret < 0) {
		printf("Failed to subscribe for device notifications!\n");
		cleanup_and_exit();
	}
	
	ret = AMRestoreRegisterForDeviceNotifications(
						dfu_connect_callback,
						recovery_connect_callback,
						dfu_disconnect_callback,
						recovery_disconnect_callback,
						0,
						NULL);
						
	if(ret < 0) {
		printf("Failed to subscribe for device restore notifications!\n");
		cleanup_and_exit();
	}


	sleep(2);

	char responseBuffer[10];
	int countdown;

	if(Status == Disconnected) {
connectDevice:
		fprintf(stdout, "Is your iPhone/iPod connected to your computer via USB?\n");
		fprintf(stdout, "Please answer (y/n): ");
		fflush(stdout);
		fgets(responseBuffer, 10, stdin);
		if(responseBuffer[0] == 'y' || responseBuffer[0] == 'Y') {
			goto isPoweringOn;
		} else if(responseBuffer[0] == 'n' || responseBuffer[0] == 'N') {
			fprintf(stdout, "Please connect your iPhone/iPod to your computer\n");
			fprintf(stdout, "Press enter when you have connected your iPhone/iPod... ");
			fflush(stdout);
			fgets(responseBuffer, 10, stdin);
			sleep(2);
			if(Status != Disconnected) {
				goto turnOffDevice;
			} else {
isPoweringOn:
				fprintf(stdout, "Is your iPhone currently powering on?\n");
				fprintf(stdout, "Please answer (y/n): ");
				fflush(stdout);
				fgets(responseBuffer, 10, stdin);
				if(responseBuffer[0] == 'y' || responseBuffer[0] == 'Y') {
					fprintf(stdout, "Waiting for iPhone/iPod to power on...\n");
					fflush(stdout);
					while(Status == Disconnected) {
						sleep(1);
					}
					goto turnOffDevice;
				} else if(responseBuffer[0] == 'n' || responseBuffer[0] == 'N') {
					goto beginDFU;
				} else {
					goto isPoweringOn;
				}
			}
		} else {
			goto connectDevice;
		}
	} else {
turnOffDevice:
		fprintf(stdout, "Please turn off your iPhone/iPod without disconnecting the cable connecting it to the computer\n");
		fprintf(stdout, "Press enter when you have turned off your iPhone/iPod... ");
		fflush(stdout);
		fgets(responseBuffer, 10, stdin);

		fprintf(stdout, "Waiting for iPhone/iPod to power off...\n");
		fflush(stdout);
		while(Status != Disconnected) {
			sleep(1);
		}
	}

beginDFU:
	fprintf(stdout, "\n!!! Your device should now be off. If it is not, please make sure it is before proceeding !!!\n\n");

	fprintf(stdout, "Timing is crucial for the following tasks. I will ask you to do the following (DON'T START YET):\n");
	fprintf(stdout, "\t1. Press and hold down the power button for five seconds\n");
	fprintf(stdout, "\t2. Without letting go of the power button, press and hold down the power AND home buttons for ten seconds\n");
	fprintf(stdout, "\t3. Without letting go of the home button, release the power button\n");
	fprintf(stdout, "\t4. Wait 30 seconds while holding down the home button\n");
	fprintf(stdout, "\nTry to get the timing as correct as possible, but don't fret if you miss it by a few seconds. It might still work, and if it doesn't, you can always try again. If you fail, you can always just turn the phone completely off by holding power and home for ten seconds, then pushing power to turn it back on.\n");
	fprintf(stdout, "\nAre you ready to begin?\n");
	fprintf(stdout, "Please answer (y/n): ");
	fflush(stdout);
	fgets(responseBuffer, 10, stdin);
	if(responseBuffer[0] != 'y' && responseBuffer[0] != 'Y')
		goto beginDFU;

	for(countdown = 5; countdown > 0; countdown--) {
		fprintf(stdout, "Beginning process in %d seconds...\n", countdown);
		fflush(stdout);
		sleep(1);
	}

	fprintf(stdout, "\nPress and hold down the POWER button (you should now be just holding the power button)... ");
	fflush(stdout);

	for(countdown = 5; countdown > 0; countdown--) {
		fprintf(stdout, "%d... ", countdown);
		fflush(stdout);
		sleep(1);
	}


	fprintf(stdout, "\n\nPress and hold down the HOME button, DO NOT LET GO OF THE POWER BUTTON (you should now be just holding both the power and home buttons)... ");
	fflush(stdout);

	for(countdown = 10; countdown > 0; countdown--) {
		fprintf(stdout, "%d... ", countdown);
		fflush(stdout);
		sleep(1);
	}

	fprintf(stdout, "\n\nRelease the POWER button, DO NOT LET GO OF THE HOME BUTTON (you should now be just holding the home button)... ");
	fflush(stdout);

	Stage = 2;

	for(countdown = 30; countdown > 0; countdown--) {
		if(Status != Disconnected)
			goto waitForFinish;

		fprintf(stdout, "%d... ", countdown);
		fflush(stdout);
		sleep(1);
	}

	fprintf(stdout, "\n\nEither you did not follow instructions correctly or your USB hardware is malfunctioning. Please use another USB port to connect your iPhone/iPod (NOT through a USB hub) and consider restarting your computer before trying again.\n");
	fflush(stdout);
	cleanup_and_exit();

waitForFinish:
	while(1) {
		msleep(1);
	}
}
Ejemplo n.º 6
0
int main(int argc, char* argv[]) {
	init_libxpwn(&argc, argv);

	OutputState *outputState;
	size_t fileLength;

	AbstractFile *signFile;
	Dictionary *signDict = NULL;
	DataValue *ticket;
	Dictionary *dict;

	AbstractFile *manifestFile;
	Dictionary* manifest;
	struct component_t *array;

	char *plist;
	int i, j, n;
	int rv, error = 0;

	X509 *x0, *y1, *y2;
	uint64_t savecid = 0;
	const unsigned char *p;

	int verbose = FALSE;
	int fromzip = FALSE;

	if (argc < 3) {
		XLOG(0, "usage %s file.shsh BuildManifest.plist [-v] [-z]\n", argv[0]);
		return 0;
	}

	for (i = 3; i < argc; i++) {
		if (!strcmp(argv[i], "-v")) {
			verbose = TRUE;
			continue;
		}

		if (!strcmp(argv[i], "-z")) {
			fromzip = TRUE;
			continue;
		}
	}

	// XXX handle gzip/bplist files
	signFile = createAbstractFileFromFile(fopen(argv[1], "rb"));
	if (!signFile) {
		XLOG(0, "FATAL: cannot open %s\n", argv[1]);
		exit(1);
	}

	fileLength = signFile->getLength(signFile);
	plist = malloc(fileLength);
	signFile->read(signFile, plist, fileLength);
	signFile->close(signFile);
	signDict = createRoot(plist);
	free(plist);

	if (!signDict) {
		XLOG(0, "FATAL: cannot parse %s\n", argv[1]);
		exit(1);
	}

	MaxLoadZipSize = 128 * 1024;
	if (fromzip) {
		outputState = loadZip2(argv[2], TRUE); // XXX ASSERT
		manifestFile = getFileFromOutputState(&outputState, "BuildManifest.plist");
	} else {
		outputState = NULL;
		manifestFile = createAbstractFileFromFile(fopen(argv[2], "rb"));
	}
	if (!manifestFile) {
		XLOG(0, "FATAL: cannot open %s\n", argv[2]);
		exit(1);
	}

	fileLength = manifestFile->getLength(manifestFile);
	plist = malloc(fileLength);
	manifestFile->read(manifestFile, plist, fileLength);
	manifestFile->close(manifestFile);
	manifest = createRoot(plist);
	free(plist);

	if (!manifest) {
		XLOG(0, "FATAL: cannot parse %s\n", argv[2]);
		exit(1);
	}

	releaseOutput(&outputState);

	array = parseManifest(manifest, &n);
	if (!array) {
		XLOG(0, "FATAL: cannot parse manifest\n");
		exit(1);
	}

	OPENSSL_add_all_algorithms_noconf();
	p = cerb;
	x0 = d2i_X509(NULL, &p, cerb_len);
	if (!x0) {
		XLOG(0, "FATAL: cannot load root CA\n");
		exit(1);
	}

	ticket = (DataValue *)getValueByKey(signDict, "APTicket");
	if (ticket) {
		p = ticket->value;
		rv = asn1_parse2(&p, ticket->len, 0, 0);
		if (!rv || !apcert.value || !rsasig.value || !theset.value) {
			XLOG(0, "FATAL: cannot parse ticket\n");
			exit(1);
		}
		if (clen > 0 && contarray->len == 8) {
			savecid = getECID(contarray->value);
		}
		if (!savecid) {
			printf("ERROR: bad, bad ECID\n");
			error = 1;
		}

		rv = extract2Certs(apcert.value, apcert.len, &y1, &y2);
		if (rv == 0) {
			rv = cryptoMagic(x0, y1, y2, theset.value, theset.len, (unsigned char *)rsasig.value, rsasig.len, NULL);
			X509_free(y1);
			X509_free(y2);
		}
		if (rv) {
			printf("ERROR: APTicket failed crypto\n");
			error = 1;
		}
	} else {
		VERBOSE("WARNING: cannot find ticket in %s\n", argv[1]);
	}

	dict = (Dictionary *)signDict->values;
	while (dict) {
		DataValue *blob = NULL;
		DataValue *partialDigest = NULL;
		if (dict->dValue.type == DictionaryType) {
			blob = (DataValue *)getValueByKey(dict, "Blob");
			partialDigest = (DataValue *)getValueByKey(dict, "PartialDigest");
		}
		if (blob && partialDigest) {
			const char *diag = checkBlob(x0, blob, partialDigest, &savecid);
			if (diag) {
				printf("ERROR: Blob for %s is invalid (%s)\n", dict->dValue.key, diag);
				error = 1;
			} else {
				for (i = 0; i < n; i++) {
					struct component_t *centry = array + i;
					if (centry->partial &&
					    partialDigest->len == centry->partial->len &&
					    !memcmp(partialDigest->value, centry->partial->value, partialDigest->len)) {
						array[i].blob = blob;
					}
				}
			}
		}
		dict = (Dictionary *)dict->dValue.next;
	}

	if (!ticket && !savecid) {
		printf("ERROR: bad, bad ECID\n");
		error = 1;
	}

	for (i = 0; i < n; i++) {
		struct component_t *centry = array + i;
		int found = FALSE;
		for (j = 0; j < clen; j++) {
			struct tuple_t *tentry = contarray + j;
			if (tentry->len == centry->digest->len && !memcmp(tentry->value, centry->digest->value, tentry->len)) {
				found = TRUE;
			}
		}
		if (!found) {
			if (centry->blob) {
				VERBOSE("WARNING: no digest for %s (%s), but it has blob\n", centry->key, centry->path);
			} else if (!centry->required) {
				VERBOSE("WARNING: no digest for %s (%s), but it is not critical\n", centry->key, centry->path);
			} else {
				printf("ERROR: no digest for %s (%s) and no blob found\n", centry->key, centry->path);
				error = 1;
			}
		} else {
			VERBOSE("INFO: %s (%s) is signed by APTicket%s\n", centry->key, centry->path, centry->blob ? " and blob" : "");
		}
	}
	free(array);
	free(contarray);

	releaseDictionary(manifest);
	releaseDictionary(signDict);

	if (error) {
		printf("%s is BROKEN\n", argv[1]);
	} else {
		printf("%s seems usable for ECID 0x%016llX\n", argv[1], savecid);
	}

	X509_free(x0);

	EVP_cleanup();
	ERR_remove_state(0);
	CRYPTO_cleanup_all_ex_data();
	return error;
}