├── .gitignore ├── CMakeLists.txt ├── Makefile ├── README ├── shared └── blob.h └── src ├── blobpack.cpp └── blobunpack.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | blobpack 3 | blobunpack 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(BlobTools) 2 | cmake_minimum_required(VERSION 2.6) 3 | SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) 4 | SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin/lib) 5 | 6 | INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/shared" "${CMAKE_SOURCE_DIR}/src") 7 | SET(SHARED_SOURCES shared/blob.h) 8 | SET(BLOBUNPACK_SOURCES src/blobunpack.cpp ${SHARED_SOURCES}) 9 | SET(BLOBPACK_SOURCES src/blobpack.cpp ${SHARED_SOURCES}) 10 | 11 | 12 | ADD_EXECUTABLE(blobunpack ${BLOBUNPACK_SOURCES}) 13 | ADD_EXECUTABLE(blobpack ${BLOBPACK_SOURCES}) 14 | 15 | 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGETS=blobunpack blobpack 2 | DEPS = Makefile shared/blob.h 3 | COMMON= 4 | 5 | CC=g++ 6 | CFLAGS+=-I. -Ishared -Wall -ggdb 7 | LDFLAGS= 8 | 9 | OBJS = $(COMMON) $(addsuffix .o, $(TARGETS)) 10 | 11 | all: $(TARGETS) 12 | 13 | $(TARGETS): %: %.o $(COMMON) $(DEPS) 14 | $(CC) $(CFLAGS) -o $@ $< $(COMMON) $(LDFLAGS) 15 | 16 | $(OBJS): %.o: src/%.cpp $(DEPS) 17 | $(CC) -c -o $@ $< $(CFLAGS) 18 | 19 | .PHONY: clean 20 | 21 | clean: 22 | rm -f $(TARGETS) *.o 23 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Tools used for unpacking and repacking blob files. 2 | 3 | The tools should be fairly selfexplanatory, but keep in mind there's very little error checking, so if it crashes, don't flash the blob ;) 4 | 5 | Copyright 2012 Jens Andersen/AndroidRoot.mobi 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | -------------------------------------------------------------------------------- /shared/blob.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Jens Andersen/AndroidRoot.mobi 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _BLOB_H 18 | #define _BLOB_H 19 | 20 | // Previous unknown fields grabbed from 21 | // http://nv-tegra.nvidia.com/gitweb/?p=android/platform/build.git;a=commitdiff;h=0adc4478615891636d8b7c476c20c2014b788537 22 | 23 | #define SECURE_MAGIC "-SIGNED-BY-SIGNBLOB-" 24 | #define SECURE_MAGIC_SIZE 20 25 | #define SECURE_OFFSET 28 26 | #define MAGIC "MSM-RADIO-UPDATE" 27 | #define MAGIC_SIZE 16 28 | #define PART_NAME_LEN 4 29 | 30 | typedef struct 31 | { 32 | unsigned char magic[MAGIC_SIZE]; 33 | unsigned int version; // Always 0x00010000 34 | unsigned int size; // Size of header 35 | unsigned int part_offset; // Same as size 36 | unsigned int num_parts; // Number of partitions 37 | unsigned int unknown[7]; // Always zero 38 | } header_type; 39 | 40 | typedef struct 41 | { 42 | unsigned char magic[SECURE_MAGIC_SIZE]; 43 | unsigned int datalen; 44 | unsigned int siglen; 45 | header_type real_header; 46 | } secure_header_type; 47 | 48 | typedef struct 49 | { 50 | char name[PART_NAME_LEN]; // Name of partition. Has to match an existing tegra2 partition name (e.g. LNX, SOS) 51 | unsigned int offset; // offset in blob where this partition starts 52 | unsigned int size; // Size of partition 53 | unsigned int version; // Version is variable, but is always 1 in this app 54 | } part_type; 55 | 56 | #endif /* _BLOB_H*/ 57 | -------------------------------------------------------------------------------- /src/blobpack.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Jens Andersen/AndroidRoot.mobi 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "blob.h" 22 | typedef struct 23 | { 24 | char *part_name; 25 | char *filename; 26 | } partition_item; 27 | 28 | // Number of required arguments before partition definition, including argv[0] 29 | #define GENERIC_ARGS 2 30 | 31 | int 32 | main (int argc, char **argv) 33 | { 34 | header_type hdr; 35 | char *outname; 36 | int i, partnums; 37 | partition_item *partitions,*curr_part; 38 | FILE *outfile; 39 | part_type *parts; 40 | 41 | memset (&hdr, 0, sizeof (header_type)); 42 | 43 | if (argc < (GENERIC_ARGS+2)) // Require at least one partition 44 | { 45 | fprintf (stderr,"Usage: %s ...\n", argv[0]); 46 | fprintf(stderr, "Any number of partitionname partitionfilename entries can be entered\n"); 47 | return -1; 48 | } 49 | 50 | outname = argv[1]; 51 | partnums = argc - GENERIC_ARGS; 52 | 53 | if(partnums <= 0 || partnums % 2 != 0) 54 | { 55 | fprintf(stderr, "Error in parameters. There needs to be equal partition names and partition filenames."); 56 | return -1; 57 | } 58 | // Two parameters per partition. 59 | // At this point we know there is a dividable-by-two number of parameters left 60 | partnums = partnums / 2; 61 | printf("Found %d partitions as commandline arguments\n", partnums); 62 | partitions = (partition_item*)calloc(partnums, sizeof(partition_item)); 63 | curr_part = partitions; 64 | for(i=GENERIC_ARGS; ipart_name = argv[i]; 68 | curr_part->filename = argv[i+1]; 69 | curr_part++; 70 | }; 71 | 72 | memcpy(hdr.magic, MAGIC, MAGIC_SIZE); 73 | hdr.version = 0x00010000; // Taken from 74 | hdr.size = hdr.part_offset = sizeof(header_type); 75 | hdr.num_parts = partnums; 76 | 77 | outfile = fopen (outname, "wb"); 78 | fwrite (&hdr, sizeof (header_type), 1, outfile); 79 | printf ("Size: %d\n", hdr.size); 80 | printf ("%d partitions starting at offset 0x%X\n", hdr.num_parts, 81 | hdr.part_offset); 82 | 83 | parts = (part_type *)calloc (hdr.num_parts, sizeof (part_type)); 84 | memset(parts, 0, sizeof(part_type)*hdr.num_parts); 85 | int currentOffset = sizeof(header_type)+sizeof(part_type)*hdr.num_parts; 86 | printf("Offset: %d\n", currentOffset); 87 | for (i = 0; i < (int)hdr.num_parts; i++) 88 | { 89 | FILE *curfile = fopen (partitions[i].filename, "rb"); 90 | long fsize; 91 | memcpy(parts[i].name, partitions[i].part_name, PART_NAME_LEN); 92 | parts[i].version = 1; // Version. OK to stay at 1 always. 93 | parts[i].offset = currentOffset; 94 | 95 | if(curfile == NULL) 96 | { 97 | fprintf(stderr,"Error opening file %s\n", partitions[i].filename); 98 | return 0; 99 | } 100 | fseek (curfile, 0, SEEK_END); 101 | fsize = ftell (curfile); 102 | fclose (curfile); 103 | parts[i].size = fsize; 104 | currentOffset += fsize; 105 | } 106 | 107 | fwrite (parts, sizeof (part_type), hdr.num_parts, outfile); 108 | for (i = 0; i < (int)hdr.num_parts; i++) 109 | { 110 | // TODO: Don't read in full file in one go. Memory usage!!! 111 | char *buffer = (char *) malloc (parts[i].size); 112 | FILE *currFile = fopen (partitions[i].filename, "rb"); // Read in update file 113 | fread (buffer, 1, parts[i].size, currFile); 114 | fclose(currFile); 115 | fwrite (buffer, 1, parts[i].size, outfile); 116 | }; 117 | 118 | fclose (outfile); 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /src/blobunpack.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 2012 Jens Andersen/AndroidRoot.mobi 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include "blob.h" 22 | #ifdef _WIN32 23 | #define snprintf _snprintf 24 | #endif 25 | void dumpPartition (FILE * file, char *basename, part_type part); 26 | #define BUFFER_SIZE 2048 27 | 28 | int secure_offset; 29 | 30 | int 31 | main (int argc, char **argv) 32 | { 33 | secure_header_type sec_hdr; 34 | header_type *hdr; 35 | FILE *file; 36 | part_type *parts; 37 | int i; 38 | char magic_tag[21]; 39 | char *blobname; 40 | memset (&sec_hdr, 0, sizeof (secure_header_type)); 41 | hdr = &sec_hdr.real_header; 42 | secure_offset=0; 43 | 44 | if (argc < 2) 45 | { 46 | fprintf (stderr, "Usage: %s \n", argv[0]); 47 | return -1; 48 | } 49 | 50 | file = fopen (argv[1], "rb"); 51 | if (file == NULL) 52 | { 53 | fprintf (stderr, "Unable to open \"%s\"\n", argv[1]); 54 | return -1; 55 | } 56 | 57 | blobname = strrchr(argv[1], '/'); 58 | if (blobname == NULL) 59 | blobname = argv[1]; 60 | else 61 | blobname++; 62 | 63 | fread (magic_tag, SECURE_MAGIC_SIZE, 1, file); 64 | if(!memcmp(magic_tag, SECURE_MAGIC, SECURE_MAGIC_SIZE)) 65 | { 66 | fseek(file, 0 , SEEK_SET); 67 | fread (&sec_hdr, sizeof (secure_header_type), 1, file); 68 | secure_offset = SECURE_OFFSET; 69 | } else if (!memcmp (magic_tag, MAGIC, MAGIC_SIZE)) 70 | { 71 | fseek(file, 0 , SEEK_SET); 72 | fread (hdr, sizeof (header_type), 1, file); 73 | } else 74 | { 75 | fprintf(stderr, "Unsupported blob file format\n"); 76 | exit(-1); 77 | } 78 | printf ("Header size: %d\n", hdr->size); 79 | printf ("%d partitions starting at offset 0x%X\n", hdr->num_parts, 80 | hdr->part_offset); 81 | printf ("Blob version: %d\n", hdr->version); 82 | 83 | fseek (file, secure_offset + hdr->part_offset, SEEK_SET); 84 | parts = (part_type *)calloc (hdr->num_parts, sizeof (part_type)); 85 | fread (parts, sizeof (part_type), hdr->num_parts, file); 86 | 87 | for (i = 0; i < (int)hdr->num_parts; i++) 88 | { 89 | printf ("Partition %d\n", i); 90 | printf ("Name: %s\n", parts[i].name); 91 | printf ("Offset: %d (0x%X)\n", parts[i].offset, parts[i].offset); 92 | printf ("Size: %d (0x%X)\n", parts[i].size, parts[i].size); 93 | dumpPartition (file, blobname, parts[i]); 94 | } 95 | fclose (file); 96 | return 0; 97 | } 98 | 99 | void 100 | dumpPartition (FILE * file, char *basename, part_type part) 101 | { 102 | int dataleft = part.size; 103 | char buffer[BUFFER_SIZE]; 104 | char filename[1024]; 105 | FILE *outfile; 106 | snprintf (filename, 1024, "%s.%s", basename, part.name); 107 | printf ("Writing file %s (%d bytes)\n", filename, part.size); 108 | 109 | fseek (file, secure_offset + part.offset, SEEK_SET); 110 | outfile = fopen (filename, "wb"); 111 | while (dataleft > 0) 112 | { 113 | int toRead = dataleft > BUFFER_SIZE ? BUFFER_SIZE : dataleft; 114 | int dataread = fread (buffer, 1, toRead, file); 115 | int datawritten = fwrite (buffer, 1, dataread, outfile); 116 | if (dataread != datawritten) 117 | abort (); 118 | dataleft -= dataread; 119 | } 120 | fclose (outfile); 121 | } 122 | --------------------------------------------------------------------------------