How do I find the offset of an ext4 filesystem?
There isn't a standard offset per-se, as of course you can start the partition wherever you want. But let's assume for a moment that you're looking for the first partition, and it was created more or less accepting defaults. There are then two places you may find it, assuming you were using a traditional DOS partition table:
- Starting at (512-byte) sector 63. This was the tradition for a very long time, and worked until someone came up with 4K disks...
- Starting at (512-byte) sector 2048. This is the new tradition, to accommodate 4K disks.
- A bonus option! Sarting at sector 56. This is what happens if someone moves the 63-start partition to make it align with a 4K sector.
Now, to proceed, you'll want to pick up your favorite hex-dump tool, and learn a little about the ext4 Disk Layout. In particular, it starts with 1024 bytes of padding, which ext4 ignores. Next comes the superblock. You can recognize the superblock by checking for the magic number 0xEF53 at offset 0x38 (from the superblock start, or 0x438 from the partition start, or 1080 in decimal.) The magic number is little-endian. So it's actually stored on disk as 0x53EF.
Here is what that looks like with xxd -a
:
0000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
*
0000400: 0040 5d00 0084 7401 33a0 1200 33db a600 .@]...t.3...3...
0000410: 4963 5300 0000 0000 0200 0000 0200 0000 IcS.............
0000420: 0080 0000 0080 0000 0020 0000 6637 0952 ......... ..f7.R
0000430: 6637 0952 0200 1600 53ef 0100 0100 0000 f7.R....S.......
0000440: 9938 f851 004e ed00 0000 0000 0100 0000 .8.Q.N..........
Note, that when you give the offset to mount (or losetup), you must give the offset to where the padding starts—not the superblock.
Now, if its not the first partition, or otherwise isn't in one of the two (three) expected spots, you basically get to search for the magic number 0xEF53. This is what testdisk
(recommended in a comment) does for you.
Based on @derobert's answer, I wrote a program (gist) that will parse an input stream from dd
and scan each sector for something that looks like the start of an ext partition.
It will work at least as fast as dd
can read from your hard disk. An abridged version is below.
The simplest usage is just sudo dd if=/dev/xxx | ext2scan
, although you will likely want to modify the dd
command to improve the block size or choose a region to search.
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main() {
unsigned char const MAGIC[2] = {0x53, 0xef};
unsigned char const ZEROS[512] = {0};
long long int sector = 0;
char buf[4][512];
int empty1, empty2;
while (read(STDIN_FILENO, buf[sector&3], 512) > 0) {
if (!memcmp(buf[sector&3] + 0x38, MAGIC, 2)) {
printf("Found a possible ext2 partition at sector %lld", sector-2);
empty1 = !memcmp(buf[(sector-2)&3], ZEROS, 512);
empty2 = !memcmp(buf[(sector-1)&3], ZEROS, 512);
if (empty1 && empty2) printf(" (first two sectors are empty :)\n");
}
sector++;
}
}
Note: it will find not just the start of partitions, but also superblocks within them.
In either case, I would recommend using dumpe2fs
to analyse the results. You can dump the start of the suspected superblock to a file (at least the first six sectors, according to my informal test), and if it is a superblock, then dumpe2fs
will tell you (among other things) the relative locations of the other superblocks.
Make a guess as to where the partition starts and apply some brute force:
bsz=512 # or 1024, 2048, 4096 higher = faster
for i in {2..10000000}; do
echo "--->$i<---"
mount -o offset=$(($bsz*$i)) -t ext4 /dev/whatever /mnt/foo
if [ $? == 0 ]; then # whahoo!
echo Eureka
break
fi
done
I imagine this could take some time, but if you've already spent 6 hours with testdisk, maybe it is worth a try.