From b7a86735a25c93e89d8d166b950ddfa71589fb75 Mon Sep 17 00:00:00 2001 From: Luchezar Georgiev Date: Wed, 17 Nov 2004 18:01:54 +0000 Subject: [PATCH] Bart enhanced EXEFLAT for smaller packed binary; now calls UPX itself git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/branches/UNSTABLE@1063 6ac86273-5f31-0410-b378-82cca8765d1b --- docs/history.txt | 2 + kernel/makefile | 1 - sys/sys.c | 4 +- utils/exeflat.c | 492 +++++++++++++++++++++++++++++------------------ 4 files changed, 306 insertions(+), 193 deletions(-) diff --git a/docs/history.txt b/docs/history.txt index d817c00..77a60ba 100644 --- a/docs/history.txt +++ b/docs/history.txt @@ -3,6 +3,8 @@ + Changes Bart * int2f.asm - bugfix: call_nls: DI register was not preserved + * exeflat.c + - new version exploiting better UPX compression for SYS files; calls UPX itself + Changes Tom * inthndlr.c - improve handling of case where eg. FindFirst(I:\*.*) fails, causes Int24, diff --git a/kernel/makefile b/kernel/makefile index db79239..b194768 100644 --- a/kernel/makefile +++ b/kernel/makefile @@ -31,7 +31,6 @@ all: ..\bin\$(TARGET).sys ..\bin\country.sys ..\bin\$(TARGET).sys: $(TARGET).lnk $(OBJS) $(LIBS) ..\utils\exeflat.exe $(LINK) @$(TARGET).lnk; - $(XUPX) kernel.exe ..\utils\exeflat kernel.exe $*.sys $(LOADSEG) -S0x10 -S0x8B $(UPXOPT) copy $*.sys ..\bin\kernel.sys diff --git a/sys/sys.c b/sys/sys.c index 1afb43d..bb7f666 100644 --- a/sys/sys.c +++ b/sys/sys.c @@ -279,7 +279,7 @@ int FDKrnConfigMain(int argc, char **argv); #define OEMKERNEL "IBMBIO.COM" #define OEMDOS "IBMDOS.COM" #define MSKERNEL "IO.SYS" -#define MSDOS "MSDOS.SYS" +#define MS_DOS "MSDOS.SYS" #define FDLOADSEG 0x60 #define OEMLOADSEG 0x70 @@ -523,7 +523,7 @@ int main(int argc, char **argv) { char *dosfn = OEMDOS; #ifdef WITHOEMCOMPATBS - if (altkern == MS_OEMKERN) dosfn = MSDOS; + if (altkern == MS_OEMKERN) dosfn = MS_DOS; #endif if ( (!get_full_path(srcPath, rootPath, dosfn, srcFile)) || diff --git a/utils/exeflat.c b/utils/exeflat.c index a24b23e..2c6ddf8 100644 --- a/utils/exeflat.c +++ b/utils/exeflat.c @@ -52,11 +52,13 @@ large portions copied from task.c #define BUFSIZE 32768u +#define KERNEL_START 0x10 /* the kernel code really starts here at 60:10 */ + typedef struct { UWORD off, seg; } farptr; -int compReloc(const void *p1, const void *p2) +static int compReloc(const void *p1, const void *p2) { farptr *r1 = (farptr *) p1; farptr *r2 = (farptr *) p2; @@ -71,7 +73,7 @@ int compReloc(const void *p1, const void *p2) return 0; } -void usage(void) +static void usage(void) { printf("usage: exeflat (src.exe) (dest.sys) (relocation-factor)\n"); printf @@ -80,9 +82,11 @@ void usage(void) exit(1); } -int main(int argc, char **argv) +static exe_header header; + +int exeflat(int UPX, const char *srcfile, const char *dstfile, + const char *start, short *silentSegments, short silentcount) { - exe_header header; int i, j; size_t bufsize; farptr *reloc; @@ -91,8 +95,246 @@ int main(int argc, char **argv) UBYTE **buffers; UBYTE **curbuf; FILE *src, *dest; - short silentSegments[20], silentcount = 0, silentdone = 0; + short silentdone = 0; + int compress_sys_file; + + if ((src = fopen(srcfile, "rb")) == NULL) + { + printf("Source file %s could not be opened\n", srcfile); + exit(1); + } + if (fread(&header, sizeof(header), 1, src) != 1) + { + printf("Error reading header from %s\n", srcfile); + fclose(src); + exit(1); + } + if (header.exSignature != MAGIC) + { + printf("Source file %s is not a valid .EXE\n", srcfile); + fclose(src); + exit(1); + } + if ((dest = fopen(dstfile, "wb+")) == NULL) + { + printf("Destination file %s could not be created\n", dstfile); + exit(1); + } + start_seg = (UWORD)strtol(start, NULL, 0); + if (header.exExtraBytes == 0) + header.exExtraBytes = 0x200; + printf("header len = %lu = 0x%lx\n", header.exHeaderSize * 16UL, + header.exHeaderSize * 16UL); + size = + ((DWORD) (header.exPages - 1) << 9) + header.exExtraBytes - + header.exHeaderSize * 16UL; + printf("image size (less header) = %lu = 0x%lx\n", size, size); + printf("first relocation offset = %u = 0x%u\n", header.exOverlay, + header.exOverlay); + + /* first read file into memory chunks */ + fseek(src, header.exHeaderSize * 16UL, SEEK_SET); + buffers = malloc((size_t)((size + BUFSIZE - 1) / BUFSIZE) * sizeof(char *)); + if (buffers == NULL) + { + printf("Allocation error\n"); + exit(1); + } + bufsize = BUFSIZE; + for (to_xfer = size, curbuf = buffers; to_xfer > 0; + to_xfer -= bufsize, curbuf++) + { + if (to_xfer < BUFSIZE) + bufsize = (size_t)to_xfer; + *curbuf = malloc(bufsize); + if (*curbuf == NULL) + { + printf("Allocation error\n"); + exit(1); + } + if (fread(*curbuf, sizeof(char), bufsize, src) != bufsize) + { + printf("Source file read error %ld %d\n", to_xfer, bufsize); + exit(1); + } + } + if (header.exRelocTable && header.exRelocItems) + { + fseek(src, header.exRelocTable, SEEK_SET); + reloc = malloc(header.exRelocItems * sizeof(farptr)); + if (reloc == NULL) + { + printf("Allocation error\n"); + exit(1); + } + if (fread(reloc, sizeof(farptr), header.exRelocItems, src) != + header.exRelocItems) + { + printf("Source file read error\n"); + exit(1); + } + } + fclose(src); + qsort(reloc, header.exRelocItems, sizeof(reloc[0]), compReloc); + for (i = 0; i < header.exRelocItems; i++) + { + ULONG spot = ((ULONG) reloc[i].seg << 4) + reloc[i].off; + UBYTE *spot0 = &buffers[(size_t)(spot / BUFSIZE)][(size_t)(spot % BUFSIZE)]; + UBYTE *spot1 = &buffers[(size_t)((spot + 1) / BUFSIZE)][(size_t)((spot + 1) % BUFSIZE)]; + UWORD segment = ((UWORD) * spot1 << 8) + *spot0; + + for (j = 0; j < silentcount; j++) + if (segment == silentSegments[j]) + { + silentdone++; + goto dontPrint; + } + + printf("relocation at 0x%04x:0x%04x ->%04x\n", reloc[i].seg, + reloc[i].off, segment); + + dontPrint: + + segment += start_seg; + *spot0 = segment & 0xff; + *spot1 = segment >> 8; + } + + compress_sys_file = size < 0x10000L; + if (UPX && !compress_sys_file) { + /* write header without relocations to file */ + exe_header nheader = header; + nheader.exRelocItems = 0; + nheader.exHeaderSize = 2; + size += 32; + nheader.exPages = (UWORD)(size >> 9); + nheader.exExtraBytes = (UWORD)size & 511; + if (nheader.exExtraBytes) + nheader.exPages++; + if (fwrite(&nheader, sizeof(nheader), 1, dest) != 1) { + printf("Destination file write error\n"); + exit(1); + } + fseek(dest, 32UL, SEEK_SET); + } + + /* write dest file from memory chunks */ + bufsize = BUFSIZE; + for (to_xfer = size, curbuf = buffers; to_xfer > 0; + to_xfer -= bufsize, curbuf++) + { + if (to_xfer < BUFSIZE) + bufsize = (size_t)to_xfer; + if (fwrite(*curbuf, sizeof(char), bufsize, dest) != bufsize) + + { + printf("Destination file write error\n"); + exit(1); + } + free(*curbuf); + } + + if (UPX && compress_sys_file) { + /* overwrite first 8 bytes with SYS header */ + UWORD dhdr[4]; + fseek(dest, 0, SEEK_SET); + for (i = 0; i < 3; i++) + dhdr[i] = 0xffff; + /* strategy will jump to us, interrupt never called */ + dhdr[3] = KERNEL_START; + fwrite(dhdr, sizeof(dhdr), 1, dest); + } + fclose(dest); + printf("\nProcessed %d relocations, %d not shown\n", + header.exRelocItems, silentdone); + return compress_sys_file; +} + +static void write_header(FILE *dest, size_t size) +{ + /* UPX HEADER jump $+2+size */ + static char JumpBehindCode[] = { + /* kernel config header - 32 bytes */ + 0xeb, 0x1b, /* jmp short realentry */ + 'C', 'O', 'N', 'F', 'I', 'G', 32 - 2 - 6 - 2 - 3, 0, /* WORD */ + 0, /* DLASortByDriveNo db 0 */ + 1, /* InitDiskShowDriveAssignment db 1 */ + 2, /* SkipConfigSeconds db 2 */ + 0, /* ForceLBA db 0 */ + 1, /* GlobalEnableLBAsupport db 1 */ + 0, /* BootHarddiskSeconds */ + + 'n', 'u', 's', 'e', 'd', /* unused filler bytes */ + 8, 7, 6, 5, 4, 3, 2, 1, + /* real-entry: jump over the 'real' image do the trailer */ + 0xe9, 0, 0 /* 100: jmp 103 */ + }; + + struct x { + char y[sizeof(JumpBehindCode) == 0x20 ? 1 : -1]; + }; + + fseek(dest, 0, SEEK_SET); + /* this assumes <= 0xfe00 code in kernel */ + *(short *)&JumpBehindCode[0x1e] += size; + /* the UPX created-header is 32 bytes long */ + fwrite(JumpBehindCode, 1, 0x20, dest); +} + +static void write_trailer(FILE *dest, size_t size, int compress_sys_file) +{ + /* UPX trailer */ + /* hand assembled - so this remains ANSI C ;-) */ + /* well almost: we still need packing and assume little endian ... */ + /* move kernel down to place CONFIG-block, which added above, + at start_seg-2:0 (e.g. 0x5e:0) instead of + start_seg:0 (e.g. 0x60:0) and store there boot drive number + from BL; kernel.asm will then check presence of additional + CONFIG-block at this address. */ + static char trailer[] = { /* shift down everything by sizeof JumpBehindCode */ + 0xB9, 0x00, 0x00, /* 0 mov cx,offset trailer */ + 0x0E, /* 3 push cs */ + 0x1F, /* 4 pop ds (=60) */ + 0x8C, 0xC8, /* 5 mov ax,cs */ + 0x48, /* 7 dec ax */ + 0x48, /* 8 dec ax */ + 0x8E, 0xC0, /* 9 mov es,ax */ + 0x93, /* 11 xchg ax,bx (to get al=bl) */ + 0x31, 0xFF, /* 12 xor di,di */ + 0xFC, /* 14 cld */ + 0xAA, /* 15 stosb (store drive number)*/ + 0x8B, 0xF7, /* 16 mov si,di */ + 0xF3, 0xA4, /* 18 rep movsb */ + 0x1E, /* 20 push ds */ + 0x58, /* 21 pop ax */ + 0x05, 0x00, 0x00, /* 22 add ax,... */ + 0x8E, 0xD0, /* 25 mov ss,ax */ + 0xBC, 0x00, 0x00, /* 27 mov sp,... */ + 0x31, 0xC0, /* 30 xor ax,ax */ + 0xFF, 0xE0 /* 32 jmp ax */ + }; + + *(short *)&trailer[1] = (short)size + 0x20; + *(short *)&trailer[23] = header.exInitSS; + *(short *)&trailer[28] = header.exInitSP; + if (compress_sys_file) + /* replace by jmp word ptr [6]: ff 26 06 00 + (the .SYS strategy handler which will unpack) */ + *(long *)&trailer[30] = 0x000626ffL; + fwrite(trailer, 1, sizeof(trailer), dest); + fclose(dest); +} + +int main(int argc, char **argv) +{ + short silentSegments[20], silentcount = 0; + int compress_sys_file; + char *upx, *tmpexe, *buffer; + char cmdbuf[128]; int UPX = FALSE; + int i; + FILE *dest; + long size; /* if no arguments provided, show usage and exit */ if (argc < 4) usage(); @@ -130,197 +372,67 @@ int main(int argc, char **argv) /* arguments left : infile outfile relocation offset */ + + compress_sys_file = exeflat(UPX, argv[1], argv[2], argv[3], + silentSegments, silentcount); + if (!UPX) + exit(0); + + /* move kernel.sys tmp$$$$$.exe */ + tmpexe = argv[2]; + if (!compress_sys_file) + { + tmpexe = "tmp$$$$$.exe"; + rename(argv[2], tmpexe); + } + + upx = getenv("XUPX"); + if (upx == NULL) + upx = "UPX"; + +#if !defined(__TURBOC__) + /* upx kernel.exe -o kernel.sys */ + _snprintf(cmdbuf, sizeof cmdbuf, "%s %s", upx, tmpexe); +#else + /* oh well, let's hope for no buffer overflow...*/ + sprintf(cmdbuf, "%s %s", upx, tmpexe); +#endif + + if (system(cmdbuf)) + { + printf("Problems executing %s\n", cmdbuf); + remove(tmpexe); + exit(1); + } + + if (!compress_sys_file) + { + size = exeflat(FALSE, tmpexe, argv[2], argv[3], + silentSegments, silentcount); + remove(tmpexe); + } + /* argv[2] does now contain the final flattened file: just + header and trailer need to be added */ + /* the compressed file has two chunks max */ - if ((src = fopen(argv[1], "rb")) == NULL) + if ((dest = fopen(argv[2], "rb+")) == NULL) { - printf("Source file %s could not be opened\n", argv[1]); - return 1; - } - if (fread(&header, sizeof(header), 1, src) != 1) - { - printf("Error reading header from %s\n", argv[1]); - fclose(src); - return 1; - } - if (header.exSignature != MAGIC) - { - printf("Source file %s is not a valid .EXE\n", argv[1]); - fclose(src); - return 1; - } - if ((dest = fopen(argv[2], "wb+")) == NULL) - { - printf("Destination file %s could not be created\n", argv[2]); - return 1; - } - start_seg = (UWORD)strtol(argv[3], NULL, 0); - if (header.exExtraBytes == 0) - header.exExtraBytes = 0x200; - printf("header len = %lu = 0x%lx\n", header.exHeaderSize * 16UL, - header.exHeaderSize * 16UL); - size = - ((DWORD) (header.exPages - 1) << 9) + header.exExtraBytes - - header.exHeaderSize * 16UL; - printf("image size (less header) = %lu = 0x%lx\n", size, size); - printf("first relocation offset = %u = 0x%u\n", header.exOverlay, - header.exOverlay); - - /* first read file into memory chunks */ - fseek(src, header.exHeaderSize * 16UL, SEEK_SET); - buffers = malloc((size_t)((size + BUFSIZE - 1) / BUFSIZE) * sizeof(char *)); - if (buffers == NULL) - { - printf("Allocation error\n"); - return 1; - } - bufsize = BUFSIZE; - for (to_xfer = size, curbuf = buffers; to_xfer > 0; - to_xfer -= bufsize, curbuf++) - { - if (to_xfer < BUFSIZE) - bufsize = (size_t)to_xfer; - *curbuf = malloc(bufsize); - if (*curbuf == NULL) - { - printf("Allocation error\n"); - return 1; - } - if (fread(*curbuf, sizeof(char), bufsize, src) != bufsize) - { - printf("Source file read error %ld %d\n", to_xfer, bufsize); - return 1; - } - } - if (header.exRelocTable && header.exRelocItems) - { - fseek(src, header.exRelocTable, SEEK_SET); - reloc = malloc(header.exRelocItems * sizeof(farptr)); - if (reloc == NULL) - { - printf("Allocation error\n"); - return 1; - } - if (fread(reloc, sizeof(farptr), header.exRelocItems, src) != - header.exRelocItems) - { - printf("Source file read error\n"); - return 1; - } - fclose(src); - qsort(reloc, header.exRelocItems, sizeof(reloc[0]), compReloc); - for (i = 0; i < header.exRelocItems; i++) - { - ULONG spot = ((ULONG) reloc[i].seg << 4) + reloc[i].off; - UBYTE *spot0 = &buffers[(size_t)(spot / BUFSIZE)][(size_t)(spot % BUFSIZE)]; - UBYTE *spot1 = &buffers[(size_t)((spot + 1) / BUFSIZE)][(size_t)((spot + 1) % BUFSIZE)]; - UWORD segment = ((UWORD) * spot1 << 8) + *spot0; - - for (j = 0; j < silentcount; j++) - if (segment == silentSegments[j]) - { - silentdone++; - goto dontPrint; - } - - printf("relocation at 0x%04x:0x%04x ->%04x\n", reloc[i].seg, - reloc[i].off, segment); - - dontPrint: - - segment += start_seg; - *spot0 = segment & 0xff; - *spot1 = segment >> 8; - } - } - - if (UPX) - { - /* UPX HEADER jump $+2+size */ - static char JumpBehindCode[] = { - /* kernel config header - 32 bytes */ - 0xeb, 0x1b, /* jmp short realentry */ - 'C', 'O', 'N', 'F', 'I', 'G', 32 - 2 - 6 - 2 - 3, 0, /* WORD */ - 0, /* DLASortByDriveNo db 0 */ - 1, /* InitDiskShowDriveAssignment db 1 */ - 2, /* SkipConfigSeconds db 2 */ - 0, /* ForceLBA db 0 */ - 1, /* GlobalEnableLBAsupport db 1 */ - 0, /* BootHarddiskSeconds */ - - 'n', 'u', 's', 'e', 'd', /* unused filler bytes */ - 8, 7, 6, 5, 4, 3, 2, 1, - /* real-entry: jump over the 'real' image do the trailer */ - 0xe9, 0, 0 /* 100: jmp 103 */ - }; - - struct x { - char y[sizeof(JumpBehindCode) == 0x20 ? 1 : -1]; - }; - - if (size >= 0xfe00u) - { - printf("kernel; size too large - must be <= 0xfe00\n"); - exit(1); - } - - /* this assumes <= 0xfe00 code in kernel */ - *(short *)&JumpBehindCode[0x1e] += (short)size; - fwrite(JumpBehindCode, 1, 0x20, dest); + printf("Destination file %s could not be opened\n", argv[2]); + exit(1); } - /* write dest file from memory chunks */ - bufsize = BUFSIZE; - for (to_xfer = size, curbuf = buffers; to_xfer > 0; - to_xfer -= bufsize, curbuf++) - { - if (to_xfer < BUFSIZE) - bufsize = (size_t)to_xfer; - if (fwrite(*curbuf, sizeof(char), bufsize, dest) != bufsize) + buffer = malloc(0xfe01); - { - printf("Destination file write error\n"); - return 1; - } - } - - if (UPX) + fread(buffer, 0xfe01, 1, dest); + size = ftell(dest); + if (size >= 0xfe00u) { - /* UPX trailer */ - /* hand assembled - so this remains ANSI C ;-) */ - /* move kernel down to place CONFIG-block, which added above, - at start_seg-2:0 (e.g. 0x5e:0) instead of - start_seg:0 (e.g. 0x60:0) and store there boot drive number - from BL; kernel.asm will then check presence of additional - CONFIG-block at this address. */ - static char trailer[] = { - 0x0E, /* 0 push cs */ - 0x1F, /* 1 pop ds ; =0x60 */ - 0x8C,0xDF, /* 2 mov di,ds */ - 0x4F, /* 4 dec di */ - 0x4F, /* 5 dec di */ - 0x8E,0xC7, /* 6 mov es,di */ - 0xFC, /* 8 cld */ - 0x33,0xFF, /* 9 xor di,di */ - 0x93, /* 11 xchg ax,bx ; mov al,bl */ - 0xAA, /* 12 stosb ; mov [es:0],al */ - 0x8B,0xF7, /* 13 mov si,di */ - 0xB9,0x00,0x00, /* 15 mov cx,offset trailer */ - 0xF3,0xA4, /* 18 rep movsb */ - 0x1E, /* 20 push ds */ - 0x58, /* 21 pop ax */ - 0x05,0x00,0x00, /* 22 add ax,... */ - 0x8E,0xD0, /* 25 mov ss,ax */ - 0xBC,0x00,0x00, /* 27 mov sp,... */ - 0x31,0xC0, /* 30 xor ax,ax */ - 0xFF,0xE0, /* 32 jmp ax ; jmp 0 */ - }; - *(short *)&trailer[16] = (short)size + 0x20; - *(short *)&trailer[23] = header.exInitSS; - *(short *)&trailer[28] = header.exInitSP; - fwrite(trailer, 1, sizeof trailer, dest); + printf("kernel; size too large - must be <= 0xfe00\n"); + exit(1); } - fclose(dest); - printf("\nProcessed %d relocations, %d not shown\n", - header.exRelocItems, silentdone); + fseek(dest, 0, SEEK_SET); + write_header(dest, (size_t)size); + fwrite(buffer, (size_t)size, 1, dest); + write_trailer(dest, (size_t)size, compress_sys_file); return 0; }