src: rework optimizeReloc handling; cleanups

This commit is contained in:
Markus F.X.J. Oberhumer 2023-02-21 15:19:24 +01:00
parent 8d364c82e2
commit 4a8efd2e2f
23 changed files with 430 additions and 381 deletions

View File

@ -268,8 +268,8 @@ jobs:
- { name: amd64-win64-vs2022, vsversion: 2022, os: windows-2022, C: msvc-14.3-x64, arch: amd64 }
- { name: arm64-win64-vs2019, vsversion: 2019, os: windows-2019, C: msvc-14.2-arm64, arch: amd64_arm64 }
- { name: arm64-win64-vs2022, vsversion: 2022, os: windows-2022, C: msvc-14.3-arm64, arch: amd64_arm64 }
- { name: arm64ec-win64-vs2022, vsversion: 2022, os: windows-2022, C: msvc-14.3-arm64ec, arch: amd64_arm64, cl_extra_flags: -arm64EC, link_machine_flags: '/machine:arm64ec' }
####- { name: arm64x-win64-vs2022, vsversion: 2022, os: windows-2022, C: msvc-14.3-arm64x, arch: amd64_arm64, cl_extra_flags: -arm64EC, link_machine_flags: '/machine:arm64x' }
- { name: arm64ec-win64-vs2022, vsversion: 2022, os: windows-2022, C: msvc-14.3-arm64ec, arch: amd64_arm64, cl_machine_flags: -arm64EC, link_machine_flags: '/machine:arm64ec' }
####- { name: arm64x-win64-vs2022, vsversion: 2022, os: windows-2022, C: msvc-14.3-arm64x, arch: amd64_arm64, cl_machine_flags: -arm64EC, link_machine_flags: '/machine:arm64x' }
- { name: i386-win32-vs2019, vsversion: 2019, os: windows-2019, C: msvc-14.2-x86, arch: amd64_x86 }
- { name: i386-win32-vs2022, vsversion: 2022, os: windows-2022, C: msvc-14.3-x86, arch: amd64_x86 }
steps:
@ -293,10 +293,10 @@ jobs:
run: |
@REM setup directories
where cl & where link
set RUN_CL=cl -MT ${{ matrix.cl_extra_flags }}
set RUN_CL=cl ${{ matrix.cl_machine_flags }} -MT
set RUN_LIB=link -lib ${{ matrix.link_machine_flags }}
set BDIR=%H%\build\%C%\%B%
set DEFS=-D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS
set BDIR=%H%\build\%C%\%B%
git rev-parse --short=12 HEAD > %BDIR%\upx\.GITREV.txt
@REM ===== build UCL =====
cd %BDIR%\ucl
@ -377,8 +377,8 @@ jobs:
- { zig_target: x86_64-macos.13-none }
- { zig_target: x86_64-windows-gnu }
env:
# 2023-02-12
ZIG_DIST_VERSION: 0.11.0-dev.1605+abc9530a8
# 2023-02-19
ZIG_DIST_VERSION: 0.11.0-dev.1650+5e7b09ce9
# for zig-cc wrapper scripts (see below):
ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING
ZIG_FLAGS: ${{ matrix.zig_flags }}

View File

@ -126,6 +126,9 @@ list(SORT upx_SOURCES)
add_executable(upx ${upx_SOURCES})
set_property(TARGET upx PROPERTY CXX_STANDARD 17)
target_link_libraries(upx upx_vendor_ucl upx_vendor_zlib)
if(NOT UPX_CONFIG_DISABLE_ZSTD)
target_link_libraries(upx upx_vendor_zstd)
endif()
#***********************************************************************
# compilation flags
@ -184,8 +187,10 @@ function(upx_compile_target_debug_with_O2 t)
endfunction()
function(upx_sanitize_target t)
if(NOT UPX_CONFIG_DISABLE_SANITIZE AND NOT MSVC)
if(CMAKE_C_PLATFORM_ID MATCHES "^MinGW" OR MINGW OR CYGWIN)
if(NOT UPX_CONFIG_DISABLE_SANITIZE)
if(MSVC)
# msvc uses -GS (similar to -fstack-protector) by default
elseif(CMAKE_C_PLATFORM_ID MATCHES "^MinGW" OR MINGW OR CYGWIN)
# avoid link errors with current MinGW-w64 versions
# see https://www.mingw-w64.org/contribute/#sanitizers-asan-tsan-usan
else()
@ -246,6 +251,9 @@ endif()
if(UPX_CONFIG_DISABLE_WERROR)
target_compile_definitions(${t} PRIVATE UPX_CONFIG_DISABLE_WERROR=1)
endif()
if(NOT UPX_CONFIG_DISABLE_ZSTD)
target_compile_definitions(${t} PRIVATE WITH_ZSTD=1)
endif()
#upx_compile_target_debug_with_O2(${t})
upx_sanitize_target(${t})
if(MSVC)
@ -253,10 +261,6 @@ if(MSVC)
else()
target_compile_options(${t} PRIVATE ${warn_Wall} ${warn_Werror})
endif()
if(NOT UPX_CONFIG_DISABLE_ZSTD)
target_compile_definitions(${t} PRIVATE WITH_ZSTD=1)
target_link_libraries(upx upx_vendor_zstd)
endif()
#***********************************************************************
# "ctest"

View File

@ -14,6 +14,7 @@ CMAKE = cmake
UPX_CMAKE_BUILD_FLAGS += --parallel
ifneq ($(VERBOSE),)
UPX_CMAKE_BUILD_FLAGS += --verbose
UPX_CMAKE_CONFIG_FLAGS += -DCMAKE_VERBOSE_MAKEFILE=ON
endif
# enable this if you prefer Ninja for the actual builds:
#UPX_CMAKE_CONFIG_FLAGS += -G Ninja

View File

@ -15,7 +15,7 @@ RUN dpkg --add-architecture i386 \
# the full UPX binary inside the container via CMake:
7zip bfs bzip2 cabextract chrpath cmake cpio curl elfutils fd-find file fzf g++ gdb gojq \
ht htop hyperfine jq libzstd-dev lsb-release lz4 lzip lzop moreutils ninja-build \
p7zip patch patchelf parallel pax-utils paxctl re2c ripgrep rsync \
p7zip parallel patch patchelf pax-utils paxctl re2c ripgrep rsync \
screen universal-ctags unzip vim zip zlib1g-dev zsh zstd \
# extra packages for compiling with "gcc -m32" and and "gcc -mx32":
g++-multilib gcc-multilib \

View File

@ -131,7 +131,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
#define upx_std_once_flag upx_std_atomic(size_t)
template <class NoexceptCallable>
inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
if (!flag) { flag = 1; f(); }
if (__acc_unlikely(!flag)) { flag = 1; f(); }
}
#else
#include <atomic>

View File

