Skip to content

Instantly share code, notes, and snippets.

@nikp123
Created July 1, 2021 13:30
Show Gist options
  • Save nikp123/ba10946f6bf13a107c216d3491a7355a to your computer and use it in GitHub Desktop.
Save nikp123/ba10946f6bf13a107c216d3491a7355a to your computer and use it in GitHub Desktop.
MBR partitioned disk parser
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <sys/types.h>
#include <math.h>
#define MAX_PATH 255
#define PARTITION_IS_BOOTABLE 0x80
#define EXTENDED_PARTITION_TYPE 0x05
typedef struct partition_raw {
u_int8_t boot_indicator;
u_int8_t starting_head;
u_int16_t starting_sector_cylinder; // combined
u_int8_t system_id;
u_int8_t ending_head;
u_int16_t ending_sector_cylinder; // combined
u_int32_t relative_sector;
u_int32_t total_sectors;
} partition_raw;
typedef struct partition {
u_int8_t boot_indicator;
u_int8_t starting_head;
u_int8_t starting_sector; // 6 bits
u_int16_t starting_cylinder; // 10 bits
u_int8_t system_id;
u_int8_t ending_head;
u_int8_t ending_sector; // 6 bits
u_int16_t ending_cylinder; // 10 bits
u_int32_t relative_sector;
u_int32_t total_sectors;
} partition;
typedef struct extended_partition extended_partition;
struct extended_partition {
partition real;
partition link;
extended_partition *next;
};
u_int32_t partition_counter;
void remap_partition_data(partition_raw *raw, partition *par) {
par->boot_indicator = raw->boot_indicator;
par->starting_head = raw->starting_head;
par->starting_sector = (raw->starting_sector_cylinder&0xfc00)>>10;
par->starting_cylinder = (raw->starting_sector_cylinder&0x3ff);
par->system_id = raw->system_id;
par->ending_head = raw->ending_head;
par->ending_sector = (raw->ending_sector_cylinder&0xfc00)>>10;
par->ending_cylinder = (raw->ending_sector_cylinder&0x3ff);
par->relative_sector = raw->relative_sector;
par->total_sectors = raw->total_sectors-1;
}
void read_primary_partitions(partition par[4], FILE *fp) {
partition_raw raw_par;
fseek(fp, 0x01BE, SEEK_SET);
fread(&raw_par, sizeof(partition_raw), 1, fp);
remap_partition_data(&raw_par, &par[0]);
fseek(fp, 0x01CE, SEEK_SET);
fread(&raw_par, sizeof(partition_raw), 1, fp);
remap_partition_data(&raw_par, &par[1]);
fseek(fp, 0x01DE, SEEK_SET);
fread(&raw_par, sizeof(partition_raw), 1, fp);
remap_partition_data(&raw_par, &par[2]);
fseek(fp, 0x01EE, SEEK_SET);
fread(&raw_par, sizeof(partition_raw), 1, fp);
remap_partition_data(&raw_par, &par[3]);
}
void print_partition_info(partition par) {
if(par.boot_indicator == PARTITION_IS_BOOTABLE) {
printf("[*]");
} else printf(" ");
if(par.total_sectors == 0) {
printf(" 0.00 B ");
} else {
int size_base = (log2(par.total_sectors)+9)/10;
switch(size_base) {
case 0:
printf(" % 4d.00 B ", par.total_sectors*512);
break;
case 1:
printf("% 8.2fKiB ", par.total_sectors/2.0);
break;
case 2:
printf("% 8.2fMiB ", par.total_sectors/(2048.0));
break;
case 3:
printf("% 8.2fGiB ", par.total_sectors/(2048.0*1024.0));
break;
default:
printf("% 8.2ftoo ", par.total_sectors/(2048.0*1024.0));
break;
}
}
printf("% 11d -> % 11d ", par.relative_sector, par.relative_sector+par.total_sectors);
printf("[%02hhx]\n", par.system_id);
}
extended_partition *read_extended_partition(FILE *fp, partition par, u_int32_t offset) {
extended_partition *ext_par = malloc(sizeof(extended_partition));
partition_raw raw_par;
fseek(fp, par.relative_sector*512+0x01BE, SEEK_SET);
fread(&raw_par, sizeof(partition_raw), 1, fp);
remap_partition_data(&raw_par, &ext_par->real);
fseek(fp, par.relative_sector*512+0x01CE, SEEK_SET);
fread(&raw_par, sizeof(partition_raw), 1, fp);
remap_partition_data(&raw_par, &ext_par->link);
ext_par->real.relative_sector += par.relative_sector;
ext_par->link.relative_sector += offset;
if(ext_par->link.system_id != EXTENDED_PARTITION_TYPE) {
ext_par->next = NULL;
} else {
ext_par->next = read_extended_partition(fp, ext_par->link, offset);
}
return ext_par;
}
void free_extended_partition(extended_partition *par) {
if(par->next != NULL)
free_extended_partition(par->next);
free(par);
}
void print_extended_partition_info(extended_partition *ext_par) {
partition_counter++;
printf("%3d ", partition_counter);
print_partition_info(ext_par->real);
printf("[L] ");
print_partition_info(ext_par->link);
if(ext_par->next != NULL)
print_extended_partition_info(ext_par->next);
}
int main(int argc, char *argv[]) {
char filename[MAX_PATH];
assert(argc > 1);
strncpy(filename, argv[1], MAX_PATH);
FILE *fp = fopen(filename, "rb");
assert(fp);
partition_counter = 4;
partition primary_partitions[4];
read_primary_partitions(primary_partitions, fp);
for(int i=0; i<4; i++) {
printf("%3d ", i+1);
print_partition_info(primary_partitions[i]);
if(primary_partitions[i].system_id == EXTENDED_PARTITION_TYPE) {
u_int32_t offset = primary_partitions[i].relative_sector;
extended_partition *ext_par = read_extended_partition(fp, primary_partitions[i], offset);
print_extended_partition_info(ext_par);
free_extended_partition(ext_par);
}
}
fclose(fp);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment