Skip to content

Instantly share code, notes, and snippets.

@giannitedesco
Created February 26, 2013 17:02
Show Gist options
  • Save giannitedesco/5040131 to your computer and use it in GitHub Desktop.
Save giannitedesco/5040131 to your computer and use it in GitHub Desktop.
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "vdisk.h"
#include "partition.h"
#include "fat32-format.h"
#include "fat32.h"
#if 1
#define dprintf printf
#else
#define dprintf(x...) do {}while(0);
#endif
struct _fat32 {
partition_t fs_part;
uint32_t *fs_fat0;
uint32_t *fs_fat1;
#if DUMP_SLACK
uint32_t *visited;
#endif
uint32_t fat_begin;
uint32_t cluster_begin;
uint32_t sectors_per_cluster;
uint32_t root_dir;
uint32_t num_clusters;
};
// cluster_begin + (cluster_number - 2) * sectors_per_cluster
static int read_cluster(struct _fat32 *fs, void *buf, uint32_t cluster)
{
//printf(" - reading cluster %u\n", cluster);
if ( cluster < 2 )
return 0;
#if DUMP_SLACK
if ( cluster < fs->num_clusters )
fs->visited[cluster] = 1;
#endif
return part_read_sectors(fs->fs_part, buf,
fs->cluster_begin + (cluster - 2) * fs->sectors_per_cluster,
fs->sectors_per_cluster);
}
static uint32_t get_next_cluster(struct _fat32 *fs, uint32_t cluster)
{
//printf(" - next cluster for %u is 0x%.8x\n",
// cluster, fs->fs_fat0[cluster]);
if ( cluster >= fs->num_clusters ) {
printf("Attempt to access beyond end of MFT\n");
return ~0;
}
if ( fs->fs_fat0[cluster] != fs->fs_fat1[cluster] )
printf(" -- FAT1 disagrees 0x%.8x\n", fs->fs_fat1[cluster]);
return fs->fs_fat0[cluster];
}
static int read_file(struct _fat32 *fs, const char *fn,
uint32_t size, uint32_t cluster)
{
uint8_t buf[SECTOR_SIZE * fs->sectors_per_cluster];
uint32_t last_cluster;
char outfn[256];
FILE *out;
printf("%s %u bytes @ 0x%x\n",
fn, size, cluster);
snprintf(outfn, sizeof(outfn), "./dump/%s", fn);
out = fopen(outfn, "w");
if ( NULL == out )
return 0;
again:
do {
size_t sz;
if ( !size )
break;
last_cluster = cluster;
if ( !read_cluster(fs, buf, cluster) ) {
printf("ugh\n");
return 0;
}
sz = (size < sizeof(buf)) ? size : sizeof(buf);
fwrite(buf, 1, sz, out);
size -= sz;
#if 0
if ( !sz )
hex_dump(buf, sizeof(buf), 0);
else if ( sz < sizeof(buf) )
hex_dump(buf + sz, sizeof(buf) - sz, 0);
#endif
cluster = get_next_cluster(fs, cluster);
}while( cluster >= 2 && cluster < 0x0ffffff8 );
if ( size ) {
//printf("ARGH! %u bytes unread\n", size);
/* just assume its in the next cluster */
cluster = last_cluster + 1;
goto again;
}
fclose(out);
return 1;
}
static int read_dir(struct _fat32 *fs, uint32_t cluster)
{
unsigned int num_dirent = (SECTOR_SIZE * fs->sectors_per_cluster) /
sizeof(struct fat32_dirent);
struct fat32_dirent dir[num_dirent];
unsigned int i, eof = 0;
do {
if ( !read_cluster(fs, dir, cluster) )
return 0;
for(i = 0; i < num_dirent; i++) {
uint32_t fclus;
char fn[13];
if ( dir[i].short_name[0] == 0 ) {
eof = 1;
continue;
}
if ( eof )
printf("hidden pat EOD: ");
if ( (dir[i].attrib & 0xf) == 0xf ) {
printf("extended filename:\n");
hex_dump((uint8_t *)(dir + i),
sizeof(dir[0]), 0);
continue;
}
if ( dir[i].short_name[0] == 0xe5 )
dir[i].short_name[0] = '+';
snprintf(fn, sizeof(fn), "%.8s.%.3s",
dir[i].short_name,
dir[i].short_name + 8);
if ( dir[i].attrib & FAT32_ATTR_DIR ) {
printf("DIR ");
}
fclus = dir[i].cluster_hi << 16;
fclus |= dir[i].cluster_lo;
read_file(fs, fn, dir[i].size, fclus);
}
cluster = get_next_cluster(fs, cluster);
}while( cluster >= 2 && cluster < 0x0fffffff );
return 1;
}
fat32_t fat32_open(partition_t part)
{
struct _fat32 *fs = NULL;
struct fat32_hdr hdr;
#if DUMP_SLACK
unsigned int i;
#endif
fs = calloc(1, sizeof(*fs));
if ( NULL == fs )
goto out;
if ( !part_read_sectors(part, &hdr, 0, 1) )
goto out_free;
printf(" - oem_name=%.*s, vol_label=%.*s, fs_label=%.*s\n",
(int)sizeof(hdr.oem_name), hdr.oem_name,
(int)sizeof(hdr.vol_label), hdr.vol_label,
(int)sizeof(hdr.fs_label), hdr.fs_label);
printf(" - %u sectors per cluster\n", hdr.sec_per_clus);
printf(" - root dir on cluster %u\n", hdr.root_dir_cluster);
printf(" - tot_sec=%u, fat_sz=%u\n", hdr.tot_sec32, hdr.fat_sz32);
printf(" - %u reserved sectors, %u FATs\n",
hdr.reserved_sec, hdr.num_fat);
printf("boot code:\n");
hex_dump(hdr._pad2, sizeof(hdr._pad2), 0);
fs->fs_part = part;
fs->fat_begin = hdr.reserved_sec;
fs->cluster_begin = fs->fat_begin + (hdr.num_fat * hdr.fat_sz32);
fs->sectors_per_cluster = hdr.sec_per_clus;
fs->root_dir = hdr.root_dir_cluster;
fs->fs_fat0 = malloc(hdr.fat_sz32 * SECTOR_SIZE);
if ( NULL == fs->fs_fat0 )
goto out_free;
if ( !part_read_sectors(fs->fs_part, fs->fs_fat0,
fs->fat_begin,
hdr.fat_sz32) )
goto out_free_fat0;
fs->fs_fat1 = malloc(hdr.fat_sz32 * SECTOR_SIZE);
if ( NULL == fs->fs_fat1 )
goto out_free;
if ( !part_read_sectors(fs->fs_part, fs->fs_fat1,
fs->fat_begin + hdr.fat_sz32,
hdr.fat_sz32) )
goto out_free_fat0;
fs->num_clusters = hdr.fat_sz32 * (SECTOR_SIZE / sizeof(uint32_t));
do {
uint8_t buf[SECTOR_SIZE * (hdr.reserved_sec - 1)];
part_read_sectors(fs->fs_part, buf, 1, hdr.reserved_sec - 1);
printf("Reserved sectors:\n");
hex_dump(buf, sizeof(buf), 0);
}while(0);
#if DUMP_SLACK
fs->visited = calloc(fs->num_clusters, SECTOR_SIZE);
if ( NULL == fs->visited)
goto out_free_fat1;
#endif
read_dir(fs, fs->root_dir);
#if DUMP_SLACK
for(i = 0; i < hdr.fat_sz32; i++) {
uint8_t buf[SECTOR_SIZE * fs->sectors_per_cluster];
unsigned int j, interesting, visited;
char fn[64];
FILE *out;
visited = fs->visited[i];
if ( !read_cluster(fs, buf, i) ) {
continue;
}
for(interesting = j = 0; j < sizeof(buf); j++) {
if ( buf[j] != 0 ) {
interesting = 1;
break;
}
}
if ( !interesting )
continue;
snprintf(fn, sizeof(fn), "clusters/cluster%.8x-%s.bin",
i, (visited) ? "live" : "dead");
//printf("writing %s\n", fn);
out = fopen(fn, "w");
fwrite(buf, 1, sizeof(buf), out);
fclose(out);
}
#endif
/* success */
goto out;
#if DUMP_SLACK
out_free_fat1:
free(fs->fs_fat1);
#endif
out_free_fat0:
free(fs->fs_fat0);
out_free:
free(fs);
fs = NULL;
out:
return fs;
}
void fat32_close(fat32_t fs)
{
if ( fs ) {
free(fs->fs_fat1);
free(fs->fs_fat0);
free(fs);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment