DF-5755 / dump5755.c
/* DF-5755 โ scan the raw FAT image for the UTF-16LE (LFN) encodings that the * kernel wrote for our overlong-UTF-8 filenames. Proves the synthesized * characters landed in on-disk directory metadata. */ #include <sys/types.h> #include <err.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> struct pat { const char *label; const unsigned char bytes[32]; size_t len; }; /* UTF-16LE encodings, as written by unix2winfn() (low byte first). * LFN entries hold 5 units in wePart1, 6 in wePart2, 2 in wePart3 โ * long names are split, so search per-part as well as whole. */ static struct pat pats[] = { { "OV/S3 LFN part1 (O V / S 3) [units 0-4, wePart1]", { 0x4f,0x00,0x56,0x00,0x2f,0x00,0x53,0x00,0x33,0x00 }, 10 }, { "OV/SLASH LFN part1 (O V / S L) [units 0-4, wePart1]", { 0x4f,0x00,0x56,0x00,0x2f,0x00,0x53,0x00,0x4c,0x00 }, 10 }, { "OV/SLASH LFN part2 (A S H NUL) [units 5-8, wePart2]", { 0x41,0x00,0x53,0x00,0x48,0x00,0x00,0x00 }, 8 }, { "OV.DOT LFN part1 (O V . D O) [units 0-4, wePart1]", { 0x4f,0x00,0x56,0x00,0x2e,0x00,0x44,0x00,0x4f,0x00 }, 10 }, { "OV.DOT LFN part2 (T NUL) [unit 5, wePart2]", { 0x54,0x00,0x00,0x00 }, 4 }, { "8.3 alias 'OV/SLASH ' (raw '/' in short entry)", { 'O','V','/','S','L','A','S','H',' ',' ',' ' }, 11 }, { "8.3 alias 'OV/S3 ' (raw '/' in short entry)", { 'O','V','/','S','3',' ',' ',' ',' ',' ',' ' }, 11 }, { NULL, { 0 }, 0 } }; int main(int argc, char **argv) { unsigned char *buf; ssize_t n; size_t sz, i; int fd, p, found_any = 0; if (argc != 2) errx(1, "usage: %s <image>", argv[0]); fd = open(argv[1], O_RDONLY); if (fd < 0) err(1, "open %s", argv[1]); sz = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); buf = malloc(sz); if (!buf) err(1, "malloc"); n = read(fd, buf, sz); if (n < 0 || (size_t)n != sz) err(1, "read"); close(fd); for (p = 0; pats[p].label; p++) { int hits = 0; for (i = 0; i + pats[p].len <= sz; i++) { if (memcmp(buf + i, pats[p].bytes, pats[p].len) == 0) { size_t j, st = i >= 16 ? i - 16 : 0; size_t en = i + pats[p].len + 16; printf("[FOUND] %s at file offset 0x%zx:\n", pats[p].label, i); printf(" context (from 0x%zx): ", st); for (j = st; j < en && j < sz; j++) printf("%02x ", buf[j]); printf("\n"); /* LFN entry header: seq at i-1 (wePart starts * at entry+1), attr 0x0F at entry+11 */ if (i >= 1) { unsigned char seq = buf[i - 1]; printf(" LFN seq=0x%02x ", seq); if (i + 10 <= sz) printf("attr@+11=0x%02x\n", buf[i + 10]); else printf("\n"); } hits++; found_any = 1; /* skip ahead to avoid duplicate overlaps */ i += pats[p].len - 1; } } if (!hits) printf("[absent] %s โ pattern NOT in image\n", pats[p].label); } free(buf); return found_any ? 0 : 2; } |