Voici les images «restaurées», grâce aux recherches approfondies de tillberg:
Comme prévu, il y a un marqueur de bloc de 5 octets tous les 0x4020 octets environ. Le format semble être le suivant:
struct marker {
uint8_t tag; /* 1 if this is the last marker in the file, 0 otherwise */
uint16_t len; /* size of the following block (little-endian) */
uint16_t notlen; /* 0xffff - len */
};
Une fois le marqueur lu, les marker.len
octets suivants forment un bloc qui fait partie du fichier. marker.notlen
est une variable de contrôle telle que marker.len + marker.notlen == 0xffff
. Le dernier bloc est tel que marker.tag == 1
.
La structure est probablement la suivante. Il existe encore des valeurs inconnues.
struct file {
uint8_t name_len; /* number of bytes in the filename */
/* (not sure whether it's uint8_t or uint16_t) */
char name[name_len]; /* filename */
uint32_t file_len; /* size of the file (little endian) */
/* eg. "40 25 01 00" is 0x12540 bytes */
uint16_t unknown; /* maybe a checksum? */
marker marker1; /* first block marker (tag == 0) */
uint8_t data1[marker1.len]; /* data of the first block */
marker marker2; /* second block marker (tag == 0) */
uint8_t data2[marker2.len]; /* data of the second block */
/* ... */
marker lastmarker; /* last block marker (tag == 1) */
uint8_t lastdata[lastmarker.len]; /* data of the last block */
uint32_t unknown2; /* end data? another checksum? */
};
Je n'ai pas compris ce qui est à la fin, mais comme les PNG acceptent le rembourrage, ce n'est pas trop dramatique. Cependant, la taille du fichier encodé indique clairement que les 4 derniers octets doivent être ignorés ...
Comme je n'avais pas accès à tous les marqueurs de bloc juste avant le début du fichier, j'ai écrit ce décodeur qui commence à la fin et tente de trouver les marqueurs de bloc. Ce n'est pas du tout robuste mais bon, cela a fonctionné pour vos images de test:
#include <stdio.h>
#include <string.h>
#define MAX_SIZE (1024 * 1024)
unsigned char buf[MAX_SIZE];
/* Usage: program infile.png outfile.png */
int main(int argc, char *argv[])
{
size_t i, len, lastcheck;
FILE *f = fopen(argv[1], "rb");
len = fread(buf, 1, MAX_SIZE, f);
fclose(f);
/* Start from the end and check validity */
lastcheck = len;
for (i = len - 5; i-- > 0; )
{
size_t off = buf[i + 2] * 256 + buf[i + 1];
size_t notoff = buf[i + 4] * 256 + buf[i + 3];
if (buf[i] >= 2 || off + notoff != 0xffff)
continue;
else if (buf[i] == 1 && lastcheck != len)
continue;
else if (buf[i] == 0 && i + off + 5 != lastcheck)
continue;
lastcheck = i;
memmove(buf + i, buf + i + 5, len - i - 5);
len -= 5;
i -= 5;
}
f = fopen(argv[2], "wb+");
fwrite(buf, 1, len, f);
fclose(f);
return 0;
}
Recherches plus anciennes
Voici ce que vous obtenez en supprimant l'octet 0x4022
de la deuxième image, puis en supprimant l'octet 0x8092
:
Il ne «répare» pas vraiment les images; Je l'ai fait par essais et erreurs. Cependant, il indique qu'il y a des données inattendues tous les 16384 octets. Je suppose que les images sont regroupées dans une sorte de structure de système de fichiers et que les données inattendues sont simplement des marqueurs de bloc que vous devez supprimer lors de la lecture des données.
Je ne sais pas exactement où sont les marqueurs de bloc et leur taille, mais la taille du bloc elle-même est très certainement de 2 ^ 14 octets.
Il serait utile que vous puissiez également fournir un vidage hexadécimal (quelques dizaines d'octets) de ce qui apparaît juste avant l'image et juste après. Cela donnerait des indications sur le type d'informations stockées au début ou à la fin des blocs.
Bien sûr, il y a aussi la possibilité qu'il y ait un bug dans votre code d'extraction. Si vous utilisez un tampon de 16384 octets pour vos opérations sur les fichiers, je vérifierais d'abord.