/* $Id: fat.c,v 1.3 2012/08/25 00:18:24 khorben Exp $ */ /* Copyright (c) 2007 khorben of Uberwall */ /* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "plugin.h" /* fat */ /* public */ /* types */ #pragma pack(1) struct fat_boot { uint8_t jmp[3]; /* magic boot code */ char oem[8]; /* OEM information */ uint16_t bps; /* bytes per sector */ uint8_t spc; /* sectors per cluster */ uint16_t ress; /* reserved sectors */ uint8_t fatcnt; /* number of FAT tables */ uint16_t rootcnt; /* FAT12 and FAT16 directory entries */ uint16_t sec16; /* 16-bits count of sectors */ uint8_t media; /* media type */ uint16_t fat16; /* 16-bits count of sectors per FAT */ uint16_t spt; /* sectors per track */ uint16_t headcnt; /* number of heads */ uint32_t hiddencnt; /* number of hidden sectors */ uint32_t sec32; /* 32-bits count of sectors */ }; struct fat_boot16 { uint8_t drive; char _padding1; uint8_t signature; uint32_t id; char label[11]; char type[8]; }; struct fat_boot32 { uint32_t fat32; uint16_t flags; uint16_t ver; uint32_t root; uint16_t fsinfo; uint16_t bootsec; char _padding0[12]; uint8_t drvnum; char _padding1; uint8_t bootsig; uint32_t id; char label[11]; char type[8]; }; #pragma pack() /* variables */ /* magic */ static unsigned char oemwin[] = "MSWIN4.1"; static unsigned char oemdos[] = "MSDOS5.0"; static unsigned char volname[] = "NO NAME "; static unsigned char type16[] = "FAT16 "; static unsigned char type32[] = "FAT32 "; static unsigned char type[] = "FAT"; static unsigned char boot[] = "\x55\xaa"; static unsigned char lead32[] = "\x41\x61\x52\x52"; static unsigned char sig32[] = "\x61\x41\x72\x72"; static PluginMagic fat_magic[] = { { 512, 3, oemwin, sizeof(oemwin)-1 }, { 512, 3, oemdos, sizeof(oemdos)-1 }, { 512, 43, volname, sizeof(volname)-1 }, { 512, 54, type16, sizeof(type16)-1 }, { 512, 71, volname, sizeof(volname)-1 }, { 512, 82, type32, sizeof(type32)-1 }, { 512, 54, type, sizeof(type)-1 }, { 512, 510, boot, sizeof(boot)-1 }, { 512, 0, lead32, sizeof(lead32)-1 }, { 512, 484, sig32, sizeof(sig32)-1 }, { 0, 0, NULL, 0 } }; /* functions */ static int fat_callback(PluginHelper * ph, int signature, FILE * fp); /* plugin */ Plugin plugin = { PT_ARCHIVE | PT_EXECUTABLE, "FAT", fat_magic, fat_callback }; /* private */ /* functions */ /* fat_callback */ static void _callback_endian(struct fat_boot * fb); static void _callback_endian32(struct fat_boot32 * fb32); static int _callback_jmp(PluginHelper * ph, struct fat_boot * fb); static int _callback_bps(PluginHelper * ph, struct fat_boot * fb); static int _callback_spc(PluginHelper * ph, struct fat_boot * fb); static int fat_callback(PluginHelper * ph, int signature, FILE * fp) { int score = 0; struct fat_boot fb; struct fat_boot32 fb32; char buf[512]; size_t i; /* FIXME not all signatures match the boot sector */ if(fread(&fb, sizeof(fb), 1, fp) != 1) return -1; _callback_endian(&fb); score += _callback_jmp(ph, &fb); strncpy(buf, fb.oem, sizeof(fb.oem)); for(i = 0; i < sizeof(fb.oem) && buf[i] != '\0'; i++); buf[i] = '\0'; ph->printf(ph, "%s%s%s", ", oem \"", buf, "\""); score += _callback_bps(ph, &fb); score += _callback_spc(ph, &fb); if(fb.ress != 0) score += 100; if(fb.fatcnt == 2 || fb.fatcnt == 1) score += 100; if(fb.rootcnt == 0) score += 100; /* only for FAT32 */ else if(fb.bps != 0 && fb.rootcnt * 32 % fb.bps == 0) score += 100; /* only for FAT12 or FAT16 */ if((fb.sec16 == 0 && fb.sec32 != 0) || (fb.sec16 != 0 && fb.sec32 == 0)) score += 100; if(fb.media >= 0xf0) score += 100; if(fb.bps != 0 && fb.spc != 0) { if(fb.fat16 != 0 && fb.sec16 != 0 && fb.sec32 == 0) { i = (fb.sec16 - fb.ress - (fb.fatcnt * fb.fat16) - (((fb.rootcnt * 32) + fb.bps - 1) / fb.bps)) / fb.spc; if(i < 4085) { ph->printf(ph, "%s%u%s", ", FAT12 with ", i, " clusters"); score+=100; } else if(i < 65525) { ph->printf(ph, "%s%u%s", ", FAT16 with ", i, " clusters"); score += 100; } else ph->printf(ph, "%s", " illegal FAT12 or FAT16"); } else if(fb.fat16 == 0 && fb.sec16 == 0 && fb.sec32 != 0 && fread(&fb32, sizeof(fb32), 1, fp) == 1 && fb32.fat32 != 0) { _callback_endian32(&fb32); ph->printf(ph, "%s", ", FAT32"); i = (fb.sec32 - fb.ress - (fb.fatcnt * fb32.fat32) - (((fb.rootcnt * 32) + fb.bps - 1) / fb.bps)) / fb.spc; ph->printf(ph, "%s%u%s", " with ", i, " clusters"); if(i >= 65525) score += 100; else ph->printf(ph, "%s", " (illegal)"); ph->printf(ph, ", ID 0x%08x", fb32.id); /* label */ strncpy(buf, fb32.label, sizeof(fb32.label)); buf[sizeof(fb32.label)] = '\0'; ph->printf(ph, ", label \"%s\"", buf); /* type */ strncpy(buf, fb32.type, sizeof(fb32.type)); buf[sizeof(fb32.type)] = '\0'; ph->printf(ph, ", type \"%s\"", buf); } else ph->printf(ph, "%s", ", illegal FAT"); } ph->printf(ph, "%s", "\n"); return score / 9; } static void _callback_endian(struct fat_boot * fb) { fb->bps = htol16(fb->bps); fb->ress = htol16(fb->ress); fb->rootcnt = htol16(fb->rootcnt); fb->sec16 = htol16(fb->sec16); fb->fat16 = htol16(fb->fat16); fb->spt = htol16(fb->spt); fb->headcnt = htol16(fb->headcnt); fb->hiddencnt = htol32(fb->hiddencnt); fb->sec32 = htol32(fb->sec32); } static void _callback_endian32(struct fat_boot32 * fb32) { fb32->fat32 = htol32(fb32->fat32); fb32->flags = htol16(fb32->flags); fb32->ver = htol16(fb32->ver); fb32->root = htol32(fb32->root); fb32->fsinfo = htol16(fb32->fsinfo); fb32->bootsec = htol16(fb32->bootsec); fb32->id = htol32(fb32->id); } static int _callback_jmp(PluginHelper * ph, struct fat_boot * fb) { if((fb->jmp[0] == 0xeb && fb->jmp[2] == 0x90) || fb->jmp[0] == 0xe9) { ph->printf(ph, "%s", "correct boot code"); return 100; } ph->printf(ph, "%s", "incorrect boot code"); return 0; } static int _callback_bps(PluginHelper * ph, struct fat_boot * fb) { if(fb->bps == 512 || fb->bps == 1024 || fb->bps == 2048 || fb->bps == 4096) { ph->printf(ph, "%s%u%s", ", ", fb->bps, " bytes/sector"); return 100; } ph->printf(ph, "%s", ", illegal bytes/sector"); return 0; } static int _callback_spc(PluginHelper * ph, struct fat_boot * fb) { if(fb->spc == 1 || fb->spc == 2 || fb->spc == 4 || fb->spc == 8 || fb->spc == 16 || fb->spc == 32 || fb->spc == 64 || fb->spc == 128) { ph->printf(ph, "%s%u%s", ", ", fb->spc, " sectors/cluster"); return 100; } ph->printf(ph, "%s", ", illegal sectors/cluster"); return 0; }