From c07d0c2d2f6f7b0eb6e92cc6204bf05037957e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 1 Sep 2014 15:43:52 +0200 Subject: Imported Upstream version 1.6.3 --- spectro/oemarch.c | 562 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 497 insertions(+), 65 deletions(-) (limited to 'spectro/oemarch.c') diff --git a/spectro/oemarch.c b/spectro/oemarch.c index 733156e..e27d25d 100644 --- a/spectro/oemarch.c +++ b/spectro/oemarch.c @@ -87,6 +87,8 @@ oem_target oemtargs = { { "/Applications/Spyder2pro 2.2/Spyder2pro.app/Contents/MacOSClassic/Spyder.lib", targ_spyd_pld }, { "/Library/Application Support/X-Rite/Devices/i1d3xrdevice/Contents/Resources/Calibrations/*.edr", targ_i1d3_edr }, + { "/Library/Application Support/X-Rite/Frameworks/XRiteDevice.framework/PlugIns/i1d3.xrdevice/Contents/Resources/Calibrations/*.edr",targ_i1d3_edr }, + { NULL } }, { /* Volume names */ @@ -168,7 +170,9 @@ int is_s4cal(xfile *xf); int is_inno(xfile *xf); int is_cab(xfile *xf); static xfile *inno_extract(xfile *xi, char *tfilename, int verb); -static xfile *msi_extract(xfile **pxf, xfile *xi, char *tname, int verb); +static xfile *ai_extract_cab(xfile **pxf, xfile *xi, char *tname, int verb); +//static xfile *aifile_extract(xfile **pxf, xfile *xi, char *tname, int verb); +static xfile *msi_extract_cab(xfile **pxf, xfile *xi, char *tname, int verb); static xfile *cab_extract(xfile **pxf, xfile *xi, char *text, int verb); /* edr to ccss functions */ @@ -180,6 +184,9 @@ int is_ccss(xfile *xf); int is_ccmx(xfile *xf); #ifdef DEBUG + +# pragma message("######### oemarch DEBUG is defined! ########") + static void list_files(char *s, xfile *xf) { int i; @@ -281,28 +288,48 @@ xfile *oemarch_get_ifiles(xfile *files, int verb) { /* If this could be i1d3 .edr files: */ if (arch->ttype & targ_i1d3_edr) { - xfile *msi = NULL; /* .msi */ + xfile *exe = NULL; /* .exe extracted */ + xfile *msi = NULL; /* .msi extracted */ -#ifdef NEVER /* Don't have to do it this way */ +#ifdef NEVER /* Don't have to do it this way for most installs */ /* Extract .msi from it */ if ((msi = inno_extract(arch, "{tmp}\\XRD i1d3.msi", verb)) != NULL) { /* Extract the .cab from it */ - if (msi_extract(&nfiles, msi, "XRD_i1d3.cab", verb) != NULL) { + if (msi_extract_cab(&nfiles, msi, "XRD_i1d3.cab", verb) != NULL) { + del_xf(msi); + continue; + } + if (msi_extract_cab(&nfiles, msi, "XRD_Manager.cab", verb) != NULL) { del_xf(msi); continue; } del_xf(msi); } + + /* Try and extract XRD Manager.exe from it */ + if ((exe = inno_extract(arch, "{tmp}\\XRD Manager.exe", verb)) != NULL) { + + /* Extract the "disk1.cab" from the AI installer exectutable */ + if ((ai_extract_cab(&nfiles, exe, "disk1.cab", verb)) != NULL) { + del_xf(exe); + continue; + } + del_xf(exe); + } #else /* Extract the .cab directly from Setup.exe */ - if (msi_extract(&nfiles, arch, "XRD_i1d3.cab", verb) != NULL) + if (msi_extract_cab(&nfiles, arch, "XRD_i1d3.cab", verb) != NULL) + continue; + if (msi_extract_cab(&nfiles, arch, "XRD_Manager.cab", verb) != NULL) continue; - if (msi_extract(&nfiles, arch, "XRD_Manager.cab", verb) != NULL) + + /* Extract the "disk1.cab" from the AI installer exectutable */ + if ((ai_extract_cab(&nfiles, arch, "disk1.cab", verb)) != NULL) continue; #endif } - if (verb) printf("Warning: unhandled '%s' discarded\n",arch->name); + if (verb) printf("Warning: unhandled archive '%s' discarded\n",arch->name); } ofiles = files; /* Swap to new list */ files = nfiles; @@ -350,7 +377,7 @@ xfile *oemarch_get_ifiles(xfile *files, int verb) { if (cab_extract(&nfiles, dllcab, ".edr", verb) != NULL) continue; } - if (verb) printf("Warning: unhandled '%s' discarded\n",dllcab->name); + if (verb) printf("Warning: unhandled dll/cab '%s' discarded\n",dllcab->name); } ofiles = files; /* Swap to new list */ files = nfiles; @@ -381,7 +408,7 @@ xfile *oemarch_get_ifiles(xfile *files, int verb) { if (edr_convert(&nfiles, files + i, verb) != NULL) continue; - if (verb) printf("Warning: unhandled '%s' discarded\n",files[i].name); + if (verb) printf("Warning: unhandled edr '%s' discarded\n",files[i].name); } ofiles = files; /* Swap to new list */ files = nfiles; @@ -1295,7 +1322,7 @@ static xfile *edr_convert(xfile **pxf, xfile *xi, int verb) { xfile *xf = NULL; ccss *c; - if (verb) printf("Translating '%s' (%d bytes)\n",xi->name, xi->len); + if (verb) printf("Translating '%s' (%d bytes)\n",xi->name, (int)xi->len); if ((c = parse_EDR(xi->buf, xi->len, xi->name, verb)) == NULL) { if (verb) printf("Failed to parse EDR '%s'\n",xi->name); @@ -1306,7 +1333,7 @@ static xfile *edr_convert(xfile **pxf, xfile *xi, int verb) { unsigned char *buf; int len; if (c->buf_write_ccss(c, &buf, &len)) { - error("Failed to create ccss for '%s'",xi->name); + error("Failed to create ccss for '%s' error '%s'",xi->name,c->err); } /* Convert .edr file name to .ccss */ @@ -1356,9 +1383,10 @@ static void dump_bytes(FILE *fp, char *pfx, unsigned char *buf, int len) { fprintf(fp,"\n"); } } + fflush(fp); } -/* Take a 64 sized return buffer, and convert it to an ORD64 */ +/* Take a 64 sized return buffer, and convert it to an ORD64, little endian */ static ORD64 buf2ord64(unsigned char *buf) { ORD64 val; val = buf[7]; @@ -1372,7 +1400,7 @@ static ORD64 buf2ord64(unsigned char *buf) { return val; } -/* Take a word sized return buffer, and convert it to an unsigned int */ +/* Take a word sized return buffer, and convert it to an unsigned int, little endian */ static unsigned int buf2uint(unsigned char *buf) { unsigned int val; val = buf[3]; @@ -1382,7 +1410,17 @@ static unsigned int buf2uint(unsigned char *buf) { return val; } -/* Take a word sized return buffer, and convert it to an int */ +/* Inverted bytes version of above */ +static unsigned int ibuf2uint(unsigned char *buf) { + unsigned int val; + val = (0xff & ~buf[3]); + val = ((val << 8) + (0xff & ~buf[2])); + val = ((val << 8) + (0xff & ~buf[1])); + val = ((val << 8) + (0xff & ~buf[0])); + return val; +} + +/* Take a word sized return buffer, and convert it to an int, little endian */ static int buf2int(unsigned char *buf) { int val; val = buf[3]; @@ -1392,7 +1430,7 @@ static int buf2int(unsigned char *buf) { return val; } -/* Take a short sized return buffer, and convert it to an int */ +/* Take a short sized return buffer, and convert it to an int, little endian */ static int buf2short(unsigned char *buf) { int val; val = buf[1]; @@ -1431,7 +1469,7 @@ static ccss *parse_EDR( char dispdesc[256]; int ttmin, ttmax; /* Min & max technology strings (inclusive) */ int *trefmodes; /* Corresponding refresh mode for tecnology */ - char **tsels; /* Corresponding UI selection chars */ + char **tsels; /* Corresponding UI selection chars */ char **ttstrings; /* Corresponding technology strings */ int ttype; /* Technology type idex */ int nsets, set; @@ -1480,7 +1518,7 @@ static ccss *parse_EDR( trefmodes[15] = 0; tsels[15] = "o"; ttstrings[15] = "LED OLED"; trefmodes[16] = 0; tsels[16] = "a"; ttstrings[16] = "LED AMOLED"; trefmodes[17] = 1; tsels[17] = "m"; ttstrings[17] = "Plasma"; - trefmodes[18] = 0; tsels[18] = NULL; ttstrings[18] = "LCD RG Phosphor"; // is this LCD ?? + trefmodes[18] = 0; tsels[18] = NULL; ttstrings[18] = "LCD RG Phosphor"; trefmodes[19] = 1; tsels[19] = NULL; ttstrings[19] = "Projector RGB Filter Wheel"; trefmodes[20] = 1; tsels[10] = NULL; ttstrings[20] = "Projector RGBW Filter Wheel"; trefmodes[21] = 1; tsels[21] = NULL; ttstrings[21] = "Projector RGBCMY Filter Wheel"; @@ -1629,6 +1667,7 @@ static ccss *parse_EDR( samples[set].spec[j] *= 1000.0; } #ifdef PLOT_SAMPLES +# pragma message("######### oemarch PLOT_SAMPLES defined! ########") /* Plot the spectra */ { double xx[500]; @@ -1911,7 +1950,26 @@ ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) { return res; } -/* extract the given file from Setup.exe */ +/* extract the given file from Inno Setup.exe */ +/* Known versions needed: + 5.3.5 ColorMunkiDisplaySetup.exe + 5.3.10 i1d3Setup.exe + 5.4.2 V1.5 i1ProfilerSetup.exe +*/ + +/* Unicode to 8 bit strncmp */ +static int ustrncmp(char *w, char *c, int n) { + int i; + for (i = 0; i < n; i++, w += 2, c++) { + if ((w[0] == '\000' && w[1] == '\000') + || c[0] == '\000') + return 0; + + if (w[0] != c[0] || w[1] != '\000') + return 1; + } + return 0; +} /* Return a list of xfiles, with one entry if successful */ /* Return NULL if not found or not inno file */ @@ -1919,8 +1977,12 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { int i, j, k; unsigned char *ibuf; unsigned long ilen; - char *headerid = "Inno Setup Setup Data (5.3.10)"; + char *headerid = "Inno Setup Setup Data "; int headerlen = strlen(headerid); + int maj, min, bfix; /* Inno version */ + int vers = 0; /* Version as int max * 1000 + min * 100 + bfix */ + int unicode = 0; /* Is it unicode filenames ? */ + int chsize = 1; /* Bytes per character */ unsigned int ldrbase = 0; unsigned long haddr, srclen; unsigned char *d1buf, *d2buf; /* Decompress buffer */ @@ -1939,14 +2001,15 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { ibuf = xi->buf; ilen = xi->len; - /* Search for the start of the loader. All the file offsets */ - /* are relative to this */ + if (verb > 1) printf("inno_extract: ilen = %lu\n",ilen); + + /* Search for the start of the loader. We need this because */ + /* All the file offsets are relative to this. */ for (i = 0; i < (ilen - 4); i++) { if (ibuf[i + 0] == 0x4d && ibuf[i + 1] == 0x5a && ibuf[i + 2] == 0x90 && ibuf[i + 3] == 0x00) { - if (verb > 1) printf("Found archive base 0x%x\n",i); ldrbase = i; break; } @@ -1955,26 +2018,51 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { if (verb) printf("Failed to locate loader base\n"); return NULL; } + if (verb > 1) printf("Found archive base 0x%x\n",ldrbase); /* Search for inno header pattern. */ - for (i = 0; i < (ilen - 64 - 4 - 5 - 4); i++) { + haddr = 0; + for (i = 1; i < (ilen - 64 - 4 - 5 - 4); i++) { if (ibuf[i] == headerid[0] && strncmp((char *)ibuf + i, headerid, headerlen) == 0 && ibuf[i + 64] != 'I' && ibuf[i + 65] != 'n' && ibuf[i + 66] != 'n' && ibuf[i + 67] != 'o') { + + /* Grab the version */ + for (j = 0; j < 64; j++) { + if (ibuf[i + j] == '\000') + break; + } + if (j >= 64) { + if (verb) printf("Failed to find null terminator after header\n"); + continue; + } + + if (sscanf((char *)ibuf + i + headerlen, " (%d.%d.%d) ",&maj,&min,&bfix) != 3) { + if (verb) printf("Failed to find Inno version number\n"); + continue; + } + vers = maj * 1000 + min * 100 + bfix; + + j = strlen((char *)ibuf + i); + if (strncmp((char *)ibuf + i + j -3, "(u)", 3) == 0) { + unicode = 1; + chsize = 2; + } haddr = i; } } - if (i >= (ilen - 64 - 4 - 5 - 4)) { + + if (haddr == 0) { if (verb) printf("Failed to locate header pattern\n"); return NULL; } - if (verb > 1) printf("Found header at 0x%x\n",i); + if (verb > 1) printf("Found header at 0x%x, Inno version %d.%d.%d%s\n",i,maj,min,bfix, unicode ? " Unicode" : ""); - /* Use the last header found (or cound search all found ?) */ + /* Use the last header found (or could search all found ?) */ haddr += 64; /* Skip Inno header */ /* Next 9 bytes are the compression header */ @@ -1994,7 +2082,7 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { } haddr += 5; /* Skip compression header */ - /* We'r now at the start of the compressed data */ + /* We're now at the start of the compressed data which holds the filenames */ d1sz = cblocklen * 30; if ((d1buf = (unsigned char *)malloc(d1sz)) == NULL) { @@ -2016,6 +2104,7 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { } if (verb > 1) printf("Decoded %ld bytes to created %ld bytes of Header output (ratio %.1f)\n",srclen,d1sz,(double)d1sz/srclen); +// printf("d1buf, file names:\n"); // dump_bytes(stdout, " ", d1buf, d1sz); /* - - - - - - - - - - - - - - - - -*/ @@ -2049,7 +2138,7 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { } haddr += 5; /* Skip compression header */ - /* We're now at the start of the compressed data */ + /* We're now at the start of the compressed data that holds the file data locations. */ d2sz = cblocklen * 10; if ((d2buf = (unsigned char *)malloc(d2sz)) == NULL) { @@ -2073,34 +2162,65 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { } if (verb > 1) printf("Decoded %ld bytes to created %ld bytes of File Location output (ratio %.1f)\n",srclen,d1sz,(double)d1sz/srclen); +// printf("d2buf, file location data:\n"); // dump_bytes(stdout, " ", d2buf, d2sz); if (verb > 1) printf("Searching for file '%s' in Header\n",tfilename); - for (i = 0; i < (d1sz - 101); i++) { - if (d1buf[i+4] == tfilename[0] - && strncmp((char *)d1buf + 4 + i, tfilename, filelen) == 0 - && d1buf[i+0] == filelen - && d1buf[i+1] == 0 - && d1buf[i+2] == 0 - && d1buf[i+3] == 0) { - if (verb > 1) printf("Found it at 0x%x\n",i); - break; + if (unicode) { + for (i = 0; i < (d1sz - 101); i++) { + if (d1buf[i+4] == tfilename[0] + && ustrncmp((char *)d1buf + 4 + i, tfilename, filelen) == 0 + && d1buf[i+0] == 2 * filelen + && d1buf[i+1] == 0 + && d1buf[i+2] == 0 + && d1buf[i+3] == 0) { + if (verb > 1) printf("Found it at 0x%x\n",i); + break; + } + } + if (i >= (d1sz - 101)) { + if (verb) printf("Failed to find file '%s'\n",tfilename); + free(d1buf); + free(d2buf); + return NULL; + } + + } else { + for (i = 0; i < (d1sz - 101); i++) { + if (d1buf[i+4] == tfilename[0] + && strncmp((char *)d1buf + 4 + i, tfilename, filelen) == 0 + && d1buf[i+0] == filelen + && d1buf[i+1] == 0 + && d1buf[i+2] == 0 + && d1buf[i+3] == 0) { + if (verb > 1) printf("Found it at 0x%x\n",i); + break; + } + } + if (i >= (d1sz - 101)) { + if (verb) printf("Failed to find file '%s'\n",tfilename); + free(d1buf); + free(d2buf); + return NULL; } } - if (i >= (d1sz - 101)) { - if (verb) printf("Failed to find file '%s'\n",tfilename); - free(d1buf); - free(d2buf); - return NULL; - } + fflush(stdout); - /* Need to skip 8 more strings */ - i += 4 + filelen; + /* Need to skip 8 more strings containing other info about the file */ + i += 4 + chsize * filelen; for (j = 0; j < 8; j++) { unsigned long len; len = buf2uint(d1buf + i); i += 4 + len; + if (i >= d1sz) { + if (verb) printf("Failed to skip 8 strings\n"); + free(d1buf); + free(d2buf); + return NULL; + } } + if (verb > 1) printf("At 0x%x after skippin another 8 strings\n",i); + /* Skip another 40 bytes to location entry index */ i += 20; @@ -2108,13 +2228,12 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { if (verb > 1) printf("Got file location index %ld at 0x%x\n",ix,i); - /* Now get the ix file entry information. */ /* They are in 74 byte structures */ i = ix * 74; if ((i + 74) > d2sz) { - if (verb) printf("File location structure is out of range\n"); + if (verb) printf("File location structure is out of range (%d > %lu)\n",i + 74, d2sz); free(d1buf); free(d2buf); return NULL; @@ -2141,7 +2260,8 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { free(d2buf); return NULL; } - /* Sanity check */ +#ifdef NEVER + /* Sanity check it's an .msi file */ if (ibuf[ldrbase + fileso + 0] != 0xd0 || ibuf[ldrbase + fileso + 1] != 0xcf || ibuf[ldrbase + fileso + 2] != 0x11 @@ -2151,6 +2271,7 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { free(d2buf); return NULL; } +#endif /* Copy to new buffer and free everything */ msisz = filesz; @@ -2181,6 +2302,9 @@ static xfile *inno_extract(xfile *xi, char *tfilename, int verb) { xf->buf = msibuf; xf->len = filesz; + xf->ftype = file_dllcab; + xf->ttype = xi->ttype; + if (verb) printf("Returning '%s' length %ld from '%s'\n",xf->name,xf->len, xi->name); return xf; @@ -2274,22 +2398,25 @@ int is_dll(xfile *xf) { return 0; } -/* Extract the .cab file from another file. */ +// ~~99 something strange about this code - it doesn't look for *tname. +// ?? What's going on ?? + +/* Extract a .cab file from another file. */ /* It's stored in the .msi uncompressed and contiguous, so we */ /* just need to identify where it is and its length. */ /* (This will work on any file that has the .cab file uncompressed and contiguous) */ /* Return NULL if not found */ -static xfile *msi_extract(xfile **pxf, xfile *xi, char *tname, int verb) { +static xfile *msi_extract_cab(xfile **pxf, xfile *xi, char *tname, int verb) { int i, j, k; xfile *xf = NULL; - char *fid = "i1d3.xrdevice"; /* File in .cab to look for */ + char *fid = "i1d3.xrdevice"; /* Known file in .cab to look for ???? */ unsigned long fle = strlen(fid); unsigned long cabo, cabsz; size_t len; if (verb) printf("Attempting to extract '%s' from '%s'\n",tname,xi->name); - /* Search for a filename in the .cab */ + /* Search for a filename that is expected to be in the right .cab */ for (i = 0; i < (xi->len - fle - 2); i++) { if (xi->buf[i + 0] == 0x00 && xi->buf[i + 1] == fid[0] @@ -2299,7 +2426,7 @@ static xfile *msi_extract(xfile **pxf, xfile *xi, char *tname, int verb) { } } if (i >= (xi->len - fle - 2)) { - if (verb) printf(".cab not found\n"); + if (verb) printf(".cab identifier file not found\n"); return NULL; } @@ -2313,12 +2440,12 @@ static xfile *msi_extract(xfile **pxf, xfile *xi, char *tname, int verb) { && xi->buf[i + 5] == 0x00 && xi->buf[i + 6] == 0x00 && xi->buf[i + 7] == 0x00) { - if (verb > 1) printf("Found '%s' at 0x%x\n",tname,i); + if (verb > 1) printf("Found .cab sig at 0x%x\n",i); break; } } if (i < 0) { - if (verb) printf(".cab not found\n"); + if (verb) printf(".cab sig not found\n"); return NULL; } @@ -2354,6 +2481,299 @@ static xfile *msi_extract(xfile **pxf, xfile *xi, char *tname, int verb) { return xf; } +/* Extract a .cab file from an "Advanced Installer" file. */ +/* It's stored in the file uncompressed and contiguous, but */ +/* with the first 0x200 bytes inverted, so we */ +/* just need to identify where it is and its length. */ +/* Return NULL if not found */ +static xfile *ai_extract_cab(xfile **pxf, xfile *xi, char *tname, int verb) { + int i, j, k; + xfile *xf = NULL; + unsigned long cabo, cabsz; + size_t len; + + if (verb) printf("Attempting to extract '%s' from '%s'\n",tname,xi->name); + + /* Search for inverted .cab signature */ + for (i = 0; i < (xi->len - 8 - 4); i++) { + if (xi->buf[i + 0] == 0xb2 + && xi->buf[i + 1] == 0xac + && xi->buf[i + 2] == 0xbc + && xi->buf[i + 3] == 0xb9 + && xi->buf[i + 4] == 0xff + && xi->buf[i + 5] == 0xff + && xi->buf[i + 6] == 0xff + && xi->buf[i + 7] == 0xff) { + if (verb > 1) printf("Found inverted .cab sig at 0x%x\n",i); + break; + } + } + if (i > (xi->len - 8 - 4)) { + if (verb) printf(".cab sig not found\n"); + return NULL; + } + + /* Lookup the .cab size (really 64 bit, but we don't care) */ + len = ibuf2uint(xi->buf + i + 8); + + if (verb > 1) printf("'%s' is length %ld\n",tname,len); + + if ((xi->len - i) < len) { + if (verb) printf("Not enough room for .cab file in source\n"); + return NULL; + } + + xf = add_xf(pxf); + xf->len = len; + + if ((xf->buf = malloc(xf->len)) == NULL) { + fprintf(stderr,"maloc of .cab buffer failed\n"); + exit(-1); + } + memmove(xf->buf, xi->buf + i ,xf->len); + + /* Restor first 0x200 bytes */ + for (i = 0; i < 0x200 && i < xf->len; i++) { + xf->buf[i] = ~xf->buf[i]; + } + + if ((xf->name = strdup(tname)) == NULL) { + fprintf(stderr,"maloc of .cab name failed\n"); + exit(-1); + } + + xf->ftype = file_dllcab; + xf->ttype = xi->ttype; + + if (verb) printf("Extacted '%s' length %ld\n",xf->name,xf->len); + +save_xfile(xf, "temp.cab", NULL, verb); + + return xf; +} + + +/* ================================================================ */ + +/* Not used: */ + +/* Given an offset into xfile, return the offset to any extra section in a PE file. */ +/* return 0 if none found or not a PE file */ +static int extraPEsection(xfile *xi, int boff, int verb) { + int i, j; + unsigned char *fbuf = xi->buf + boff; + int flen = xi->len - boff; + int off; + int nsect; /* Number of sections */ + int ophsz; /* Optional header size */ + int chars; /* File characteristics */ + int plus = 0; /* PE32+ format */ + int nddirs; /* Number of data directories */ + int ddirroff; /* Offset of data directories */ + unsigned int asects = 0; /* Offset after all the sections */ + + if (flen < 0x40 + || fbuf[0] != 0x4d + || fbuf[1] != 0x5a) { + if (verb) printf("'%s' is not an executable file\n",xi->name); + return 0; + } + + off = fbuf[0x3c] /* Offset to PE header */ + + (fbuf[0x3d] << 8) + + (fbuf[0x3e] << 16) + + (fbuf[0x3f] << 24); + + if (verb > 2) printf("PE header at 0x%x\n",off); + + if (flen < (off + 0x18) || off > 0x1000 || (off & 7) != 0) { + if (verb) printf("'%s' is not a PE file (1)\n",xi->name); + return 0; + } + + if (fbuf[off + 0] != 0x50 /* "PE" */ + || fbuf[off + 1] != 0x45 + || fbuf[off + 2] != 0x00 + || fbuf[off + 3] != 0x00) { + if (verb) printf("'%s' is not a PE file (2)\n",xi->name); + return 0; + } + + nsect = fbuf[off + 0x06] /* Number of sections */ + + (fbuf[off + 0x07] << 8); + + ophsz = fbuf[off + 0x14] /* Optional header size */ + + (fbuf[off + 0x15] << 8); + + chars = fbuf[off + 0x16] /* PE Characteristics */ + + (fbuf[off + 0x17] << 8); + /* + 0x0002 = executable (no unresolved refs) + 0x1000 = .sys driver + 0x2000 = DLL + */ + + if (verb > 1) printf("Number of sections = %d, chars = 0x%x\n",nsect,chars); + if (verb > 1) printf("Opt header size = %d = 0x%x\n",ophsz,ophsz); + + /* Skip to optional header */ + off = off + 0x18; + if (flen < off + ophsz) { + if (verb) printf("'%s' not big enough for optional header\n",xi->name); + return 0; + } + if (verb > 2) printf("opt header at 0x%x\n",off); + if ( fbuf[off + 0] != 0x0b + || (fbuf[off + 1] != 0x01 && fbuf[off + 1] != 0x02)) { + if (verb) printf("'%s' is not a PE file (3)\n",xi->name); + return 0; + } + if (fbuf[off + 1] == 0x02) + plus = 1; /* PE32+ format */ + + if (plus) { + nddirs = fbuf[off+0x6c+0] + + (fbuf[off+0x6c+1] << 8) + + (fbuf[off+0x6c+2] << 16) + + (fbuf[off+0x6c+3] << 24); + ddirroff = 0x70; + } else { + nddirs = fbuf[off+0x5c+0] + + (fbuf[off+0x5c+1] << 8) + + (fbuf[off+0x5c+2] << 16) + + (fbuf[off+0x5c+3] << 24); + ddirroff = 0x60; + } + + /* Go through each data directory */ + for (i = 0; i < nddirs; i++) { + unsigned int addr, size; + + j = off + ddirroff + 8 * i; + + addr = fbuf[j+0] + + (fbuf[j+1] << 8) + + (fbuf[j+2] << 16) + + (fbuf[j+3] << 24); + size = fbuf[j+4] + + (fbuf[j+5] << 8) + + (fbuf[j+6] << 16) + + (fbuf[j+7] << 24); + + if (verb > 2) printf("Data block %d addr 0x%x size %u\n",i,addr,size); + } + + /* Skip to start of section headers */ + off = off + ophsz; + + /* Go through each section header and locat size used by them */ + asects = 0; + for (i = 0; i < nsect; i++) { + char sname[9] = { '\000' }; + unsigned int vaddr, vsize; + unsigned int paddr, psize; + unsigned int flags; + + if (flen < (off + 0x28)) { + if (verb) printf("'%s' not big enough for section headers\n",xi->name); + return 0; + } + + strncpy(sname, (char *)fbuf + off, 8); + + vsize = fbuf[off+0x08+0] + + (fbuf[off+0x08+1] << 8) + + (fbuf[off+0x08+2] << 16) + + (fbuf[off+0x08+3] << 24); + + vaddr = fbuf[off+0x0c+0] + + (fbuf[off+0x0c+1] << 8) + + (fbuf[off+0x0c+2] << 16) + + (fbuf[off+0x0c+3] << 24); + + psize = fbuf[off+0x10+0] + + (fbuf[off+0x10+1] << 8) + + (fbuf[off+0x10+2] << 16) + + (fbuf[off+0x10+3] << 24); + + paddr = fbuf[off+0x14+0] + + (fbuf[off+0x14+1] << 8) + + (fbuf[off+0x14+2] << 16) + + (fbuf[off+0x14+3] << 24); + + flags = fbuf[off+0x24+0] + + (fbuf[off+0x24+1] << 8) + + (fbuf[off+0x24+2] << 16) + + (fbuf[off+0x24+3] << 24); + + if (verb > 1) printf("Section '%s' phys off 0x%x size %u\n",sname,paddr,psize); + + if ((paddr + psize) > asects) + asects = paddr + psize; + off += 0x28; + } + if (verb > 2) printf("After section hedares at 0x%x\n",off); + + if (flen <= asects) { + if (verb) printf("No extra section at end\n"); + return 0; + } + + if (verb > 1) printf("Extra data at 0x%x, %d bytes\n",asects, flen - asects); + + return boff + asects; +} + +/* Not used */ + +/* Extract a module from a PE "Advance Installer" .exe file */ +/* Return NULL if not found */ +static xfile *aifile_extract(xfile **pxf, xfile *xi, char *tname, int verb) { + xfile *xf = NULL; + int i, j; + int asects; /* Offset after all the sections */ + int off; + + /* First we parse up the PE to figure out how much room is */ + /* used for known sections */ + if ((asects = extraPEsection(xi, 0, verb)) == 0) { + return NULL; + } + + /* Now we can search the "Advanced Installer" archive */ + /* It seems to be a set of concatenated PE files ? */ + + for (i= 0, off = asects; off != 0; i++) { + printf("\nPE %d at 0x%x\n",i,off); + off = extraPEsection(xi, off, verb > 2 ? 2 : verb); + } + + if (verb) printf(" pefile_extract_mod not implemented yet\n"); + return NULL; + +#ifdef NEVER + xf = add_xf(pxf); + xf->len = len; + + if ((xf->buf = malloc(xf->len)) == NULL) { + fprintf(stderr,"maloc of .cab buffer failed\n"); + exit(-1); + } + memmove(xf->buf, xi->buf + i ,xf->len); + + if ((xf->name = strdup(tname)) == NULL) { + fprintf(stderr,"maloc of .cab name failed\n"); + exit(-1); + } + + xf->ftype = file_dllcab; + xf->ttype = xi->ttype; + + if (verb) printf("Extacted '%s' length %ld\n",xf->name,xf->len); + + return xf; +#endif +} /* ================================================================ */ /* Extract files of a given type from a .cab file */ @@ -2407,6 +2827,8 @@ static xfile *cab_extract(xfile **pxf, xfile *xi, char *text, int verb) { unsigned long len = xi->len; unsigned long off; unsigned long filesize, headeroffset, datastart; + int headerres = 0, folderres = 0, datares = 0; + int hextra = 0; int nofolders, nofiles, flags, comptype; unsigned int totubytes; int ufiles = 0; @@ -2443,18 +2865,28 @@ static xfile *cab_extract(xfile **pxf, xfile *xi, char *text, int verb) { fprintf(stderr,"'%s' has more than one folder\n",xi->name); exit(-1); } - if (flags != 0) { - fprintf(stderr,"'%s' has non-zero flags\n",xi->name); + if (flags != 0 && flags != 4) { + fprintf(stderr,"'%s' has unhandled flags 0x%x\n",xi->name,flags); exit(-1); } + if (flags & 4) { /* If researved fields */ + // cbCFHeader, cbCFFolder, and cbCFData are present. + headerres = buf2short(buf + 0x24); + folderres = buf[0x26]; + datares = buf[0x27]; + + hextra = 4 + headerres; + } + /* Read the first folders info (assumed flags == 0) */ - datastart = buf2uint(buf + 0x24); - comptype = buf[0x2a]; + datastart = buf2uint(buf + hextra + 0x24); + comptype = buf[hextra + 0x2a]; if (comptype!= 1) { - fprintf(stderr,"'%s' doesn't use MSZip compression\n",xi->name); + fprintf(stderr,"'%s' doesn't use MSZip compression, uses %d\n",xi->name,comptype); exit(-1); } + /* Should skip folderres bytes here */ if (verb > 1) printf(".cab headeroffset = 0x%lx, datastart = 0x%lx, nofiles = %d\n",headeroffset,datastart,nofiles); @@ -2502,7 +2934,7 @@ static xfile *cab_extract(xfile **pxf, xfile *xi, char *text, int verb) { totubytes += ubytes; - off += 8 + cbytes; + off += 8 + datares + cbytes; } @@ -2530,7 +2962,7 @@ static xfile *cab_extract(xfile **pxf, xfile *xi, char *text, int verb) { cbytes = buf2short(buf + off + 0x04); ubytes = buf2short(buf + off + 0x06); - i_buf = buf + off + 8; + i_buf = buf + off + 8 + datares; i_len = cbytes; i_ix = 0; @@ -2548,7 +2980,7 @@ static xfile *cab_extract(xfile **pxf, xfile *xi, char *text, int verb) { /* The history buffer is meant to survive from one block to the next. */ /* Not sure what that means, as it seems to work as is... */ - off += 8 + cbytes; + off += 8 + datares + cbytes; } xf = add_xf(pxf); @@ -2569,8 +3001,8 @@ static xfile *cab_extract(xfile **pxf, xfile *xi, char *text, int verb) { fname[94] = '\000'; namelen = strlen(fname); - /* Lop of the junk in the filename */ - if ((cp = strrchr(fname, '.')) != NULL) + /* Lop of the junk in the filename, if it's present */ + if ((cp = strrchr(fname, '.')) != NULL && cp != strchr(fname, '.')) *cp = '\000'; /* See if it's the type of file we want */ -- cgit v1.2.3