char* xpwntool_get_kbag(char* fileName) { char* strbuf = NULL; AbstractFile* inFile; inFile = openAbstractFile2(createAbstractFileFromFile(fopen(fileName, "rb")), NULL, NULL); if (inFile != NULL && inFile->type == AbstractFileTypeImg3) { Img3Info* i3i = (Img3Info*)(inFile->data); if (i3i != NULL) { Img3Element* kbag = i3i->kbag; if (kbag != NULL && kbag->data != NULL && kbag->header != NULL) { size_t buflen = 1 + 2 * kbag->header->dataSize; strbuf = (char*)HeapAlloc(GetProcessHeap(), 0, buflen); char* bytes = (char*)kbag->data; for (size_t i = 0; i < kbag->header->dataSize; ++i) { snprintf(strbuf + 2 * i, 2, "%02X", (unsigned char) bytes[i]); } strbuf[buflen-1] = '\0'; return strbuf; } } inFile->close(inFile); } return strbuf; }
int xpwntool_enc_dec(char* srcName, char* destName, char* templateFileName, char* ivStr, char* keyStr) { char* inData; size_t inDataSize; AbstractFile* templateFile = NULL; unsigned int* key = NULL; unsigned int* iv = NULL; int hasKey = TRUE; int hasIV = TRUE; if (templateFileName != NULL && strlen(templateFileName) != 0) { templateFile = createAbstractFileFromFile(fopen(templateFileName, "rb")); if(!templateFile) { fprintf(stderr, "error: cannot open template\n"); return 1; } } size_t bytes; hexToInts(keyStr, &key, &bytes); if (bytes == 0) { free(key); key = NULL; } else { hexToInts(ivStr, &iv, &bytes); } AbstractFile* inFile; inFile = openAbstractFile2(createAbstractFileFromFile(fopen(srcName, "rb")), key, iv); if(!inFile) { fprintf(stderr, "error: cannot open infile\n"); return 2; } AbstractFile* outFile = createAbstractFileFromFile(fopen(destName, "wb")); if(!outFile) { fprintf(stderr, "error: cannot open outfile\n"); return 3; } AbstractFile* newFile; if(templateFile) { newFile = duplicateAbstractFile2(templateFile, outFile, key, iv, NULL); if(!newFile) { fprintf(stderr, "error: cannot duplicate file from provided template\n"); return 4; } } else { newFile = outFile; } if(newFile->type == AbstractFileTypeImg3) { AbstractFile2* abstractFile2 = (AbstractFile2*) newFile; if (key != NULL) { abstractFile2->setKey(abstractFile2, key, iv); } } inDataSize = (size_t) inFile->getLength(inFile); inData = (char*) malloc(inDataSize); inFile->read(inFile, inData, inDataSize); inFile->close(inFile); newFile->write(newFile, inData, inDataSize); newFile->close(newFile); free(inData); if(key) free(key); if(iv) free(iv); return 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; }
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; }
int convertToPNG(AbstractFile* imageWrapper, const unsigned int* key, const unsigned int* iv, const char* png) { AbstractFile* imageFile; FILE *fp = fopen(png, "wb"); if(!fp) return -1; if(key != NULL) { imageFile = openAbstractFile2(imageWrapper, key, iv); } else { imageFile = openAbstractFile(imageWrapper); } InfoIBootIM* info = (InfoIBootIM*) (imageFile->data); png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, pngError, pngWarn); if (!png_ptr) { return -1; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return -1; } png_init_io(png_ptr, fp); int color_type; int bytes_per_pixel; if(info->header.format == IBOOTIM_ARGB) { XLOG(3, "ARGB"); color_type = PNG_COLOR_TYPE_RGB_ALPHA; bytes_per_pixel = 4; } else if(info->header.format == IBOOTIM_GREY) { XLOG(3, "Grayscale"); color_type = PNG_COLOR_TYPE_GRAY_ALPHA; bytes_per_pixel = 2; } else { XLOG(3, "Unknown color type!"); } png_set_IHDR(png_ptr, info_ptr, info->header.width, info->header.height, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_bgr(png_ptr); png_set_invert_alpha(png_ptr); png_write_info(png_ptr, info_ptr); void* imageBuffer = malloc(imageFile->getLength(imageFile)); imageFile->read(imageFile, imageBuffer, imageFile->getLength(imageFile)); png_bytepp row_pointers = (png_bytepp) malloc(sizeof(png_bytep) * info->header.height); int i; for(i = 0; i < png_get_image_height(png_ptr, info_ptr); i++) { row_pointers[i] = imageBuffer + (info->header.width * bytes_per_pixel * i); } png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, NULL); free(imageBuffer); return 0; }