src/pefile.cpp: cleanup reloc handling and add more checks

This commit is contained in:
Markus F.X.J. Oberhumer
2023-10-14 19:24:44 +02:00
parent 2b371e99bd
commit d8be2ed276
6 changed files with 209 additions and 109 deletions
+5 -1
View File
@@ -1246,8 +1246,12 @@ void Packer::compressWithFilters(Filter *ft, const unsigned overlap_range,
byte *i_ptr = ibuf + ibuf_off; byte *i_ptr = ibuf + ibuf_off;
unsigned i_len = ph.u_len; unsigned i_len = ph.u_len;
byte *o_ptr = obuf + obuf_off; byte *o_ptr = obuf + obuf_off;
byte *f_ptr = ibuf + filter_off;
unsigned f_len = ft->buf_len ? ft->buf_len : i_len; unsigned f_len = ft->buf_len ? ft->buf_len : i_len;
if (filter_strategy == -3) {
filter_off = 0;
f_len = 0;
}
byte *f_ptr = ibuf + filter_off;
assert(f_ptr + f_len <= i_ptr + i_len); assert(f_ptr + f_len <= i_ptr + i_len);
+25 -1
View File
@@ -51,6 +51,12 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
if (relocnum == 0) if (relocnum == 0)
return 0; return 0;
upx_qsort(raw_bytes(relocs, 4 * relocnum), relocnum, 4, le32_compare); upx_qsort(raw_bytes(relocs, 4 * relocnum), relocnum, 4, le32_compare);
if (0) {
printf("optimizeReloc: u_reloc %9u checksum=0x%08x\n", 4 * relocnum,
upx_adler32(relocs, 4 * relocnum));
printf("optimizeReloc: u_image %9u checksum=0x%08x\n", image_size,
upx_adler32(image, image_size));
}
unsigned pc = (unsigned) -4; unsigned pc = (unsigned) -4;
for (unsigned i = 0; i < relocnum; i++) { for (unsigned i = 0; i < relocnum; i++) {
@@ -84,7 +90,13 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
} }
} }
*fix++ = 0; // end marker *fix++ = 0; // end marker
return ptr_udiff_bytes(fix, out); const unsigned bytes = ptr_udiff_bytes(fix, out);
if (0) {
printf("optimizeReloc: c_reloc %9u checksum=0x%08x\n", bytes, upx_adler32(out, bytes));
printf("optimizeReloc: c_image %9u checksum=0x%08x\n", image_size,
upx_adler32(image, image_size));
}
return bytes;
} }
/************************************************************************* /*************************************************************************
@@ -113,6 +125,12 @@ unsigned Packer::unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P
} }
} }
NO_fprintf(stderr, "relocnum=%x\n", relocnum); NO_fprintf(stderr, "relocnum=%x\n", relocnum);
if (0) {
const unsigned bytes = ptr_udiff_bytes(fix + 1, in);
printf("unoptimizeReloc: c_reloc %9u checksum=0x%08x\n", bytes, upx_adler32(in, bytes));
printf("unoptimizeReloc: c_image %9u checksum=0x%08x\n", image_size,
upx_adler32(image, image_size));
}
out.alloc(4 * (relocnum + 1)); // one extra entry out.alloc(4 * (relocnum + 1)); // one extra entry
SPAN_S_VAR(LE32, relocs, out); SPAN_S_VAR(LE32, relocs, out);
@@ -146,6 +164,12 @@ unsigned Packer::unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P
} }
in = fix + 1; // advance in = fix + 1; // advance
assert(relocnum == ptr_udiff_bytes(relocs, raw_bytes(out, 0)) / 4); assert(relocnum == ptr_udiff_bytes(relocs, raw_bytes(out, 0)) / 4);
if (0) {
printf("unoptimizeReloc: u_reloc %9u checksum=0x%08x\n", 4 * relocnum,
upx_adler32(out, 4 * relocnum));
printf("unoptimizeReloc: u_image %9u checksum=0x%08x\n", image_size,
upx_adler32(image, image_size));
}
return relocnum; return relocnum;
} }
+146 -86
View File
@@ -295,73 +295,129 @@ struct FixDeleter { // don't leak memory on exceptions
}; };
} // namespace } // namespace
struct alignas(1) PeFile::Reloc::reloc { static constexpr unsigned RELOC_BUF_OFFSET = 64 * 1024;
LE32 pagestart;
LE32 size;
};
void PeFile::Reloc::newRelocPos(void *p) { PeFile::Reloc::~Reloc() noexcept {
rel = (reloc *) p; COMPILE_TIME_ASSERT(sizeof(BaseReloc) == 8)
rel1 = (LE16 *) ((char *) p + sizeof(reloc)); COMPILE_TIME_ASSERT_ALIGNED1(BaseReloc)
// prevent leak on exceptions
if (start_did_alloc)
delete[] start;
} }
PeFile::Reloc::Reloc(byte *s, unsigned si) : start(s), size(si), rel(nullptr), rel1(nullptr) { // constructor for compression only
COMPILE_TIME_ASSERT(sizeof(reloc) == 8) PeFile::Reloc::Reloc(byte *s, unsigned si) : start(s), start_size_in_bytes(si) {
COMPILE_TIME_ASSERT_ALIGNED1(reloc) assert(opt->cmd == CMD_COMPRESS);
memset(counts, 0, sizeof(counts)); initSpans();
// check size
constexpr unsigned BRS = sizeof(BaseReloc); // 8
if (si == 0) // empty
return;
if (si == BRS) {
unsigned x = get_le32(start_buf + 4); // size_of_block
if (x == 0 || x == BRS) // ignore strange empty relocs
return;
}
if (si < BRS + sizeof(LE16)) // 10
throwCantPack("bad reloc size %d", si);
// fill counts
unsigned pos, type; unsigned pos, type;
while (next(pos, type)) while (next(pos, type))
counts[type]++; counts[type]++;
} }
PeFile::Reloc::Reloc(unsigned relocnum) : start(nullptr), size(0), rel(nullptr), rel1(nullptr) { PeFile::Reloc::Reloc(unsigned relocnum) {
start = new byte[mem_size(4, relocnum, 8192)]; // => oxrelocs start_size_in_bytes = mem_size(4, relocnum, RELOC_BUF_OFFSET, 8192);
counts[0] = 0; start = new byte[start_size_in_bytes]; // => transfer to oxrelocs[] in finish()
start_did_alloc = true;
initSpans();
} }
bool PeFile::Reloc::next(unsigned &pos, unsigned &type) { void PeFile::Reloc::initSpans() {
if (!rel) start_buf = SPAN_S_MAKE(byte, start, start_size_in_bytes);
newRelocPos(start); rel = SPAN_S_CAST(BaseReloc, start_buf);
if (ptr_diff_bytes(rel, start) >= (int) size) { rel1 = SPAN_S_CAST(LE16, start_buf);
rel = nullptr; // rewind rel = nullptr;
return false; rel1 = nullptr;
} }
pos = rel->pagestart + (*rel1 & 0xfff); void PeFile::Reloc::advanceBaseRelocPos(void *p) {
type = *rel1++ >> 12; unsigned off = ptr_udiff_bytes(p, start);
NO_printf("%x %d\n", pos, type); if (!start_did_alloc && off == start_size_in_bytes) { // final entry
if (ptr_diff_bytes(rel1, rel) >= (int) rel->size) rel = (BaseReloc *) p;
newRelocPos(rel1); rel1 = nullptr;
return type == 0 ? next(pos, type) : true; } else {
rel = (BaseReloc *) p;
rel1 = (LE16 *) ((byte *) p + sizeof(BaseReloc));
}
}
bool PeFile::Reloc::next(unsigned &result_pos, unsigned &result_type) {
assert(!start_did_alloc);
unsigned pos, type;
do {
if (rel == nullptr)
advanceBaseRelocPos(start);
if (ptr_udiff_bytes(rel, start) >= start_size_in_bytes) {
rel = nullptr; // rewind
rel1 = nullptr; // rewind
return false;
}
pos = rel->pagestart + (*rel1 & 0xfff);
type = *rel1++ >> 12;
NO_printf("%x %d\n", pos, type);
if (ptr_udiff_bytes(raw_bytes(rel1, 0), rel) >= rel->size_of_block)
advanceBaseRelocPos(raw_bytes(rel1, 0));
} while (type == 0);
result_pos = pos;
result_type = type;
return true;
} }
void PeFile::Reloc::add(unsigned pos, unsigned type) { void PeFile::Reloc::add(unsigned pos, unsigned type) {
set_le32(start + 1024 + 4 * counts[0]++, (pos << 4) + type); assert(start_did_alloc);
set_le32(start_buf + (RELOC_BUF_OFFSET + 4 * counts[0]), (pos << 4) + type);
counts[0] += 1;
} }
void PeFile::Reloc::finish(byte *&p, unsigned &siz) { void PeFile::Reloc::finish(byte *&result_ptr, unsigned &result_size) {
unsigned prev = 0xffffffff; assert(start_did_alloc);
set_le32(start + 1024 + 4 * counts[0]++, 0xf0000000); // sentinel to force final advanceBaseRelocPos()
upx_qsort(start + 1024, counts[0], 4, le32_compare); set_le32(start_buf + (RELOC_BUF_OFFSET + 4 * counts[0]), 0xfff00000);
counts[0] += 1;
upx_qsort(raw_index_bytes(start_buf, RELOC_BUF_OFFSET, 4 * counts[0]), counts[0], 4,
le32_compare);
rel = (reloc *) start; rel = nullptr;
rel1 = (LE16 *) start; rel1 = nullptr;
unsigned prev = 0xffffffff;
for (unsigned ic = 0; ic < counts[0]; ic++) { for (unsigned ic = 0; ic < counts[0]; ic++) {
unsigned pos = get_le32(start + 1024 + 4 * ic); unsigned pos = get_le32(start_buf + (RELOC_BUF_OFFSET + 4 * ic));
if ((pos ^ prev) >= 0x10000) { if (ic == 0) {
prev = pos; prev = pos;
*rel1 = 0; advanceBaseRelocPos(start);
rel->size = ALIGN_UP(ptr_diff_bytes(rel1, rel), 4);
newRelocPos((char *) rel + rel->size);
rel->pagestart = (pos >> 4) & ~0xfff; rel->pagestart = (pos >> 4) & ~0xfff;
rel->size_of_block = 0; // to be filled later
} else if ((pos ^ prev) >= 0x10000) {
prev = pos;
*rel1 = 0; // clear align-up memory
rel->size_of_block = ALIGN_UP(ptr_udiff_bytes(raw_bytes(rel1, 0), rel), 4u);
advanceBaseRelocPos((char *) raw_bytes(rel, rel->size_of_block) + rel->size_of_block);
rel->pagestart = (pos >> 4) & ~0xfff;
rel->size_of_block = 0;
} }
*rel1++ = (pos << 12) + ((pos >> 4) & 0xfff); *rel1++ = (pos << 12) + ((pos >> 4) & 0xfff);
} }
p = start; assert(ptr_udiff_bytes(raw_bytes(rel1, 0), rel) == 10); // sentinel
siz = ptr_udiff_bytes(rel1, start) & ~3; result_size = ptr_udiff_bytes(rel, start);
siz -= 8; assert((result_size & 3) == 0);
// siz can be 0 in 64-bit mode // assert(siz > 0); // assert(result_size > 0); // result_size can be 0 in 64-bit mode
start = nullptr; // safety // transfer ownership
assert(start_did_alloc);
result_ptr = start;
start = nullptr; // safety
start_buf = nullptr; // safety
start_did_alloc = false;
} }
void PeFile::processRelocs(Reloc *rel) // pass2 void PeFile::processRelocs(Reloc *rel) // pass2
@@ -375,20 +431,22 @@ void PeFile32::processRelocs() // pass1
{ {
big_relocs = 0; big_relocs = 0;
const unsigned skip1 = IDADDR(PEDIR_RELOC); const unsigned skip1 = IDADDR(PEDIR_BASERELOC);
const unsigned take1 = IDSIZE(PEDIR_RELOC); const unsigned take1 = IDSIZE(PEDIR_BASERELOC);
Reloc rel(ibuf.subref("bad reloc %#x", skip1, take1), take1); Reloc rel(ibuf.subref("bad reloc %#x", skip1, take1), take1);
const unsigned *counts = rel.getcounts(); const unsigned *const counts = rel.getcounts();
unsigned relocnum = 0; unsigned relocnum = 0;
unsigned ic; unsigned ic;
for (ic = 1; ic < 16; ic++) for (ic = 1; ic < 16; ic++)
relocnum += counts[ic]; relocnum += counts[ic];
for (ic = 0; ic < 16; ic++)
NO_printf("reloc counts[%u] %u\n", ic, counts[ic]);
if (opt->win32_pe.strip_relocs || relocnum == 0) { if (opt->win32_pe.strip_relocs || relocnum == 0) {
if (IDSIZE(PEDIR_RELOC)) { if (IDSIZE(PEDIR_BASERELOC)) {
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); ibuf.fill(IDADDR(PEDIR_BASERELOC), IDSIZE(PEDIR_BASERELOC), FILLVAL);
ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects); ih.objects = tryremove(IDADDR(PEDIR_BASERELOC), ih.objects);
} }
mb_orelocs.alloc(1); mb_orelocs.alloc(1);
orelocs = mb_orelocs; // => orelocs now is a SPAN_S orelocs = mb_orelocs; // => orelocs now is a SPAN_S
@@ -429,7 +487,7 @@ void PeFile32::processRelocs() // pass1
if (fix[ic][kc] != prev) if (fix[ic][kc] != prev)
prev = fix[ic][jc++] = fix[ic][kc]; prev = fix[ic][jc++] = fix[ic][kc];
NO_printf("xcounts[%u] %u->%u\n", ic, xcounts[ic], jc); NO_printf("reloc xcounts[%u] %u->%u\n", ic, xcounts[ic], jc);
xcounts[ic] = jc; xcounts[ic] = jc;
} }
@@ -440,7 +498,7 @@ void PeFile32::processRelocs() // pass1
set_le32(ibuf + pos, w - ih.imagebase - rvamin); set_le32(ibuf + pos, w - ih.imagebase - rvamin);
} }
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); ibuf.fill(IDADDR(PEDIR_BASERELOC), IDSIZE(PEDIR_BASERELOC), FILLVAL);
mb_orelocs.alloc(mem_size(4, relocnum, 8192)); // 8192 - safety mb_orelocs.alloc(mem_size(4, relocnum, 8192)); // 8192 - safety
orelocs = mb_orelocs; // => orelocs now is a SPAN_S orelocs = mb_orelocs; // => orelocs now is a SPAN_S
sorelocs = optimizeReloc(xcounts[3], (byte *) fix[3], orelocs, ibuf + rvamin, ibufgood - rvamin, sorelocs = optimizeReloc(xcounts[3], (byte *) fix[3], orelocs, ibuf + rvamin, ibufgood - rvamin,
@@ -465,7 +523,7 @@ void PeFile32::processRelocs() // pass1
} }
} }
info("Relocations: original size: %u bytes, preprocessed size: %u bytes", info("Relocations: original size: %u bytes, preprocessed size: %u bytes",
(unsigned) IDSIZE(PEDIR_RELOC), sorelocs); (unsigned) IDSIZE(PEDIR_BASERELOC), sorelocs);
} }
// FIXME - this is too similar to PeFile32::processRelocs // FIXME - this is too similar to PeFile32::processRelocs
@@ -473,8 +531,8 @@ void PeFile64::processRelocs() // pass1
{ {
big_relocs = 0; big_relocs = 0;
const unsigned skip = IDADDR(PEDIR_RELOC); const unsigned skip = IDADDR(PEDIR_BASERELOC);
const unsigned take = IDSIZE(PEDIR_RELOC); const unsigned take = IDSIZE(PEDIR_BASERELOC);
Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take); Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take);
const unsigned *counts = rel.getcounts(); const unsigned *counts = rel.getcounts();
unsigned relocnum = 0; unsigned relocnum = 0;
@@ -484,9 +542,9 @@ void PeFile64::processRelocs() // pass1
relocnum += counts[ic]; relocnum += counts[ic];
if (opt->win32_pe.strip_relocs || relocnum == 0) { if (opt->win32_pe.strip_relocs || relocnum == 0) {
if (IDSIZE(PEDIR_RELOC)) { if (IDSIZE(PEDIR_BASERELOC)) {
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); ibuf.fill(IDADDR(PEDIR_BASERELOC), IDSIZE(PEDIR_BASERELOC), FILLVAL);
ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects); ih.objects = tryremove(IDADDR(PEDIR_BASERELOC), ih.objects);
} }
mb_orelocs.alloc(1); mb_orelocs.alloc(1);
orelocs = mb_orelocs; // => orelocs now is a SPAN_S orelocs = mb_orelocs; // => orelocs now is a SPAN_S
@@ -513,7 +571,6 @@ void PeFile64::processRelocs() // pass1
while (rel.next(pos, type)) { while (rel.next(pos, type)) {
// FIXME add check for relocations which try to modify the // FIXME add check for relocations which try to modify the
// PE header or other relocation records // PE header or other relocation records
if (pos >= ih.imagesize) if (pos >= ih.imagesize)
continue; // skip out-of-bounds record continue; // skip out-of-bounds record
if (type < 16) if (type < 16)
@@ -540,7 +597,7 @@ void PeFile64::processRelocs() // pass1
set_le64(ibuf + pos, w - ih.imagebase - rvamin); set_le64(ibuf + pos, w - ih.imagebase - rvamin);
} }
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); ibuf.fill(IDADDR(PEDIR_BASERELOC), IDSIZE(PEDIR_BASERELOC), FILLVAL);
mb_orelocs.alloc(mem_size(4, relocnum, 8192)); // 8192 - safety mb_orelocs.alloc(mem_size(4, relocnum, 8192)); // 8192 - safety
orelocs = mb_orelocs; // => orelocs now is a SPAN_S orelocs = mb_orelocs; // => orelocs now is a SPAN_S
sorelocs = optimizeReloc(xcounts[10], (byte *) fix[10], orelocs, ibuf + rvamin, sorelocs = optimizeReloc(xcounts[10], (byte *) fix[10], orelocs, ibuf + rvamin,
@@ -567,7 +624,7 @@ void PeFile64::processRelocs() // pass1
} }
#endif #endif
info("Relocations: original size: %u bytes, preprocessed size: %u bytes", info("Relocations: original size: %u bytes, preprocessed size: %u bytes",
(unsigned) IDSIZE(PEDIR_RELOC), sorelocs); (unsigned) IDSIZE(PEDIR_BASERELOC), sorelocs);
} }
/************************************************************************* /*************************************************************************
@@ -1305,8 +1362,8 @@ void PeFile::processTls1(Interval *iv, typename tls_traits<LEXX>::cb_value_t ima
const unsigned tlsdataend = tlsp->dataend - imagebase; const unsigned tlsdataend = tlsp->dataend - imagebase;
// now some ugly stuff: find the relocation entries in the tls data area // now some ugly stuff: find the relocation entries in the tls data area
const unsigned skip2 = IDADDR(PEDIR_RELOC); const unsigned skip2 = IDADDR(PEDIR_BASERELOC);
const unsigned take2 = IDSIZE(PEDIR_RELOC); const unsigned take2 = IDSIZE(PEDIR_BASERELOC);
Reloc rel(ibuf.subref("bad tls reloc %#x", skip2, take2), take2); Reloc rel(ibuf.subref("bad tls reloc %#x", skip2, take2), take2);
unsigned pos, type; unsigned pos, type;
while (rel.next(pos, type)) while (rel.next(pos, type))
@@ -1341,7 +1398,7 @@ void PeFile::processTls1(Interval *iv, typename tls_traits<LEXX>::cb_value_t ima
} }
template <typename LEXX> template <typename LEXX>
void PeFile::processTls2(Reloc *rel, const Interval *iv, unsigned newaddr, void PeFile::processTls2(Reloc *const rel, const Interval *const iv, unsigned newaddr,
typename tls_traits<LEXX>::cb_value_t imagebase) // pass 2 typename tls_traits<LEXX>::cb_value_t imagebase) // pass 2
{ {
typedef typename tls_traits<LEXX>::tls tls; typedef typename tls_traits<LEXX>::tls tls;
@@ -1365,7 +1422,7 @@ void PeFile::processTls2(Reloc *rel, const Interval *iv, unsigned newaddr,
SPAN_S_VAR(tls, const tlsp, mb_otls); SPAN_S_VAR(tls, const tlsp, mb_otls);
// now the relocation entries in the tls data area // now the relocation entries in the tls data area
for (ic = 0; ic < iv->ivnum; ic += 4) { for (ic = 0; ic < iv->ivnum; ic += 4) {
SPAN_S_VAR(byte, pp, SPAN_S_VAR(byte, const pp,
otls + (iv->ivarr[ic].start - (tlsp->datastart - imagebase) + sizeof(tls))); otls + (iv->ivarr[ic].start - (tlsp->datastart - imagebase) + sizeof(tls)));
LEXX *const p = (LEXX *) raw_bytes(pp, sizeof(LEXX)); LEXX *const p = (LEXX *) raw_bytes(pp, sizeof(LEXX));
cb_value_t kc = *p; cb_value_t kc = *p;
@@ -1417,8 +1474,8 @@ void PeFile::processLoadConf(Interval *iv) // pass 1
// if there were relocation entries referring to the load config table // if there were relocation entries referring to the load config table
// then we need them for the copy of the table too // then we need them for the copy of the table too
const unsigned skip = IDADDR(PEDIR_RELOC); const unsigned skip = IDADDR(PEDIR_BASERELOC);
const unsigned take = IDSIZE(PEDIR_RELOC); const unsigned take = IDSIZE(PEDIR_BASERELOC);
Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take); Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take);
unsigned pos, type; unsigned pos, type;
while (rel.next(pos, type)) while (rel.next(pos, type))
@@ -2084,7 +2141,7 @@ unsigned PeFile::readSections(unsigned objs, unsigned usize, unsigned ih_fileali
unsigned ih_datasize) { unsigned ih_datasize) {
const unsigned xtrasize = UPX_MAX(ih_datasize, 65536u) + IDSIZE(PEDIR_IMPORT) + const unsigned xtrasize = UPX_MAX(ih_datasize, 65536u) + IDSIZE(PEDIR_IMPORT) +
IDSIZE(PEDIR_BOUND_IMPORT) + IDSIZE(PEDIR_IAT) + IDSIZE(PEDIR_BOUND_IMPORT) + IDSIZE(PEDIR_IAT) +
IDSIZE(PEDIR_DELAY_IMPORT) + IDSIZE(PEDIR_RELOC); IDSIZE(PEDIR_DELAY_IMPORT) + IDSIZE(PEDIR_BASERELOC);
ibuf.alloc(usize + xtrasize); ibuf.alloc(usize + xtrasize);
// BOUND IMPORT support. FIXME: is this ok? // BOUND IMPORT support. FIXME: is this ok?
@@ -2136,8 +2193,8 @@ void PeFile::callCompressWithFilters(Filter &ft, int filter_strategy, unsigned i
void PeFile::callProcessRelocs(Reloc &rel, unsigned &ic) { void PeFile::callProcessRelocs(Reloc &rel, unsigned &ic) {
// WinCE wants relocation data at the beginning of a section // WinCE wants relocation data at the beginning of a section
PeFile::processRelocs(&rel); PeFile::processRelocs(&rel);
ODADDR(PEDIR_RELOC) = soxrelocs ? ic : 0; ODADDR(PEDIR_BASERELOC) = soxrelocs ? ic : 0;
ODSIZE(PEDIR_RELOC) = soxrelocs; ODSIZE(PEDIR_BASERELOC) = soxrelocs;
ic += soxrelocs; ic += soxrelocs;
} }
@@ -2498,7 +2555,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
oh.imagesize = (osection[3].vaddr + osection[3].vsize + oam1) & ~oam1; oh.imagesize = (osection[3].vaddr + osection[3].vsize + oam1) & ~oam1;
if (soresources == 0) { if (soresources == 0) {
oh.objects = 3; oh.objects = 3;
memset(&osection[3], 0, sizeof(osection[3])); mem_clear(&osection[3]);
} }
} }
@@ -2508,8 +2565,10 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
oh.codesize = osection[1].vsize; oh.codesize = osection[1].vsize;
oh.codebase = osection[1].vaddr; oh.codebase = osection[1].vaddr;
setOhHeaderSize(osection); setOhHeaderSize(osection);
if (rvamin < osection[0].rawdataptr) if (rvamin < osection[0].rawdataptr) {
throwCantPack("object alignment too small"); throwCantPack("object alignment too small rvamin=%#x oraw=%#x", rvamin,
unsigned(osection[0].rawdataptr));
}
if (opt->win32_pe.strip_relocs) if (opt->win32_pe.strip_relocs)
oh.flags |= IMAGE_FILE_RELOCS_STRIPPED; oh.flags |= IMAGE_FILE_RELOCS_STRIPPED;
@@ -2574,6 +2633,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
printf("%-13s: exports : %8d bytes\n", getName(), (int) soexport); printf("%-13s: exports : %8d bytes\n", getName(), (int) soexport);
printf("%-13s: relocs : %8d bytes\n", getName(), (int) soxrelocs); printf("%-13s: relocs : %8d bytes\n", getName(), (int) soxrelocs);
printf("%-13s: loadconf : %8d bytes\n", getName(), (int) soloadconf); printf("%-13s: loadconf : %8d bytes\n", getName(), (int) soloadconf);
// linker->dumpSymbols();
#endif #endif
// verify // verify
@@ -2594,12 +2654,13 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
void PeFile::rebuildRelocs(SPAN_S(byte) & extra_info, unsigned bits, unsigned flags, void PeFile::rebuildRelocs(SPAN_S(byte) & extra_info, unsigned bits, unsigned flags,
upx_uint64_t imagebase) { upx_uint64_t imagebase) {
assert(bits == 32 || bits == 64); assert(bits == 32 || bits == 64);
if (!ODADDR(PEDIR_RELOC) || !ODSIZE(PEDIR_RELOC) || (flags & IMAGE_FILE_RELOCS_STRIPPED)) if (!ODADDR(PEDIR_BASERELOC) || !ODSIZE(PEDIR_BASERELOC) ||
(flags & IMAGE_FILE_RELOCS_STRIPPED))
return; return;
if (ODSIZE(PEDIR_RELOC) == 8) // some tricky dlls use this if (ODSIZE(PEDIR_BASERELOC) == 8) // some tricky dlls use this
{ {
omemcpy(obuf + (ODADDR(PEDIR_RELOC) - rvamin), "\x0\x0\x0\x0\x8\x0\x0\x0", 8); omemcpy(obuf + (ODADDR(PEDIR_BASERELOC) - rvamin), "\x0\x0\x0\x0\x8\x0\x0\x0", 8);
return; return;
} }
@@ -2611,9 +2672,8 @@ void PeFile::rebuildRelocs(SPAN_S(byte) & extra_info, unsigned bits, unsigned fl
MemBuffer mb_wrkmem; MemBuffer mb_wrkmem;
unsigned relocnum = unoptimizeReloc(rdata, mb_wrkmem, obuf, orig_crelocs, bits, true); unsigned relocnum = unoptimizeReloc(rdata, mb_wrkmem, obuf, orig_crelocs, bits, true);
unsigned r16 = 0; unsigned r16 = 0;
if (big & 6) // 16 bit relocations if (big & 6) { // count 16 bit relocations
{ SPAN_S_VAR(const LE32, q, SPAN_S_CAST(const LE32, rdata));
SPAN_S_VAR(const LE32, q, (const LE32 *) raw_bytes(rdata, 0), obuf);
while (*q++) while (*q++)
r16++; r16++;
if ((big & 6) == 6) if ((big & 6) == 6)
@@ -2621,14 +2681,14 @@ void PeFile::rebuildRelocs(SPAN_S(byte) & extra_info, unsigned bits, unsigned fl
r16++; r16++;
} }
Reloc rel(relocnum + r16); Reloc rel(relocnum + r16);
if (big & 6) { if (big & 6) { // add 16 bit relocations
SPAN_S_VAR(const LE32, q, (const LE32 *) raw_bytes(rdata, 0), obuf); SPAN_S_VAR(const LE32, q, SPAN_S_CAST(const LE32, rdata));
while (*q) while (*q)
rel.add(*q++ + rvamin, (big & 4) ? 2 : 1); rel.add(*q++ + rvamin, (big & 4) ? 2 : 1);
if ((big & 6) == 6) if ((big & 6) == 6)
while (*++q) while (*++q)
rel.add(*q + rvamin, 1); rel.add(*q + rvamin, 1);
// rdata = (byte *) raw_bytes(q, 0); // ??? // rdata = (const byte *) raw_bytes(q, 0); // advance rdata
} }
SPAN_S_VAR(byte, const wrkmem, mb_wrkmem); SPAN_S_VAR(byte, const wrkmem, mb_wrkmem);
@@ -2642,12 +2702,12 @@ void PeFile::rebuildRelocs(SPAN_S(byte) & extra_info, unsigned bits, unsigned fl
} }
rel.finish(oxrelocs, soxrelocs); rel.finish(oxrelocs, soxrelocs);
omemcpy(obuf + (ODADDR(PEDIR_RELOC) - rvamin), oxrelocs, soxrelocs); omemcpy(obuf + (ODADDR(PEDIR_BASERELOC) - rvamin), oxrelocs, soxrelocs);
delete[] oxrelocs; delete[] oxrelocs;
oxrelocs = nullptr; oxrelocs = nullptr;
mb_wrkmem.dealloc(); mb_wrkmem.dealloc();
ODSIZE(PEDIR_RELOC) = soxrelocs; ODSIZE(PEDIR_BASERELOC) = soxrelocs;
} }
void PeFile::rebuildExports() { void PeFile::rebuildExports() {
@@ -2866,8 +2926,8 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask,
// FIXME: ih.flags is checked here because of a bug in UPX 0.92 // FIXME: ih.flags is checked here because of a bug in UPX 0.92
if (ih.flags & IMAGE_FILE_RELOCS_STRIPPED) { if (ih.flags & IMAGE_FILE_RELOCS_STRIPPED) {
oh.flags |= IMAGE_FILE_RELOCS_STRIPPED; oh.flags |= IMAGE_FILE_RELOCS_STRIPPED;
ODADDR(PEDIR_RELOC) = 0; ODADDR(PEDIR_BASERELOC) = 0;
ODSIZE(PEDIR_RELOC) = 0; ODSIZE(PEDIR_BASERELOC) = 0;
} }
rebuildImports<LEXX>(extra_info, ord_mask, set_oft); rebuildImports<LEXX>(extra_info, ord_mask, set_oft);
+22 -15
View File
@@ -233,7 +233,6 @@ protected:
PEDIR_EXCEPTION = 3, // Exception table PEDIR_EXCEPTION = 3, // Exception table
PEDIR_SECURITY = 4, // Certificate table (file pointer) PEDIR_SECURITY = 4, // Certificate table (file pointer)
PEDIR_BASERELOC = 5, PEDIR_BASERELOC = 5,
PEDIR_RELOC = PEDIR_BASERELOC,
PEDIR_DEBUG = 6, PEDIR_DEBUG = 6,
PEDIR_ARCHITECTURE = 7, // Architecture-specific data PEDIR_ARCHITECTURE = 7, // Architecture-specific data
PEDIR_GLOBALPTR = 8, // Global pointer PEDIR_GLOBALPTR = 8, // Global pointer
@@ -359,14 +358,14 @@ protected:
}; };
class Interval : private noncopyable { class Interval : private noncopyable {
unsigned capacity; unsigned capacity = 0;
void *base; void *base = nullptr;
public: public:
struct interval { struct interval {
unsigned start, len; unsigned start, len;
} *ivarr; };
struct interval *ivarr = nullptr;
unsigned ivnum; unsigned ivnum = 0;
explicit Interval(void *b); explicit Interval(void *b);
~Interval() noexcept; ~Interval() noexcept;
@@ -385,25 +384,33 @@ protected:
}; };
class Reloc : private noncopyable { class Reloc : private noncopyable {
byte *start; // these are set in constructor
unsigned size; byte *start = nullptr;
unsigned start_size_in_bytes = 0;
bool start_did_alloc = false;
SPAN_0(byte) start_buf = nullptr;
void newRelocPos(void *p); struct alignas(1) BaseReloc {
LE32 pagestart;
LE32 size_of_block;
};
SPAN_0(BaseReloc) rel = nullptr;
SPAN_0(LE16) rel1 = nullptr;
void advanceBaseRelocPos(void *p);
struct reloc; unsigned counts[16] = {};
reloc *rel;
LE16 *rel1;
unsigned counts[16];
public: public:
explicit Reloc(byte *, unsigned); explicit Reloc(byte *, unsigned);
explicit Reloc(unsigned relocnum); explicit Reloc(unsigned relocnum);
void initSpans();
~Reloc() noexcept;
// //
bool next(unsigned &pos, unsigned &type); bool next(unsigned &result_pos, unsigned &result_type);
const unsigned *getcounts() const { return counts; } const unsigned *getcounts() const { return counts; }
// //
void add(unsigned pos, unsigned type); void add(unsigned pos, unsigned type);
void finish(byte *&p, unsigned &size); void finish(byte *&result_ptr, unsigned &result_size); // => transfer ownership
}; };
class Resource : private noncopyable { class Resource : private noncopyable {
+4 -6
View File
@@ -35,11 +35,9 @@
// default: for any regular pointer, raw_bytes() is just the pointer itself // default: for any regular pointer, raw_bytes() is just the pointer itself
template <class T> template <class T>
inline typename std::enable_if<std::is_pointer<T>::value && !upx::is_bounded_array<T>::value && inline
(upx_is_integral<typename std::remove_pointer<T>::type>::value || typename std::enable_if<std::is_pointer<T>::value && !upx::is_bounded_array<T>::value, T>::type
std::is_void<typename std::remove_pointer<T>::type>::value), raw_bytes(T ptr, size_t size_in_bytes) {
T>::type
raw_bytes(T ptr, size_t size_in_bytes) {
if (size_in_bytes > 0) { if (size_in_bytes > 0) {
if very_unlikely (ptr == nullptr) if very_unlikely (ptr == nullptr)
throwCantPack("raw_bytes unexpected NULL ptr"); throwCantPack("raw_bytes unexpected NULL ptr");
@@ -53,7 +51,7 @@ raw_bytes(T ptr, size_t size_in_bytes) {
// NOTE: index == number of elements, *NOT* size in bytes! // NOTE: index == number of elements, *NOT* size in bytes!
template <class T> template <class T>
inline typename std::enable_if<std::is_pointer<T>::value && !upx::is_bounded_array<T>::value && inline typename std::enable_if<std::is_pointer<T>::value && !upx::is_bounded_array<T>::value &&
upx_is_integral<typename std::remove_pointer<T>::type>::value, !std::is_void<typename std::remove_pointer<T>::type>::value,
T>::type T>::type
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) { raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
typedef typename std::remove_pointer<T>::type element_type; typedef typename std::remove_pointer<T>::type element_type;
+7
View File
@@ -125,6 +125,13 @@ public:
return assign(Self(other)); return assign(Self(other));
} }
template <class U>
CSelf<U> type_cast() const {
assertInvariants();
typedef CSelf<U> R;
return R(reinterpret_cast<typename R::pointer>(ptr));
}
// comparison // comparison
bool operator==(pointer other) const { return ptr == other; } bool operator==(pointer other) const { return ptr == other; }