/******************************************************************************
* *
* EXE header list and modify *
* *
* by Pierre Martineau, 91/01/29 *
* *
* Version 1.2 *
* *
>*****************************************************************************<
* Modified (stephen@estragon.uchicago.edu): *
* 1990oct23 sps Overlay splitter-outer first cut *
* 31 Error handling; some #defines *
* nov01 /l *
* 91jan29 Changed default overlay file names to conform to ovlmgr 30a0 *
******************************************************************************/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
/** parameters ***************************************************************/
#define MAXFILENAME 128 /* Probably overkill - theoretical limit is 80 */
#define NPARTS 36 /* Maximum # of overlay files (excluding root .EXE)*/
#define COPYBUFSIZE 32768 /* Fair sized buffer for file copy */
#define BAKEXT ".BAK"/* Extension for .exe backups */
#define OVLEXT ".OVL"/* Default extension for overlay files */
/* #define MANYZEROES */ /* Old style default: foo00001.ovl, not foo0.ovl */
/*****************************************************************************/
#define BOOLEAN int
#define TRUE 1
#define FALSE 0
int sstrccnt(register char const *s, register char c)
{ int n = 0;
while (*s) if (*s++ == c) n++;
return n;
}
FILE *wrkfile, *outfile;
long min, max, stk;
BOOLEAN listflg = FALSE;
BOOLEAN verbose = FALSE;
BOOLEAN minflg = FALSE;
BOOLEAN maxflg = FALSE;
BOOLEAN stkflg = FALSE;
int column = 0;
struct exehdr {
unsigned signature;
unsigned mod512;
unsigned pages;
unsigned relocitems;
unsigned headerparas;
unsigned minalloc;
unsigned maxalloc;
unsigned ss;
unsigned sp;
unsigned checksum;
unsigned ip;
unsigned cs;
unsigned relocptr;
unsigned ovlnum;
} exehdr_area;
main(argc, argv)
int argc;
char *argv[];
{
char *dot, *slash;
char fname[MAXFILENAME], oname[MAXFILENAME], zname[MAXFILENAME];
char *jname = NULL;
char *args;
int i;
long offset, oldstk;
unsigned nparts = 0, part = 0, partstart[NPARTS + 2];
printf("EXE list and modify V1.1s, by Pierre Martineau, 90/05/20.\n");
printf("This program may be freely distributed.\n");
if ((argc < 2) || (argc > NPARTS + 2)) {
usage();
return;
}
/* Process any remaining arguments */
if (argc == 2) {
listflg = TRUE;
verbose = TRUE; /* ??? */
}
else {
i = 2;
while (argc-- > 2) {
args = argv[i];
if ('0' <= args[0] && args[0] <= '9') { /* File split request */
if (nparts >= NPARTS) {
printf("\nToo many .OVL files requested (max. %d)\n", NPARTS);
usage();
return;
}
else if (!atoi(args)) {
printf("\nCan't relocate the root overlay (#0)\n");
usage();
return;
}
else if (nparts && partstart[nparts - 1] >= atoi(args)) {
printf("\nOverlay starts must be in ascending order\n");
usage();
return;
}
partstart[nparts++] = atoi(args);
} else {
if ((args[0] != '-') && (args[0] != '/')) {
printf("\nInvalid switch in paramater %s!\n", argv[i]);
usage();
return;
}
args++;
if (strnicmp(args, "min", 3) == 0) {
args += 3;
min = atol(args);
minflg = TRUE;
}
else if (strnicmp(args, "max", 3) == 0) {
args += 3;
max = atol(args);
maxflg = TRUE;
}
else if (strnicmp(args, "stk", 3) == 0) {
args += 3;
stk = atol(args);
stkflg = TRUE;
}
else if (strnicmp(args, "v", 1) == 0) {
listflg = TRUE;
verbose = TRUE;
}
else if (strnicmp(args, "l", 1) == 0)
listflg = TRUE;
else if (strnicmp(args, "p", 1) == 0) {
args++;
jname = args;
}
else {
printf("\nInvalid paramater %s!\n", argv[i]);
usage();
return;
}
}
i++;
}
}
/* Extract filename from first argumemt */
strcpy(fname, argv[1]);
dot = strrchr(fname, '.');
slash = strrchr(fname, '\\');
if ((dot == NULL) || (slash > dot))
strcat(fname, ".exe");
if (nparts) {
strcpy(oname,fname);
*strrchr(fname, '.') = '\0';
strcat(fname,BAKEXT);
if (!stricmp(oname,fname)) {
printf(
"\nI refuse to split a file with extension "BAKEXT": %s\n",
oname
);
return;
}
if (!jname || nparts > 1 && !sstrccnt(jname, '?')) {
char ext[5];
char *t;
if (!jname) {
strcpy(zname, oname);
*strrchr(zname, '.') = '\0';
strcpy(ext, OVLEXT);
} else {
if (strrchr(jname, '.') &&
(!strrchr(jname, '\\') ||
strrchr(jname, '.') > strrchr(jname, '\\')
)
) {
strncpy(ext, strrchr(jname, '.'), sizeof(ext));
ext[sizeof(ext) - 1] = '\0';
strncpy(zname, jname, strrchr(jname, '.') - jname);
zname[strrchr(jname, '.') - jname] = '\0';
} else {
strcpy(zname, jname);
strcpy(ext, OVLEXT);
}
}
t = strrchr(zname, '\\') ? strrchr(zname, '\\') + 1:
strrchr(zname, ':') ? strrchr(zname, ':') + 1:
zname;
if (strlen(t) >= 8)
t[7] = '\0';
#if defined(MANYZEROES)
while (strlen(t) < 8)
#endif
strcat(t, "?");
strcat(zname, ext);
jname = zname;
}
if (rename(oname,fname)) { /* This assumes oldname, newname.
There's some confusion. OK for TC2.0 */
printf("\nCouldn't rename (original) %s to %s\n", oname, fname);
return;
}
if ((outfile = fopen(oname, "wb")) == NULL) {
printf("\nCouldn't create file %s\n",oname);
return;
}
}
if ((wrkfile = fopen(fname, "r+b")) == NULL) {
printf("\nCouldn't open file %s\n", fname);
return;
}
fread(&exehdr_area, sizeof (struct exehdr), 1, wrkfile);
if (exehdr_area.signature != 0x5a4d) {
printf("\nNot an EXE file!\n");
return;
}
while(!feof(wrkfile)) {
if (nparts) {
if (exehdr_area.ovlnum == partstart[part]) {
fclose(outfile);
{
int p = part + 1;
strcpy(oname, jname);
while (sstrccnt(oname, '?') > 1) {
*strrchr(oname, '?') = '0' + p % 10;
p /= 10;
}
*strchr(oname, '?') = (p > 9 ? 'a' - 10 : '0') + p;
}
part++;
if ((outfile = fopen(oname, "wb")) == NULL) {
printf("\nCan't open file %s\n", oname);
return;
}
}
fwrite(&exehdr_area, sizeof (struct exehdr), 1, outfile);
if (ferror(outfile)) {
printf("\nWrite error while moving overlay header in %s\n", oname);
return;
}
}
if (listflg)
show_hdr();
else if (nparts)
printf("[overlay %d]\r", exehdr_area.ovlnum); /* Keep talking... */
if ((minflg || maxflg || stkflg) && (exehdr_area.ovlnum == 0) && (exehdr_area.signature == 0x5a4d)) {
if (minflg)
exehdr_area.minalloc = min;
if (maxflg)
exehdr_area.maxalloc = max;
if (stkflg) {
oldstk = exehdr_area.sp;
exehdr_area.sp = stk;
if (!minflg) {
exehdr_area.minalloc += ((stk - oldstk) / 16);
printf("\nAdjusting size of minalloc!\n");
}
}
fseek(nparts ? outfile : wrkfile, ftell(wrkfile) - sizeof (struct exehdr), SEEK_SET);
fwrite(&exehdr_area, sizeof (struct exehdr), 1, nparts ? outfile : wrkfile);
if (ferror(nparts ? outfile : wrkfile)) {
printf("Write error while trying to update header!\n");
fclose(nparts ? outfile : wrkfile);
return;
}
}
offset = exehdr_area.pages;
offset *= 512L;
offset -= sizeof(struct exehdr);
if (nparts) { /* Copy the stuff across */
static char buffer[COPYBUFSIZE];
while (offset > sizeof(buffer)) {
fread(buffer, sizeof(buffer), 1, wrkfile);
if (ferror(wrkfile)) {
printf("\nRead error in overlay body\n");
return;
}
fwrite(buffer, sizeof(buffer), 1, outfile);
if (ferror(outfile)) {
printf("\nWrite error moving overlay body, file %s\n", oname);
return;
}
offset -= sizeof(buffer);
}
fread(buffer, (unsigned)offset, 1, wrkfile);
if (ferror(wrkfile)) {
printf("\nRead error in overlay body\n");
return;
}
fwrite(buffer, (unsigned)offset, 1, outfile);
if (ferror(outfile)) {
printf("\nWrite error moving overlay body, file %s\n", oname);
return;
}
} else fseek(wrkfile, offset, SEEK_CUR);
fread(&exehdr_area, sizeof (struct exehdr), 1, wrkfile);
if (ferror(wrkfile)) {
printf("Read error while trying to get a header!\n");
fclose(wrkfile);
return;
}
}
if (nparts) {
fclose(outfile);
if (!listflg) printf(" \r");
}
fclose(wrkfile);
if (listflg && !verbose && column % 4) printf("\n");
}
show_hdr()
{
long lsize;
lsize = exehdr_area.pages;
if (exehdr_area.mod512 != 0)
lsize--;
lsize *= 512L;
lsize += exehdr_area.minalloc * 16;
lsize += exehdr_area.mod512;
lsize -= exehdr_area.headerparas * 16;
if (verbose) {
printf("\nOverlay: %d\n", exehdr_area.ovlnum);
printf("Size (512 byte pages)\t-%6x\t\t%6u\n", exehdr_area.pages, exehdr_area.pages);
printf("Remainder (last page)\t-%6x\t\t%6u\n", exehdr_area.mod512, exehdr_area.mod512);
printf("Header size (in paras)\t-%6x\t\t%6u\n", exehdr_area.headerparas, exehdr_area.headerparas);
printf("Minalloc (in paras)\t-%6x\t\t%6u\n", exehdr_area.minalloc, exehdr_area.minalloc);
printf("Maxalloc (in paras)\t-%6x\t\t%6u\n", exehdr_area.maxalloc, exehdr_area.maxalloc);
printf("Load size (in bytes)\t-%6lx\t\t%6lu\n", lsize, lsize);
printf("Relocation items\t-%6x\t\t%6u\n", exehdr_area.relocitems, exehdr_area.relocitems);
printf("Relocation table offset\t-%6x\t\t%6u\n", exehdr_area.relocptr, exehdr_area.relocptr);
printf("Checksum\t\t-%6x\t\t%6u\n", exehdr_area.checksum, exehdr_area.checksum);
printf("Initial CS:IP\t\t- %04x:%04x\n", exehdr_area.cs, exehdr_area.ip);
printf("Initial SS:SP\t\t- %04x:%04x\n", exehdr_area.ss, exehdr_area.sp);
} else {
if (!exehdr_area.ovlnum) {
printf("\nOverlay: %d\n", exehdr_area.ovlnum);
printf("Minalloc (in paras)\t-%6x\t\t%6u\n", exehdr_area.minalloc, exehdr_area.minalloc);
printf("Maxalloc (in paras)\t-%6x\t\t%6u\n", exehdr_area.maxalloc, exehdr_area.maxalloc);
printf("Stored size (in bytes)\t-%6lx\t\t%6lu\n", exehdr_area.pages * 512L, exehdr_area.pages * 512L);
printf("Load size (in bytes)\t-%6lx\t\t%6lu\n", lsize, lsize);
printf("Initial CS:IP, SS:SP\t- %04x:%04x\t %04x:%04x\n", exehdr_area.cs, exehdr_area.ip, exehdr_area.ss, exehdr_area.sp);
} else {
static bis = 0;
if (!bis++)
printf("\nOvl StrdSz LoadSz | Ovl StrdSz LoadSz | Ovl StrdSz LoadSz | Ovl StrdSz LoadSz\n");
printf("%3d:%6lu %6lu%s", exehdr_area.ovlnum, exehdr_area.pages * 512L, lsize, ++column % 4 ? " | " : "\n");
}
}
}
usage()
{
printf("\nUsage: exesmurf exe_file [/l] [/v] [/min#####] [/max#####] [/stk#####]\n");
printf(" [n1 n2...nn] [/p????????.???]\n");
printf(" where: min = minalloc\n");
printf(" max = maxalloc\n");
printf(" stk = stack size\n");
printf(" ##### = decimal number of paragraphs\n");
printf(" ni = overlay starting each new .OVL file, n1 < n2 <...< nn\n");
printf(" p = DOS filename, maybe with ?s, for overlay files.\n");
}