exeflat: implement new-style UPX compression in DOS/SYS format
This commit is contained in:
parent
9382d7ce00
commit
10b4d1581f
@ -36,8 +36,8 @@ production: ../bin/$(TARGET).sys ../bin/country.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
|
||||
..$(DIRSEP)utils$(DIRSEP)exeflat.exe kernel.exe kernel.sys $(LOADSEG) -S0x10 -S0x78 -S0x79 -E..$(DIRSEP)utils$(DIRSEP)upxentry.bin $(UPXOPT) $(XUPX)
|
||||
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.exe: $(TARGET).lnk $(OBJS) $(LIBS)
|
||||
$(LINK) @$(TARGET).lnk;
|
||||
|
166
utils/exeflat.c
166
utils/exeflat.c
@ -53,7 +53,6 @@ large portions copied from task.c
|
||||
|
||||
#define BUFSIZE 32768u
|
||||
|
||||
#define KERNEL_START 0x16 /* the kernel code really starts here at 60:16 */
|
||||
#define KERNEL_CONFIG_LENGTH (32 - 2 - 4)
|
||||
/* 32 entrypoint structure,
|
||||
2 entrypoint short jump,
|
||||
@ -90,7 +89,8 @@ static void usage(void)
|
||||
|
||||
static int exeflat(const char *srcfile, const char *dstfile,
|
||||
const char *start, short *silentSegments, short silentcount,
|
||||
int UPX, UWORD stubsize, UWORD entryparagraphs, exe_header *header)
|
||||
int UPX, UWORD stubexesize, UWORD stubdevsize,
|
||||
UWORD entryparagraphs, exe_header *header)
|
||||
{
|
||||
int i, j;
|
||||
size_t bufsize;
|
||||
@ -103,7 +103,7 @@ static int exeflat(const char *srcfile, const char *dstfile,
|
||||
FILE *src, *dest;
|
||||
short silentdone = 0;
|
||||
int compress_sys_file;
|
||||
UWORD realentry;
|
||||
UWORD stubsize = 0;
|
||||
|
||||
if ((src = fopen(srcfile, "rb")) == NULL)
|
||||
{
|
||||
@ -214,16 +214,6 @@ static int exeflat(const char *srcfile, const char *dstfile,
|
||||
memcpy(kernel_config, &buffers[0][2], KERNEL_CONFIG_LENGTH);
|
||||
}
|
||||
|
||||
realentry = KERNEL_START;
|
||||
if (buffers[0][0] == 0xeb /* jmp short */)
|
||||
{
|
||||
realentry = buffers[0][1] + 2;
|
||||
}
|
||||
else if (buffers[0][0] == 0xe9 /* jmp near */)
|
||||
{
|
||||
realentry = ((UWORD)(buffers[0][2]) << 8) + buffers[0][1] + 3;
|
||||
}
|
||||
|
||||
if ((dest = fopen(dstfile, "wb+")) == NULL)
|
||||
{
|
||||
printf("Destination file %s could not be created\n", dstfile);
|
||||
@ -235,6 +225,7 @@ static int exeflat(const char *srcfile, const char *dstfile,
|
||||
if (UPX) {
|
||||
printf("Compressing kernel - %s format\n", (compress_sys_file)?"sys":"exe");
|
||||
if (!compress_sys_file) {
|
||||
stubsize = stubexesize;
|
||||
ULONG realsize;
|
||||
/* write header without relocations to file */
|
||||
exe_header nheader = *header;
|
||||
@ -265,10 +256,34 @@ static int exeflat(const char *srcfile, const char *dstfile,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("DOS/SYS format for UPX not yet supported.\n");
|
||||
/* create device header. it goes before the image. after
|
||||
decompression its strategy is entered from the UPX
|
||||
depacker. it consists of 5 words and a far jump:
|
||||
next device offset, next device segment, attributes,
|
||||
the fourth word is the offset of strategy entry,
|
||||
the fifth word would be offset of interrupt entry
|
||||
(not used by UPX apparently but better to give it). */
|
||||
UBYTE deviceheader[16] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
UWORD segment = start_seg;
|
||||
UWORD offset = 0xC0;
|
||||
stubsize = stubdevsize + 0x10; /* 0x10 for deviceheader */
|
||||
/* strategy will jump to us, interrupt never called */
|
||||
deviceheader[6] = 10;
|
||||
deviceheader[7] = 0; /* needed: strategy entry */
|
||||
deviceheader[8] = 10;
|
||||
deviceheader[9] = 0; /* interrupt entry */
|
||||
deviceheader[10] = 0xEA; /* jump far immediate */
|
||||
deviceheader[11] = offset & 0xFF;
|
||||
deviceheader[12] = (offset >> 8) & 0xFF;
|
||||
deviceheader[13] = segment & 0xFF;
|
||||
deviceheader[14] = (segment >> 8) & 0xFF;
|
||||
if (fwrite(deviceheader, 1, sizeof deviceheader, dest)
|
||||
!= sizeof deviceheader) {
|
||||
printf("Destination file write error\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* write dest file from memory chunks */
|
||||
{
|
||||
@ -280,15 +295,10 @@ static int exeflat(const char *srcfile, const char *dstfile,
|
||||
stub in the first iteration of the loop below. */
|
||||
};
|
||||
}
|
||||
if (UPX) {
|
||||
/* stubsize = 0 if not UPX */
|
||||
curbufoffset = stubsize;
|
||||
bufsize = BUFSIZE - stubsize;
|
||||
to_xfer = size - stubsize;
|
||||
} else {
|
||||
curbufoffset = 0;
|
||||
bufsize = BUFSIZE;
|
||||
to_xfer = size;
|
||||
}
|
||||
for (curbuf = buffers; to_xfer > 0;
|
||||
to_xfer -= bufsize, curbuf++, curbufoffset = 0, bufsize = BUFSIZE)
|
||||
{
|
||||
@ -301,24 +311,12 @@ static int exeflat(const char *srcfile, const char *dstfile,
|
||||
}
|
||||
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] = realentry; /* KERNEL_START; */
|
||||
fwrite(dhdr, sizeof(dhdr), 1, dest);
|
||||
printf("KERNEL_START = 0x%04x\n", realentry);
|
||||
}
|
||||
fclose(dest);
|
||||
return compress_sys_file;
|
||||
}
|
||||
|
||||
static void write_header(FILE *dest, unsigned char * code, UWORD stubsize,
|
||||
const char *start, exe_header *header)
|
||||
const char *start, int compress_sys_file, exe_header *header)
|
||||
{
|
||||
UWORD stackpointerpatch, stacksegmentpatch, psppatch, csippatch, patchvalue;
|
||||
UWORD end;
|
||||
@ -329,15 +327,29 @@ static void write_header(FILE *dest, unsigned char * code, UWORD stubsize,
|
||||
psppatch = code[0x104] + code[0x104 + 1] * 256U;
|
||||
csippatch = code[0x106] + code[0x106 + 1] * 256U;
|
||||
end = code[0x108] + code[0x108 + 1] * 256U;
|
||||
if (stackpointerpatch > (end - 2) || stackpointerpatch < 32
|
||||
|| stacksegmentpatch > (end - 2) || stacksegmentpatch < 32
|
||||
|| psppatch > (end - 2) || psppatch < 32
|
||||
|| csippatch > (end - 4) || csippatch < 32
|
||||
if (csippatch > (end - 4) || csippatch < 32
|
||||
|| end > 0xC0 || end < 32) {
|
||||
printf("Invalid entry file patch offsets\n");
|
||||
exit(1);
|
||||
}
|
||||
if (compress_sys_file) {
|
||||
if (stackpointerpatch != 0
|
||||
|| stacksegmentpatch != 0
|
||||
|| psppatch != 0
|
||||
|| end > (0xC0 - 0x10) || end < 32) {
|
||||
printf("Invalid entry file patch offsets\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
if (stackpointerpatch > (end - 2) || stackpointerpatch < 32
|
||||
|| stacksegmentpatch > (end - 2) || stacksegmentpatch < 32
|
||||
|| psppatch > (end - 2) || psppatch < 32) {
|
||||
printf("Invalid entry file patch offsets\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!compress_sys_file) {
|
||||
patchvalue = code[stackpointerpatch] + code[stackpointerpatch + 1] * 256U;
|
||||
patchvalue += header->exInitSP;
|
||||
code[stackpointerpatch] = patchvalue & 0xFF;
|
||||
@ -350,6 +362,8 @@ static void write_header(FILE *dest, unsigned char * code, UWORD stubsize,
|
||||
patchvalue += start_seg + (stubsize >> 4);
|
||||
code[psppatch] = patchvalue & 0xFF;
|
||||
code[psppatch + 1] = (patchvalue >> 8) & 0xFF;
|
||||
}
|
||||
/* ip and cs entered into header for DOS/SYS format*/
|
||||
patchvalue = header->exInitIP;
|
||||
code[csippatch] = patchvalue & 0xFF;
|
||||
code[csippatch + 1] = (patchvalue >> 8) & 0xFF;
|
||||
@ -384,13 +398,14 @@ int main(int argc, char **argv)
|
||||
int i;
|
||||
size_t sz, len, len2, n;
|
||||
int compress_sys_file;
|
||||
char *buffer, *tmpexe, *cmdbuf, *entryfilename = "";
|
||||
char *buffer, *tmpexe, *cmdbuf, *entryexefilename = "", *entrydevfilename = "";
|
||||
FILE *dest, *source;
|
||||
long size;
|
||||
static unsigned char code[256 + 10 + 1];
|
||||
static unsigned char execode[256 + 10 + 1];
|
||||
static unsigned char devcode[256 + 10 + 1];
|
||||
FILE * entryf = NULL;
|
||||
UWORD end;
|
||||
UWORD stubsize = 0;
|
||||
UWORD stubexesize = 0, stubdevsize = 0;
|
||||
|
||||
/* if no arguments provided, show usage and exit */
|
||||
if (argc < 4) usage();
|
||||
@ -411,7 +426,10 @@ int main(int argc, char **argv)
|
||||
UPX = i;
|
||||
break;
|
||||
case 'E':
|
||||
entryfilename = &argptr[1];
|
||||
entryexefilename = &argptr[1];
|
||||
break;
|
||||
case 'D':
|
||||
entrydevfilename = &argptr[1];
|
||||
break;
|
||||
case 'S':
|
||||
if (silentcount >= LENGTH(silentSegments))
|
||||
@ -430,21 +448,44 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (UPX) {
|
||||
entryf = fopen(entryfilename, "rb");
|
||||
if (*entryexefilename) {
|
||||
entryf = fopen(entryexefilename, "rb");
|
||||
if (!entryf) {
|
||||
printf("Cannot open entry file\n");
|
||||
exit(1);
|
||||
}
|
||||
if (fread(code, 1, 256 + 10 + 1, entryf) != 256 + 10) {
|
||||
if (fread(execode, 1, 256 + 10 + 1, entryf) != 256 + 10) {
|
||||
printf("Invalid entry file length\n");
|
||||
exit(1);
|
||||
}
|
||||
end = code[0x108] + code[0x108 + 1] * 256U;
|
||||
end = execode[0x108] + execode[0x108 + 1] * 256U;
|
||||
if (end > 0xC0 || end < 32) {
|
||||
printf("Invalid entry file patch offsets\n");
|
||||
exit(1);
|
||||
}
|
||||
stubsize = (end + 15U) & ~15U;
|
||||
stubexesize = (end + 15U) & ~15U;
|
||||
fclose(entryf);
|
||||
entryf = NULL;
|
||||
}
|
||||
if (*entrydevfilename) {
|
||||
entryf = fopen(entrydevfilename, "rb");
|
||||
if (!entryf) {
|
||||
printf("Cannot open entry file\n");
|
||||
exit(1);
|
||||
}
|
||||
if (fread(devcode, 1, 256 + 10 + 1, entryf) != 256 + 10) {
|
||||
printf("Invalid entry file length\n");
|
||||
exit(1);
|
||||
}
|
||||
end = devcode[0x108] + devcode[0x108 + 1] * 256U;
|
||||
if (end > (0xC0 - 0x10) || end < 32) { /* 0x10 for device header */
|
||||
printf("Invalid entry file patch offsets\n");
|
||||
exit(1);
|
||||
}
|
||||
stubdevsize = (end + 15U) & ~15U;
|
||||
fclose(entryf);
|
||||
entryf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* arguments left :
|
||||
@ -452,17 +493,18 @@ int main(int argc, char **argv)
|
||||
|
||||
compress_sys_file = exeflat(argv[1], argv[2], argv[3],
|
||||
silentSegments, silentcount,
|
||||
UPX, stubsize, 0, &header);
|
||||
UPX, stubexesize, stubdevsize, 0, &header);
|
||||
if (!UPX)
|
||||
exit(0);
|
||||
|
||||
/* move kernel.sys tmp.exe */
|
||||
tmpexe = argv[2];
|
||||
if (!compress_sys_file)
|
||||
{
|
||||
tmpexe = "tmp.exe";
|
||||
rename(argv[2], tmpexe);
|
||||
} else {
|
||||
tmpexe = "tmp.sys";
|
||||
}
|
||||
rename(argv[2], tmpexe);
|
||||
|
||||
len2 = strlen(tmpexe) + 1;
|
||||
sz = len2;
|
||||
@ -497,16 +539,31 @@ int main(int argc, char **argv)
|
||||
|
||||
if (!compress_sys_file)
|
||||
{
|
||||
exeflat(tmpexe, argv[2], argv[3],
|
||||
exeflat(tmpexe, "tmp.bin", argv[3],
|
||||
silentSegments, silentcount,
|
||||
FALSE, stubsize, stubsize >> 4, &header);
|
||||
FALSE, stubexesize, 0, stubexesize >> 4, &header);
|
||||
} else {
|
||||
FILE * devfile = fopen("tmp.sys", "rb");
|
||||
if (!devfile) {
|
||||
printf("Source file %s could not be opened\n", "tmp.sys");
|
||||
exit(1);
|
||||
}
|
||||
UBYTE deviceheader[16];
|
||||
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");
|
||||
}
|
||||
|
||||
/* argv[2] now contains the final flattened file: just
|
||||
header and trailer need to be added */
|
||||
/* the compressed file has two chunks max */
|
||||
|
||||
rename(argv[2], "tmp.bin");
|
||||
if ((dest = fopen(argv[2], "wb")) == NULL)
|
||||
{
|
||||
printf("Destination file %s could not be opened\n", argv[2]);
|
||||
@ -525,7 +582,11 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
write_header(dest, code, stubsize, argv[3], &header);
|
||||
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) {
|
||||
@ -534,6 +595,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
} while (size);
|
||||
|
||||
fclose(source);
|
||||
remove("tmp.bin");
|
||||
|
||||
return 0;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
CFLAGS = -I..$(DIRSEP)hdr
|
||||
|
||||
production: patchobj.com exeflat.exe upxentry.bin
|
||||
production: patchobj.com exeflat.exe upxentry.bin upxdevic.bin
|
||||
|
||||
patchobj.com: patchobj.c
|
||||
$(CLT) $(CFLAGS) patchobj.c
|
||||
@ -10,6 +10,9 @@ patchobj.com: patchobj.c
|
||||
upxentry.bin: upxentry.asm
|
||||
$(NASM) -f bin upxentry.asm -o upxentry.bin
|
||||
|
||||
upxdevic.bin: upxdevic.asm
|
||||
$(NASM) -f bin upxdevic.asm -o upxdevic.bin
|
||||
|
||||
exeflat.exe: exeflat.c ../hdr/exe.h
|
||||
$(CLC) $(CFLAGS) exeflat.c
|
||||
|
||||
@ -18,5 +21,5 @@ clobber: clean
|
||||
|
||||
clean:
|
||||
$(RM) *.obj *.bak *.crf *.xrf *.map *.lst *.las *.cod *.err status.me
|
||||
$(RM) exeflat.exe patchobj.com upxentry.bin
|
||||
$(RM) exeflat.exe patchobj.com upxentry.bin upxdevic.bin
|
||||
|
||||
|
37
utils/upxdevic.asm
Normal file
37
utils/upxdevic.asm
Normal file
@ -0,0 +1,37 @@
|
||||
cpu 8086
|
||||
org 0
|
||||
|
||||
bootloadunit: ; (byte of short jump re-used)
|
||||
start:
|
||||
jmp strict short entry
|
||||
times (32 - 4) - ($ - $$) db 0
|
||||
; area for CONFIG block
|
||||
|
||||
bootloadstack: ; (dword re-used for original ss:sp)
|
||||
entry:
|
||||
; common setup (copied from kernel.asm)
|
||||
push cs
|
||||
pop ds
|
||||
xor di, di
|
||||
mov byte [di + bootloadunit - $$], bl
|
||||
push bp
|
||||
mov word [di + bootloadstack - $$], sp
|
||||
mov word [di + bootloadstack + 2 - $$], ss
|
||||
|
||||
; the UPX DOS/SYS depacker does not need a certain ss:sp
|
||||
; however it appears to need cs == ds
|
||||
|
||||
mov ds, word [di + patchcsip + 2 - $$]
|
||||
jmp 0:0
|
||||
patchcsip: equ $ - 4
|
||||
end:
|
||||
|
||||
times 0C0h - ($ - $$) nop
|
||||
entry_common:
|
||||
|
||||
times 100h - ($ - $$) db 0
|
||||
dw 0
|
||||
dw 0
|
||||
dw 0
|
||||
dw patchcsip
|
||||
dw end
|
Loading…
Reference in New Issue
Block a user