Created
July 1, 2021 13:30
-
-
Save nikp123/ba10946f6bf13a107c216d3491a7355a to your computer and use it in GitHub Desktop.
MBR partitioned disk parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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