PageRenderTime 64ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/ipsw-patch/main.c

https://github.com/reventi/xpwn
C | 490 lines | 400 code | 90 blank | 0 comment | 111 complexity | 20eb5f29a4367580837613691f423f67 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0
  1. #include <stdlib.h>
  2. #include <sys/types.h>
  3. #include <string.h>
  4. #include "common.h"
  5. #include <xpwn/libxpwn.h>
  6. #include <xpwn/nor_files.h>
  7. #include <dmg/dmg.h>
  8. #include <dmg/filevault.h>
  9. #include <xpwn/ibootim.h>
  10. #include <xpwn/plist.h>
  11. #include <xpwn/outputstate.h>
  12. #include <hfs/hfslib.h>
  13. #include <dmg/dmglib.h>
  14. #include <xpwn/pwnutil.h>
  15. #include <stdio.h>
  16. #ifdef WIN32
  17. #include <windows.h>
  18. #endif
  19. char endianness;
  20. static char* tmpFile = NULL;
  21. static AbstractFile* openRoot(void** buffer, size_t* rootSize) {
  22. static char tmpFileBuffer[512];
  23. if((*buffer) != NULL) {
  24. return createAbstractFileFromMemoryFile(buffer, rootSize);
  25. } else {
  26. if(tmpFile == NULL) {
  27. #ifdef WIN32
  28. char tmpFilePath[512];
  29. GetTempPath(512, tmpFilePath);
  30. GetTempFileName(tmpFilePath, "root", 0, tmpFileBuffer);
  31. CloseHandle(CreateFile(tmpFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL));
  32. #else
  33. strcpy(tmpFileBuffer, "/tmp/rootXXXXXX");
  34. close(mkstemp(tmpFileBuffer));
  35. FILE* tFile = fopen(tmpFileBuffer, "wb");
  36. fclose(tFile);
  37. #endif
  38. tmpFile = tmpFileBuffer;
  39. }
  40. return createAbstractFileFromFile(fopen(tmpFile, "r+b"));
  41. }
  42. }
  43. void closeRoot(void* buffer) {
  44. if(buffer != NULL) {
  45. free(buffer);
  46. }
  47. if(tmpFile != NULL) {
  48. unlink(tmpFile);
  49. }
  50. }
  51. int main(int argc, char* argv[]) {
  52. init_libxpwn();
  53. Dictionary* info;
  54. Dictionary* firmwarePatches;
  55. Dictionary* patchDict;
  56. ArrayValue* patchArray;
  57. void* buffer;
  58. StringValue* actionValue;
  59. StringValue* pathValue;
  60. StringValue* fileValue;
  61. StringValue* patchValue;
  62. char* patchPath;
  63. char* rootFSPathInIPSW;
  64. io_func* rootFS;
  65. Volume* rootVolume;
  66. size_t rootSize;
  67. size_t preferredRootSize = 0;
  68. size_t minimumRootSize = 0;
  69. char* ramdiskFSPathInIPSW;
  70. unsigned int ramdiskKey[16];
  71. unsigned int ramdiskIV[16];
  72. unsigned int* pRamdiskKey = NULL;
  73. unsigned int* pRamdiskIV = NULL;
  74. io_func* ramdiskFS;
  75. Volume* ramdiskVolume;
  76. char* updateRamdiskFSPathInIPSW = NULL;
  77. int i;
  78. OutputState* outputState;
  79. char* bundlePath;
  80. char* bundleRoot = "FirmwareBundles/";
  81. int mergePaths;
  82. char* outputIPSW;
  83. void* imageBuffer;
  84. size_t imageSize;
  85. AbstractFile* bootloader39 = NULL;
  86. AbstractFile* bootloader46 = NULL;
  87. AbstractFile* applelogo = NULL;
  88. AbstractFile* recoverymode = NULL;
  89. char noWipe = FALSE;
  90. char unlockBaseband = FALSE;
  91. char selfDestruct = FALSE;
  92. char use39 = FALSE;
  93. char use46 = FALSE;
  94. char doBootNeuter = FALSE;
  95. char updateBB = FALSE;
  96. char useMemory = FALSE;
  97. unsigned int key[16];
  98. unsigned int iv[16];
  99. unsigned int* pKey = NULL;
  100. unsigned int* pIV = NULL;
  101. if(argc < 3) {
  102. 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]);
  103. return 0;
  104. }
  105. outputIPSW = argv[2];
  106. int* toRemove = NULL;
  107. int numToRemove = 0;
  108. for(i = 3; i < argc; i++) {
  109. if(argv[i][0] != '-') {
  110. break;
  111. }
  112. if(strcmp(argv[i], "-memory") == 0) {
  113. useMemory = TRUE;
  114. continue;
  115. }
  116. if(strcmp(argv[i], "-s") == 0) {
  117. int size;
  118. sscanf(argv[i + 1], "%d", &size);
  119. preferredRootSize = size;
  120. i++;
  121. continue;
  122. }
  123. if(strcmp(argv[i], "-nowipe") == 0) {
  124. noWipe = TRUE;
  125. continue;
  126. }
  127. if(strcmp(argv[i], "-bbupdate") == 0) {
  128. updateBB = TRUE;
  129. continue;
  130. }
  131. if(strcmp(argv[i], "-e") == 0) {
  132. numToRemove++;
  133. toRemove = realloc(toRemove, numToRemove * sizeof(int));
  134. toRemove[numToRemove - 1] = i + 1;
  135. i++;
  136. continue;
  137. }
  138. if(strcmp(argv[i], "-unlock") == 0) {
  139. unlockBaseband = TRUE;
  140. continue;
  141. }
  142. if(strcmp(argv[i], "-cleanup") == 0) {
  143. selfDestruct = TRUE;
  144. continue;
  145. }
  146. if(strcmp(argv[i], "-use39") == 0) {
  147. if(use46) {
  148. XLOG(0, "error: select only one of -use39 and -use46\n");
  149. exit(1);
  150. }
  151. use39 = TRUE;
  152. continue;
  153. }
  154. if(strcmp(argv[i], "-use46") == 0) {
  155. if(use39) {
  156. XLOG(0, "error: select only one of -use39 and -use46\n");
  157. exit(1);
  158. }
  159. use46 = TRUE;
  160. continue;
  161. }
  162. if(strcmp(argv[i], "-b") == 0) {
  163. applelogo = createAbstractFileFromFile(fopen(argv[i + 1], "rb"));
  164. if(!applelogo) {
  165. XLOG(0, "cannot open %s\n", argv[i + 1]);
  166. exit(1);
  167. }
  168. i++;
  169. continue;
  170. }
  171. if(strcmp(argv[i], "-r") == 0) {
  172. recoverymode = createAbstractFileFromFile(fopen(argv[i + 1], "rb"));
  173. if(!recoverymode) {
  174. XLOG(0, "cannot open %s\n", argv[i + 1]);
  175. exit(1);
  176. }
  177. i++;
  178. continue;
  179. }
  180. if(strcmp(argv[i], "-3") == 0) {
  181. bootloader39 = createAbstractFileFromFile(fopen(argv[i + 1], "rb"));
  182. if(!bootloader39) {
  183. XLOG(0, "cannot open %s\n", argv[i + 1]);
  184. exit(1);
  185. }
  186. i++;
  187. continue;
  188. }
  189. if(strcmp(argv[i], "-4") == 0) {
  190. bootloader46 = createAbstractFileFromFile(fopen(argv[i + 1], "rb"));
  191. if(!bootloader46) {
  192. XLOG(0, "cannot open %s\n", argv[i + 1]);
  193. exit(1);
  194. }
  195. i++;
  196. continue;
  197. }
  198. }
  199. mergePaths = i;
  200. if(use39 || use46 || unlockBaseband || selfDestruct || bootloader39 || bootloader46) {
  201. if(!(bootloader39) || !(bootloader46)) {
  202. XLOG(0, "error: you must specify both bootloader files.\n");
  203. exit(1);
  204. } else {
  205. doBootNeuter = TRUE;
  206. }
  207. }
  208. info = parseIPSW2(argv[1], bundleRoot, &bundlePath, &outputState, useMemory);
  209. if(info == NULL) {
  210. XLOG(0, "error: Could not load IPSW\n");
  211. exit(1);
  212. }
  213. firmwarePatches = (Dictionary*)getValueByKey(info, "FilesystemPatches");
  214. int j;
  215. for(j = 0; j < numToRemove; j++) {
  216. removeKey(firmwarePatches, argv[toRemove[j]]);
  217. }
  218. free(toRemove);
  219. firmwarePatches = (Dictionary*)getValueByKey(info, "FirmwarePatches");
  220. patchDict = (Dictionary*) firmwarePatches->values;
  221. while(patchDict != NULL) {
  222. fileValue = (StringValue*) getValueByKey(patchDict, "File");
  223. StringValue* keyValue = (StringValue*) getValueByKey(patchDict, "Key");
  224. StringValue* ivValue = (StringValue*) getValueByKey(patchDict, "IV");
  225. pKey = NULL;
  226. pIV = NULL;
  227. if(keyValue) {
  228. sscanf(keyValue->value, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
  229. &key[0], &key[1], &key[2], &key[3], &key[4], &key[5], &key[6], &key[7], &key[8],
  230. &key[9], &key[10], &key[11], &key[12], &key[13], &key[14], &key[15]);
  231. pKey = key;
  232. }
  233. if(ivValue) {
  234. sscanf(ivValue->value, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
  235. &iv[0], &iv[1], &iv[2], &iv[3], &iv[4], &iv[5], &iv[6], &iv[7], &iv[8],
  236. &iv[9], &iv[10], &iv[11], &iv[12], &iv[13], &iv[14], &iv[15]);
  237. pIV = iv;
  238. }
  239. if(strcmp(patchDict->dValue.key, "Restore Ramdisk") == 0) {
  240. ramdiskFSPathInIPSW = fileValue->value;
  241. if(pKey) {
  242. memcpy(ramdiskKey, key, sizeof(key));
  243. memcpy(ramdiskIV, iv, sizeof(iv));
  244. pRamdiskKey = ramdiskKey;
  245. pRamdiskIV = ramdiskIV;
  246. } else {
  247. pRamdiskKey = NULL;
  248. pRamdiskIV = NULL;
  249. }
  250. }
  251. if(strcmp(patchDict->dValue.key, "Update Ramdisk") == 0) {
  252. updateRamdiskFSPathInIPSW = fileValue->value;
  253. }
  254. patchValue = (StringValue*) getValueByKey(patchDict, "Patch2");
  255. if(patchValue) {
  256. if(noWipe) {
  257. XLOG(0, "%s: ", patchDict->dValue.key); fflush(stdout);
  258. doPatch(patchValue, fileValue, bundlePath, &outputState, pKey, pIV, useMemory);
  259. patchDict = (Dictionary*) patchDict->dValue.next;
  260. continue; /* skip over the normal Patch */
  261. }
  262. }
  263. patchValue = (StringValue*) getValueByKey(patchDict, "Patch");
  264. if(patchValue) {
  265. XLOG(0, "%s: ", patchDict->dValue.key); fflush(stdout);
  266. doPatch(patchValue, fileValue, bundlePath, &outputState, pKey, pIV, useMemory);
  267. }
  268. if(strcmp(patchDict->dValue.key, "AppleLogo") == 0 && applelogo) {
  269. XLOG(0, "replacing %s\n", fileValue->value); fflush(stdout);
  270. ASSERT((imageBuffer = replaceBootImage(getFileFromOutputState(&outputState, fileValue->value), pKey, pIV, applelogo, &imageSize)) != NULL, "failed to use new image");
  271. addToOutput(&outputState, fileValue->value, imageBuffer, imageSize);
  272. }
  273. if(strcmp(patchDict->dValue.key, "RecoveryMode") == 0 && recoverymode) {
  274. XLOG(0, "replacing %s\n", fileValue->value); fflush(stdout);
  275. ASSERT((imageBuffer = replaceBootImage(getFileFromOutputState(&outputState, fileValue->value), pKey, pIV, recoverymode, &imageSize)) != NULL, "failed to use new image");
  276. addToOutput(&outputState, fileValue->value, imageBuffer, imageSize);
  277. }
  278. patchDict = (Dictionary*) patchDict->dValue.next;
  279. }
  280. fileValue = (StringValue*) getValueByKey(info, "RootFilesystem");
  281. rootFSPathInIPSW = fileValue->value;
  282. size_t defaultRootSize = ((IntegerValue*) getValueByKey(info, "RootFilesystemSize"))->value;
  283. minimumRootSize = defaultRootSize * 1000 * 1000;
  284. minimumRootSize -= minimumRootSize % 512;
  285. if(preferredRootSize == 0) {
  286. preferredRootSize = defaultRootSize;
  287. }
  288. rootSize = preferredRootSize * 1000 * 1000;
  289. rootSize -= rootSize % 512;
  290. if(useMemory) {
  291. buffer = malloc(rootSize);
  292. } else {
  293. buffer = NULL;
  294. }
  295. if(buffer == NULL) {
  296. XLOG(2, "using filesystem backed temporary storage\n");
  297. }
  298. extractDmg(
  299. createAbstractFileFromFileVault(getFileFromOutputState(&outputState, rootFSPathInIPSW), ((StringValue*)getValueByKey(info, "RootFilesystemKey"))->value),
  300. openRoot((void**)&buffer, &rootSize), -1);
  301. rootFS = IOFuncFromAbstractFile(openRoot((void**)&buffer, &rootSize));
  302. rootVolume = openVolume(rootFS);
  303. XLOG(0, "Growing root to minimum: %ld\n", (long) defaultRootSize); fflush(stdout);
  304. grow_hfs(rootVolume, minimumRootSize);
  305. if(rootSize > minimumRootSize) {
  306. XLOG(0, "Growing root: %ld\n", (long) preferredRootSize); fflush(stdout);
  307. grow_hfs(rootVolume, rootSize);
  308. }
  309. firmwarePatches = (Dictionary*)getValueByKey(info, "FilesystemPatches");
  310. patchArray = (ArrayValue*) firmwarePatches->values;
  311. while(patchArray != NULL) {
  312. for(i = 0; i < patchArray->size; i++) {
  313. patchDict = (Dictionary*) patchArray->values[i];
  314. fileValue = (StringValue*) getValueByKey(patchDict, "File");
  315. actionValue = (StringValue*) getValueByKey(patchDict, "Action");
  316. if(strcmp(actionValue->value, "ReplaceKernel") == 0) {
  317. pathValue = (StringValue*) getValueByKey(patchDict, "Path");
  318. XLOG(0, "replacing kernel... %s -> %s\n", fileValue->value, pathValue->value); fflush(stdout);
  319. add_hfs(rootVolume, getFileFromOutputState(&outputState, fileValue->value), pathValue->value);
  320. } if(strcmp(actionValue->value, "Patch") == 0) {
  321. patchValue = (StringValue*) getValueByKey(patchDict, "Patch");
  322. patchPath = (char*) malloc(sizeof(char) * (strlen(bundlePath) + strlen(patchValue->value) + 2));
  323. strcpy(patchPath, bundlePath);
  324. strcat(patchPath, "/");
  325. strcat(patchPath, patchValue->value);
  326. XLOG(0, "patching %s (%s)... ", fileValue->value, patchPath);
  327. doPatchInPlace(rootVolume, fileValue->value, patchPath);
  328. free(patchPath);
  329. }
  330. }
  331. patchArray = (ArrayValue*) patchArray->dValue.next;
  332. }
  333. for(; mergePaths < argc; mergePaths++) {
  334. XLOG(0, "merging %s\n", argv[mergePaths]);
  335. AbstractFile* tarFile = createAbstractFileFromFile(fopen(argv[mergePaths], "rb"));
  336. if(tarFile == NULL) {
  337. XLOG(1, "cannot find %s, make sure your slashes are in the right direction\n", argv[mergePaths]);
  338. releaseOutput(&outputState);
  339. closeRoot(buffer);
  340. exit(0);
  341. }
  342. hfs_untar(rootVolume, tarFile);
  343. tarFile->close(tarFile);
  344. }
  345. if(pRamdiskKey) {
  346. ramdiskFS = IOFuncFromAbstractFile(openAbstractFile2(getFileFromOutputStateForOverwrite(&outputState, ramdiskFSPathInIPSW), pRamdiskKey, pRamdiskIV));
  347. } else {
  348. XLOG(0, "unencrypted ramdisk\n");
  349. ramdiskFS = IOFuncFromAbstractFile(openAbstractFile(getFileFromOutputStateForOverwrite(&outputState, ramdiskFSPathInIPSW)));
  350. }
  351. ramdiskVolume = openVolume(ramdiskFS);
  352. XLOG(0, "growing ramdisk: %d -> %d\n", ramdiskVolume->volumeHeader->totalBlocks * ramdiskVolume->volumeHeader->blockSize, (ramdiskVolume->volumeHeader->totalBlocks + 4) * ramdiskVolume->volumeHeader->blockSize);
  353. grow_hfs(ramdiskVolume, (ramdiskVolume->volumeHeader->totalBlocks + 4) * ramdiskVolume->volumeHeader->blockSize);
  354. if(doBootNeuter) {
  355. firmwarePatches = (Dictionary*)getValueByKey(info, "BasebandPatches");
  356. if(firmwarePatches != NULL) {
  357. patchDict = (Dictionary*) firmwarePatches->values;
  358. while(patchDict != NULL) {
  359. pathValue = (StringValue*) getValueByKey(patchDict, "Path");
  360. fileValue = (StringValue*) getValueByKey(patchDict, "File");
  361. if(fileValue) {
  362. XLOG(0, "copying %s -> %s... ", fileValue->value, pathValue->value); fflush(stdout);
  363. if(copyAcrossVolumes(ramdiskVolume, rootVolume, fileValue->value, pathValue->value)) {
  364. patchValue = (StringValue*) getValueByKey(patchDict, "Patch");
  365. if(patchValue) {
  366. patchPath = malloc(sizeof(char) * (strlen(bundlePath) + strlen(patchValue->value) + 2));
  367. strcpy(patchPath, bundlePath);
  368. strcat(patchPath, "/");
  369. strcat(patchPath, patchValue->value);
  370. XLOG(0, "patching %s (%s)... ", pathValue->value, patchPath); fflush(stdout);
  371. doPatchInPlace(rootVolume, pathValue->value, patchPath);
  372. free(patchPath);
  373. }
  374. }
  375. }
  376. if(strcmp(patchDict->dValue.key, "Bootloader 3.9") == 0 && bootloader39 != NULL) {
  377. add_hfs(rootVolume, bootloader39, pathValue->value);
  378. }
  379. if(strcmp(patchDict->dValue.key, "Bootloader 4.6") == 0 && bootloader46 != NULL) {
  380. add_hfs(rootVolume, bootloader46, pathValue->value);
  381. }
  382. patchDict = (Dictionary*) patchDict->dValue.next;
  383. }
  384. }
  385. fixupBootNeuterArgs(rootVolume, unlockBaseband, selfDestruct, use39, use46);
  386. }
  387. createRestoreOptions(ramdiskVolume, preferredRootSize, updateBB);
  388. closeVolume(ramdiskVolume);
  389. CLOSE(ramdiskFS);
  390. if(updateRamdiskFSPathInIPSW)
  391. removeFileFromOutputState(&outputState, updateRamdiskFSPathInIPSW);
  392. closeVolume(rootVolume);
  393. CLOSE(rootFS);
  394. buildDmg(openRoot((void**)&buffer, &rootSize), getFileFromOutputStateForReplace(&outputState, rootFSPathInIPSW));
  395. closeRoot(buffer);
  396. writeOutput(&outputState, outputIPSW);
  397. releaseDictionary(info);
  398. free(bundlePath);
  399. return 0;
  400. }