@ -143,6 +143,30 @@ void throwEOFException(const char *msg, int e) {
//
**************************************************************************/
template <>
void throwCantPack(const char *format, ...) {
char msg[1024];
va_list ap;
va_start(ap, format);
(void) upx_safe_vsnprintf(msg, sizeof(msg), format, ap);
va_end(ap);
throwCantPack(msg);
}
template <>
void throwCantUnpack(const char *format, ...) {
char msg[1024];
va_list ap;
va_start(ap, format);
(void) upx_safe_vsnprintf(msg, sizeof(msg), format, ap);
va_end(ap);
throwCantUnpack(msg);
}
/*************************************************************************
//
**************************************************************************/
const char *prettyName(const char *n) noexcept {
if (n == nullptr)
return "(null)";

View File

@ -26,8 +26,6 @@
*/
#pragma once
#ifndef UPX_EXCEPT_H__
#define UPX_EXCEPT_H__ 1
const char *prettyName(const char *n) noexcept;
@ -213,8 +211,15 @@ NORET void throwOutOfMemoryException(const char *msg = nullptr);
NORET void throwIOException(const char *msg = nullptr, int e = 0);
NORET void throwEOFException(const char *msg = nullptr, int e = 0);
template <class T>
void throwCantPack(const T *, ...) = delete;
template <>
NORET void throwCantPack(const char *format, ...) attribute_format(1, 2);
template <class T>
void throwCantUnpack(const T *, ...) = delete;
template <>
NORET void throwCantUnpack(const char *format, ...) attribute_format(1, 2);
#undef NORET
#endif /* already included */
/* vim:set ts=4 sw=4 et: */

View File

@ -148,7 +148,7 @@ void LeFile::readImage() {
soimage = pages * mps;
mb_iimage.alloc(soimage);
mb_iimage.clear();
iimage = mb_iimage;
iimage = mb_iimage; // => now a SPAN_S
unsigned ic, jc;
for (ic = jc = 0; ic < pages; ic++) {

View File

@ -241,7 +241,7 @@ bool PackExe::canPack() {
if (!readFileHeader())
return false;
if (file_size < 1024)
throwCantPack("file is too small");
throwCantPack("file is too small for dos/exe");
fi->seek(0x3c, SEEK_SET);
LE32 offs;
fi->readx(&offs, sizeof(offs));
@ -249,7 +249,7 @@ bool PackExe::canPack() {
if (opt->dos_exe.force_stub)
opt->overlay = opt->COPY_OVERLAY;
else
throwCantPack("can't pack new-exe");
throwCantPack("dos/exe: can't pack new-exe");
}
return true;
}

View File

@ -35,8 +35,6 @@
static const CLANG_FORMAT_DUMMY_STATEMENT
#include "stub/i386-dos32.tmt.h"
#define EXTRA_INFO 4 // original entry point
/*************************************************************************
//
**************************************************************************/
@ -100,7 +98,7 @@ int PackTmt::readFileHeader() {
fi->seek(adam_offset, SEEK_SET);
fi->readx(h, sizeof(h));
if (memcmp(h, "MZ", 2) == 0) // dos exe
if (memcmp(h, "MZ", 2) == 0) // dos/exe
{
exe_offset = adam_offset;
adam_offset += H(2) * 512 + H(1);
@ -135,14 +133,15 @@ int PackTmt::readFileHeader() {
fi->seek(adam_offset, SEEK_SET);
fi->readx(&ih, sizeof(ih));
// FIXME: should add more checks for the values in 'ih'
unsigned const imagesize = ih.imagesize;
unsigned const entry = ih.entry;
unsigned const relocsize = ih.relocsize;
if (imagesize < sizeof(ih) || entry < sizeof(ih) || file_size_u <= imagesize ||
file_size_u <= entry || file_size_u <= relocsize) {
printWarn(getName(), "bad header; imagesize=%#x entry=%#x relocsize=%#x", imagesize,
entry, relocsize);
// TODO: could add more checks for the values in 'ih'
const unsigned imagesize = ih.imagesize;
const unsigned entry = ih.entry;
const unsigned rsize = ih.relocsize;
if (imagesize < sizeof(ih) || imagesize >= file_size_u || entry >= file_size_u ||
rsize >= file_size_u) {
throwCantPack("%s: bad header: imagesize=%#x entry=%#x relocsize=%#x", getName(), imagesize,
entry, rsize);
return 0;
}
@ -168,44 +167,47 @@ void PackTmt::pack(OutputFile *fo) {
const unsigned usize = ih.imagesize;
const unsigned rsize = ih.relocsize;
const unsigned relocnum = rsize / 4;
ibuf.alloc(usize + rsize + 128);
obuf.allocForCompression(usize + rsize + 128);
MemBuffer mb_wrkmem;
mb_wrkmem.alloc(rsize + EXTRA_INFO + 4); // relocations + original entry point + relocsize
SPAN_S_VAR(upx_byte, wrkmem, mb_wrkmem);
fi->seek(adam_offset + sizeof(ih), SEEK_SET);
fi->readx(ibuf, usize);
fi->readx(wrkmem + 4, rsize);
const unsigned overlay = file_size - fi->tell();
if (find_le32(ibuf, UPX_MIN(128u, usize), get_le32("UPX ")) >= 0)
throwAlreadyPacked();
if (rsize == 0)
throwCantPack("file is already compressed with another packer");
MemBuffer mb_relocs(rsize);
SPAN_S_VAR(upx_byte, relocs, mb_relocs);
fi->readx(relocs, rsize);
const unsigned overlay = file_size - fi->tell();
checkOverlay(overlay);
unsigned relocsize = 0;
// if (rsize)
{
for (unsigned ic = 4; ic <= rsize; ic += 4)
set_le32(wrkmem + ic, get_le32(wrkmem + ic) - 4);
relocsize =
optimizeReloc32(wrkmem + 4, rsize / 4, wrkmem, ibuf, file_size, true, &big_relocs);
}
for (unsigned ic = 0; ic < relocnum; ic++)
set_le32(relocs + ic * 4, get_le32(relocs + ic * 4) - 4);
wrkmem[relocsize++] = 0;
set_le32(wrkmem + relocsize, ih.entry); // save original entry point
relocsize += 4;
set_le32(wrkmem + relocsize, relocsize + 4);
relocsize += 4;
memcpy(raw_index_bytes(ibuf, usize, relocsize), wrkmem, relocsize);
MemBuffer mb_orelocs(4 * relocnum + 8192); // relocations + extra_info
SPAN_S_VAR(upx_byte, orelocs, mb_orelocs);
unsigned orelocsize =
optimizeReloc(relocnum, relocs, orelocs, ibuf, usize, 32, true, &big_relocs);
relocs.destroy(); // done
mb_relocs.dealloc(); // done
// extra_info
orelocs[orelocsize++] = 0; // why is this needed - historical oversight ???
set_le32(orelocs + orelocsize, ih.entry); // save original entry point
orelocsize += 4;
set_le32(orelocs + orelocsize, orelocsize + 4); // save orelocsize
orelocsize += 4;
memcpy(raw_index_bytes(ibuf, usize, orelocsize), orelocs, orelocsize);
orelocs.destroy(); // done
mb_orelocs.dealloc(); // done
// prepare packheader
ph.u_len = usize + relocsize;
ph.u_len = usize + orelocsize;
// prepare filter
Filter ft(ph.level);
ft.buf_len = usize;
@ -247,7 +249,7 @@ void PackTmt::pack(OutputFile *fo) {
fo->write(loader, e_len);
fo->write(obuf, ph.c_len);
fo->write(loader + lsize - d_len, d_len); // decompressor
char rel_entry[4];
unsigned char rel_entry[4];
set_le32(rel_entry, 5 + s_point);
fo->write(rel_entry, sizeof(rel_entry));
@ -281,10 +283,10 @@ void PackTmt::unpack(OutputFile *fo) {
// decompress
decompress(ibuf, obuf);
// decode relocations
const unsigned osize = ph.u_len - get_le32(obuf + (ph.u_len - 4));
SPAN_P_VAR(upx_byte, relocs, obuf + osize);
const unsigned origstart = get_le32(obuf + (ph.u_len - 8));
// read extra_info
const unsigned orig_entry = mem_size(1, get_le32(obuf + ph.u_len - 8));
const unsigned orelocsize = mem_size(1, get_le32(obuf + ph.u_len - 4));
const unsigned osize = mem_size(1, ph.u_len - orelocsize);
// unfilter
if (ph.filter) {
@ -292,21 +294,23 @@ void PackTmt::unpack(OutputFile *fo) {
ft.init(ph.filter, 0);
ft.cto = (unsigned char) ph.filter_cto;
if (ph.version < 11)
ft.cto = (unsigned char) (get_le32(obuf + (ph.u_len - 12)) >> 24);
ft.unfilter(obuf, ptr_udiff_bytes(relocs, obuf));
ft.cto = (unsigned char) (get_le32(obuf + ph.u_len - 12) >> 24);
ft.unfilter(obuf, osize);
}
// decode relocations
MemBuffer mb_wrkmem;
const unsigned relocn = unoptimizeReloc32(relocs, obuf, mb_wrkmem, true);
SPAN_S_VAR(upx_byte, wrkmem, mb_wrkmem);
for (unsigned ic = 0; ic < relocn; ic++)
set_le32(wrkmem + ic * 4, get_le32(wrkmem + ic * 4) + 4);
SPAN_S_VAR(const upx_byte, orelocs, raw_index_bytes(obuf, osize, orelocsize), orelocsize);
SPAN_S_VAR(upx_byte, reloc_image, raw_index_bytes(obuf, 0, osize), osize);
MemBuffer mb_relocs;
const unsigned relocnum = unoptimizeReloc(orelocs, mb_relocs, reloc_image, osize, 32, true);
SPAN_S_VAR(upx_byte, relocs, mb_relocs);
for (unsigned ic = 0; ic < relocnum; ic++)
set_le32(relocs + ic * 4, get_le32(relocs + ic * 4) + 4);
memcpy(&oh, &ih, sizeof(oh));
oh.imagesize = osize;
oh.entry = origstart;
oh.relocsize = relocn * 4;
oh.entry = orig_entry;
oh.relocsize = relocnum * 4;
const unsigned overlay = file_size - adam_offset - ih.imagesize - ih.relocsize - sizeof(ih);
checkOverlay(overlay);
@ -315,7 +319,7 @@ void PackTmt::unpack(OutputFile *fo) {
if (fo) {
fo->write(&oh, sizeof(oh));
fo->write(obuf, osize);
fo->write(raw_bytes(wrkmem, relocn * 4), relocn * 4);
fo->write(relocs, relocnum * 4);
}
// copy the overlay

View File

@ -62,8 +62,8 @@ protected:
virtual void buildLoader(const Filter *ft) override;
virtual Linker *newLinker() const override;
unsigned adam_offset;
int big_relocs;
unsigned adam_offset = 0;
int big_relocs = 0;
struct alignas(1) tmt_header_t {
char _[16]; // signature,linkerversion,minversion,exesize,imagestart

View File

@ -181,7 +181,7 @@ void PackWcle::encodeObjectTable() {
OOT(0, base_address) = IOT(0, base_address);
ic = IOT(objects - 1, my_base_address) + IOT(objects - 1, virtual_size);
jc = pages * mps + sofixups + 1024;
jc = mem_size(mps, pages, sofixups, 1024);
if (ic < jc)
ic = jc;
@ -247,14 +247,14 @@ void PackWcle::preprocessFixups() {
throwCantPack("files without relocations are not supported");
}
MemBuffer rl_membuf(jc);
MemBuffer mb_relocs(jc);
ByteArray(srf, counts[objects + 0] + 1);
ByteArray(slf, counts[objects + 1] + 1);
SPAN_S_VAR(upx_byte, rl, rl_membuf);
SPAN_S_VAR(upx_byte, relocs, mb_relocs);
SPAN_S_VAR(upx_byte, selector_fixups, srf_membuf);
SPAN_S_VAR(upx_byte, selfrel_fixups, slf_membuf);
unsigned rc = 0;
unsigned relocnum = 0;
upx_byte *fix = ifixups;
for (ic = jc = 0; ic < pages; ic++) {
@ -295,7 +295,7 @@ void PackWcle::preprocessFixups() {
}
dputc('p', stdout);
memcpy(iimage + jc + fixp2, fix + 5, (fix[1] & 0x10) ? 4 : 2);
set_le32(rl + 4 * rc++, jc + fixp2);
set_le32(relocs + 4 * relocnum++, jc + fixp2);
set_le32(iimage + jc + fixp2,
get_le32(iimage + jc + fixp2) + IOT(fix[4] - 1, my_base_address));
@ -316,8 +316,8 @@ void PackWcle::preprocessFixups() {
// work around a pmwunlite bug: remove duplicated fixups
// FIXME: fix the other cases too
if (rc == 0 || get_le32(rl + 4 * rc - 4) != jc + fixp2) {
set_le32(rl + 4 * rc++, jc + fixp2);
if (relocnum == 0 || get_le32(relocs + 4 * relocnum - 4) != jc + fixp2) {
set_le32(relocs + 4 * relocnum++, jc + fixp2);
set_le32(iimage + jc + fixp2,
get_le32(iimage + jc + fixp2) + IOT(fix[4] - 1, my_base_address));
}
@ -348,11 +348,14 @@ void PackWcle::preprocessFixups() {
}
// resize ifixups if it's too small
if (sofixups < 1000) {
if (sofixups < 4 * relocnum + 8192) {
delete[] ifixups;
ifixups = new upx_byte[1000];
sofixups = 4 * relocnum + 8192;
ifixups = New(upx_byte, sofixups);
}
fix = ifixups + optimizeReloc32(rl, rc, ifixups, iimage, file_size, 1, &big_relocs);
SPAN_S_VAR(upx_byte, orelocs, ifixups, sofixups);
fix =
ifixups + optimizeReloc(relocnum, relocs, orelocs, iimage, soimage, 32, true, &big_relocs);
has_extra_code = ptr_udiff_bytes(selector_fixups, srf) != 0;
// FIXME: this could be removed if has_extra_code = false
// but then we'll need a flag
@ -380,7 +383,7 @@ void PackWcle::encodeImage(Filter *ft) {
ifixups = nullptr;
mb_oimage.allocForCompression(isize, RESERVED + 512);
oimage = mb_oimage;
oimage = mb_oimage; // => now a SPAN_S
// prepare packheader
ph.u_len = isize;
// prepare filter [already done]
@ -424,7 +427,7 @@ void PackWcle::pack(OutputFile *fo) {
preprocessFixups();
const unsigned text_size = IOT(ih.init_cs_object - 1, npages) * mps;
const unsigned text_size = mem_size(mps, IOT(ih.init_cs_object - 1, npages));
const unsigned text_vaddr = IOT(ih.init_cs_object - 1, my_base_address);
// attach some useful data at the end of preprocessed fixups
@ -437,7 +440,8 @@ void PackWcle::pack(OutputFile *fo) {
set_le32(ifixups + sofixups,
ih.init_esp_offset + IOT(ih.init_ss_object - 1, my_base_address)); // old stack pointer
set_le32(ifixups + sofixups + 4, ih.init_eip_offset + text_vaddr); // real entry point
set_le32(ifixups + sofixups + 8, mps * pages); // virtual address of unpacked relocations
set_le32(ifixups + sofixups + 8,
mem_size(mps, pages)); // virtual address of unpacked relocations
ifixups[sofixups + 12] = (unsigned char) (unsigned) objects;
sofixups += 13;
@ -478,7 +482,7 @@ void PackWcle::pack(OutputFile *fo) {
linker->defineSymbol("original_entry", ih.init_eip_offset + text_vaddr);
linker->defineSymbol("original_stack",
ih.init_esp_offset + IOT(ih.init_ss_object - 1, my_base_address));
linker->defineSymbol("start_of_relocs", mps * pages);
linker->defineSymbol("start_of_relocs", mem_size(mps, pages));
defineDecompressorSymbols();
defineFilterSymbols(&ft);
linker->defineSymbol("filter_buffer_start", text_vaddr);
@ -518,19 +522,17 @@ void PackWcle::pack(OutputFile *fo) {
**************************************************************************/
void PackWcle::decodeFixups() {
SPAN_P_VAR(upx_byte, p, oimage + soimage);
// assert(p.raw_size_in_bytes() == mb_oimage.getSize()); // Span sanity check
mb_iimage.dealloc();
iimage = nullptr;
MemBuffer tmpbuf;
unsigned const fixupn = unoptimizeReloc32(p, oimage, tmpbuf, true);
SPAN_S_VAR(const upx_byte, p, oimage + soimage);
MemBuffer mb_relocs;
unsigned const fixupn = unoptimizeReloc(p, mb_relocs, oimage, soimage, 32, true);
MemBuffer wrkmem(8 * fixupn + 8);
unsigned ic, jc, o, r;
for (ic = 0; ic < fixupn; ic++) {
jc = get_le32(tmpbuf + 4 * ic);
jc = get_le32(mb_relocs + 4 * ic);
set_le32(wrkmem + ic * 8, jc);
o = soobject_table;
r = get_le32(oimage + jc);
@ -539,13 +541,13 @@ void PackWcle::decodeFixups() {
set_le32(oimage + jc, r);
}
set_le32(wrkmem + ic * 8, 0xFFFFFFFF); // end of 32-bit offset fixups
tmpbuf.dealloc();
mb_relocs.dealloc(); // done
// selector fixups then self-relative fixups
SPAN_P_VAR(const upx_byte, selector_fixups, p);
SPAN_S_VAR(const upx_byte, selector_fixups, p);
// Find selfrel_fixups by skipping over selector_fixups.
SPAN_P_VAR(const upx_byte, q, selector_fixups);
SPAN_S_VAR(const upx_byte, q, selector_fixups);
// The code is a subroutine that ends in RET (0xC3).
while (*q != 0xC3) {
// Defend against tampered selector_fixups; see PackWcle::preprocessFixups().
@ -563,10 +565,9 @@ void PackWcle::decodeFixups() {
}
// Guard against run-away.
static unsigned char const blank[9] = {0};
if (ptr_diff_bytes(oimage + ph.u_len - sizeof(blank), raw_bytes(q, 0)) <
0 // catastrophic worst case
|| !memcmp(blank, q, sizeof(blank)) // no-good early warning
) {
// catastrophic worst case or no-good early warning
if (ptr_diff_bytes(oimage + ph.u_len - sizeof(blank), raw_bytes(q, 0)) < 0 ||
!memcmp(blank, q, sizeof(blank))) {
char msg[50];
snprintf(msg, sizeof(msg), "bad selector_fixups %d",
ptr_diff_bytes(q, selector_fixups));
@ -575,7 +576,7 @@ void PackWcle::decodeFixups() {
q += 9;
}
unsigned selectlen = ptr_udiff_bytes(q, selector_fixups) / 9;
SPAN_P_VAR(const upx_byte, selfrel_fixups, q + 1); // Skip the 0xC3
SPAN_S_VAR(const upx_byte, selfrel_fixups, q + 1); // Skip the 0xC3
const unsigned fbytes = fixupn * 9 + 1000 + selectlen * 5;
ofixups = New(upx_byte, fbytes);
@ -611,7 +612,7 @@ void PackWcle::decodeFixups() {
dputc('s', stdout);
}
// 32 bit offset fixups
while (get_le32(wrkmem + 4 * jc) < ic * mps) {
while (get_le32(wrkmem + 4 * jc) < mem_size(mps, ic)) {
if (jc > 1 &&
((get_le32(wrkmem + 4 * (jc - 2)) + 3) & (mps - 1)) < 3) // cross page fixup?
{
@ -770,7 +771,7 @@ void PackWcle::unpack(OutputFile *fo) {
// unfilter
if (ph.filter) {
const unsigned text_size = OOT(oh.init_cs_object - 1, npages) * mps;
const unsigned text_size = mem_size(mps, OOT(oh.init_cs_object - 1, npages));
const unsigned text_vaddr = OOT(oh.init_cs_object - 1, my_base_address);
Filter ft(ph.level);

View File

@ -60,7 +60,7 @@ void Packer::assertPacker() const {
assert(getVersion() >= 11);
assert(getVersion() <= 14);
assert(strlen(getName()) <= 15);
// info: 36 is the limit for show_all_packers() in help.cpp
// info: 36 is the limit for show_all_packers() in help.cpp, but 32 should be enough
assert(strlen(getFullName(opt)) <= 32);
assert(strlen(getFullName(nullptr)) <= 32);
if (bele == nullptr)
@ -77,8 +77,9 @@ void Packer::assertPacker() const {
fprintf(stderr, "%s\n", getName());
assert(bele == format_bele);
}
#if 1
#if DEBUG
Linker *l = newLinker();
assert(l != nullptr);
if (bele != l->bele)
fprintf(stderr, "%s\n", getName());
assert(bele == l->bele);
@ -268,7 +269,7 @@ bool Packer::compress(SPAN_P(upx_byte) i_ptr, unsigned i_len, SPAN_P(upx_byte) o
}
}
// printf("\nPacker::compress: %d/%d: %7d -> %7d\n", method, ph.level, ph.u_len, ph.c_len);
NO_printf("\nPacker::compress: %d/%d: %7d -> %7d\n", method, ph.level, ph.u_len, ph.c_len);
if (!checkCompressionRatio(ph.u_len, ph.c_len))
return false;
// return in any case if not compressible
@ -298,14 +299,6 @@ bool Packer::compress(SPAN_P(upx_byte) i_ptr, unsigned i_len, SPAN_P(upx_byte) o
return true;
}
#if 0
bool Packer::compress(upx_bytep in, upx_bytep out,
const upx_compress_config_t *cconf)
{
return ph_compress(ph, in, out, cconf);
}
#endif
bool Packer::checkDefaultCompressionRatio(unsigned u_len, unsigned c_len) const {
assert((int) u_len > 0);
assert((int) c_len > 0);
@ -316,14 +309,12 @@ bool Packer::checkDefaultCompressionRatio(unsigned u_len, unsigned c_len) const
if (gain < 512) // need at least 512 bytes gain
return false;
#if 1
if (gain >= 4096) // ok if we have 4096 bytes gain
return true;
if (gain >= u_len / 16) // ok if we have 6.25% gain
return true;
return false;
#else
if (gain >= 4096) // ok if we have at least 4096 bytes gain
return true;
#endif
if (gain >= u_len / 16) // ok if we have at least 6.25% gain
return true;
return false;
}
bool Packer::checkCompressionRatio(unsigned u_len, unsigned c_len) const {
@ -823,136 +814,6 @@ int Packer::patch_le32(void *b, int blen, const void *old, unsigned new_) {
return boff;
}
/*************************************************************************
// relocation util
**************************************************************************/
unsigned Packer::optimizeReloc(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big,
int bits) {
if (opt->exact)
throwCantPackExact();
*big = 0;
if (relocnum == 0)
return 0;
qsort(raw_bytes(in, 4 * relocnum), relocnum, 4, le32_compare);
unsigned jc, pc, oc;
SPAN_P_VAR(upx_byte, fix, out);
pc = (unsigned) -4;
for (jc = 0; jc < relocnum; jc++) {
oc = get_le32(in + jc * 4) - pc;
if (oc == 0)
continue;
else if ((int) oc < 4)
throwCantPack("overlapping fixups");
else if (oc < 0xF0)
*fix++ = (unsigned char) oc;
else if (oc < 0x100000) {
*fix++ = (unsigned char) (0xF0 + (oc >> 16));
*fix++ = (unsigned char) oc;
*fix++ = (unsigned char) (oc >> 8);
} else {
*big = 1;
*fix++ = 0xf0;
*fix++ = 0;
*fix++ = 0;
set_le32(fix, oc);
fix += 4;
}
pc += oc;
if (headway <= pc) {
char msg[80];
snprintf(msg, sizeof(msg), "bad reloc[%#x] = %#x", jc, oc);
throwCantPack(msg);
}
if (bswap) {
if (bits == 32)
set_be32(image + pc, get_le32(image + pc));
else if (bits == 64)
set_be64(image + pc, get_le64(image + pc));
else
throwInternalError("optimizeReloc problem");
}
}
*fix++ = 0;
return ptr_udiff_bytes(fix, out);
}
unsigned Packer::optimizeReloc32(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big) {
return optimizeReloc(in, relocnum, out, image, headway, bswap, big, 32);
}
unsigned Packer::optimizeReloc64(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big) {
return optimizeReloc(in, relocnum, out, image, headway, bswap, big, 64);
}
unsigned Packer::unoptimizeReloc(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out,
bool bswap, int bits) {
SPAN_P_VAR(upx_byte, p, in);
unsigned relocn = 0;
for (; *p; p++, relocn++)
if (*p >= 0xF0) {
if (*p == 0xF0 && get_le16(p + 1) == 0)
p += 4;
p += 2;
}
SPAN_P_VAR(upx_byte, const in_end, p);
// fprintf(stderr,"relocnum=%x\n",relocn);
out.alloc(4 * (relocn + 1)); // one extra entry
SPAN_S_VAR(LE32, relocs, out);
unsigned jc = (unsigned) -4;
for (p = in; p < in_end; p++) {
if (*p < 0xF0)
jc += *p;
else {
unsigned dif = (*p & 0x0F) * 0x10000 + get_le16(p + 1);
p += 2;
if (dif == 0) {
dif = get_le32(p + 1);
p += 4;
}
jc += dif;
}
*relocs++ = jc; // FIXME: range check jc
if (!relocn--) {
break;
}
if (bswap && image != nullptr) {
if (bits == 32) {
set_be32(image + jc, get_le32(image + jc));
if ((unsigned) ptr_diff_bytes(p, image + jc) < 4) {
// data must not overlap control
p = image + jc + (4 - 1); // -1: 'for' also increments
}
} else if (bits == 64) {
set_be64(image + jc, get_le64(image + jc));
if ((unsigned) ptr_diff_bytes(p, image + jc) < 8) {
// data must not overlap control
p = image + jc + (8 - 1); // -1: 'for' also increments
}
} else
throwInternalError("unoptimizeReloc problem");
}
}
in = p + 1;
return ptr_udiff_bytes(relocs, out) / 4; // return number of relocs
}
unsigned Packer::unoptimizeReloc32(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out,
bool bswap) {
return unoptimizeReloc(in, image, out, bswap, 32);
}
unsigned Packer::unoptimizeReloc64(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out,
bool bswap) {
return unoptimizeReloc(in, image, out, bswap, 64);
}
/*************************************************************************
// loader util (interface to linker)
**************************************************************************/

View File

@ -271,20 +271,11 @@ protected:
void checkPatch(void *b, int blen, int boff, int size);
// relocation util
static unsigned optimizeReloc(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big,
int bits);
static unsigned unoptimizeReloc(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out,
bool bswap, int bits);
static unsigned optimizeReloc32(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big);
static unsigned unoptimizeReloc32(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out,
bool bswap);
static unsigned optimizeReloc64(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out,
SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big);
static unsigned unoptimizeReloc64(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out,
static unsigned optimizeReloc(unsigned relocnum, SPAN_P(upx_byte) relocs, SPAN_S(upx_byte) out,
SPAN_P(upx_byte) image, unsigned image_size, int bits, bool bswap,
int *big);
static unsigned unoptimizeReloc(SPAN_S(const upx_byte) & in, MemBuffer &out,
SPAN_P(upx_byte) image, unsigned image_size, int bits,
bool bswap);
// Target Endianness abstraction

144
src/packer_r.cpp Normal file
View File

@ -0,0 +1,144 @@
/* packer_r.cpp -- Packer relocation handling
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2023 Laszlo Molnar
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#include "conf.h"
#include "packer.h"
/*************************************************************************
// sort and delta-compress relocations with optional bswap within image
// returns number of bytes written to |out|
**************************************************************************/
unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(upx_byte) relocs, SPAN_S(upx_byte) out,
SPAN_P(upx_byte) image, unsigned image_size, int bits, bool bswap,
int *big) {
assert(bits == 32 || bits == 64);
mem_size_assert(1, image_size);
SPAN_P_VAR(upx_byte, fix, out);
*big = 0;
if (opt->exact)
throwCantPackExact();
if (relocnum == 0)
return 0;
qsort(raw_bytes(relocs, 4 * relocnum), relocnum, 4, le32_compare);
unsigned pc = (unsigned) -4;
for (unsigned i = 0; i < relocnum; i++) {
unsigned delta = get_le32(relocs + i * 4) - pc;
if (delta == 0)
continue;
else if ((int) delta < 4)
throwCantPack("overlapping fixups");
else if (delta < 0xf0)
*fix++ = (unsigned char) delta;
else if (delta < 0x100000) {
*fix++ = (unsigned char) (0xf0 + (delta >> 16));
*fix++ = (unsigned char) delta;
*fix++ = (unsigned char) (delta >> 8);
} else {
*big = 1;
*fix++ = 0xf0;
*fix++ = 0;
*fix++ = 0;
set_le32(fix, delta);
fix += 4;
}
pc += delta;
if (pc + 4 >= image_size)
throwCantPack("bad reloc[%#x] = %#x", i, pc);
if (bswap) {
if (bits == 32)
set_be32(image + pc, get_le32(image + pc));
else
set_be64(image + pc, get_le64(image + pc));
}
}
*fix++ = 0; // end marker
return ptr_udiff_bytes(fix, out);
}
/*************************************************************************
// delta-decompress relocations
// advances |in|
// allocates |out| and returns number of relocs written to |out|
**************************************************************************/
unsigned Packer::unoptimizeReloc(SPAN_S(const upx_byte) & in, MemBuffer &out,
SPAN_P(upx_byte) image, unsigned image_size, int bits,
bool bswap) {
assert(bits == 32 || bits == 64);
mem_size_assert(1, image_size);
SPAN_S_VAR(const upx_byte, fix, in);
// count
unsigned relocnum = 0;
for (fix = in; *fix; fix++, relocnum++) {
if (*fix >= 0xf0) {
if (*fix == 0xf0 && get_le16(fix + 1) == 0)
fix += 4;
fix += 2;
}
}
NO_fprintf(stderr, "relocnum=%x\n", relocnum);
out.alloc(4 * (relocnum + 1)); // one extra entry
SPAN_S_VAR(LE32, relocs, out);
fix = in;
unsigned pc = (unsigned) -4;
for (unsigned i = 0; i < relocnum; i++) {
unsigned delta;
if (*fix < 0xf0)
delta = *fix++;
else {
delta = (*fix & 0x0f) * 0x10000 + get_le16(fix + 1);
fix += 3;
if (delta == 0) {
delta = get_le32(fix);
fix += 4;
}
}
if ((int) delta < 4)
throwCantUnpack("overlapping fixups");
pc += delta;
if (pc + 4 >= image_size)
throwCantUnpack("bad reloc[%#x] = %#x", i, pc);
*relocs++ = pc;
if (bswap && image != nullptr) {
if (bits == 32)
set_be32(image + pc, get_le32(image + pc));
else
set_be64(image + pc, get_le64(image + pc));
}
}
in = fix + 1; // advance
assert(relocnum == ptr_udiff_bytes(relocs, out) / 4);
return relocnum;
}
/* vim:set ts=4 sw=4 et: */

View File

@ -174,12 +174,12 @@ bool PackHeader::decodePackHeaderFromBuf(SPAN_S(const upx_byte) buf, int blen) {
int boff = find_le32(raw_bytes(buf, blen), blen, UPX_MAGIC_LE32);
if (boff < 0)
return false;
blen -= boff; // bytes remaining in buf
if (blen < 20)
throwCantUnpack("header corrupted 1");
SPAN_S_VAR(const upx_byte, const p, buf + boff);
unsigned const headway = blen - boff; // bytes remaining in buf
if (headway < (1 + 7))
throwCantUnpack("header corrupted 1");
version = p[4];
format = p[5];
method = p[6];
@ -201,33 +201,25 @@ bool PackHeader::decodePackHeaderFromBuf(SPAN_S(const upx_byte) buf, int blen) {
// decode the new variable length header
//
unsigned off_filter = 0;
int off_filter = 0;
if (format < 128) {
if (headway < 16) {
throwCantUnpack("header corrupted 2");
}
u_adler = get_le32(p + 8);
c_adler = get_le32(p + 12);
if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS) {
if (headway < 20) {
throwCantUnpack("header corrupted 5");
}
u_len = get_le16(p + 16);
c_len = get_le16(p + 18);
u_file_size = u_len;
off_filter = 20;
} else if (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH) {
if (headway < 25) {
if (blen < 25)
throwCantUnpack("header corrupted 6");
}
u_len = get_le24(p + 16);
c_len = get_le24(p + 19);
u_file_size = get_le24(p + 22);
off_filter = 25;
} else {
if (headway < (3 + 28)) {
if (blen < 31)
throwCantUnpack("header corrupted 7");
}
u_len = get_le32(p + 16);
c_len = get_le32(p + 20);
u_file_size = get_le32(p + 24);
@ -236,9 +228,8 @@ bool PackHeader::decodePackHeaderFromBuf(SPAN_S(const upx_byte) buf, int blen) {
n_mru = p[30] ? 1 + p[30] : 0;
}
} else {
if (headway < (3 + 28)) {
if (blen < 31)
throwCantUnpack("header corrupted 8");
}
u_len = get_be32(p + 8);
c_len = get_be32(p + 12);
u_adler = get_be32(p + 16);
@ -250,9 +241,8 @@ bool PackHeader::decodePackHeaderFromBuf(SPAN_S(const upx_byte) buf, int blen) {
}
if (version >= 10) {
if (headway < (1 + off_filter)) {
if (blen < off_filter + 1)
throwCantUnpack("header corrupted 9");
}
filter = p[off_filter];
} else if ((level & 128) == 0)
filter = 0;
@ -273,9 +263,9 @@ bool PackHeader::decodePackHeaderFromBuf(SPAN_S(const upx_byte) buf, int blen) {
if (version == 0xff)
throwCantUnpack("cannot unpack UPX ;-)");
// check header_checksum
if (version > 9) {
unsigned const size = getPackHeaderSize(); // expected; based on format and version
if (headway < size || p[size - 1] != get_packheader_checksum(p, size - 1))
if (version >= 10) {
int size = getPackHeaderSize(); // expected; based on format and version
if (size > blen || p[size - 1] != get_packheader_checksum(p, size - 1))
throwCantUnpack("header corrupted 3");
}
if (c_len < 2 || u_len < 2 || !mem_size_valid_bytes(c_len) || !mem_size_valid_bytes(u_len))

View File

@ -265,8 +265,8 @@ PeFile::Reloc::Reloc(upx_byte *s, unsigned si) : start(s), size(si), rel(nullptr
counts[type]++;
}
PeFile::Reloc::Reloc(unsigned rnum) : start(nullptr), size(0), rel(nullptr), rel1(nullptr) {
start = new upx_byte[mem_size(4, rnum, 8192)]; // => oxrelocs
PeFile::Reloc::Reloc(unsigned relocnum) : start(nullptr), size(0), rel(nullptr), rel1(nullptr) {
start = new upx_byte[mem_size(4, relocnum, 8192)]; // => oxrelocs
counts[0] = 0;
}
@ -330,13 +330,13 @@ void PeFile32::processRelocs() // pass1
unsigned const skip1 = IDADDR(PEDIR_RELOC);
Reloc rel(ibuf.subref("bad reloc %#x", skip1, take1), take1);
const unsigned *counts = rel.getcounts();
unsigned rnum = 0;
unsigned relocnum = 0;
unsigned ic;
for (ic = 1; ic < 16; ic++)
rnum += counts[ic];
relocnum += counts[ic];
if (opt->win32_pe.strip_relocs || rnum == 0) {
if (opt->win32_pe.strip_relocs || relocnum == 0) {
if (IDSIZE(PEDIR_RELOC)) {
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects);
@ -388,17 +388,17 @@ void PeFile32::processRelocs() // pass1
}
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
mb_orelocs.alloc(mem_size(4, rnum, 1024)); // 1024 - safety
mb_orelocs.alloc(mem_size(4, relocnum, 8192)); // 8192 - safety
orelocs = mb_orelocs; // => orelocs now is a SPAN_S
sorelocs = optimizeReloc32((upx_byte *) fix[3], xcounts[3], orelocs, ibuf + rvamin,
ibufgood - rvamin, true, &big_relocs);
sorelocs = optimizeReloc(xcounts[3], (upx_byte *) fix[3], orelocs, ibuf + rvamin,
ibufgood - rvamin, 32, true, &big_relocs);
delete[] fix[3];
// Malware that hides behind UPX often has PE header info that is
// deliberately corrupt. Sometimes it is even tuned to cause us trouble!
// Use an extra check to avoid AccessViolation (SIGSEGV) when appending
// the relocs into one array.
if ((rnum * 4 + 1024) < (sorelocs + 4 * (2 + xcounts[2] + xcounts[1])))
if ((4 * relocnum + 8192) < (sorelocs + 4 * (2 + xcounts[2] + xcounts[1])))
throwCantUnpack("Invalid relocs");
// append relocs type "LOW" then "HIGH"
@ -426,13 +426,13 @@ void PeFile64::processRelocs() // pass1
unsigned const skip = IDADDR(PEDIR_RELOC);
Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take);
const unsigned *counts = rel.getcounts();
unsigned rnum = 0;
unsigned relocnum = 0;
unsigned ic;
for (ic = 1; ic < 16; ic++)
rnum += counts[ic];
relocnum += counts[ic];
if (opt->win32_pe.strip_relocs || rnum == 0) {
if (opt->win32_pe.strip_relocs || relocnum == 0) {
if (IDSIZE(PEDIR_RELOC)) {
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects);
@ -487,10 +487,10 @@ void PeFile64::processRelocs() // pass1
}
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
mb_orelocs.alloc(mem_size(4, rnum, 1024)); // 1024 - safety
mb_orelocs.alloc(mem_size(4, relocnum, 8192)); // 8192 - safety
orelocs = mb_orelocs; // => orelocs now is a SPAN_S
sorelocs = optimizeReloc64((upx_byte *) fix[10], xcounts[10], orelocs, ibuf + rvamin,
ibufgood - rvamin, true, &big_relocs);
sorelocs = optimizeReloc(xcounts[10], (upx_byte *) fix[10], orelocs, ibuf + rvamin,
ibufgood - rvamin, 64, true, &big_relocs);
for (ic = 15; ic; ic--)
delete[] fix[ic];
@ -500,7 +500,7 @@ void PeFile64::processRelocs() // pass1
// deliberately corrupt. Sometimes it is even tuned to cause us trouble!
// Use an extra check to avoid AccessViolation (SIGSEGV) when appending
// the relocs into one array.
if ((rnum * 4 + 1024) < (sorelocs + 4*(2 + xcounts[2] + xcounts[1])))
if ((4 * relocnum + 8192) < (sorelocs + 4*(2 + xcounts[2] + xcounts[1])))
throwCantUnpack("Invalid relocs");
// append relocs type "LOW" then "HIGH"
@ -925,7 +925,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
Interval names(ibuf), iats(ibuf), lookups(ibuf);
// create the preprocessed data
SPAN_P_VAR(upx_byte, ppi, oimport); // preprocessed imports
SPAN_S_VAR(upx_byte, ppi, oimport); // preprocessed imports
for (ic = 0; ic < dllnum; ic++) {
LEXX *tarr = idlls[ic]->lookupt;
set_le32(ppi, ilinker->getAddress(idlls[ic]->name));
@ -2203,7 +2203,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
ph.u_len = newvsize + soimport + sorelocs;
// some extra data for uncompression support
// some extra_info data for uncompression support
unsigned s = 0;
upx_byte *const p1 = ibuf.subref("bad ph.u_len %#x", ph.u_len, sizeof(ih));
memcpy(p1 + s, &ih, sizeof(ih));
@ -2224,7 +2224,8 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
set_le16(p1 + s, icondir_count);
s += 2;
}
// end of extra data
// end of extra_info data
set_le32(p1 + s, ptr_diff_bytes(p1, ibuf) - rvamin);
s += 4;
ph.u_len += s;
@ -2535,7 +2536,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
// unpack
**************************************************************************/
void PeFile::rebuildRelocs(SPAN_S(upx_byte) & extrainfo, unsigned bits, unsigned flags,
void PeFile::rebuildRelocs(SPAN_S(upx_byte) & extra_info, unsigned bits, unsigned flags,
upx_uint64_t imagebase) {
assert(bits == 32 || bits == 64);
if (!ODADDR(PEDIR_RELOC) || !ODSIZE(PEDIR_RELOC) || (flags & RELOCS_STRIPPED))
@ -2547,13 +2548,13 @@ void PeFile::rebuildRelocs(SPAN_S(upx_byte) & extrainfo, unsigned bits, unsigned
return;
}
SPAN_P_VAR(upx_byte, rdata, obuf);
rdata += get_le32(extrainfo);
const upx_byte big = extrainfo[4];
extrainfo += 5;
const unsigned orig_crelocs = mem_size(1, get_le32(extra_info));
const upx_byte big = extra_info[4];
extra_info += 5;
SPAN_S_VAR(const upx_byte, rdata, obuf + orig_crelocs, obuf);
MemBuffer mb_wrkmem;
unsigned relocn = unoptimizeReloc(rdata, obuf, mb_wrkmem, true, bits);
unsigned relocnum = unoptimizeReloc(rdata, mb_wrkmem, obuf, orig_crelocs, bits, true);
unsigned r16 = 0;
if (big & 6) // 16 bit relocations
{
@ -2564,10 +2565,9 @@ void PeFile::rebuildRelocs(SPAN_S(upx_byte) & extrainfo, unsigned bits, unsigned
while (*++q)
r16++;
}
Reloc rel(relocn + r16);
Reloc rel(relocnum + r16);
if (big & 6) {
SPAN_S_VAR(LE32, q, (LE32 *) raw_bytes(rdata, 0), obuf);
SPAN_S_VAR(const LE32, q, (const LE32 *) raw_bytes(rdata, 0), obuf);
while (*q)
rel.add(*q++ + rvamin, (big & 4) ? 2 : 1);
if ((big & 6) == 6)
@ -2577,7 +2577,7 @@ void PeFile::rebuildRelocs(SPAN_S(upx_byte) & extrainfo, unsigned bits, unsigned
}
SPAN_S_VAR(upx_byte, const wrkmem, mb_wrkmem);
for (unsigned ic = 0; ic < relocn; ic++) {
for (unsigned ic = 0; ic < relocnum; ic++) {
OPTR_VAR(upx_byte, const p, obuf + get_le32(wrkmem + 4 * ic));
if (bits == 32)
set_le32(p, get_le32(p) + imagebase + rvamin);
@ -2610,12 +2610,12 @@ void PeFile::rebuildTls() {
// this is an easy one : just do nothing ;-)
}
void PeFile::rebuildResources(SPAN_S(upx_byte) & extrainfo, unsigned lastvaddr) {
void PeFile::rebuildResources(SPAN_S(upx_byte) & extra_info, unsigned lastvaddr) {
if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0)
return;
icondir_count = get_le16(extrainfo);
extrainfo += 2;
icondir_count = get_le16(extra_info);
extra_info += 2;
const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
@ -2646,13 +2646,13 @@ void PeFile::rebuildResources(SPAN_S(upx_byte) & extrainfo, unsigned lastvaddr)
}
template <typename LEXX, typename ord_mask_t>
void PeFile::rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, bool set_oft) {
void PeFile::rebuildImports(SPAN_S(upx_byte) & extra_info, ord_mask_t ord_mask, bool set_oft) {
if (ODADDR(PEDIR_IMPORT) == 0 || ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc))
return;
OPTR_VAR(const upx_byte, const imdata, obuf + get_le32(extrainfo));
const unsigned inamespos = get_le32(extrainfo + 4);
extrainfo += 8;
OPTR_VAR(const upx_byte, const imdata, obuf + mem_size(1, get_le32(extra_info)));
const unsigned inamespos = mem_size(1, get_le32(extra_info + 4));
extra_info += 8;
unsigned sdllnames = 0;
@ -2660,7 +2660,7 @@ void PeFile::rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, b
OPTR_VAR(const upx_byte, p, raw_bytes(imdata, 4));
for (; get_le32(p) != 0; ++p) {
const upx_byte *dname = raw_bytes(import + get_le32(p), 1);
const upx_byte *dname = raw_bytes(import + mem_size(1, get_le32(p)), 1);
const unsigned dlen = strlen(dname);
ICHECK(dname, dlen + 1);
@ -2768,12 +2768,12 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask,
decompress(ibuf, obuf);
unsigned skip = get_le32(obuf + (ph.u_len - 4));
unsigned take = sizeof(oh);
SPAN_S_VAR(upx_byte, extrainfo, obuf);
extrainfo = obuf.subref("bad extrainfo offset %#x", skip, take);
// upx_byte * const eistart = raw_bytes(extrainfo, 0);
SPAN_S_VAR(upx_byte, extra_info, obuf);
extra_info = obuf.subref("bad extra_info offset %#x", skip, take);
// upx_byte * const eistart = raw_bytes(extra_info, 0);
memcpy(&oh, extrainfo, take);
extrainfo += take;
memcpy(&oh, extra_info, take);
extra_info += take;
skip += take;
unsigned objs = oh.objects;
@ -2781,9 +2781,9 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask,
throwCantUnpack("unexpected value in the PE header");
Array(pe_section_t, osection, objs);
take = sizeof(pe_section_t) * objs;
extrainfo = obuf.subref("bad extra section size at %#x", skip, take);
memcpy(osection, extrainfo, take);
extrainfo += take;
extra_info = obuf.subref("bad extra section size at %#x", skip, take);
memcpy(osection, extra_info, take);
extra_info += take;
skip += take;
rvamin = osection[0].vaddr;
@ -2811,8 +2811,8 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask,
ODSIZE(PEDIR_RELOC) = 0;
}
rebuildImports<LEXX>(extrainfo, ord_mask, set_oft);
rebuildRelocs(extrainfo, sizeof(ih.imagebase) * 8, oh.flags, oh.imagebase);
rebuildImports<LEXX>(extra_info, ord_mask, set_oft);
rebuildRelocs(extra_info, sizeof(ih.imagebase) * 8, oh.flags, oh.imagebase);
rebuildTls();
rebuildExports();
@ -2824,11 +2824,11 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask,
fi->readx(ibuf, ibufgood = isection[3].size);
}
rebuildResources(extrainfo, isection[ih.objects - 1].vaddr);
rebuildResources(extra_info, isection[ih.objects - 1].vaddr);
// FIXME: this does bad things if the relocation section got removed
// during compression ...
// memset(eistart, 0, ptr_udiff_bytes(extrainfo, eistart) + 4);
// memset(eistart, 0, ptr_udiff_bytes(extra_info, eistart) + 4);
// fill the data directory
ODADDR(PEDIR_DEBUG) = 0;
@ -3033,7 +3033,7 @@ void PeFile64::processTls(Reloc *r, const Interval *iv, unsigned a) {
}
/*
extra info added to help uncompression:
extra_info added to help uncompression:
<ih sizeof(pe_head)>
<pe_section_t objs*sizeof(pe_section_t)>

View File

@ -92,7 +92,7 @@ protected:
unsigned processImports0(ord_mask_t ord_mask);
template <typename LEXX, typename ord_mask_t>
void rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, bool set_oft);
void rebuildImports(SPAN_S(upx_byte) & extra_info, ord_mask_t ord_mask, bool set_oft);
virtual unsigned processImports() = 0;
virtual void processImports2(unsigned, unsigned);
MemBuffer mb_oimport;
@ -365,7 +365,7 @@ protected:
public:
Reloc(upx_byte *, unsigned);
Reloc(unsigned rnum);
Reloc(unsigned relocnum);
//
bool next(unsigned &pos, unsigned &type);
const unsigned *getcounts() const { return counts; }

View File

@ -1,10 +1,9 @@
#
# UPX stub Makefile - needs GNU make 3.81 or better
#
# You also will need a number of special build tools like various
# cross-assemblers and cross-compilers - please see README.SRC
# for details.
# And see misc/rebuild-stubs-with-podman how to use Podman/Docker.
# Preferred: see misc/rebuild-stubs-with-podman how to use Podman/Docker.
# Otherwise you will need a number of special build tools like various
# cross-assemblers and cross-compilers - see README.SRC.
#
# Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
#
@ -22,10 +21,6 @@ empty :=
space := $(empty) $(empty)
tab := $(empty) $(empty)
ifneq ($(findstring $(firstword $(MAKE_VERSION)),3.77 3.78 3.78.1 3.79 3.79.1 3.80),)
$(error GNU make 3.81 or better is required)
endif
ifndef srcdir
srcdir := $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
srcdir := $(shell echo '$(srcdir)' | sed 's,/*$$,,')
@ -207,7 +202,7 @@ tc_objdump_disasm_options =
ECHO_e = /bin/echo -e
ECHO_E = /bin/echo -E
PERL = perl
PYTHON = python2
PYTHON2 = python2
UNIX2DOS := $(PERL) -i -pe 's/$$/\r/;'
# trim (strip) trailing whitespace
@ -240,15 +235,15 @@ define tc
endef
# default tools
tc.default.bin2h = $(PYTHON) $(top_srcdir)/src/stub/scripts/bin2h.py --ident=auto-stub
tc.default.bin2h = $(PYTHON2) $(top_srcdir)/src/stub/scripts/bin2h.py --ident=auto-stub
##tc.default.bin2h-c = $(call tc,bin2h) --compress=14,15,0
tc.default.bin2h-c = $(call tc,bin2h) --compress=0
tc.default.brandelf = $(PYTHON) $(top_srcdir)/src/stub/scripts/brandelf.py $(if $(tc_bfdname),--bfdname=$(tc_bfdname))
tc.default.gpp_inc = $(PYTHON) $(top_srcdir)/src/stub/scripts/gpp_inc.py
tc.default.gpp_mkdep = $(PYTHON) $(top_srcdir)/src/stub/scripts/gpp_inc.py -o /dev/null
tc.default.brandelf = $(PYTHON2) $(top_srcdir)/src/stub/scripts/brandelf.py $(if $(tc_bfdname),--bfdname=$(tc_bfdname))
tc.default.gpp_inc = $(PYTHON2) $(top_srcdir)/src/stub/scripts/gpp_inc.py
tc.default.gpp_mkdep = $(PYTHON2) $(top_srcdir)/src/stub/scripts/gpp_inc.py -o /dev/null
tc.default.pp-as = i386-linux-gcc-3.4.6 -E -nostdinc -x assembler-with-cpp -Wall
tc.default.sstrip = sstrip-20060518
tc.default.xstrip = $(PYTHON) $(top_srcdir)/src/stub/scripts/xstrip.py
tc.default.xstrip = $(PYTHON2) $(top_srcdir)/src/stub/scripts/xstrip.py
# default multiarch-binutils
tc.default.m-ar = multiarch-ar-2.17

View File

@ -179,38 +179,42 @@ void MemBuffer::fill(unsigned off, unsigned len, int value) {
void MemBuffer::checkState() const {
if (!ptr)
throwInternalError("block not allocated");
assert(size_in_bytes > 0);
if (use_simple_mcheck()) {
if (get_ne32(ptr - 4) != MAGIC1(ptr))
const unsigned char *p = (const unsigned char *) ptr;
if (get_ne32(p - 4) != MAGIC1(p))
throwInternalError("memory clobbered before allocated block 1");
if (get_ne32(ptr - 8) != size_in_bytes)
if (get_ne32(p - 8) != size_in_bytes)
throwInternalError("memory clobbered before allocated block 2");
if (get_ne32(ptr + size_in_bytes) != MAGIC2(ptr))
if (get_ne32(p + size_in_bytes) != MAGIC2(p))
throwInternalError("memory clobbered past end of allocated block");
}
}
void MemBuffer::alloc(upx_uint64_t size) {
void MemBuffer::alloc(upx_uint64_t bytes) {
// NOTE: we don't automatically free a used buffer
assert(ptr == nullptr);
assert(size_in_bytes == 0);
//
assert(size > 0);
assert(bytes > 0);
debug_set(debug.last_return_address_alloc, upx_return_address());
size_t bytes = mem_size(1, size, use_simple_mcheck() ? 32 : 0);
unsigned char *p = (unsigned char *) malloc(bytes);
NO_printf("MemBuffer::alloc %llu: %p\n", size, p);
size_t malloc_bytes = mem_size(1, bytes);
if (use_simple_mcheck())
malloc_bytes += 32;
unsigned char *p = (unsigned char *) ::malloc(malloc_bytes);
NO_printf("MemBuffer::alloc %llu: %p\n", bytes, p);
if (!p)
throwOutOfMemoryException();
ptr = p;
size_in_bytes = ACC_ICONV(unsigned, size);
size_in_bytes = ACC_ICONV(unsigned, bytes);
if (use_simple_mcheck()) {
ptr = p + 16;
p += 16;
// store magic constants to detect buffer overruns
set_ne32(ptr - 8, size_in_bytes);
set_ne32(ptr - 4, MAGIC1(ptr));
set_ne32(ptr + size_in_bytes, MAGIC2(ptr));
set_ne32(ptr + size_in_bytes + 4, stats.global_alloc_counter);
set_ne32(p - 8, size_in_bytes);
set_ne32(p - 4, MAGIC1(p));
set_ne32(p + size_in_bytes, MAGIC2(p));
set_ne32(p + size_in_bytes + 4, stats.global_alloc_counter);
}
ptr = (pointer) (void *) p;
#if !defined(__SANITIZE_ADDRESS__) && 0
fill(0, size_in_bytes, (rand() & 0xff) | 1); // debug
(void) VALGRIND_MAKE_MEM_UNDEFINED(ptr, size_in_bytes);
@ -218,23 +222,29 @@ void MemBuffer::alloc(upx_uint64_t size) {
stats.global_alloc_counter += 1;
stats.global_total_bytes += size_in_bytes;
stats.global_total_active_bytes += size_in_bytes;
#if DEBUG
checkState();
#endif
}
void MemBuffer::dealloc() {
if (ptr != nullptr) {
debug_set(debug.last_return_address_dealloc, upx_return_address());
checkState();
stats.global_dealloc_counter += 1;
stats.global_total_active_bytes -= size_in_bytes;
if (use_simple_mcheck()) {
unsigned char *p = (unsigned char *) ptr;
// clear magic constants
set_ne32(ptr - 8, 0);
set_ne32(ptr - 4, 0);
set_ne32(ptr + size_in_bytes, 0);
set_ne32(ptr + size_in_bytes + 4, 0);
set_ne32(p - 8, 0);
set_ne32(p - 4, 0);
set_ne32(p + size_in_bytes, 0);
set_ne32(p + size_in_bytes + 4, 0);
//
::free(ptr - 16);
} else
::free(p - 16);
} else {
::free(ptr);
}
ptr = nullptr;
size_in_bytes = 0;
} else {
@ -263,16 +273,26 @@ TEST_CASE("MemBuffer") {
CHECK_NOTHROW(64 + mb);
CHECK_THROWS(65 + mb);
#endif
CHECK_NOTHROW(mb.subref("", 0, 64));
CHECK_NOTHROW(mb.subref("", 64, 0));
CHECK_THROWS(mb.subref("", 1, 64));
CHECK_THROWS(mb.subref("", 64, 1));
if (use_simple_mcheck()) {
upx_byte *b = raw_bytes(mb, 0);
unsigned magic1 = get_ne32(b - 4);
set_ne32(b - 4, magic1 ^ 1);
unsigned char *p = raw_bytes(mb, 0);
unsigned magic1 = get_ne32(p - 4);
set_ne32(p - 4, magic1 ^ 1);
CHECK_THROWS(mb.checkState());
set_ne32(b - 4, magic1);
set_ne32(p - 4, magic1);
mb.checkState();
}
}
TEST_CASE("MemBuffer unused") {
MemBuffer mb;
CHECK(mb.raw_ptr() == nullptr);
CHECK(mb.raw_size_in_bytes() == 0);
}
TEST_CASE("MemBuffer::getSizeForCompression") {
CHECK_THROWS(MemBuffer::getSizeForCompression(0));
CHECK_THROWS(MemBuffer::getSizeForDecompression(0));

View File

@ -49,9 +49,10 @@ public:
MemBufferBase() : ptr(nullptr), size_in_bytes(0) {}
// NOTE: implicit conversion to underlying pointer
// NOTE: for fully bound-checked pointer use XSPAN_S from xspan.h
// HINT: for fully bound-checked pointer use XSPAN_S from xspan.h
operator pointer() const { return ptr; }
// membuffer + n -> pointer
template <class U>
typename std::enable_if<std::is_integral<U>::value, pointer>::type operator+(U n) const {
size_t bytes = mem_size(sizeof(T), n); // check mem_size
@ -59,7 +60,7 @@ public:
}
private:
// NOT allowed; use raw_bytes() instead
// membuffer - n -> pointer; not allowed - use raw_bytes() if needed
template <class U>
typename std::enable_if<std::is_integral<U>::value, pointer>::type operator-(U n) const
DELETED_FUNCTION;
@ -82,13 +83,13 @@ public: // raw access
class MemBuffer final : public MemBufferBase<unsigned char> {
public:
MemBuffer() : MemBufferBase<unsigned char>() {}
explicit MemBuffer(upx_uint64_t size_in_bytes);
explicit MemBuffer(upx_uint64_t bytes);
~MemBuffer();
static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra = 0);
static unsigned getSizeForDecompression(unsigned uncompressed_size, unsigned extra = 0);
void alloc(upx_uint64_t size);
void alloc(upx_uint64_t bytes);
void allocForCompression(unsigned uncompressed_size, unsigned extra = 0);
void allocForDecompression(unsigned uncompressed_size, unsigned extra = 0);
@ -96,7 +97,7 @@ public:
void checkState() const;
unsigned getSize() const { return size_in_bytes; }
// explicit converstion
// explicit conversion
void *getVoidPtr() { return (void *) ptr; }
const void *getVoidPtr() const { return (const void *) ptr; }
@ -119,6 +120,7 @@ private:
// static debug stats
struct Stats {
upx_std_atomic(upx_uint32_t) global_alloc_counter;
upx_std_atomic(upx_uint32_t) global_dealloc_counter;
upx_std_atomic(upx_uint64_t) global_total_bytes;
upx_std_atomic(upx_uint64_t) global_total_active_bytes;
};

View File

@ -46,7 +46,8 @@
ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_MEM == UPX_RSIZE_MAX)
ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_STR <= UPX_RSIZE_MAX / 256)
ACC_COMPILE_TIME_ASSERT_HEADER(2ull * UPX_RSIZE_MAX * 9 / 8 + 16 * 1024 * 1024 < INT_MAX)
ACC_COMPILE_TIME_ASSERT_HEADER(2ull * UPX_RSIZE_MAX * 9 / 8 + 256 * 1024 * 1024 < INT_MAX)
ACC_COMPILE_TIME_ASSERT_HEADER(2ull * UPX_RSIZE_MAX * 10 / 8 + 128 * 1024 * 1024 <= INT_MAX + 1u)
ACC_COMPILE_TIME_ASSERT_HEADER(5ull * UPX_RSIZE_MAX < UINT_MAX)
ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX >= 8192 * 65536)
ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_STR >= 1024)

View File

@ -95,6 +95,12 @@ forceinline pointer ensureBase() const {
public:
inline ~CSelf() {}
void destroy() {
assertInvariants();
base = ptr;
size_in_bytes = 0;
assertInvariants();
}
// constructors from pointers
CSelf(pointer first, XSpanCount count)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count.count)) {