Hardware, dissected
You are not logged in.
This quick & dirty application decompiles Palm ROM files for Treo755p, Palm Emulator, et al.
Usage: lrom <path_to_rom_file>
It will create a bunch of individual files.
Somebody with a lot of spare time , please turn this it into a GUI ROM Customizer application.
lrom.h
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
/* ROM file chunk header */
typedef struct {
u32 length:24;
u8 padbytes:8;
u32 flags;
} ChunkHeader;
#pragma pack(push, 1)
typedef struct {
u32 datap;
u8 attr;
/* struct {
int delete : 1;
int dirty : 1;
int busy : 1;
int secret : 1;
int category : 4;
} attr; */
u8 uid[3];
} PDBRsrcHeader;
typedef struct {
u32 name;
u32 id;
u32 datap;
} PRCRsrcHeaderROM;
typedef struct {
u32 name;
u16 id; /*u32 in ROM */
u32 datap;
} PRCRsrcHeader;
typedef struct {
char name[32];
u16 flags;
u16 version;
u32 ctime;
u32 mtime;
u32 btime;
u32 modnum;
u32 ainfo;
u32 sinfo;
u32 type;
u32 id;
u32 idseed;
u32 nextrec;
u16 numrec;
} ROMPRCHeader;
typedef struct {
char sig[0x10]; /* ROM Store signature */
char unkn1[0x18]; /* all zeroes */
u32 heapptr; /* pointer to ROM=HEAP=DESCRIPTOR */
u32 num2; /* Points to data chunk w/no file header == 0x0 for Emulator images */
u32 num3; /* Points to small data chunk w/no file header, likely config info. == 0x0 for Emulator images */
u32 dirptr; /* pointer to filesystem directory */
char unkn2[0x18]; /* all zeroes */
u32 num5; /* Points to data chunk w/no file header */
u32 osdata; /* Pointer to contents of "PalmOS Data" file */
u32 num7;
char unkn3[0x08]; /* all zeroes */
u32 num8; /* Points to data chunk w/no file header */
char unkn4[0x88]; /* all zeroes */
u32 num9; /* Points to data chunk w/no file header. ARM boot? == 0x0 for Emulator images */
char unkn5[0x8]; /* all zeroes */
u32 unkn6; /* == 0xFFFFFFFF */
/* [ROM=HEAP=DESCRIPTOR] */
u32 heapid; /* == 0x00000001 */
u32 heapstart; /* pointer to ROM=HEAP=START */
u32 unkn9; /* == 0x0 */
/* [ROM=HEAP=START] ROM heap starts here */
u16 heapflags; /* == 2001 (ROM) */
u16 unkn10; /* == 0xFFFF */
u32 heapsize;
u32 num11;
u32 unkn11; /* == 0xFFFF0000 */
u32 unkn12; /* == 0x0 */
} ROMStoreHeader;
/* filesystem directory is in chunk 0
u32 unkn0 // == 0x00
u32 numfiles
u32 fileptr[numfiles]
*/
#pragma pack(pop)lrom.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include "lrom.h"
/* Rom base address, may need adjusting */
u32 ROMBASE;
/*=========================================================================*/
void die(char *msg){
printf("%s\n",msg);
exit(-1);
}
/*=========================================================================*/
u32 swap32(u32 i){
return ((i<<24)&0xFF000000) |
((i<<8) &0x00FF0000) |
((i>>8) &0x0000FF00) |
((i>>24)&0x000000FF);
}
u16 swap16(u16 i){
return ((i<<8)&0xFF00) |
((i>>8) &0x00FF);
}
/*=========================================================================*/
void PrintROMHeaderInfo(ROMStoreHeader *rhp){
printf("ROM Store Header, size=0x%X ----------------------\n",sizeof(ROMStoreHeader));
printf("\tHeapP:\t0x%08X\n",rhp->heapptr);
printf("\tNum2:\t0x%08X\n",rhp->num2);
printf("\tNum3:\t0x%08X\n",rhp->num3);
printf("\tDirPtr:\t0x%08X\n",rhp->dirptr);
printf("\tNum5:\t0x%08X\n",rhp->num5);
printf("\tOSData:\t0x%08X\n",rhp->osdata);
printf("\tNum7:\t0x%08X\n",rhp->num7);
printf("\tNum8:\t0x%08X\n",rhp->num8);
printf("\tNum9:\t0x%08X\n",rhp->num9);
printf("\tNum11:\t0x%08X\n",rhp->num11);
printf("\tHeapID:\t0x%08X\n",rhp->heapid);
printf("\tHStart:\t0x%08X\n",rhp->heapstart);
printf("\tHSize:\t0x%08X\n",rhp->heapsize);
printf("\tHFlags:\t0x%04X\n",rhp->heapflags);
}
/*=========================================================================*/
void PrintPRCHeaderInfo(ROMPRCHeader *ph){
printf("PRC Header, size=0x%X ----------------------\n",sizeof(ROMPRCHeader));
printf("\tName:\t%s\n",ph->name);
printf("\tFlags:\t0x%04X\n",ph->flags);
printf("\tVer:\t0x%04X\n",ph->version);
printf("\tCtime:\t0x%08X\n",ph->ctime);
printf("\tMtime:\t0x%08X\n",ph->mtime);
printf("\tBtime:\t0x%08X\n",ph->btime);
printf("\tModNum:\t0x%08X\n",ph->modnum);
printf("\tAinfo:\t0x%08X\n",ph->ainfo);
printf("\tSinfo:\t0x%08X\n",ph->sinfo);
printf("\tType:\t0x%08X\n",ph->type);
printf("\tId:\t0x%08X\n",ph->id);
printf("\tIdSeed:\t0x%08X\n",ph->idseed);
printf("\tNxtRec:\t0x%08X\n",ph->nextrec);
printf("\tNumRec:\t0x%04X\n",ph->numrec);
}
/*=========================================================================*/
void MakeFilenameSafe(u8 *name) {
u32 i=0;
u8 b;
while((b=name[i])!=0){
if ((b < '0') && (b!= '.')) name[i]='_';
if ((b > 'z') && (b!= '~')) name[i]='_';
if ((b > '9') && (b < 'A')) name[i]='_';
if ((b > 'Z') && (b < 'a')) name[i]='_';
i++;
}
}
/*=========================================================================*/
int UnpackFile(FILE *fh, u32 filep) {
ChunkHeader chdr;
ROMPRCHeader prch;
PRCRsrcHeader *rsrch=NULL;
PRCRsrcHeaderROM rsrchR;
PDBRsrcHeader *pdbh=NULL;
u32 datap;
u16 i,padbytes;
FILE *fw;
char wfname[256];
u32 file_offset;
u8 **dptr = NULL;
u32 *chunklen = NULL;
printf("Extracting file at:\t0x%08X\n",filep);
if (fseek(fh,filep-sizeof(ChunkHeader)-ROMBASE,SEEK_SET)!=0) { /* seek to PRC header */
printf("Cannot seek to file at %08X\n",filep-sizeof(ChunkHeader)-ROMBASE);
return -1;
}
if (fread(&chdr,1,sizeof(ChunkHeader),fh)!=sizeof(ChunkHeader)) {
printf("Cannot read chunk header\n");
return -1;
}
if ((chdr.padbytes>=chdr.length)||(chdr.padbytes>3)) {
printf("Invalid chunk header\n");
return -1;
}
if (fread(&prch,1,sizeof(prch),fh)!=sizeof(prch)) {
printf("Cannot read PRC header\n");
return -1;
}
/* Skip pad bytes */
if (chdr.padbytes >0) fseek(fh,chdr.padbytes,SEEK_CUR);
printf("***FileHdr: len=%06X, padbytes=%0d, flags=%08X %s\n",chdr.length,chdr.padbytes,chdr.flags,
(chdr.flags==0xF1000000)? "":"***WARNING***: Unexpected flags value");
PrintPRCHeaderInfo(&prch);
strncpy(wfname,prch.name,32);
strcat(wfname,(prch.flags &1) ? ".prc":".pdb");
MakeFilenameSafe(wfname); /* replace special characters */
if ((fw = fopen(wfname, "wb")) == NULL) {
printf("Cannot create file %s\n",wfname);
return -1;
}
file_offset=sizeof(ROMPRCHeader);
if (prch.flags &1) {
if ((rsrch=malloc(prch.numrec*sizeof(PRCRsrcHeader)))==NULL) { /* resource headers list */
printf("Cannot allocate memory for rsrs headers\n");
return -1;
}
for (i=0;i<prch.numrec;i++) {
if (fread(&rsrchR,1,sizeof(PRCRsrcHeaderROM),fh)!=sizeof(PRCRsrcHeaderROM)) {
printf("Cannot read resource list\n");
free(rsrch);
return -1;
}
rsrch[i].name=rsrchR.name;
rsrch[i].id=rsrchR.id;
rsrch[i].datap=rsrchR.datap;
}
file_offset+=prch.numrec*sizeof(PRCRsrcHeader);
}else{
if ((pdbh=malloc(prch.numrec*sizeof(PDBRsrcHeader)))==NULL) { /* resource headers list */
printf("Cannot allocate memory for pdb headers\n");
return -1;
}
if (fread(pdbh,1,prch.numrec*sizeof(PDBRsrcHeader),fh)!=sizeof(PDBRsrcHeader)*prch.numrec) {
printf("Cannot read resource list\n");
free(pdbh);
return -1;
}
file_offset+=prch.numrec*sizeof(PDBRsrcHeader);
}
file_offset+=2; /* pad at the end of table */
if ((chunklen=malloc(prch.numrec*sizeof(u32*)))==NULL) {
printf("Cannot allocate memory for data [1]\n");
return -1;
}
if ((dptr=malloc(prch.numrec*sizeof(u8*)))==NULL) {
printf("Cannot allocate memory for data [2]\n");
return -1;
}
for (i=0;i<prch.numrec;i++){
if (prch.flags &1) {
printf("Resource: name=%08X, id=%04X, datap=%08X\n",rsrch[i].name,rsrch[i].id,rsrch[i].datap);
datap=rsrch[i].datap;
}else{
printf("RsrcData: uid=%06X, attr=%02X, datap=%08X\n",pdbh[i].uid,pdbh[i].attr,pdbh[i].datap);
datap=pdbh[i].datap;
}
/*-----------------------------*/
if (fseek(fh,datap-sizeof(ChunkHeader)-ROMBASE,SEEK_SET)!=0) {
printf("Cannot seek to data at %08X\n",datap-sizeof(ChunkHeader)-ROMBASE);
return -1;
}
if (fread(&chdr,1,sizeof(ChunkHeader),fh)!=sizeof(ChunkHeader)) {
printf("Cannot read chunk header\n");
return -1;
}
if ((chdr.padbytes>=chdr.length)||(chdr.padbytes>3)) {
printf("Invalid chunk header\n");
return -1;
}
chunklen[i]=chdr.length-chdr.padbytes-8;
if ((dptr[i]=malloc(chunklen[i]))==NULL) {
printf("Cannot allocate memory for data\n");
return -1;
}
if (fread(dptr[i],1,chunklen[i],fh)!=chunklen[i]) {
printf("Cannot read data\n");
return -1;
}
printf("***FileData: len=%06X, padbytes=%d, flags=%08X %s\n",chunklen[i],chdr.padbytes,chdr.flags,
(chdr.flags==0xF2000000)? "":"***WARNING***: Unexpected flags value");
/*-----------------------------*/
if (prch.flags &1) {
/* Convert & update rsrc[i] table */
rsrch[i].datap=swap32(file_offset);
rsrch[i].name=swap32(rsrch[i].name);
rsrch[i].id=swap16(rsrch[i].id);
}else{
/* Convert & update data[i] table */
pdbh[i].datap=swap32(file_offset);
pdbh[i].attr=pdbh[i].attr;
//pdbh[i].uid=pdbh[i].uid;
}
file_offset+=chunklen[i];
}
/* Convert header */
prch.flags = swap16(prch.flags);
prch.version = swap16(prch.version);
prch.ctime = swap32(prch.ctime);
prch.mtime = swap32(prch.mtime);
prch.btime = swap32(prch.btime);
prch.modnum = swap32(prch.modnum);
prch.ainfo = swap32(prch.ainfo);
prch.sinfo = swap32(prch.sinfo);
prch.type = swap32(prch.type);
prch.id = swap32(prch.id);
prch.idseed = swap32(prch.idseed);
prch.nextrec = swap32(prch.nextrec);
prch.numrec = swap16(prch.numrec);
/* Write file header */
if (fwrite(&prch,1,sizeof(ROMPRCHeader),fw)!=sizeof(ROMPRCHeader)) {
printf("Cannot write to %s\n",wfname);
return -1;
}
/* Restore values we use */
prch.flags = swap16(prch.flags);
prch.numrec = swap16(prch.numrec);
/* Write file table */
if (prch.flags &1) {
fwrite(rsrch,1,prch.numrec*sizeof(PRCRsrcHeader),fw);
}else{
fwrite(pdbh,1,prch.numrec*sizeof(PDBRsrcHeader),fw);
}
i=0x0;fwrite(&i,1,2,fw); /* resource/data table is padded with 0x0000 */
/* Write file data */
for (i=0;i<prch.numrec;i++){
fwrite(dptr[i],1,chunklen[i],fw);
// fwrite(dptr[i]+8,1,chunklen[i]-8,fw);
}
fclose(fw);
for (i=0;i<prch.numrec;i++){
if (dptr[i]) free(dptr[i]);
}
if (rsrch) free(rsrch);
if (pdbh) free(pdbh);
if (dptr) free(dptr);
if (chunklen) free(chunklen);
return 0;
}
/*=========================================================================*/
int UnpackROM(FILE *fh, u32 dirp) {
u32 nfiles,i;
u32 *pfiles;
if (fseek(fh,dirp+4-ROMBASE,SEEK_SET)!=0) { /* seek to file directory+4 */
printf("Cannot seek to dir at %08X\n",dirp+4-ROMBASE);
return -1;
}
if (fread(&nfiles,1,4,fh)!=4) { /* number of files */
printf("Cannot read directory [1]\n");
return -1;
}
if ((pfiles=malloc(nfiles*4))==NULL) {
printf("Cannot allocate memory for file directory\n");
return -1;
}
if (fread(pfiles,1,4*nfiles,fh)!=4*nfiles) {
printf("Cannot read directory [2]\n");
free(pfiles);
return -1;
}
for (i=0;i<nfiles;i++){
if (UnpackFile(fh,pfiles[i])!=0) {
free(pfiles);
return -1;
}
}
free(pfiles);
return 0;
}
/*=========================================================================*/
int main(int argc, char **argv){
u32 addr;
FILE *fh;
u8 buf[0x400];
u32 i,romoffset=0xffffffff;
ROMStoreHeader rh;
if (argc != 2) {
printf("Usage: %s <filename>\n",argv[0]);
exit(1);
}
if ((fh = fopen(argv[1], "rb")) == NULL) {
printf("Cannot open file %s\n",argv[1]);
exit(1);
}
printf("Scanning %s\n",argv[1]);
if (fread(buf,1,0x400,fh)!=0x400) die("Not a Palm ROM file");
for (i=0;i<0x3F0;i++) {
if (strcmp(&buf[i],"ROM Store")==0) {
romoffset=i;
i=0x400;
}
}
if (romoffset==0xffffffff) die("No ROM Store signature");
printf("ROM Store signature located at 0x%08X\n",romoffset);
fseek(fh,romoffset,SEEK_SET); /* skip junk at start */
if (fread(&rh,1,sizeof(rh),fh)!= sizeof(rh)) die("Cannot read header");
ROMBASE=rh.heapptr & 0xFFFF0000;
printf("ROM Base address seems to be 0x%08X\n",ROMBASE);
if ((ROMBASE & 0x00FFFFFF)!=0) {
printf("***WARNING*** ROM base address looks weird\n");
}
PrintROMHeaderInfo(&rh);
UnpackROM(fh, rh.dirptr);
fclose(fh);
exit(0);
}Last edited by fearwall (2008-02-22 23:24:44)
Offline
I have tried lrom.exe with several 700p roms, and it does not work with them. Do you know what I would have to change to make it work?
Every attempt resembles the following:
D:\Palm\Out>Irom d:\Palm\Out\torino.rom
Scanning d:\Palm\Out\torino.rom
ROM Store signature located at 0x00000108
ROM Base address seems to be 0x20000000
ROM Store Header, size=0x120 ----------------------
HeapP: 0x20000208
Num2: 0x20028020
Num3: 0x200284A0
DirPtr: 0x20000230
Num5: 0x20155C20
OSData: 0x201517A0
Num7: 0x00170000
Num8: 0x20A19800
Num9: 0x200284C0
Num11: 0x00000748
HeapID: 0x00000001
HStart: 0x20000214
HSize: 0x01E5FDEC
HFlags: 0x2001
Extracting file at: 0x2025F778
Invalid chunk header
Thank You
Offline