src/pefile.cpp: cleanup reloc handling and add more checks
This commit is contained in:
+5
-1
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
Reference in New Issue
Block a user