Skip to content

Instantly share code, notes, and snippets.

@apramorbis
Created November 7, 2024 23:24
Show Gist options
  • Save apramorbis/c9fb55a237d298e5b28e25f3ccb36be6 to your computer and use it in GitHub Desktop.
Save apramorbis/c9fb55a237d298e5b28e25f3ccb36be6 to your computer and use it in GitHub Desktop.
dz2tot
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <sys/types.h>
#include <strings.h>
#include <endian.h>
#include "zlib.h"
#define DZ_FILE_MAGIC 0x74189632
#define DZ_PART_MAGIC 0x78951230
#define TOT_FILE_MAGIC_1 0xAA55DD44
#define TOT_FILE_MAGIC_2 0x8FF7C88F
#define TOT_FLASHMAP_MAGIC 0xAA55EC33
#define TOT_INFO_MAGIC 0x56781234
#define TOTLOC_FLASHMAP_MAGIC 0x2000
#define TOTLOC_FLASHMAP 0x2010
#define TOTLOC_INFO 0x6010
#define TOTLOC_PARTLABELS 0x6230
#define BLOCK_SIZE 512
typedef struct __attribute__((packed)) {
uint32_t magic;
uint32_t unk1;
uint32_t unk2;
uint32_t unk3;
char model[0x20];
char image[0x90];
uint32_t partsCount;
char chksum [0x10];
uint8_t unknown[0x0A];
char chksum2 [0x10];
char serial[50];
char user[15];
} main_header;
typedef struct __attribute__((packed)) {
uint32_t magic;
char name[0x20];
char filename[0x40];
uint32_t unpackedSize;
uint32_t packedSize;
uint8_t checksum[0x10];
uint32_t flashAtBlock;
uint32_t lengthInBlocks;
uint8_t trash[0x17C];
} part_header;
typedef struct __attribute__((packed)) {
uint32_t flashAtBlock;
uint32_t readFromFileAtBlock;
uint32_t lengthInBlocks;
uint32_t unknownAlwaysZero;
} tot_flashmap_record;
typedef struct __attribute__((packed)) {
uint32_t magic;
char model[0x10];
char image[0x90];
char serial[50];
char user[15];
} tot_info_record;
typedef struct __attribute__((packed)) {
char partName[0x20];
} tot_partname_record;
void initTot(uint8_t* totHeader, int numberOfParts, main_header* mainHeader) {
memset(totHeader,0xff,0x100000);
*(uint32_t*)(totHeader) = TOT_FILE_MAGIC_1;
*(uint32_t*)(totHeader+8) = TOT_FILE_MAGIC_2;
*(uint32_t*)(totHeader+TOTLOC_FLASHMAP_MAGIC) = TOT_FLASHMAP_MAGIC;
memset(totHeader+TOTLOC_INFO,0x00,0xE4);
memset(totHeader+TOTLOC_PARTLABELS,0x00,sizeof(tot_partname_record)*numberOfParts);
*(uint32_t*)(totHeader+TOTLOC_INFO) = TOT_INFO_MAGIC;
strcpy(((tot_info_record*)(totHeader+TOTLOC_INFO))->model,mainHeader->model);
strcpy(((tot_info_record*)(totHeader+TOTLOC_INFO))->image,mainHeader->image);
strcpy(((tot_info_record*)(totHeader+TOTLOC_INFO))->serial,mainHeader->serial);
strcpy(((tot_info_record*)(totHeader+TOTLOC_INFO))->user,mainHeader->user);
}
int main(int argc, char **argv) {
if (argc<2) {
printf("usage: dz2tot <dz filename>\n");
exit(-1);
}
FILE* dzFile;
FILE* outFile;
uint32_t partsCount;
uint64_t mergeSizeInBlocks = 0;
uint8_t* totHeader;
tot_flashmap_record* totFlashMapRecord;
tot_partname_record* totPartNameRecord;
uint8_t* buff;
uint8_t* compBuff;
uint8_t* decompBuff;
totHeader = malloc(0x100000);
dzFile = fopen(argv[1],"rb");
if (dzFile==NULL) {
printf("Error opening file :(\n");
exit(-1);
}
buff = malloc(sizeof(main_header));
fread(buff,sizeof(main_header),1,dzFile);
if (((main_header*)buff)->magic != DZ_FILE_MAGIC) {
printf("Unsupported file type :(\n");
exit(-1);
}
printf("DZ file format identifier detected\n");
printf("Model: %s\n",((main_header*)buff)->model);
printf("Image: %s\n",((main_header*)buff)->image);
printf("Serial: %s\n",((main_header*)buff)->serial);
printf("User: %s\n",((main_header*)buff)->user);
partsCount = ((main_header*)buff)->partsCount;
printf("File contains %d (parts of) flash partitions.\n",partsCount);
initTot(totHeader,partsCount, ((main_header*)buff));
totFlashMapRecord = (tot_flashmap_record*)(totHeader+TOTLOC_FLASHMAP);
totPartNameRecord = (tot_partname_record*)(totHeader+TOTLOC_PARTLABELS);
free(buff);
fseek(dzFile,0x200,SEEK_SET);
outFile = fopen("NewFile.tot","wb");
fseek(outFile,0x100000,SEEK_SET);
for (int part=0;part<partsCount;part++){
buff=malloc(sizeof(part_header));
fread(buff,sizeof(part_header),1,dzFile);
if (((part_header*)buff)->magic != DZ_PART_MAGIC) {
printf("Unsupported file type, can't find parts :(\n");
exit(-1);
}
printf("--------------------------------------\n");
printf("Partition name: %s \n",((part_header*)buff)->name);
printf("File name: %s \n",((part_header*)buff)->filename);
printf("\n");
printf("Unpacked data size: 0x%04x \n",((part_header*)buff)->unpackedSize);
printf("Compressed data size: 0x%04x \n",((part_header*)buff)->packedSize);
printf("Checksum: ");
for(int x=0;x<16;x++){ printf("%02X",((part_header*)buff)->checksum[x]); }
printf("\n");
printf("Part start: block 0x%04x (byte offset 0x%04X) \n",((part_header*)buff)->flashAtBlock,((part_header*)buff)->flashAtBlock * BLOCK_SIZE);
printf("Part length: 0x%04x blocks (0x%04X bytes) \n",((part_header*)buff)->lengthInBlocks,((part_header*)buff)->lengthInBlocks * BLOCK_SIZE);
compBuff = malloc(((part_header*)buff)->packedSize);
decompBuff = malloc(((part_header*)buff)->unpackedSize);
fread(compBuff,1,((part_header*)buff)->packedSize,dzFile);
uint64_t bufsz = (((part_header*)buff)->unpackedSize);
if (uncompress(decompBuff,&bufsz,compBuff,((part_header*)buff)->packedSize) == 0) {
fwrite(decompBuff,bufsz,1,outFile);
} else {
printf("Decompression error on %s :(\n",((part_header*)buff)->filename);
exit(-1);
}
free(compBuff);
free(decompBuff);
totFlashMapRecord->flashAtBlock=((part_header*)buff)->flashAtBlock;
totFlashMapRecord->readFromFileAtBlock=mergeSizeInBlocks;
totFlashMapRecord->lengthInBlocks=((part_header*)buff)->unpackedSize / BLOCK_SIZE;
totFlashMapRecord->unknownAlwaysZero=0;
strcpy(totPartNameRecord->partName,((part_header*)buff)->name);
mergeSizeInBlocks += ((part_header*)buff)->unpackedSize / BLOCK_SIZE;
totFlashMapRecord++;
totPartNameRecord++;
free(buff);
}
fseek(outFile,0,SEEK_SET);
fwrite(totHeader,0x100000,1,outFile);
free(totHeader);
fclose(dzFile);
fclose(outFile);
}

Quick & dirty weekend procrastrination project to convert a .dz file (extracted from some* LG .kdz update archives) to the .tot format for use with BoardDiag and probably other tools.

BoardDiag works with Qualcomm SoCs' dead download mode ( related VID/PID: 05C6 / 9008, device names: QHUSB_BULK / QDLoader 9008 ) but requires a .tot image for reading/writing the flash partitions The .kdz/.dz format is readily available, .tot isn't.

gcc dz2tot.c -o dz2tot -lz ./d2ztot

Qualcomm SoCs of this era appear to be very easily recoverable in the majority of mis-flash scenarios so chances are if you think you need this you also need a hot-air station and a replacement eMMC chip.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment