/* ** read dbx - frank philipse - 030108/030111 - v1.00 */ /* ** note: int is 32 bits */ #include #include #include #include #include FILE *ifp; FILE *lfp; FILE *ofp; unsigned char logfname[]="rdbx.log"; unsigned char targetpath[MAXPATH]; unsigned char fname[MAXPATH]; unsigned char subject[MAXPATH]; unsigned int signature[4] = {0xFE12ADCF, 0x6F74FDC5, 0x11D1E366, 0xC0004E9A}; unsigned char *filebuf; #pragma pack(1) struct { unsigned int self; unsigned int blocksize; unsigned char unknown1; unsigned char unknown2; unsigned char numitems; unsigned char unknown3; } emlhdr; #pragma pack() #pragma pack(1) struct { unsigned int signature[4]; unsigned int unknown1[5]; unsigned int unknownptr1; unsigned int unknown2[2]; unsigned int unknownptr2; unsigned int unknown3[2]; unsigned int unknownptr3; unsigned int unknown4[7]; unsigned int numitems1; unsigned int unknown5[10]; unsigned int unknownptr4; unsigned int unknown6[14]; unsigned int numitems; unsigned int unknown7[7]; unsigned int maintblptr; unsigned int unknown8[6]; } dbxheader; #pragma pack() #pragma pack(1) struct { unsigned int pointer; unsigned int unknown1; unsigned int unknown2; } itemblock; #pragma pack() #pragma pack(1) struct { unsigned int self; unsigned int blocksize; unsigned short datasize; unsigned char items; unsigned char unk1; unsigned int next; } emailblock; #pragma pack() unsigned int *maintable; int numemail; int pointersfound; int emailfound; typedef enum { READY, USAGE, OPTION, FOPERR, FCLERR, FSKERR, FRDERR, FWRERR, MEMERR, REASON, NSPERR, TBDERR } reason; void quit(int e, unsigned char *p) { switch(e) { case READY : break; case OPTION : fprintf(stderr, "unknown option %s\n", p); break; case USAGE : fprintf(stderr, "Usage: %s sourcefilename.dbx targetpath\n", p); break; case FOPERR : fprintf(stderr, "can't open file %s\n", p); break; case FRDERR : fprintf(stderr, "can't read file %s\n", p); break; case MEMERR : fprintf(stderr, "not enough memory\n"); break; case NSPERR : fprintf(stderr, "path not found\n"); break; case REASON : fprintf(stderr, "aborted: %s\n", p); break; default : fprintf(stderr, "undefined error: %d %s\n", e, p); break; } exit(e); } void readheader(void) { int i; if(fread(&dbxheader, sizeof(dbxheader), 1, ifp)!=1) quit(FRDERR, "signature"); for(i=0; i<4; i++) if(dbxheader.signature[i]!=signature[i]) quit(REASON, "probably not a dbx file comntaining email"); numemail=dbxheader.numitems; fprintf(lfp, " dbx file header:\n"); fprintf(lfp, "%-8u number of emails\n", numemail); fprintf(lfp, "%08X main table pointer\n", dbxheader.maintblptr); } void findemail(unsigned int baseptr, unsigned char nni) { #pragma pack(1) struct { unsigned int self; unsigned int unknown1; unsigned int next; unsigned int parent; unsigned char unknown2; unsigned char numitems; unsigned char unknown3; unsigned char unknown4; unsigned char nextnumitems; unsigned char unknown5; unsigned char unknown6; unsigned char unknown7; } tblhdr; #pragma pack() #pragma pack(1) struct { unsigned int emailptr; unsigned int next; unsigned char nextnumitems; unsigned char unknown2; unsigned char unknown3; unsigned char unknown4; } pointerblock; #pragma pack() int i; int filepossave; filepossave=ftell(ifp); fprintf(lfp, " reading table header at %08X:\n", baseptr); if(fseek(ifp, baseptr, SEEK_SET)!=0) quit(FRDERR, "seeking table header"); if(fread(&tblhdr, sizeof(tblhdr), 1, ifp)!=1) quit(FRDERR, "table header"); if(baseptr!=tblhdr.self) quit(REASON, "table self pointer invalid"); if(nni!=0) if(nni!=tblhdr.numitems) quit(REASON, "number of items inconsistent"); fprintf(lfp, "%08X self\n", tblhdr.self); fprintf(lfp, "%08X unk1\n", tblhdr.unknown1); fprintf(lfp, "%08X next\n", tblhdr.next); fprintf(lfp, "%08X parent\n", tblhdr.parent); fprintf(lfp, "%02X unk2\n", tblhdr.unknown2); fprintf(lfp, "%-8d number of items\n", tblhdr.numitems); fprintf(lfp, "%02X unk3\n", tblhdr.unknown3); fprintf(lfp, "%02X unk4\n", tblhdr.unknown4); fprintf(lfp, "%-8d next number of items\n", tblhdr.nextnumitems); fprintf(lfp, "%02X unk5\n", tblhdr.unknown5); fprintf(lfp, "%02X unk6\n", tblhdr.unknown6); fprintf(lfp, "%02X unk7\n", tblhdr.unknown7); if(tblhdr.next==0) { for(i=0; i<(int)tblhdr.numitems; i++) { if(fread(&itemblock, sizeof(itemblock), 1, ifp)!=1) quit(FRDERR, "item block"); if(pointersfound>=numemail) quit(REASON, "found more emails then specified in dbx file header"); maintable[pointersfound++]=itemblock.pointer; } fprintf(lfp, " result finding email pointers:\n", pointersfound); fprintf(lfp, "%-8d up to now\n", pointersfound); } else { findemail(tblhdr.next, tblhdr.nextnumitems); for(i=0; i<(int)tblhdr.numitems; i++) { if(fread(&pointerblock, sizeof(pointerblock), 1, ifp)!=1) quit(FRDERR, "pointer block"); fprintf(lfp, " pointer block:\n"); fprintf(lfp, "%08X unk1\n", pointerblock.emailptr); fprintf(lfp, "%08X next\n", pointerblock.next); fprintf(lfp, "%-8d number of items\n", pointerblock.nextnumitems); fprintf(lfp, "%02X unk2\n", pointerblock.unknown2); fprintf(lfp, "%02X unk3\n", pointerblock.unknown3); fprintf(lfp, "%02X unk4\n", pointerblock.unknown4); if(pointersfound>=numemail) quit(REASON, "found more emails then specified in dbx file header"); maintable[pointersfound++]=pointerblock.emailptr; findemail(pointerblock.next, pointerblock.nextnumitems); } } if(fseek(ifp, filepossave, SEEK_SET)!=0) quit(FRDERR, "restoring file position"); } void getemail(unsigned int emlhdrptr) { int i, j; unsigned int u; unsigned int itemindex; unsigned int emaildataptr; unsigned int saveemaildataptr; unsigned char *emlitems; unsigned int maxblocklength; unsigned char *emaildatablock; unsigned int emailid; fprintf(lfp, " reading email header at %08X:\n", emlhdrptr); if(fseek(ifp, emlhdrptr, SEEK_SET)!=0) quit(FRDERR, "seeking email header"); if(fread(&emlhdr, sizeof(emlhdr), 1, ifp)!=1) quit(FRDERR, "email header"); if(emlhdrptr!=emlhdr.self) quit(REASON, "email header self pointer invalid"); fprintf(lfp, "%08X self\n", emlhdr.self); fprintf(lfp, "%08X block size\n", emlhdr.blocksize); fprintf(lfp, "%02X unk1\n", emlhdr.unknown1); fprintf(lfp, "%02X unk2\n", emlhdr.unknown2); fprintf(lfp, "%-8d numitems\n", emlhdr.numitems); fprintf(lfp, "%02X unk3\n", emlhdr.unknown3); emlitems=(unsigned char*)malloc(emlhdr.blocksize); if(emlitems==NULL) quit(MEMERR, "email items"); if(fread(emlitems, 1, emlhdr.blocksize, ifp)!=emlhdr.blocksize) quit(FRDERR, "email items"); emaildataptr=0; fprintf(lfp, " email items:\n"); for(i=0; i<(emlhdr.numitems); i++) { for(j=3; j>=0; j--) fprintf(lfp, "%02X", emlitems[i*4+j]); fprintf(lfp, " email item %d ", i+1); itemindex=emlitems[i*4+1]+(emlitems[i*4+2]<<8)+(emlitems[i*4+3]<<16)+emlhdr.numitems*4; switch(emlitems[i*4]) { case 0x02 : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x04 : for(j=0; j<4; j++) emaildataptr+=(emlitems[itemindex+j]<<(j*8)); fprintf(lfp, "file offset to email data: %08X", emaildataptr); break; case 0x05 : fprintf(lfp, "subject: %s", &emlitems[itemindex]); break; case 0x06 : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x07 : fprintf(lfp, "message id ?: %s", &emlitems[itemindex]); break; case 0x08 : fprintf(lfp, "subject with Re: %s", &emlitems[itemindex]); strcpy(subject, &emlitems[itemindex]); break; case 0x09 : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x0a : fprintf(lfp, "parent email id: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x0b : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x0c : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x0d : fprintf(lfp, "sender name: %s", &emlitems[itemindex]); break; case 0x0e : fprintf(lfp, "sender mail: %s", &emlitems[itemindex]); break; case 0x11 : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x12 : fprintf(lfp, "unknown: "); for(j=0; j<8; j++) fprintf(lfp, "%02X ", emlitems[itemindex+j]); break; case 0x13 : fprintf(lfp, "recipient name: %s", &emlitems[itemindex]); break; case 0x14 : fprintf(lfp, "recipient mail: %s", &emlitems[itemindex]); break; case 0x16 : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x18 : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x19 : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x1a : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x1b : fprintf(lfp, "some ascii number: %s", &emlitems[itemindex]); break; case 0x1c : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x80 : emailid=emlitems[i*4+1]+(emlitems[i*4+2]<<8)+(emlitems[i*4+3]<<16); fprintf(lfp, "numeric id: %d", emailid); break; case 0x81 : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x84 : emaildataptr=emlitems[i*4+1]+(emlitems[i*4+2]<<8)+(emlitems[i*4+3]<<16); fprintf(lfp, "file offset to email data: %08X", emaildataptr); break; case 0x90 : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; case 0x91 : fprintf(lfp, "unknown: %02X%02X%02X", emlitems[i*4+3], emlitems[i*4+2], emlitems[i*4+1]); break; default : break; } fprintf(lfp, "\n"); } saveemaildataptr=emaildataptr; maxblocklength=0; while(emaildataptr!=0) { if(fseek(ifp, emaildataptr, SEEK_SET)!=0) quit(FRDERR, "seeking email block"); if(fread(&emailblock, sizeof(emailblock), 1, ifp)!=1) quit(FRDERR, "email block"); if(emaildataptr!=emailblock.self) quit(REASON, "email block self pointer invalid"); fprintf(lfp, "%08X %08X %04X %02X %02X %08X\n", emailblock.self, emailblock.blocksize, emailblock.datasize, emailblock.items, emailblock.unk1, emailblock.next); if(emailblock.blocksize>maxblocklength) maxblocklength=emailblock.blocksize; emaildataptr=emailblock.next; } for(i=0; i<(int)strlen(subject); i++) { if(isprint(subject[i])==0) subject[i]='-'; else { switch(subject[i]) { case '/' : case '\\' : case ':' : case '?' : case '"' : case '>' : case '<' : case '|' : subject[i]='-'; default : break; } } } i=strlen(targetpath)+strlen(subject)+6; if(i>MAXPATH) subject[strlen(subject)-(i-MAXPATH)]='\0'; sprintf(fname, "%s\\%04d_%s.eml", targetpath, emailid, subject); fprintf(lfp, "%s\n", fname); emaildataptr=saveemaildataptr; emaildatablock=(unsigned char*)malloc(maxblocklength); if(emaildatablock==NULL) quit(MEMERR, "email datablock"); if((ofp=fopen(fname, "wb"))==NULL) quit(FOPERR, fname); while(emaildataptr!=0) { if(fseek(ifp, emaildataptr, SEEK_SET)!=0) quit(FRDERR, "seeking email block"); if(fread(&emailblock, sizeof(emailblock), 1, ifp)!=1) quit(FRDERR, "email block"); if(emaildataptr!=emailblock.self) quit(REASON, "email block self pointer invalid"); if(fread(emaildatablock, 1, emailblock.blocksize, ifp)!=emailblock.blocksize) quit(FRDERR, "email data block"); for(i=emailblock.items*4; i<(emailblock.items*4+emailblock.datasize); i++) { fputc(emaildatablock[i], ofp); } /* if((int)fwrite(&emaildatablock[emailblock.items*4], 1, (int)emailblock.datasize, ofp)!=(int)emailblock.datasize) quit(FWRERR, "email data block"); */ emaildataptr=emailblock.next; } fclose(ofp); free(emaildatablock); free(emlitems); } void main(int argc, char *argv[]) { int i; fprintf(stdout, "OE5 email extraction experiment - v1.00 - frank philipse - 030111\n"); if(argc!=3) quit(USAGE, argv[0]); if((strlen(argv[2])+strlen(logfname)+2)>MAXPATH) quit(REASON, "destination path too long"); sprintf(fname, "%s\\%s", argv[2], logfname); if((lfp=fopen(fname, "w"))==NULL) quit(FOPERR, fname); strcpy(targetpath, argv[2]); if((ifp=fopen(argv[1], "rb"))==NULL) quit(FOPERR, argv[1]); fprintf(lfp, "%s\n", argv[1]); readheader(); if(numemail==0) quit(REASON, "seems to be nothing there"); maintable=(unsigned int *)malloc(numemail*sizeof(int)); if(maintable==NULL) quit(MEMERR, "maintable"); for(i=0; i