blob: e86b860baa53b464f3a98a9c8285a1b3b95b552c [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001/*
2 * This binary allows you to back up the second (recovery) ramdisk on
3 * typical Samsung boot images and to inject a new second ramdisk into
4 * an existing boot image.
5 *
6 * This program is free software; you can redistribute it and/or modify
Dees Troy3be70a82013-10-22 14:25:12 +00007 * it under the terms of the GNU General Public License version 3 and
Dees_Troy51a0e822012-09-05 15:24:24 -04008 * only version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA.
19 *
20 * The code was written from scratch by Dees_Troy dees_troy at
21 * yahoo
22 *
23 * Copyright (c) 2012
24 */
25#include <stdio.h>
26#include <string.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <sys/stat.h>
30
31#define INJECT_USE_TMP 1
32
33int scan_file_for_data(char *filename, unsigned char *data, int data_size, unsigned long start_location, unsigned long *data_address) {
34 FILE *pFile;
35 unsigned long lSize;
36 unsigned char *buffer, *last_needle = NULL;
37 unsigned char needle[data_size];
38 size_t result;
39 int i, return_val = 0;
40
41 pFile = fopen(filename, "rb");
42 if(pFile==NULL){
43 printf("Unabled to open file '%s'.\nFailed\n", filename);
44 return -1;
45 }
46
47 fseek (pFile , 0 , SEEK_END);
48 lSize = ftell(pFile);
49 rewind(pFile);
50
51 buffer = (unsigned char*)malloc(sizeof(unsigned char) * lSize);
52 if(buffer == NULL){
53 printf("Memory allocation error on '%s'!\nFailed\n", filename);
54 return -1;
55 }
56
57 result = fread(buffer, 1, lSize, pFile);
58 if (result != lSize) {
59 printf("Error reading file '%s'\nFailed\n", filename);
60 return -1;
61 }
62
63 for (i=0; i<data_size; i++) {
64 needle[i] = *data;
65 data++;
66 }
67
68 unsigned char *p = memmem(buffer + start_location, lSize - start_location, needle, data_size);
69
70 if (!p) {
71 return_val = -1;
72 } else {
73 *data_address = p - buffer + data_size;
74 }
75
76 fclose(pFile);
77 free(buffer);
78 return return_val;
79}
80
81int write_new_ramdisk(char *bootimage, char *newramdisk, unsigned long start_location, char *outputimage) {
82 FILE *bFile; // bootimage
83 FILE *rFile; // ramdisk
84 FILE *oFile; // output file
85 unsigned long blSize, rlSize, offset_table, ramdisk_len;
86 unsigned char *bbuffer, *rbuffer;
87 size_t result;
88 int return_val;
89
90 // Read the original boot image
91 printf("Reading the original boot image...\n");
92 bFile = fopen(bootimage, "rb");
93 if(bFile==NULL){
94 printf("Unabled to open original boot image '%s'.\nFailed\n", bootimage);
95 exit(0);
96 }
97
98 fseek (bFile , 0 , SEEK_END);
99 blSize = ftell(bFile);
100 rewind(bFile);
101 printf("Size of original boot is %lu\n", blSize);
102
103 bbuffer = (unsigned char*)malloc(sizeof(unsigned char) * blSize);
104 if(bbuffer == NULL){
105 printf("File read error on original boot image '%s'!\nFailed\n", bootimage);
106 exit(0);
107 }
108
109 result = fread(bbuffer, 1, blSize, bFile);
110 if (result != blSize) {
111 printf("Error reading original boot image '%s'\nFailed\n", bootimage);
112 exit(0);
113 }
114
115 // Find the ramdisk offset table
116 unsigned char needle[13] = "recovery_len=";
117 return_val = scan_file_for_data(bootimage, &needle, 13, 0, &offset_table);
118 if (return_val < 0) {
119 fclose(bFile);
120 printf("Ramdisk offset table not found in %s!\nFailed\n", bootimage);
121 exit(0);
122 }
123 printf("Ramdisk offset table found at 0x%08x\n", offset_table);
124
125 // Read the ramdisk to insert into the boot image
126 printf("Reading the ramdisk...\n");
127 rFile = fopen(newramdisk, "rb");
128 if(rFile==NULL){
129 printf("Unabled to open ramdisk image '%s'.\nFailed\n", newramdisk);
130 exit(0);
131 }
132
133 fseek (rFile , 0 , SEEK_END);
134 rlSize = ftell(rFile);
135 rewind(rFile);
136 printf("Size of new ramdisk is %lu\n", rlSize);
137 ramdisk_len = rlSize / 512;
138 if ((rlSize % 512) != 0)
139 ramdisk_len++;
140 printf("Ramdisk length for offset table: %lu\n", ramdisk_len);
141
142 rbuffer = (unsigned char*)malloc(sizeof(unsigned char) * blSize);
143 if(rbuffer == NULL){
144 printf("File read error on ramdisk image '%s'!\nFailed\n", newramdisk);
145 exit(0);
146 }
147
148 result = fread(rbuffer, 1, rlSize, rFile);
149 if (result != rlSize) {
150 printf("Error reading ramdisk image '%s'\nFailed\n", newramdisk);
151 exit(0);
152 }
153
154 // Open the output image for writing
155 printf("Opening the output image for writing...\n");
156 oFile = fopen(outputimage, "wb");
157 if(oFile==NULL){
158 printf("Unabled to open output image '%s'.\nFailed\n", outputimage);
159 exit(0);
160 }
161
162 printf("Writing kernel and first ramdisk...\n");
163 result = fwrite(bbuffer, 1, start_location - 1, oFile);
164 if (result != start_location - 1) {
165 printf("Write count does not match! (1)\n");
166 }
167 fseek(oFile, start_location, SEEK_SET);
168 printf("Writing new second ramdisk...\n");
169 result = fwrite(rbuffer, 1, rlSize, oFile);
170 if (result != rlSize) {
171 printf("Write count does not match! (2)\n");
172 } else {
173 printf("Finished writing new boot image '%s'\n", outputimage);
174 }
175
176 // Write new ramdisk_len to offset table
177 printf("Writing new ramdisk length to offset table...\n");
178 fseek(oFile, offset_table, SEEK_SET);
179 char ramdisk_lens[20];
180 sprintf(ramdisk_lens, "%lu;\n\n", ramdisk_len);
181 fwrite(ramdisk_lens, 1, strlen(ramdisk_lens), oFile);
182
183 fclose(bFile);
184 fclose(rFile);
185 fclose(oFile);
186 free(bbuffer);
187 free(rbuffer);
188
189 printf("All done writing new image: '%s'\n", outputimage);
190 return 1;
191}
192
193int backup_recovery_ramdisk(char *bootimage, unsigned long start_location, char *outputimage) {
194 FILE *bFile; // bootimage
195 FILE *rFile; // ramdisk
196 FILE *oFile; // output file
197 unsigned long blSize, offset_table, ramdisk_len;
198 unsigned char *bbuffer;
199 size_t result;
200 unsigned char ramdisk_lens[4], *p;
201 int return_val, i;
202
203 // Read the original boot image
204 printf("Reading the original boot image...\n");
205 bFile = fopen(bootimage, "rb");
206 if(bFile==NULL){
207 printf("Unabled to open original boot image '%s'.\nFailed\n", bootimage);
208 exit(0);
209 }
210
211 fseek (bFile , 0 , SEEK_END);
212 blSize = ftell(bFile);
213 rewind(bFile);
214 printf("Size of original boot is %lu\n", blSize);
215
216 bbuffer = (unsigned char*)malloc(sizeof(unsigned char) * blSize);
217 if(bbuffer == NULL){
218 printf("File read error on original boot image '%s'!\nFailed\n", bootimage);
219 exit(0);
220 }
221
222 result = fread(bbuffer, 1, blSize, bFile);
223 if (result != blSize) {
224 printf("Error reading original boot image '%s'\nFailed\n", bootimage);
225 exit(0);
226 }
227
228 // Find the ramdisk offset table
229 unsigned char needle[13] = "recovery_len=";
230 return_val = scan_file_for_data(bootimage, &needle, 13, 0, &offset_table);
231 if (return_val < 0) {
232 fclose(bFile);
233 printf("Ramdisk offset table not found in %s!\nFailed\n", bootimage);
234 exit(0);
235 }
236 printf("Ramdisk offset table found at 0x%08x\n", offset_table);
237 for (i=0; i<4; i++) {
238 p = bbuffer + offset_table + i;
239 if (*p == ';') {
240 ramdisk_lens[i] = 0;
241 } else {
242 ramdisk_lens[i] = *p;
243 }
244 }
245 ramdisk_len = atoi(ramdisk_lens);
246 ramdisk_len *= 512;
247 printf("Ramdisk length: %lu\n", ramdisk_len);
248
249 // Open the output image for writing
250 printf("Opening the output image for writing...\n");
251 oFile = fopen(outputimage, "wb");
252 if(oFile==NULL){
253 printf("Unabled to open output image '%s'.\nFailed\n", outputimage);
254 exit(0);
255 }
256
257 printf("Writing backup ramdisk...\n");
258 result = fwrite(bbuffer + start_location, 1, ramdisk_len, oFile);
259 if (result != ramdisk_len) {
260 printf("Write count does not match! (1)\n");
261 } else {
262 printf("Finished backing up ramdisk image '%s'\n", outputimage);
263 }
264
265 fclose(bFile);
266 fclose(oFile);
267 free(bbuffer);
268 return 1;
269}
270
271int find_gzip_recovery_ramdisk(char *boot_image, unsigned long *ramdisk_address) {
272 unsigned char gzip_ramdisk[6] = {0x00, 0x00, 0x00, 0x00, 0x1f, 0x8b};
273 unsigned long address1, address2;
274 int return_val;
275
276 // Find the first ramdisk
277 return_val = scan_file_for_data(boot_image, &gzip_ramdisk, 6, 0, &address1);
278 if (return_val < 0) {
279 printf("No ramdisk found in '%s'\nFailed\n", boot_image);
280 printf("This boot image may not be using gzip compression.\n");
281 return -1;
282 }
283 address1 -= 2;
284 printf("Ramdisk found in '%s' at offset 0x%08x\n", boot_image, address1);
285
286 // Find the second (recovery) ramdisk
287 return_val = scan_file_for_data(boot_image, &gzip_ramdisk, 6, address1 + 50, &address2);
288 if (return_val < 0) {
289 printf("No recovery ramdisk found in '%s'\nFailed\n", boot_image, address2);
290 return -1;
291 }
292 address2 -= 2;
293 printf("Recovery ramdisk found in '%s' at offset 0x%08x\n", boot_image, address2);
294
295 *ramdisk_address = address2;
296 return 0;
297}
298
299int main(int argc, char** argv) {
Dees_Troy06b4fe92012-10-16 11:43:20 -0400300 int arg_error = 0, delete_ind = 0, return_val, index, len;
Dees_Troy51a0e822012-09-05 15:24:24 -0400301 unsigned long address2;
302 unsigned char regular_check[8] = "ANDROID!";
Dees_Troy06b4fe92012-10-16 11:43:20 -0400303 char boot_image[512], backup_image[512], boot_block_device[512], command[512];
Dees_Troy51a0e822012-09-05 15:24:24 -0400304
305 printf("-- InjectTWRP Recovery Ramdisk Injection Tool for Samsung devices. --\n");
306 printf("-- by Dees_Troy and Team Win --\n");
307 printf("-- http://teamw.in --\n");
308 printf("-- Bringing some win to Samsung! --\n");
309 printf("-- This tool comes with no warranties whatsoever! --\n");
310 printf("-- Use at your own risk and always keep a backup! --\n\n");
Dees_Troy06b4fe92012-10-16 11:43:20 -0400311 printf("Version 0.2 beta\n\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400312
313 // Parse the arguments
Dees_Troy06b4fe92012-10-16 11:43:20 -0400314 if (argc < 2 || argc > 6)
Dees_Troy51a0e822012-09-05 15:24:24 -0400315 arg_error = 1;
316 else {
Dees_Troy06b4fe92012-10-16 11:43:20 -0400317 strcpy(boot_block_device, "boot");
318 for (index = 1; index < argc; index++) {
319 len = strlen(argv[index]);
320 if (len > 3 && strncmp(argv[index], "bd=", 3) == 0) {
321 strcpy(boot_block_device, argv[index] + 3);
322 index = argc;
323 }
324 }
325 if ((argc >= 2 && argc <= 4) && (strcmp(argv[1], "-b") == 0 || strcmp(argv[1], "--backup") == 0)) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400326 // Backup existing boot image
327 printf("Dumping boot image...\n");
328#ifdef INJECT_USE_TMP
Dees_Troy06b4fe92012-10-16 11:43:20 -0400329 sprintf(command, "dump_image %s /tmp/original_boot.img", boot_block_device);
330 system(command);
Dees_Troy51a0e822012-09-05 15:24:24 -0400331 strcpy(boot_image, "/tmp/original_boot.img");
332
333 if (argc == 2)
334 strcpy(backup_image, "/tmp/recovery_ramdisk.img");
335 else
336 strcpy(backup_image, argv[2]);
337#else
338 system("mount /cache");
Dees_Troy06b4fe92012-10-16 11:43:20 -0400339 sprintf(command, "dump_image %s /cache/original_boot.img", boot_block_device);
340 system(command);
Dees_Troy51a0e822012-09-05 15:24:24 -0400341 strcpy(boot_image, "/cache/original_boot.img");
342
343 if (argc == 2)
344 strcpy(backup_image, "/cache/recovery_ramdisk.img");
345 else
346 strcpy(backup_image, argv[2]);
347#endif
348
349 // Check if this is a normal Android image or a Samsung image
350 return_val = scan_file_for_data(boot_image, &regular_check, 8, 0, &address2);
351 if (return_val >= 0) {
352 printf("This is not a properly formatted Samsung boot image!\nFailed\n");
353 return 1;
354 }
355
356 // Find the ramdisk
357 return_val = find_gzip_recovery_ramdisk(boot_image, &address2);
358 if (return_val < 0) {
359 return 1;
360 }
361
362 backup_recovery_ramdisk(boot_image, address2, backup_image);
363 return 0;
364 } else {
365 // Inject new ramdisk
366 if (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--dump") == 0) {
367 printf("Dumping boot image...\n");
368#ifdef INJECT_USE_TMP
Dees_Troy06b4fe92012-10-16 11:43:20 -0400369 sprintf(command, "dump_image %s /tmp/original_boot.img", boot_block_device);
370 system(command);
Dees_Troy51a0e822012-09-05 15:24:24 -0400371 strcpy(boot_image, "/tmp/original_boot.img");
372#else
373 system("mount /cache");
Dees_Troy06b4fe92012-10-16 11:43:20 -0400374 sprintf(command, "dump_image %s /cache/original_boot.img", boot_block_device);
375 system(command);
Dees_Troy51a0e822012-09-05 15:24:24 -0400376 strcpy(boot_image, "/cache/original_boot.img");
Dees_Troy51a0e822012-09-05 15:24:24 -0400377 delete_ind = -1;
Dees_Troy06b4fe92012-10-16 11:43:20 -0400378#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400379 } else
380 strcpy(boot_image, argv[1]);
381
382 // Check if this is a normal Android image or a Samsung image
383 return_val = scan_file_for_data(boot_image, &regular_check, 8, 0, &address2);
384 if (return_val >= 0) {
385 printf("This is not a properly formatted Samsung boot image!\nFailed\n");
386 return 1;
387 }
388
389 // Find the ramdisk
390 return_val = find_gzip_recovery_ramdisk(boot_image, &address2);
391 if (return_val < 0) {
392 return 1;
393 }
394
395 // Write the new image
396 write_new_ramdisk(boot_image, argv[2], address2, argv[3]);
397
398 // Delete --dump image if needed
399 if (delete_ind) {
400 printf("Deleting dumped boot image from /cache\n");
401 system("rm /cache/original_boot.img");
402 }
403
Dees_Troy06b4fe92012-10-16 11:43:20 -0400404 if (argc >= 5 && (strcmp(argv[4], "-f") == 0 || strcmp(argv[4], "--flash") == 0)) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400405 printf("Flashing new image...\n");
Dees_Troy06b4fe92012-10-16 11:43:20 -0400406 sprintf(command, "erase_image %s", boot_block_device);
407 system(command);
408 sprintf(command, "flash_image %s %s", boot_block_device, argv[3]);
Dees_Troy51a0e822012-09-05 15:24:24 -0400409 system(command);
410 printf("Flash complete.\n");
411 }
412 return 0;
413 }
414 }
415
416 if (arg_error) {
417 printf("Invalid arguments supplied.\n");
418 printf("Usage:\n\n");
419 printf("Backup existing recovery ramdisk (requires dump_image):\n");
420 printf("injecttwrp --backup [optionalbackuplocation.img]\n\n");
421 printf("Inject new recovery ramdisk:\n");
422 printf("injecttwrp originalboot.img ramdisk-recovery.img outputboot.img\n");
423 printf("injecttwrp --dump ramdisk-recovery.img outputboot.img [--flash]\n");
424 printf("--dump will use dump_image to dump your existing boot image\n");
425 printf("--flash will use flash_image to flash the new boot image\n\n");
Dees_Troy06b4fe92012-10-16 11:43:20 -0400426 printf("NOTE: dump_image, erase_image, and flash_image must already be installed!\n\n");
427 printf("If needed you can add bd=/dev/block/mmcblk0p5 to indicate the location\n");
428 printf("of the boot partition on emmc devices as the final parameter.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400429 return 0;
430 }
431
432 return 0;
433}