Skip to content

Instantly share code, notes, and snippets.

@iscle
Created November 7, 2025 20:14
Show Gist options
  • Select an option

  • Save iscle/83044319e7a66df26547024a07732440 to your computer and use it in GitHub Desktop.

Select an option

Save iscle/83044319e7a66df26547024a07732440 to your computer and use it in GitHub Desktop.
/*
* GFH Header Parser and Payload Extractor
* Based on MediaTek BootROM GFH (Generic File Header) format
*
* This program opens a file with 0x014d4d4d header, displays its information,
* and dumps the payload to a file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
/* GFH Header definitions (all fields are little-endian) */
#define GFH_HEADER_MAGIC 0x4D4D4D
#define GFH_HEADER_VERSION_SHIFT 24
#define GFH_HEADER_MAGIC_VERSION 0x014d4d4d /* Version 1, Magic 0x4D4D4D */
#define GFH_TYPE_FILE_INFO 0
#define GFH_TYPE_BL_INFO 1
#define GFH_TYPE_BROM_CFG 7
#define GFH_TYPE_BL_SEC_KEY 3
#define GFH_TYPE_ANTI_CLONE 2
#define GFH_TYPE_BROM_SEC_CFG 8
#define GFH_FILE_INFO_NAME "FILE_INFO"
#define GFH_FLASH_TYPE_GEN 5
#define GFH_FLASH_TYPE_NAND 2
#define GFH_SIG_TYPE_NONE 0
#define GFH_SIG_TYPE_SHA256 1
#define SHA256_SUM_LEN 32
struct gfh_common_header {
uint32_t magic_version;
uint16_t size;
uint16_t type;
} __attribute__((packed));
struct gfh_file_info {
struct gfh_common_header gfh;
char name[12];
uint32_t unused;
uint16_t file_type;
uint8_t flash_type;
uint8_t sig_type;
uint32_t load_addr;
uint32_t total_size;
uint32_t max_size;
uint32_t hdr_size;
uint32_t sig_size;
uint32_t jump_offset;
uint32_t processed;
} __attribute__((packed));
/* Helper functions for little-endian conversion */
static inline uint16_t le16_to_cpu(uint16_t val)
{
return val;
}
static inline uint32_t le32_to_cpu(uint32_t val)
{
return val;
}
/* Find GFH header in the file */
static off_t find_gfh_header(const uint8_t *data, size_t size)
{
size_t i;
/* Search for GFH magic (0x014d4d4d) */
for (i = 0; i < size - sizeof(struct gfh_common_header); i++) {
uint32_t magic = *(uint32_t *)(data + i);
if (magic == GFH_HEADER_MAGIC_VERSION) {
return (off_t)i;
}
}
return -1;
}
/* Extract and display GFH information */
static int parse_gfh_header(const uint8_t *data, size_t file_size, off_t gfh_offset)
{
const struct gfh_file_info *file_info;
uint32_t magic_version, version, magic;
uint16_t size, type;
uint32_t load_addr, total_size, hdr_size, sig_size;
uint8_t flash_type, sig_type;
char flash_type_str[32];
file_info = (const struct gfh_file_info *)(data + gfh_offset);
/* Parse common header */
magic_version = le32_to_cpu(file_info->gfh.magic_version);
version = (magic_version >> GFH_HEADER_VERSION_SHIFT) & 0xFF;
magic = magic_version & 0xFFFFFF;
size = le16_to_cpu(file_info->gfh.size);
type = le16_to_cpu(file_info->gfh.type);
printf("=== GFH Header Information ===\n");
printf("Magic Version: 0x%08x\n", magic_version);
printf(" Version: %u\n", version);
printf(" Magic: 0x%06x\n", magic);
printf("Header Size: %u bytes\n", size);
printf("Header Type: %u", type);
if (type == GFH_TYPE_FILE_INFO)
printf(" (FILE_INFO)");
else if (type == GFH_TYPE_BL_INFO)
printf(" (BL_INFO)");
else if (type == GFH_TYPE_BROM_CFG)
printf(" (BROM_CFG)");
printf("\n");
/* Verify it's a FILE_INFO header */
if (type != GFH_TYPE_FILE_INFO) {
fprintf(stderr, "Error: Expected FILE_INFO header (type 0), got type %u\n", type);
return -1;
}
/* Verify name */
if (strncmp(file_info->name, GFH_FILE_INFO_NAME, sizeof(file_info->name)) != 0) {
fprintf(stderr, "Warning: Name mismatch. Expected '%s', got '%.12s'\n",
GFH_FILE_INFO_NAME, file_info->name);
}
/* Parse file info */
flash_type = file_info->flash_type;
sig_type = file_info->sig_type;
load_addr = le32_to_cpu(file_info->load_addr);
total_size = le32_to_cpu(file_info->total_size);
hdr_size = le32_to_cpu(file_info->hdr_size);
sig_size = le32_to_cpu(file_info->sig_size);
if (flash_type == GFH_FLASH_TYPE_GEN)
strcpy(flash_type_str, "Generic (NOR/SD/eMMC)");
else if (flash_type == GFH_FLASH_TYPE_NAND)
strcpy(flash_type_str, "NAND");
else
snprintf(flash_type_str, sizeof(flash_type_str), "Unknown (0x%02x)", flash_type);
printf("\n=== File Information ===\n");
printf("Name: %.12s\n", file_info->name);
printf("File Type: %u\n", le16_to_cpu(file_info->file_type));
printf("Flash Type: %s\n", flash_type_str);
printf("Signature Type: ");
if (sig_type == GFH_SIG_TYPE_NONE)
printf("None\n");
else if (sig_type == GFH_SIG_TYPE_SHA256)
printf("SHA256\n");
else
printf("Unknown (0x%02x)\n", sig_type);
printf("Load Address: 0x%08x\n", load_addr);
printf("Total Size: %u bytes (0x%x)\n", total_size, total_size);
printf("Header Size: %u bytes (0x%x)\n", hdr_size, hdr_size);
printf("Signature Size: %u bytes\n", sig_size);
printf("Jump Offset: 0x%08x\n", le32_to_cpu(file_info->jump_offset));
printf("Processed: %u\n", le32_to_cpu(file_info->processed));
return 0;
}
/* Extract payload to file */
static int extract_payload(const uint8_t *data, size_t file_size, off_t gfh_offset,
const char *output_file)
{
const struct gfh_file_info *file_info;
FILE *out_fp;
off_t payload_offset;
size_t payload_size;
size_t written;
file_info = (const struct gfh_file_info *)(data + gfh_offset);
/* Calculate payload offset and size */
payload_offset = gfh_offset + le32_to_cpu(file_info->hdr_size);
payload_size = le32_to_cpu(file_info->total_size);
/* Subtract signature size if present */
if (file_info->sig_type == GFH_SIG_TYPE_SHA256) {
uint32_t sig_size = le32_to_cpu(file_info->sig_size);
if (payload_size >= sig_size)
payload_size -= sig_size;
}
/* Check bounds */
if (payload_offset + payload_size > file_size) {
fprintf(stderr, "Error: Payload extends beyond file size\n");
fprintf(stderr, " Payload offset: 0x%lx\n", (unsigned long)payload_offset);
fprintf(stderr, " Payload size: %zu bytes\n", payload_size);
fprintf(stderr, " File size: %zu bytes\n", file_size);
return -1;
}
/* Open output file */
out_fp = fopen(output_file, "wb");
if (!out_fp) {
fprintf(stderr, "Error: Cannot open output file '%s': %s\n",
output_file, strerror(errno));
return -1;
}
/* Write payload */
written = fwrite(data + payload_offset, 1, payload_size, out_fp);
if (written != payload_size) {
fprintf(stderr, "Error: Failed to write payload: %s\n", strerror(errno));
fclose(out_fp);
return -1;
}
fclose(out_fp);
printf("\n=== Payload Extraction ===\n");
printf("Payload Offset: 0x%lx\n", (unsigned long)payload_offset);
printf("Payload Size: %zu bytes\n", payload_size);
printf("Output File: %s\n", output_file);
printf("Extraction: Success\n");
return 0;
}
static void usage(const char *progname)
{
fprintf(stderr, "Usage: %s <input_file> [output_file]\n", progname);
fprintf(stderr, "\n");
fprintf(stderr, " input_file - File containing GFH header (0x014d4d4d)\n");
fprintf(stderr, " output_file - Output file for payload (default: payload.bin)\n");
fprintf(stderr, "\n");
}
int main(int argc, char **argv)
{
const char *input_file, *output_file;
FILE *fp;
uint8_t *data;
struct stat st;
size_t file_size;
off_t gfh_offset;
int ret = 0;
if (argc < 2) {
usage(argv[0]);
return 1;
}
input_file = argv[1];
output_file = (argc >= 3) ? argv[2] : "payload.bin";
/* Open input file */
fp = fopen(input_file, "rb");
if (!fp) {
fprintf(stderr, "Error: Cannot open input file '%s': %s\n",
input_file, strerror(errno));
return 1;
}
/* Get file size */
if (fstat(fileno(fp), &st) < 0) {
fprintf(stderr, "Error: Cannot stat file '%s': %s\n",
input_file, strerror(errno));
fclose(fp);
return 1;
}
file_size = st.st_size;
if (file_size == 0) {
fprintf(stderr, "Error: Input file is empty\n");
fclose(fp);
return 1;
}
/* Read entire file into memory */
data = malloc(file_size);
if (!data) {
fprintf(stderr, "Error: Cannot allocate memory: %s\n", strerror(errno));
fclose(fp);
return 1;
}
if (fread(data, 1, file_size, fp) != file_size) {
fprintf(stderr, "Error: Failed to read file: %s\n", strerror(errno));
free(data);
fclose(fp);
return 1;
}
fclose(fp);
/* Find GFH header */
gfh_offset = find_gfh_header(data, file_size);
if (gfh_offset < 0) {
fprintf(stderr, "Error: GFH header (0x014d4d4d) not found in file\n");
free(data);
return 1;
}
printf("GFH header found at offset: 0x%lx\n\n", (unsigned long)gfh_offset);
/* Parse and display header information */
if (parse_gfh_header(data, file_size, gfh_offset) < 0) {
free(data);
return 1;
}
/* Extract payload */
if (extract_payload(data, file_size, gfh_offset, output_file) < 0) {
ret = 1;
}
free(data);
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment