WIP Propagate CETCOMPAT flag for PeFile.

https://github.com/upx/upx/issues/909
	modified:   pefile.cpp
	modified:   pefile.h
This commit is contained in:
John Reiser 2025-09-13 15:50:01 -07:00 committed by Markus F.X.J. Oberhumer
parent b11f043d64
commit 3b71139426
2 changed files with 55 additions and 19 deletions

View File

@ -96,6 +96,7 @@ PeFile::PeFile(InputFile *f) : super(f) {
use_tls_callbacks = false; use_tls_callbacks = false;
oloadconf = nullptr; oloadconf = nullptr;
soloadconf = 0; soloadconf = 0;
dbgCET = nullptr;
isdll = false; isdll = false;
isrtm = false; isrtm = false;
@ -2083,25 +2084,32 @@ unsigned PeFile::stripDebug(unsigned overlaystart) {
if (IDADDR(PEDIR_DEBUG) == 0) if (IDADDR(PEDIR_DEBUG) == 0)
return overlaystart; return overlaystart;
struct alignas(1) DebugDir final {
byte _[16]; // flags, time/date, version, type
LE32 size;
byte __[4]; // rva
LE32 fpos;
};
COMPILE_TIME_ASSERT(sizeof(DebugDir) == 28) COMPILE_TIME_ASSERT(sizeof(DebugDir) == 28)
COMPILE_TIME_ASSERT_ALIGNED1(DebugDir) COMPILE_TIME_ASSERT_ALIGNED1(DebugDir)
COMPILE_TIME_ASSERT(sizeof(((DebugDir *) nullptr)->_) == 16)
COMPILE_TIME_ASSERT(sizeof(((DebugDir *) nullptr)->__) == 4)
const unsigned skip = IDADDR(PEDIR_DEBUG); const unsigned skip = IDADDR(PEDIR_DEBUG);
const unsigned take = IDSIZE(PEDIR_DEBUG); const unsigned take = IDSIZE(PEDIR_DEBUG);
const DebugDir *dd = (const DebugDir *) ibuf.subref("bad debug %#x", skip, take); DebugDir *const dd0 = (DebugDir *) ibuf.subref("bad debug %#x", skip, take);
for (unsigned ic = 0; ic < IDSIZE(PEDIR_DEBUG) / sizeof(DebugDir); ic++, dd++) DebugDir *dd = dd0;
for (unsigned ic = 0; ic < IDSIZE(PEDIR_DEBUG) / sizeof(DebugDir); ic++, dd++) {
if (IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS == dd->type && dd->size == sizeof(LE32) &&
dd->fpos <= (file_size_u - sizeof(LE32))) {
// fpos need not belong to any PEDIR_* section.
// Read directly from input file, but keep position (paranoia).
LE32 word;
upx_off_t const now_pos = fi->tell();
fi->seek(dd->fpos, SEEK_SET);
fi->read(&word, sizeof(word));
fi->seek(now_pos, SEEK_SET);
if (IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT & word) {
*(dbgCET = dd0) = *dd; // remember presence; copy to front
}
}
if (overlaystart == dd->fpos) if (overlaystart == dd->fpos)
overlaystart += dd->size; overlaystart += dd->size;
ibuf.fill(IDADDR(PEDIR_DEBUG), IDSIZE(PEDIR_DEBUG), FILLVAL); }
ibuf.fill((!dbgCET ? 0 : sizeof(DebugDir)) + IDADDR(PEDIR_DEBUG),
(!dbgCET ? 0 : -(int) sizeof(DebugDir)) + IDSIZE(PEDIR_DEBUG), FILLVAL);
return overlaystart; return overlaystart;
} }
@ -2488,8 +2496,8 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
obuf.clear(ph.c_len, c_len - ph.c_len); obuf.clear(ph.c_len, c_len - ph.c_len);
const unsigned aligned_sotls = ALIGN_UP(sotls, usizeof(LEXX)); const unsigned aligned_sotls = ALIGN_UP(sotls, usizeof(LEXX));
const unsigned s1size = const unsigned s1size = ALIGN_UP(ic + c_len + codesize, usizeof(LEXX)) + aligned_sotls +
ALIGN_UP(ic + c_len + codesize, usizeof(LEXX)) + aligned_sotls + soloadconf; soloadconf + (dbgCET ? (sizeof(LE32) + sizeof(*dbgCET)) : 0);
const unsigned s1addr = (newvsize - (ic + c_len) + oam1) & ~oam1; const unsigned s1addr = (newvsize - (ic + c_len) + oam1) & ~oam1;
const unsigned ncsection = (s1addr + s1size + oam1) & ~oam1; const unsigned ncsection = (s1addr + s1size + oam1) & ~oam1;
@ -2507,7 +2515,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
oh.chksum = 0; oh.chksum = 0;
// fill the data directory // fill the data directory
ODADDR(PEDIR_DEBUG) = 0; ODADDR(PEDIR_DEBUG) = 0; // dbgCET later
ODSIZE(PEDIR_DEBUG) = 0; ODSIZE(PEDIR_DEBUG) = 0;
ODADDR(PEDIR_IAT) = 0; ODADDR(PEDIR_IAT) = 0;
ODSIZE(PEDIR_IAT) = 0; ODSIZE(PEDIR_IAT) = 0;
@ -2515,7 +2523,8 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
ODSIZE(PEDIR_BOUND_IMPORT) = 0; ODSIZE(PEDIR_BOUND_IMPORT) = 0;
// tls & loadconf are put into section 1 // tls & loadconf are put into section 1
ic = s1addr + s1size - aligned_sotls - soloadconf; ic = s1addr + s1size - aligned_sotls - soloadconf -
(dbgCET ? (sizeof(LE32) + sizeof(*dbgCET)) : 0);
if (use_tls_callbacks) if (use_tls_callbacks)
tls_handler_offset = linker->getSymbolOffset("PETLSC2") + upxsection; tls_handler_offset = linker->getSymbolOffset("PETLSC2") + upxsection;
@ -2530,6 +2539,11 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
ODSIZE(PEDIR_LOAD_CONFIG) = soloadconf; ODSIZE(PEDIR_LOAD_CONFIG) = soloadconf;
ic += soloadconf; ic += soloadconf;
if (dbgCET) {
ODADDR(PEDIR_DEBUG) = ic;
ODSIZE(PEDIR_DEBUG) = sizeof(*dbgCET);
ic += sizeof(LE32) + ODSIZE(PEDIR_DEBUG);
}
const bool rel_at_sections_start = last_section_rsrc_only; const bool rel_at_sections_start = last_section_rsrc_only;
ic = ncsection; ic = ncsection;
@ -2675,6 +2689,19 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
fo->write(ibuf, sizeof(LEXX) - ic); fo->write(ibuf, sizeof(LEXX) - ic);
fo->write(otls, aligned_sotls); fo->write(otls, aligned_sotls);
fo->write(oloadconf, soloadconf); fo->write(oloadconf, soloadconf);
if (dbgCET) {
ic = fo->getBytesWritten();
dbgCET->fpos = ic + sizeof(*dbgCET);
dbgCET->rva = rvamin + 0x400 + dbgCET->fpos; // 0x400 => soheaders
LE32 word;
set_le32(&word, IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT);
if (0) { // set all bytes t0 zero
memset(dbgCET, 0, sizeof(*dbgCET));
set_le32(&word, 0);
}
fo->write(dbgCET, sizeof(*dbgCET));
fo->write(&word, sizeof(word));
}
if ((ic = fo->getBytesWritten() & fam1) != 0) if ((ic = fo->getBytesWritten() & fam1) != 0)
fo->write(ibuf, oh.filealign - ic); fo->write(ibuf, oh.filealign - ic);
if (!last_section_rsrc_only) if (!last_section_rsrc_only)
@ -2695,7 +2722,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
fo->write(ibuf, oh.filealign - ic); fo->write(ibuf, oh.filealign - ic);
} }
#if 0 #if 0 // (debug) print section sizes
printf("%-13s: program hdr : %8d bytes\n", getName(), (int) sizeof(oh)); printf("%-13s: program hdr : %8d bytes\n", getName(), (int) sizeof(oh));
printf("%-13s: sections : %8d bytes\n", getName(), (int) sizeof(osection[0]) * oobjs); printf("%-13s: sections : %8d bytes\n", getName(), (int) sizeof(osection[0]) * oobjs);
printf("%-13s: ident : %8d bytes\n", getName(), (int) identsize); printf("%-13s: ident : %8d bytes\n", getName(), (int) identsize);
@ -3030,8 +3057,6 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask,
// memset(eistart, 0, ptr_udiff_bytes(extra_info, eistart) + 4); // memset(eistart, 0, ptr_udiff_bytes(extra_info, eistart) + 4);
// fill the data directory // fill the data directory
ODADDR(PEDIR_DEBUG) = 0;
ODSIZE(PEDIR_DEBUG) = 0;
ODADDR(PEDIR_IAT) = 0; ODADDR(PEDIR_IAT) = 0;
ODSIZE(PEDIR_IAT) = 0; ODSIZE(PEDIR_IAT) = 0;
ODADDR(PEDIR_BOUND_IMPORT) = 0; ODADDR(PEDIR_BOUND_IMPORT) = 0;

View File

@ -519,6 +519,17 @@ protected:
void build(char *base, unsigned newoffs); void build(char *base, unsigned newoffs);
unsigned getsize() const { return size; } unsigned getsize() const { return size; }
}; };
struct alignas(1) DebugDir final {
LE32 flags, date_time, version;
LE32 type;
LE32 size;
LE32 rva;
LE32 fpos;
};
enum { IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS = 20 };
enum { IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT = 0x001 };
struct DebugDir *dbgCET;
}; };
class PeFile32 : public PeFile { class PeFile32 : public PeFile {