PageRenderTime 42ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/mr500.c

https://gitlab.com/GrieverV/rockbox
C | 457 lines | 205 code | 69 blank | 183 comment | 46 complexity | 36c88100701077cf4d29b393e4ab5bbe MD5 | raw file
  1. /***************************************************************************
  2. * __________ __ ___.
  3. * Open \______ \ ____ ____ | | _\_ |__ _______ ___
  4. * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
  5. * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
  6. * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
  7. * \/ \/ \/ \/ \/
  8. *
  9. * Copyright (C) 2009 by Karl Kurbjun
  10. * based on work by Shirour:
  11. * http://www.mrobe.org/forum/viewtopic.php?f=6&t=2176
  12. * $Id$
  13. *
  14. * All files in this archive are subject to the GNU General Public License.
  15. * See the file COPYING in the source tree root for full license agreement.
  16. *
  17. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  18. * KIND, either express or implied.
  19. *
  20. ****************************************************************************/
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #include <fcntl.h>
  25. #include <errno.h>
  26. #include <unistd.h>
  27. #include <inttypes.h>
  28. #include <sys/stat.h>
  29. #include "mr500.h"
  30. /* Notes about firmware:
  31. * These notes are based on the work and observations of Shirour on the M:Robe
  32. * forums.
  33. *
  34. * The firmware for the M:Robe has basic encryption on it. The data is XORed
  35. * and scrambled. The mr500_save_data function provides an implemenation of the
  36. * encryption/decryption.
  37. *
  38. * When a firmware update is done the "{#4F494D4346575550#}" folder is stored
  39. * in the system folder on the player. The "{#4F494D4346575550#}" should only
  40. * contain the encrypted N5002-BD.BIN file. At the end of a firmware update
  41. * the "{#4F494D4346575550#}" folder and it's contents are removed from the
  42. * player.
  43. *
  44. * An interesting note is that the name "{#4F494D4346575550#}" is actually the
  45. * Hex representation of the magic text found at the beginning of the firmware
  46. * image "OIMCFWUP".
  47. */
  48. /* These two arrays are used for descrambling or scrambling the data */
  49. int decrypt_array[16]={2, 0, 3, 1, 5, 7, 4, 6, 11, 10, 9, 8, 14, 12, 13, 15};
  50. int encrypt_array[16];
  51. /* mr500_patch_file: This function modifies the specified file with the patches
  52. * struct.
  53. *
  54. * Parameters:
  55. * filename: text filename
  56. * patches: pointer to structure array of patches
  57. * num_patches: number of patches to apply (applied in reverse order)
  58. *
  59. * Returns:
  60. * Returns 0 if there was no error, -1 if there was an error
  61. */
  62. int mr500_patch_file(char *filename, struct patch_single *patches,
  63. int num_patches) {
  64. int fdo;
  65. int ret=0;
  66. uint32_t endian_int;
  67. /* Open the file write only. */
  68. fdo = open(filename, O_WRONLY);
  69. if(fdo<0) {
  70. ret=-1;
  71. }
  72. while(num_patches--) {
  73. /* seek to patch offset */
  74. if(lseek(fdo, patches[num_patches].offset, SEEK_SET)
  75. != patches[num_patches].offset) {
  76. ret=-1;
  77. break;
  78. }
  79. /* Make sure patch is written in little endian format */
  80. endian_int = htole32(patches[num_patches].value);
  81. /* Write the patch value to the file */
  82. if(write(fdo, (void *) &endian_int, sizeof(endian_int)) < 0) {
  83. ret = -1;
  84. break;
  85. }
  86. }
  87. /* Close the file and check for errors */
  88. if(close (fdo) < 0) {
  89. ret = -1;
  90. }
  91. return ret;
  92. }
  93. /* mr500_save_header: This function saves the Olympus header to the firmware
  94. * image. The values stored in the header are explained above. Note that this
  95. * will truncate a file. The header is stored in little endian format.
  96. *
  97. * Parameters:
  98. * filename: text filename
  99. * header: pointer to header structure to be saved
  100. *
  101. * Returns:
  102. * Returns 0 if there was no error, -1 if there was an error
  103. */
  104. int mr500_save_header(char *filename, struct olympus_header *header) {
  105. int fdo;
  106. int ret=0;
  107. /* Temporary header used for storing the header in little endian. */
  108. struct olympus_header save;
  109. /* Open the file write only and truncate it. If it doesn't exist create. */
  110. fdo = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
  111. if(fdo<0) {
  112. ret=-1;
  113. }
  114. /* Header is stored at offset 0 (Not really needed) */
  115. if(lseek(fdo, 0, SEEK_SET) != 0) {
  116. ret=-1;
  117. }
  118. /* Convert header to Little Endian */
  119. memcpy(&save.magic_name, &header->magic_name, 8*sizeof(int8_t));
  120. save.unknown = htole32(header->unknown);
  121. save.header_length = htole16(header->header_length);
  122. save.flags = htole16(header->flags);
  123. save.unknown_zeros = htole32(header->unknown_zeros);
  124. save.image_length = htole32(header->image_length);
  125. /* Write the header to the file */
  126. if(write(fdo, (void *) &save, sizeof(save)) < 0) {
  127. ret = -1;
  128. }
  129. /* Close the file and check for errors */
  130. if(close (fdo) < 0) {
  131. ret = -1;
  132. }
  133. return ret;
  134. }
  135. /* mr500_read_header: This function reads the Olympus header and converts it to
  136. * the host endian format. The values stored in the header are explained above.
  137. * The header is stored in little endian format.
  138. *
  139. * Parameters:
  140. * filename: text filename
  141. * header: pointer to header structure to store header read from file
  142. *
  143. * Returns:
  144. * Returns 0 if there was no error, -1 if there was an error
  145. */
  146. int mr500_read_header(char *filename, struct olympus_header *header) {
  147. int fdi;
  148. int ret = 0;
  149. /* Open the file read only */
  150. fdi = open(filename, O_RDONLY);
  151. if(fdi<0) {
  152. ret=-1;
  153. }
  154. /* Header is stored at offset 0 (Not really needed) */
  155. if(lseek(fdi, 0, SEEK_SET) != 0) {
  156. ret=-1;
  157. }
  158. /* Read in the header */
  159. if(read(fdi, (void *) header, sizeof(*header)) < 0) {
  160. ret = -1;
  161. }
  162. /* Convert header to system endian */
  163. header->unknown = le32toh(header->unknown);
  164. header->header_length = le16toh(header->header_length);
  165. header->flags = le16toh(header->flags);
  166. header->unknown_zeros = le32toh(header->unknown_zeros);
  167. header->image_length = le32toh(header->image_length);
  168. /* Close the file and check for errors */
  169. if(close (fdi) < 0) {
  170. ret = -1;
  171. }
  172. return ret;
  173. }
  174. /* mr500_save_crc: This function saves the 'CRC' of the Olympus firmware image.
  175. * Note that the 'CRC' must be calculated on the decrytped image. It is stored
  176. * in little endian.
  177. *
  178. * Parameters:
  179. * filename: text filename
  180. * offset: Offset to store the 'CRC' (header size + data size)
  181. * crc_value: pointer to crc value to save
  182. *
  183. * Returns:
  184. * Returns 0 if there was no error, -1 if there was an error
  185. */
  186. int mr500_save_crc(char *filename, off_t offset, uint32_t *crc_value) {
  187. int fdo;
  188. int ret = 0;
  189. uint32_t save_crc;
  190. /* Open the file write only */
  191. fdo = open(filename, O_WRONLY);
  192. if(fdo<0) {
  193. ret=-1;
  194. }
  195. /* Seek to offset and check for errors */
  196. if(lseek(fdo, offset, SEEK_SET) != offset) {
  197. ret=-1;
  198. }
  199. /* Convert 'CRC' to little endian from system native endian */
  200. save_crc = htole32(*crc_value);
  201. /* Write the 'CRC' and check for errors */
  202. if(write(fdo, (void *) &save_crc, sizeof(unsigned int)) < 0) {
  203. ret = -1;
  204. }
  205. /* Close the file and check for errors */
  206. if(close (fdo) < 0) {
  207. ret = -1;
  208. }
  209. return ret;
  210. }
  211. /* mr500_read_crc: This function reads the 'CRC' of the Olympus firmware image.
  212. * Note that the 'CRC' is calculated on the decrytped values. It is stored
  213. * in little endian.
  214. *
  215. * Parameters:
  216. * filename: text filename
  217. * offset: Offset to read the 'CRC' (header size + data size)
  218. * crc_value: pointer to crc value to save
  219. *
  220. * Returns:
  221. * Returns 0 if there was no error, -1 if there was an error
  222. */
  223. int mr500_read_crc(char *filename, off_t offset, uint32_t *crc_value) {
  224. int fdi;
  225. int ret = 0;
  226. /* Open the file read only */
  227. fdi = open(filename, O_RDONLY);
  228. if(fdi<0) {
  229. ret = -1;
  230. }
  231. /* Seek to offset and check for errors */
  232. if(lseek(fdi, offset, SEEK_SET) != offset) {
  233. ret=-1;
  234. }
  235. /* Read in the 'CRC' */
  236. if(read(fdi, (void *) crc_value, sizeof(uint32_t)) < 0) {
  237. ret = -1;
  238. }
  239. /* Convert the 'CRC' from little endian to system native format */
  240. *crc_value = le32toh(*crc_value);
  241. /* Close the file and check for errors */
  242. if(close (fdi) < 0) {
  243. ret = -1;
  244. }
  245. return ret;
  246. }
  247. /* mr500_calculate_crc: This function calculates the 'CRC' of the Olympus
  248. * firmware image. Note that the 'CRC' must be calculated on decrytped values.
  249. * It is stored in little endian.
  250. *
  251. * Parameters:
  252. * filename: text filename
  253. * offset: Offset to the start of the data (header size)
  254. * length: Length of data to calculate
  255. * crc_value: pointer to crc value to save
  256. *
  257. * Returns:
  258. * Returns 0 if there was no error, -1 if there was an error
  259. */
  260. int mr500_calculate_crc( char *filename, off_t offset, unsigned int length,
  261. uint32_t *crc_value){
  262. uint32_t temp;
  263. int fdi;
  264. int ret = 0;
  265. /* Open the file read only */
  266. fdi = open(filename, O_RDONLY);
  267. if(fdi<0) {
  268. ret = -1;
  269. }
  270. /* Seek to offset and check for errors */
  271. if(lseek(fdi, offset, SEEK_SET) != offset) {
  272. ret=-1;
  273. }
  274. /* Initialize the crc_value to make sure this starts at 0 */
  275. *crc_value = 0;
  276. /* Run this loop till the entire sum is created */
  277. do {
  278. /* Read an integer at a time */
  279. if(read(fdi, &temp, sizeof(uint32_t)) < 0) {
  280. ret = -1;
  281. break;
  282. }
  283. /* Keep summing the values */
  284. *crc_value+=temp;
  285. } while (length-=4);
  286. /* Close the file and check for errors */
  287. if(close (fdi) < 0) {
  288. ret = -1;
  289. }
  290. return ret;
  291. }
  292. /* mr500_save_data: This function encypts or decrypts the Olympus firmware
  293. * image based on the dictionary passed to it.
  294. *
  295. * Parameters:
  296. * source_filename: text filename where data is read from
  297. * dest_filename: text filename where data is written to
  298. * offset: Offset to the start of the data (header size)
  299. * length: Length of data to modify
  300. * dictionary: pointer to dictionary used for scrambling
  301. *
  302. * Returns:
  303. * Returns 0 if there was no error, -1 if there was an error
  304. */
  305. int mr500_save_data(
  306. char *source_filename, char *dest_filename, off_t offset,
  307. unsigned int length, int* dictionary) {
  308. int fdi, fdo;
  309. int ret = 0;
  310. int i;
  311. /* read_count stores the number of bytes actually read */
  312. int read_count;
  313. /* read_request stores the number of bytes to be requested */
  314. int read_request;
  315. /* These two buffers are used for reading data and scrambling or
  316. * descrambling
  317. */
  318. int8_t buffer_original[16];
  319. int8_t buffer_modified[16];
  320. /* Open input read only, output write only */
  321. fdi = open(source_filename, O_RDONLY);
  322. fdo = open(dest_filename, O_WRONLY);
  323. /* If there was an error loading the files set ret appropriately */
  324. if(fdi<0 || fdo < 0) {
  325. ret = -1;
  326. }
  327. /* Input file: Seek to offset and check for errors */
  328. if(lseek(fdi, offset, SEEK_SET) != offset) {
  329. ret=-1;
  330. }
  331. /* Output file: Seek to offset and check for errors */
  332. if(lseek(fdo, offset, SEEK_SET) != offset) {
  333. ret=-1;
  334. }
  335. /* Run this loop till size is 0 */
  336. do {
  337. /* Choose the amount of data to read - normally in 16 byte chunks, but
  338. * when the end of the file is near may be less.
  339. */
  340. if( length > sizeof(buffer_original)){
  341. read_request = sizeof(buffer_original);
  342. } else {
  343. read_request = length;
  344. }
  345. /* Read in the data */
  346. read_count = read(fdi, (void *) &buffer_original, read_request);
  347. /* If there was an error set the flag and break */
  348. if(read_count < 0) {
  349. ret = -1;
  350. break;
  351. }
  352. for(i=0; i<read_count; i++) {
  353. /* XOR all of the bits to de/encrypt them */
  354. buffer_original[i] ^= 0xFF;
  355. /* Handle byte scrambling */
  356. buffer_modified[dictionary[i]] = buffer_original[i];
  357. }
  358. /* write the data: If there was an error set the flag and break */
  359. if(write(fdo, (void *) &buffer_modified, read_count) < 0) {
  360. ret = -1;
  361. break;
  362. }
  363. } while (length -= read_count);
  364. /* Close the files and check for errors */
  365. if(close (fdi) < 0) {
  366. ret = -1;
  367. }
  368. if(close (fdo) < 0) {
  369. ret = -1;
  370. }
  371. return ret;
  372. }
  373. /* mr500_init: This function initializes the encryption array
  374. *
  375. * Parameters:
  376. * None
  377. *
  378. * Returns:
  379. * Returns 0
  380. */
  381. int mr500_init(void) {
  382. int i;
  383. /* Initialize the encryption array */
  384. for(i=0; i<16; i++) {
  385. encrypt_array[decrypt_array[i]]=i;
  386. }
  387. return 0;
  388. }