Major rewrite: added buildLoader() and fillExeHeader().

committer: mfx <mfx> 978189850 +0000
This commit is contained in:
Markus F.X.J. Oberhumer
2000-12-30 15:24:10 +00:00
parent f36feee0dc
commit 85bebf0b43
2 changed files with 153 additions and 127 deletions
+146 -126
View File
@@ -39,6 +39,8 @@ static const
#define MAXMATCH 0x2000 #define MAXMATCH 0x2000
#define MAXRELOCS (0x8000-MAXMATCH) #define MAXRELOCS (0x8000-MAXMATCH)
#define DI_LIMIT 0xff00 // see the assembly why
/************************************************************************* /*************************************************************************
// //
@@ -68,16 +70,113 @@ const int *PackExe::getFilters() const
} }
int PackExe::fillExeHeader(struct exe_header_t *eh) const
{
#define oh (*eh)
// fill new exe header
int flag = 0;
if (!opt->dos.no_reloc)
flag |= USEJUMP;
if (ih.relocs == 0)
flag |= NORELOC;
memset(&oh,0,sizeof(oh));
oh.ident = 'M' + 'Z' * 256;
oh.headsize16 = 2;
oh.ip = 0;
unsigned destpara = (ph.u_len + ph.overlap_overhead - ph.c_len + 31) / 16;
oh.ss = ph.c_len/16 + destpara;
if (ih.ss*16 + ih.sp < 0x100000 && ih.ss > oh.ss && ih.sp > 0x200)
oh.ss = ih.ss;
oh.sp = ih.sp > 0x200 ? ih.sp : 0x200;
if (oh.ss*16u + 0x50 < ih.ss*16u + ih.sp
&& oh.ss*16u + 0x200 > ih.ss*16u + ih.sp)
oh.ss += 0x20;
if (oh.ss != ih.ss)
flag |= SS;
if (oh.sp != ih.sp)
flag |= SP;
return flag;
#undef oh
}
int PackExe::buildLoader(const Filter *)
{
struct exe_header_t tmp_oh;
int flag = fillExeHeader(&tmp_oh);
// prepare loader
initLoader(nrv_loader,sizeof(nrv_loader));
addLoader("EXEENTRY",
relocsize ? "EXERELPU" : "",
"EXEMAIN4""+G5DXXXX""UPX1HEAD""EXECUTPO",
NULL
);
if (ph.method == M_NRV2B_8)
addLoader("NRV2B16S", // decompressor
ph.u_len > DI_LIMIT ? "NDIGT64K" : "",
"NRV2BEX1",
opt->cpu == opt->CPU_8086 ? "N2BX8601" : "N2B28601",
"NRV2BEX2",
opt->cpu == opt->CPU_8086 ? "N2BX8602" : "N2B28602",
"NRV2BEX3",
ph.c_len > 0xffff ? "NSIGT64K" : "",
"NRV2BEX9""NRV2B16E",
NULL
);
else if (ph.method == M_NRV2D_8)
addLoader("NRV2D16S",
ph.u_len > DI_LIMIT ? "NDIGT64D" : "",
"NRV2DEX1",
opt->cpu == opt->CPU_8086 ? "N2DX8601" : "N2D28601",
"NRV2DEX2",
opt->cpu == opt->CPU_8086 ? "N2DX8602" : "N2D28602",
"NRV2DEX3",
ph.c_len > 0xffff ? "NSIGT64D" : "",
"NRV2DEX9""NRV2D16E",
NULL
);
else
throwInternalError("unknown compression method");
addLoader("EXEMAIN5", NULL);
if (relocsize)
addLoader(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? "EXENOADJ" : "EXEADJUS",
"EXERELO1",
has_9a ? "EXEREL9A" : "",
"EXERELO2",
ih_exesize > 0xFE00 ? "EXEREBIG" : "",
"EXERELO3",
NULL
);
addLoader("EXEMAIN8",
(flag & SS) ? "EXESTACK" : "",
(flag & SP) ? "EXESTASP" : "",
(flag & USEJUMP) ? "EXEJUMPF" : "",
NULL
);
if (!(flag & USEJUMP))
addLoader(ih.cs ? "EXERCSPO" : "",
"EXERETIP",
NULL
);
return getLoaderSize();
}
/************************************************************************* /*************************************************************************
// //
**************************************************************************/ **************************************************************************/
bool PackExe::readFileHeader() int PackExe::readFileHeader()
{ {
ih_exesize = ih_imagesize = ih_overlay = 0; ih_exesize = ih_imagesize = ih_overlay = 0;
fi->readx(&ih,sizeof(ih)); fi->readx(&ih,sizeof(ih));
if (ih.ident != 'M' + 'Z'*256 && ih.ident != 'Z' + 'M'*256) if (ih.ident != 'M' + 'Z'*256 && ih.ident != 'Z' + 'M'*256)
return false; return 0;
ih_exesize = ih.m512 + ih.p512*512 - (ih.m512 ? 512 : 0); ih_exesize = ih.m512 + ih.p512*512 - (ih.m512 ? 512 : 0);
ih_imagesize = ih_exesize - ih.headsize16*16; ih_imagesize = ih_exesize - ih.headsize16*16;
ih_overlay = file_size - ih_exesize; ih_overlay = file_size - ih_exesize;
@@ -88,7 +187,7 @@ bool PackExe::readFileHeader()
#if 0 #if 0
printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay); printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay);
#endif #endif
return true; return UPX_F_DOS_EXE;
} }
@@ -241,34 +340,25 @@ unsigned optimize_relocs(upx_byte *b, const unsigned size,
void PackExe::pack(OutputFile *fo) void PackExe::pack(OutputFile *fo)
{ {
unsigned ic; unsigned ic;
unsigned char flag = 0;
unsigned char extra_info[32];
unsigned eisize = 0;
//
const unsigned exesize = ih_exesize;
const unsigned imagesize = ih_imagesize;
const unsigned overlay = ih_overlay;
if (ih.relocs > MAXRELOCS) if (ih.relocs > MAXRELOCS)
throwCantPack("too many relocations"); throwCantPack("too many relocations");
checkOverlay(overlay); checkOverlay(ih_overlay);
// alloc buffers // alloc buffers
unsigned relocsize = RSFCRI + 4*ih.relocs; relocsize = RSFCRI + 4*ih.relocs;
ibuf.alloc(ih_imagesize+16+relocsize+2);
ibuf.alloc(imagesize+16+relocsize+2); obuf.allocForCompression(ih_imagesize+16+relocsize+2);
obuf.allocForCompression(imagesize+16+relocsize+2);
// read image // read image
fi->seek(ih.headsize16*16,SEEK_SET); fi->seek(ih.headsize16*16,SEEK_SET);
fi->readx(ibuf,imagesize); fi->readx(ibuf,ih_imagesize);
checkAlreadyPacked(ibuf, UPX_MIN(imagesize, 127u)); checkAlreadyPacked(ibuf, UPX_MIN(ih_imagesize, 127u));
// relocations // relocations
has_9a = false; has_9a = false;
upx_byte *w = ibuf + imagesize; upx_byte *w = ibuf + ih_imagesize;
if (ih.relocs) if (ih.relocs)
{ {
upx_byte *wr = w + RSFCRI; upx_byte *wr = w + RSFCRI;
@@ -282,7 +372,7 @@ void PackExe::pack(OutputFile *fo)
set_le32(wr+4*ic, (jc>>16)*16+(jc&0xffff)); set_le32(wr+4*ic, (jc>>16)*16+(jc&0xffff));
} }
qsort(wr,ih.relocs,4,le32_compare); qsort(wr,ih.relocs,4,le32_compare);
relocsize = optimize_relocs(ibuf, imagesize, wr, ih.relocs, w, &has_9a); relocsize = optimize_relocs(ibuf, ih_imagesize, wr, ih.relocs, w, &has_9a);
set_le16(w+relocsize, relocsize+2); set_le16(w+relocsize, relocsize+2);
relocsize += 2; relocsize += 2;
if (relocsize > MAXRELOCS) if (relocsize > MAXRELOCS)
@@ -297,121 +387,38 @@ void PackExe::pack(OutputFile *fo)
} }
else else
{ {
flag |= NORELOC;
relocsize = 0; relocsize = 0;
} }
ph.u_len = imagesize + relocsize; Filter ft(opt->level);
ph.u_len = ih_imagesize + relocsize;
if (!compress(ibuf,obuf,0,MAXMATCH)) if (!compress(ibuf,obuf,0,MAXMATCH))
throwNotCompressible(); throwNotCompressible();
const unsigned overlapoh = findOverlapOverhead(obuf,32);
if (ph.max_run_found + ph.max_match_found > 0x8000) if (ph.max_run_found + ph.max_match_found > 0x8000)
throwCantPack("decompressor limit exceeded, send a bugreport"); throwCantPack("decompressor limit exceeded, send a bugreport");
ph.overlap_overhead = findOverlapOverhead(obuf,32);
#ifdef TESTING #ifdef TESTING
if (opt->debug) if (opt->debug)
{ {
printf("image+relocs %d -> %d\n",imagesize+relocsize,ph.c_len); printf("image+relocs %d -> %d\n",ih_imagesize+relocsize,ph.c_len);
printf("offsets: %d - %d\nmatches: %d - %d\nruns: %d - %d\n", printf("offsets: %d - %d\nmatches: %d - %d\nruns: %d - %d\n",
0/*ph.min_offset_found*/,ph.max_offset_found, 0/*ph.min_offset_found*/,ph.max_offset_found,
0/*ph.min_match_found*/,ph.max_match_found, 0/*ph.min_match_found*/,ph.max_match_found,
0/*ph.min_run_found*/,ph.max_run_found); 0/*ph.min_run_found*/,ph.max_run_found);
} }
#endif #endif
const unsigned packedsize = ph.c_len;
if (!opt->dos.no_reloc) int flag = fillExeHeader(&oh);
flag |= USEJUMP; const unsigned lsize = buildLoader(&ft);
// fill new exe header
memset(&oh,0,sizeof(oh));
oh.ident = 'M' + 'Z' * 256;
unsigned destpara = (ph.u_len+overlapoh-packedsize+31)/16;
oh.ss = packedsize/16 + destpara;
if (ih.ss*16 + ih.sp < 0x100000 && ih.ss > oh.ss && ih.sp > 0x200)
oh.ss = ih.ss;
oh.sp = ih.sp > 0x200 ? ih.sp : 0x200;
if (oh.ss*16u + 0x50 < ih.ss*16u + ih.sp
&& oh.ss*16u + 0x200 > ih.ss*16u + ih.sp)
oh.ss += 0x20;
destpara = oh.ss - packedsize/16;
if (oh.ss != ih.ss)
{
set_le16(extra_info+eisize,ih.ss);
eisize += 2;
flag |= SS;
}
if (oh.sp != ih.sp)
{
set_le16(extra_info+eisize,ih.sp);
eisize += 2;
flag |= SP;
}
#define DI_LIMIT 0xff00 // see the assembly why
// prepare loader
initLoader(nrv_loader,sizeof(nrv_loader));
addLoader("EXEENTRY",
relocsize ? "EXERELPU" : "",
"EXEMAIN4""+G5DXXXX""UPX1HEAD""EXECUTPO",
NULL
);
if (ph.method == M_NRV2B_8)
addLoader("NRV2B16S", // decompressor
ph.u_len > DI_LIMIT ? "NDIGT64K" : "",
"NRV2BEX1",
opt->cpu == opt->CPU_8086 ? "N2BX8601" : "N2B28601",
"NRV2BEX2",
opt->cpu == opt->CPU_8086 ? "N2BX8602" : "N2B28602",
"NRV2BEX3",
packedsize > 0xffff ? "NSIGT64K" : "",
"NRV2BEX9""NRV2B16E",
NULL
);
else if (ph.method == M_NRV2D_8)
addLoader("NRV2D16S",
ph.u_len > DI_LIMIT ? "NDIGT64D" : "",
"NRV2DEX1",
opt->cpu == opt->CPU_8086 ? "N2DX8601" : "N2D28601",
"NRV2DEX2",
opt->cpu == opt->CPU_8086 ? "N2DX8602" : "N2D28602",
"NRV2DEX3",
packedsize > 0xffff ? "NSIGT64D" : "",
"NRV2DEX9""NRV2D16E",
NULL
);
else
throwInternalError("unknown compression method");
addLoader("EXEMAIN5", NULL);
if (relocsize)
addLoader(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? "EXENOADJ" : "EXEADJUS",
"EXERELO1",
has_9a ? "EXEREL9A" : "",
"EXERELO2",
exesize > 0xFE00 ? "EXEREBIG" : "",
"EXERELO3",
NULL
);
addLoader("EXEMAIN8",
(flag & SS) ? "EXESTACK" : "",
(flag & SP) ? "EXESTASP" : "",
(flag & USEJUMP) ? "EXEJUMPF" : "",
NULL
);
if (!(flag & USEJUMP))
addLoader(ih.cs ? "EXERCSPO" : "",
"EXERETIP",
NULL
);
const unsigned lsize = getLoaderSize();
MemBuffer loader(lsize); MemBuffer loader(lsize);
memcpy(loader,getLoader(),lsize); memcpy(loader,getLoader(),lsize);
//OutputFile::dump("xxloader.dat", loader, lsize); //OutputFile::dump("xxloader.dat", loader, lsize);
// patch loader // patch loader
const unsigned packedsize = ph.c_len;
const unsigned e_len = getLoaderSectionStart("EXECUTPO"); const unsigned e_len = getLoaderSectionStart("EXECUTPO");
const unsigned d_len = lsize - e_len; const unsigned d_len = lsize - e_len;
assert((e_len&15) == 0); assert((e_len&15) == 0);
@@ -419,17 +426,29 @@ void PackExe::pack(OutputFile *fo)
const unsigned copysize = (1+packedsize+d_len) & ~1; const unsigned copysize = (1+packedsize+d_len) & ~1;
const unsigned firstcopy = copysize%0x10000 ? copysize%0x10000 : 0x10000; const unsigned firstcopy = copysize%0x10000 ? copysize%0x10000 : 0x10000;
oh.headsize16 = 2; // set oh.min & oh.max
oh.ip = 0; ic = ih.min*16 + ih_imagesize;
ic = ih.min*16+imagesize;
if (ic < oh.ss*16u + oh.sp) if (ic < oh.ss*16u + oh.sp)
ic = oh.ss*16u + oh.sp; ic = oh.ss*16u + oh.sp;
oh.min = (ic - (packedsize + lsize)) / 16; oh.min = (ic - (packedsize + lsize)) / 16;
ic = ((unsigned) oh.min) + (ih.max - ih.min); ic = oh.min + (ih.max - ih.min);
oh.max = ic < 0xffff && ih.max != 0xffff ? ic : 0xffff; oh.max = ic < 0xffff && ih.max != 0xffff ? ic : 0xffff;
// set extra info
unsigned char extra_info[9];
unsigned eisize = 0;
if (oh.ss != ih.ss)
{
set_le16(extra_info+eisize,ih.ss);
eisize += 2;
assert((flag & SS) != 0); // set in fillExeHeader()
}
if (oh.sp != ih.sp)
{
set_le16(extra_info+eisize,ih.sp);
eisize += 2;
assert((flag & SP) != 0); // set in fillExeHeader()
}
if (ih.min != oh.min) if (ih.min != oh.min)
{ {
set_le16(extra_info+eisize,ih.min); set_le16(extra_info+eisize,ih.min);
@@ -442,7 +461,9 @@ void PackExe::pack(OutputFile *fo)
eisize += 2; eisize += 2;
flag |= MAXMEM; flag |= MAXMEM;
} }
extra_info[eisize++] = (unsigned char) flag;
// patch loader
if (flag & USEJUMP) if (flag & USEJUMP)
{ {
// I use a relocation entry to set the original cs // I use a relocation entry to set the original cs
@@ -474,6 +495,7 @@ void PackExe::pack(OutputFile *fo)
patch_le16(loader,e_len,"BX",0x800F + 0x10*((packedsize&15)+1) - 0x10); patch_le16(loader,e_len,"BX",0x800F + 0x10*((packedsize&15)+1) - 0x10);
patch_le16(loader,e_len,"BP",(packedsize&15)+1); patch_le16(loader,e_len,"BP",(packedsize&15)+1);
unsigned destpara = oh.ss - ph.c_len/16;
patch_le16(loader,e_len,"ES",destpara-e_len/16); patch_le16(loader,e_len,"ES",destpara-e_len/16);
patch_le16(loader,e_len,"DS",e_len/16+(copysize-firstcopy)/16); patch_le16(loader,e_len,"DS",e_len/16+(copysize-firstcopy)/16);
patch_le16(loader,e_len,"SI",firstcopy-2); patch_le16(loader,e_len,"SI",firstcopy-2);
@@ -483,12 +505,11 @@ void PackExe::pack(OutputFile *fo)
//if (ih.relocoffs >= 0x40 && memcmp(&ih.relocoffs,">TIPPACH",8)) //if (ih.relocoffs >= 0x40 && memcmp(&ih.relocoffs,">TIPPACH",8))
// throwCantPack("FIXME"); // throwCantPack("FIXME");
extra_info[eisize++] = flag;
const unsigned outputlen = sizeof(oh)+lsize+packedsize+eisize; const unsigned outputlen = sizeof(oh)+lsize+packedsize+eisize;
oh.m512 = outputlen & 511; oh.m512 = outputlen & 511;
oh.p512 = (outputlen + 511) >> 9; oh.p512 = (outputlen + 511) >> 9;
//fprintf(stderr,"\ne_len=%x d_len=%x clen=%x oo=%x ulen=%x destp=%x copys=%x images=%x",e_len,d_len,packedsize,overlapoh,ph.u_len,destpara,copysize,imagesize); //fprintf(stderr,"\ne_len=%x d_len=%x clen=%x oo=%x ulen=%x destp=%x copys=%x images=%x",e_len,d_len,packedsize,ph.overlap_overhead,ph.u_len,destpara,copysize,ih_imagesize);
// write header + write loader + compressed file // write header + write loader + compressed file
#ifdef TESTING #ifdef TESTING
@@ -510,10 +531,10 @@ void PackExe::pack(OutputFile *fo)
#endif #endif
// verify // verify
verifyOverlappingDecompression(&obuf, overlapoh); verifyOverlappingDecompression(&obuf, ph.overlap_overhead);
// copy the overlay // copy the overlay
copyOverlay(fo, overlay, &obuf); copyOverlay(fo, ih_overlay, &obuf);
//fprintf (stderr,"%x %x\n",relocsize,ph.u_len); //fprintf (stderr,"%x %x\n",relocsize,ph.u_len);
// finally check the compression ratio // finally check the compression ratio
@@ -548,7 +569,6 @@ void PackExe::unpack(OutputFile *fo)
// read the file // read the file
unsigned imagesize = ih_imagesize; unsigned imagesize = ih_imagesize;
const unsigned overlay = ih_overlay;
fi->seek(ih.headsize16*16,SEEK_SET); fi->seek(ih.headsize16*16,SEEK_SET);
fi->readx(ibuf,imagesize); fi->readx(ibuf,imagesize);
@@ -558,7 +578,7 @@ void PackExe::unpack(OutputFile *fo)
if (imagesize <= e_len + ph.c_len) if (imagesize <= e_len + ph.c_len)
throwCantUnpack("file damaged"); throwCantUnpack("file damaged");
checkOverlay(overlay); checkOverlay(ih_overlay);
// decompress // decompress
decompress(ibuf+e_len,obuf); decompress(ibuf+e_len,obuf);
@@ -656,7 +676,7 @@ void PackExe::unpack(OutputFile *fo)
fo->write(obuf,relocs-obuf); fo->write(obuf,relocs-obuf);
// copy the overlay // copy the overlay
copyOverlay(fo, overlay, &obuf); copyOverlay(fo, ih_overlay, &obuf);
} }
+7 -1
View File
@@ -63,7 +63,12 @@ public:
} }
protected: protected:
virtual bool readFileHeader(void); struct exe_header_t;
virtual int readFileHeader(void);
virtual int fillExeHeader(struct exe_header_t *) const;
virtual int buildLoader(const Filter *ft);
struct exe_header_t struct exe_header_t
{ {
@@ -87,6 +92,7 @@ protected:
unsigned ih_exesize; unsigned ih_exesize;
unsigned ih_imagesize; unsigned ih_imagesize;
unsigned ih_overlay; unsigned ih_overlay;
unsigned relocsize;
bool has_9a; bool has_9a;