From a5b516dd7bc87d10e082dc1db4e6925b79e3bac4 Mon Sep 17 00:00:00 2001 From: Jiri Malak Date: Sun, 14 Jul 2024 17:59:18 +0200 Subject: [PATCH] exeflat: add support for response file to exeflat utility the command line can overflow DOS max length that it fixes this issue --- ci_build.sh | 1 + kernel/makefile | 16 ++- utils/exeflat.c | 352 ++++++++++++++++++++++++++++-------------------- 3 files changed, 222 insertions(+), 147 deletions(-) diff --git a/ci_build.sh b/ci_build.sh index 4bb7a2e..582d15b 100755 --- a/ci_build.sh +++ b/ci_build.sh @@ -74,6 +74,7 @@ git clean -x -d -f -e test -e _output -e _downloads -e _watcom echo set XCPU=386 echo set XFAT=32 echo set XNASM='C:\\devel\\nasm\\nasm' + echo set XUPX=upx --8086 --best echo set OLDPATH=%PATH% echo set PATH='%WATCOM%\\binw;C:\\bin;%OLDPATH%' } | unix2dos > config.bat diff --git a/kernel/makefile b/kernel/makefile index 7680141..6d53129 100644 --- a/kernel/makefile +++ b/kernel/makefile @@ -36,8 +36,8 @@ production: ../bin/$(TARGET).sys # -S to avoid showing expected relocations # 0x10 & 0x78 or 0x79 depending on compilation options -kernel.sys: kernel.exe ../utils/exeflat.exe ../utils/upxentry.bin ../utils/upxdevic.bin - ..$(DIRSEP)utils$(DIRSEP)exeflat.exe kernel.exe kernel.sys $(LOADSEG) -S0x10 -S0x78 -S0x79 -E..$(DIRSEP)utils$(DIRSEP)upxentry.bin -D..$(DIRSEP)utils$(DIRSEP)upxdevic.bin $(UPXOPT) $(XUPX) +kernel.sys: kernel.exe ../utils/exeflat.exe ../utils/upxentry.bin ../utils/upxdevic.bin exeflat.rsp + ..$(DIRSEP)utils$(DIRSEP)exeflat.exe kernel.exe kernel.sys $(LOADSEG) @exeflat.rsp kernel.exe: $(TARGET).lnk $(OBJS) $(LIBS) $(LINK) @$(TARGET).lnk; @@ -46,11 +46,21 @@ clobber: clean -$(RM) kernel.exe kernel.sys status.me clean: - -$(RM) *.obj *.bak *.crf *.xrf *.map *.lst *.cod *.err *.lnk + -$(RM) *.obj *.bak *.crf *.xrf *.map *.lst *.cod *.err *.lnk *.rsp # XXX: This is a very ugly way of linking the kernel, forced upon us by the # inability of Turbo `make' 2.0 to perform command line redirection. -- ror4 +exeflat.rsp: makefile + -$(RM) exeflat.rsp + $(ECHOTO) exeflat.rsp -S0x10 + $(ECHOTO) exeflat.rsp -S0x78 + $(ECHOTO) exeflat.rsp -S0x79 + $(ECHOTO) exeflat.rsp -E..$(DIRSEP)utils$(DIRSEP)upxentry.bin + $(ECHOTO) exeflat.rsp -D..$(DIRSEP)utils$(DIRSEP)upxdevic.bin + $(ECHOTO) exeflat.rsp $(UPXOPT) + $(ECHOTO) exeflat.rsp $(XUPX) + $(TARGET).lnk: turboc.cfg makefile ../mkfiles/generic.mak ../mkfiles/$(COMPILER).mak -$(RM) *.lnk $(ECHOTO) $(TARGET).lnk $(OBJS1)+ diff --git a/utils/exeflat.c b/utils/exeflat.c index e08c024..26d8281 100644 --- a/utils/exeflat.c +++ b/utils/exeflat.c @@ -90,7 +90,7 @@ static void usage(void) static int exeflat(const char *srcfile, const char *dstfile, const char *start, short *silentSegments, short silentcount, - int UPX, UWORD stubexesize, UWORD stubdevsize, + int use_upx, UWORD stubexesize, UWORD stubdevsize, UWORD entryparagraphs, exe_header *header) { int i, j; @@ -207,7 +207,7 @@ static int exeflat(const char *srcfile, const char *dstfile, printf("\nProcessed %d relocations, %d not shown\n", header->exRelocItems, silentdone); - if (UPX) + if (use_upx) { struct x { char y[(KERNEL_CONFIG_LENGTH + 2) <= BUFSIZE ? 1 : -1]; @@ -224,7 +224,7 @@ static int exeflat(const char *srcfile, const char *dstfile, /* The biggest .sys file that UPX accepts seems to be 65419 bytes long. Actually, UPX 3.96 appears to accept DOS/SYS files up to 65426 bytes. To avoid problems we use a slightly lower limit. */ - if (UPX) { + if (use_upx) { if (stubdevsize && stubexesize) compress_sys_file = (size - stubdevsize) <= /* 65426 */ 65400; /* would need to subtract 0x10 for the device header here @@ -407,13 +407,59 @@ static void write_header(FILE *dest, unsigned char * code, UWORD stubsize, } } +int my_isspace( int c ) +{ + switch( c ) { + case ' ': + case '\n': + case '\r': + case '\f': + case '\t': + case '\v': + return( 1 ); + default: + return( 0 ); + } +} + +char *getarg( FILE *fp ) +{ + static char buff[256]; + char *str; + size_t len; + + while( (str = fgets( buff, sizeof(buff) - 1, fp )) != NULL ) { + buff[sizeof(buff) - 1] = '\0'; + len = strlen(buff); + while( len > 0 ) { + len--; + if( my_isspace( buff[len] ) ) { + buff[len] = '\0'; + continue; + } + len++; + break; + } + while( len-- > 0 ) { + if( !my_isspace(*str) ) { + break; + } + } + if( *str != '\0' ) { + break; + } + } + return( str ); +} + int main(int argc, char **argv) { short silentSegments[20], silentcount = 0; static exe_header header; /* must be initialized to zero */ - int UPX = FALSE; + int use_upx = 0; + char *upx_cmd; int i; - size_t sz, len, len2, n; + size_t len; int compress_sys_file; char *buffer, *tmpexe, *cmdbuf, *entryexefilename = "", *entrydevfilename = ""; FILE *dest, *source; @@ -423,48 +469,81 @@ int main(int argc, char **argv) FILE * entryf = NULL; UWORD end; UWORD stubexesize = 0, stubdevsize = 0; + FILE *indir = NULL; - /* if no arguments provided, show usage and exit */ + /* if no arguments provided, show usage and exit */ if (argc < 4) usage(); + upx_cmd = malloc(1); + *upx_cmd = '\0'; + i = 4; /* do optional argument processing here */ - for (i = 4; i < argc && !UPX; i++) + while ( i < argc || indir != NULL ) { - char *argptr = argv[i]; - - if (argptr[0] != '-' && argptr[0] != '/') - usage(); - - argptr++; + char *argptr = NULL; - switch (toupper(argptr[0])) - { - case 'U': - UPX = i; - break; - case 'E': - entryexefilename = &argptr[1]; - break; - case 'D': - entrydevfilename = &argptr[1]; - break; - case 'S': - if (silentcount >= LENGTH(silentSegments)) - { - printf("can't handle more then %d silent's\n", - (int)LENGTH(silentSegments)); - exit(1); - } - - silentSegments[silentcount++] = (short)strtol(argptr + 1, NULL, 0); - break; - - default: - usage(); + if( indir != NULL ) { + argptr = getarg( indir ); + if(argptr == NULL) { + fclose( indir ); + indir = NULL; + continue; + } + } + if( argptr == NULL ) { + argptr = argv[i++]; + } + if( use_upx ) { + len = strlen( upx_cmd ); + if( len > 0 ) len++; + upx_cmd = realloc( upx_cmd, len + strlen( argptr ) + 1 ); + if( len > 0 ) upx_cmd[len - 1] = ' '; + strcpy( upx_cmd + len, argptr ); + } else { + switch (*(unsigned char *)argptr++) + { + case '@': + indir = fopen( argptr, "r" ); + if( indir == NULL ) { + printf("can't open indirect file '%s'\n", argptr); + exit(1); + } + break; + case '-': + case '/': + switch (toupper(*(unsigned char *)argptr++)) + { + case 'U': + use_upx = 1; + break; + case 'E': + entryexefilename = malloc(strlen(argptr) + 1); + strcpy(entryexefilename, argptr); + break; + case 'D': + entrydevfilename = malloc(strlen(argptr) + 1); + strcpy(entrydevfilename, argptr); + break; + case 'S': + if (silentcount >= LENGTH(silentSegments)) + { + printf("can't handle more then %d silent's\n", + (int)LENGTH(silentSegments)); + exit(1); + } + silentSegments[silentcount++] = (short)strtol(argptr, NULL, 0); + break; + default: + usage(); + } + break; + default: + usage(); + } } } - if (UPX) { + if (use_upx) { if (*entryexefilename) { entryf = fopen(entryexefilename, "rb"); if (!entryf) { @@ -510,115 +589,100 @@ int main(int argc, char **argv) compress_sys_file = exeflat(argv[1], argv[2], argv[3], silentSegments, silentcount, - UPX, stubexesize, stubdevsize, 0, &header); - if (!UPX) - exit(0); - - /* move kernel.sys tmp.exe */ - if (!compress_sys_file) + use_upx, stubexesize, stubdevsize, 0, &header); + if (use_upx) { - tmpexe = "tmp.exe"; - } else { - tmpexe = "tmp.sys"; - } - if (rename(argv[2], tmpexe)) - { - printf("Can not rename %s to %s\n", argv[2], tmpexe); - exit(1); - } - - len2 = strlen(tmpexe) + 1; - sz = len2; - if (sz < 256) sz = 256; - cmdbuf = malloc(sz); - len = 0; - for (i = UPX+1; i < argc; i++) - { - n = strlen(argv[i]); - if (len + len2 + n + 2 >= sz) { - sz *= 2; - cmdbuf = realloc(cmdbuf, sz); + /* move kernel.sys tmp.exe */ + if (!compress_sys_file) + { + tmpexe = "tmp.exe"; + } else { + tmpexe = "tmp.sys"; } - if (i > UPX+1) - cmdbuf[len++] = ' '; - memcpy(cmdbuf + len, argv[i], n + 1); - len += n; - } - cmdbuf[len++] = ' '; - /* if tmpexe is tmpfile set above no quotes needed, if user needs quotes should add on cmd line */ - memcpy(cmdbuf + len, tmpexe, len2); - cmdbuf[len + len2] = '\0'; - printf("%s\n", cmdbuf); - fflush(stdout); - if (system(cmdbuf)) - { - printf("Problems executing %s\n", cmdbuf); - printf("Removing [%s]\n", tmpexe); + if (rename(argv[2], tmpexe)) + { + printf("Can not rename %s to %s\n", argv[2], tmpexe); + exit(1); + } + + len = strlen(upx_cmd); + cmdbuf = malloc(len + 1 + strlen(tmpexe) + 1); + strcpy(cmdbuf, upx_cmd); + cmdbuf[len] = ' '; + /* if tmpexe is tmpfile set above no quotes needed, if user needs quotes should add on cmd line */ + strcpy(cmdbuf + len + 1, tmpexe); + printf("%s\n", cmdbuf); + fflush(stdout); + if (system(cmdbuf)) + { + printf("Problems executing %s\n", cmdbuf); + printf("Removing [%s]\n", tmpexe); + remove(tmpexe); + exit(1); + } + free(cmdbuf); + + if (!compress_sys_file) + { + exeflat(tmpexe, "tmp.bin", argv[3], + silentSegments, silentcount, + FALSE, stubexesize, 0, stubexesize >> 4, &header); + } else { + UBYTE deviceheader[16]; + FILE * devfile = fopen("tmp.sys", "rb"); + if (!devfile) { + printf("Source file %s could not be opened\n", "tmp.sys"); + exit(1); + } + if (fread(deviceheader, 1, sizeof deviceheader, devfile) + != sizeof deviceheader) { + printf("Source file %s could not be read\n", "tmp.sys"); + exit(1); + } + fclose(devfile); + header.exInitIP = deviceheader[6] + deviceheader[7] * 256U; + header.exInitCS = 0; + rename("tmp.sys", "tmp.bin"); + } + + /* tmp.bin now contains the final flattened file: just + the UPX entry header needs to be added. */ + /* the compressed file may exceed 64 KiB for DOS/EXE format. */ + + if ((dest = fopen(argv[2], "wb")) == NULL) + { + printf("Destination file %s could not be opened\n", argv[2]); + exit(1); + } + if ((source = fopen("tmp.bin", "rb")) == NULL) + { + printf("Source file %s could not be opened\n", "tmp.bin"); + exit(1); + } + + buffer = malloc(32 * 1024); + if (!buffer) + { + printf("Memory allocation failure\n"); + exit(1); + } + + write_header(dest, + compress_sys_file ? devcode : execode, + compress_sys_file ? stubdevsize : stubexesize, + argv[3], compress_sys_file, &header); + + do { + size = fread(buffer, 1, 32 * 1024, source); + if (fwrite(buffer, 1, size, dest) != size) { + printf("Write failure\n"); + exit(1); + } + } while (size); + + fclose(source); + remove("tmp.bin"); remove(tmpexe); - exit(1); } - free(cmdbuf); - - if (!compress_sys_file) - { - exeflat(tmpexe, "tmp.bin", argv[3], - silentSegments, silentcount, - FALSE, stubexesize, 0, stubexesize >> 4, &header); - } else { - UBYTE deviceheader[16]; - FILE * devfile = fopen("tmp.sys", "rb"); - if (!devfile) { - printf("Source file %s could not be opened\n", "tmp.sys"); - exit(1); - } - if (fread(deviceheader, 1, sizeof deviceheader, devfile) - != sizeof deviceheader) { - printf("Source file %s could not be read\n", "tmp.sys"); - exit(1); - } - fclose(devfile); - header.exInitIP = deviceheader[6] + deviceheader[7] * 256U; - header.exInitCS = 0; - rename("tmp.sys", "tmp.bin"); - } - - /* tmp.bin now contains the final flattened file: just - the UPX entry header needs to be added. */ - /* the compressed file may exceed 64 KiB for DOS/EXE format. */ - - if ((dest = fopen(argv[2], "wb")) == NULL) - { - printf("Destination file %s could not be opened\n", argv[2]); - exit(1); - } - if ((source = fopen("tmp.bin", "rb")) == NULL) - { - printf("Source file %s could not be opened\n", "tmp.bin"); - exit(1); - } - - buffer = malloc(32 * 1024); - if (!buffer) - { - printf("Memory allocation failure\n"); - exit(1); - } - - write_header(dest, - compress_sys_file ? devcode : execode, - compress_sys_file ? stubdevsize : stubexesize, - argv[3], compress_sys_file, &header); - - do { - size = fread(buffer, 1, 32 * 1024, source); - if (fwrite(buffer, 1, size, dest) != size) { - printf("Write failure\n"); - exit(1); - } - } while (size); - - fclose(source); - remove("tmp.bin"); - remove(tmpexe); return 0; }