Yes I did. In the meantime I’ve even made my own tool, written in C# (bit easier for me to understand). The CRC shouldn’t be in hex, if I’m not mistaken it’s regular Crc32C (not sure about this though).
Repacking should be easy, just use the sizes + start position after header (which should be fixed if I’m not mistaken, to 128) to calculate size, then calculate CRC, and done.
Though I’m not a 100% sure that the header is fixed size - there’s a reason why they used a separator, so it is possible that more than the four currently used kernel objects can be added. The separator is there so that the reader can recognize when to stop processing entries (basically - read length until 0x55 0xAA, divide by three (since all entries have a start, an end, and a CRC), from there, assign the appropriate arrays, etc.
I also had the idea of making a brand new, clean firmware that does not necessarily require the HDDs to be in place, but rather contains a small installer that has error handling, web UI, et cetera - basically it would work similar to Synology’s solution, but a more pure approach with e.g. Debian + OMV (though I’d prefer Ubuntu then). Even the current Debian install could be modified, I think, into something automated, to an extent.
Made some progress on discovering the firmware. So basically the header is fixed 128 bytes (at least so far).
First segment is the data blocks definition:
- 4 bytes for kernel start
- 4 bytes for kernel size
- 4 bytes for ramdisk start
- 4 bytes for ramdisk size
- 4 bytes for rootfs start
- 4 bytes for rootfs size
- 4 bytes for config start
- 4 bytes for config size
Then comes the CRC:
- 4 bytes for kernel CRC
- 4 bytes for ramdisk CRC
- 4 bytes for rootfs CRC
- 4 bytes for config CRC
We’re at byte 48 now. 2 bytes follow up (delimiter, 0x55 0xAA), then the model/platform name (I’d guess latter since it repeats on different models that are actually the same board), which is fixed 8 characters long (padded to end with 0x00 if shorter). Then again the delimiter. Position is at 60.
After this comes another device identifier magic, 5 bytes. 0x00, 0x14, a device (generation? model name?) specific value (0x00, 0x01, 0x02, etc.), 0x01, 0x01. Apart from the third varying value, the rest seems kinda magic value-y to me.
So we’re at 65 of 128. This block is followed by 55 characters, the version (as mentioned before), plus 0x00 padding to 55.
The interesting part is after this. 8 bytes, of which the single last byte matches in every firmware.At 0x7F, in every firmware, regardless of what the other 7 bytes are, is 0x06. The rest changes between the same device’s firmwares, and even basically the same firmwares (e.g. MyCloud Mirror Gen2 and EX2 Ultra) have different values there!
I’m currently stuck at unsquashfs-ing the rootfs, I’m getting a no superblock found error, but might be my extraction.