VistaBug forums

Hardware, dissected

You are not logged in.

Announcement

Xebba Virtual PBX
PBX, IVR, Fax, Recordings, Anonymous calls. Free toll-free number. No monthly fees.
www.xebba.com

#1 2008-02-22 17:28:31

fearwall
Member
Registered: 2006-10-19
Posts: 16

PalmOS5 ROM Decompiler

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

Code:

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

Code:

#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

 

#2 2008-06-29 00:34:48

MySelf
New member
Registered: 2008-06-29
Posts: 1

Re: PalmOS5 ROM Decompiler

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

 

Board footer

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson