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
+6 -6
View File
@@ -268,8 +268,8 @@ jobs:
- { name: amd64-win64-vs2022, vsversion: 2022, os: windows-2022, C: msvc-14.3-x64, arch: amd64 } - { 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-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: 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: 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_extra_flags: -arm64EC, link_machine_flags: '/machine:arm64x' } ####- { 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-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 } - { name: i386-win32-vs2022, vsversion: 2022, os: windows-2022, C: msvc-14.3-x86, arch: amd64_x86 }
steps: steps:
@@ -293,10 +293,10 @@ jobs:
run: | run: |
@REM setup directories @REM setup directories
where cl & where link 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 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 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 git rev-parse --short=12 HEAD > %BDIR%\upx\.GITREV.txt
@REM ===== build UCL ===== @REM ===== build UCL =====
cd %BDIR%\ucl cd %BDIR%\ucl
@@ -377,8 +377,8 @@ jobs:
- { zig_target: x86_64-macos.13-none } - { zig_target: x86_64-macos.13-none }
- { zig_target: x86_64-windows-gnu } - { zig_target: x86_64-windows-gnu }
env: env:
# 2023-02-12 # 2023-02-19
ZIG_DIST_VERSION: 0.11.0-dev.1605+abc9530a8 ZIG_DIST_VERSION: 0.11.0-dev.1650+5e7b09ce9
# for zig-cc wrapper scripts (see below): # for zig-cc wrapper scripts (see below):
ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING
ZIG_FLAGS: ${{ matrix.zig_flags }} ZIG_FLAGS: ${{ matrix.zig_flags }}
+10 -6
View File
@@ -126,6 +126,9 @@ list(SORT upx_SOURCES)
add_executable(upx ${upx_SOURCES}) add_executable(upx ${upx_SOURCES})
set_property(TARGET upx PROPERTY CXX_STANDARD 17) set_property(TARGET upx PROPERTY CXX_STANDARD 17)
target_link_libraries(upx upx_vendor_ucl upx_vendor_zlib) 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 # compilation flags
@@ -184,8 +187,10 @@ function(upx_compile_target_debug_with_O2 t)
endfunction() endfunction()
function(upx_sanitize_target t) function(upx_sanitize_target t)
if(NOT UPX_CONFIG_DISABLE_SANITIZE AND NOT MSVC) if(NOT UPX_CONFIG_DISABLE_SANITIZE)
if(CMAKE_C_PLATFORM_ID MATCHES "^MinGW" OR MINGW OR CYGWIN) 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 # avoid link errors with current MinGW-w64 versions
# see https://www.mingw-w64.org/contribute/#sanitizers-asan-tsan-usan # see https://www.mingw-w64.org/contribute/#sanitizers-asan-tsan-usan
else() else()
@@ -246,6 +251,9 @@ endif()
if(UPX_CONFIG_DISABLE_WERROR) if(UPX_CONFIG_DISABLE_WERROR)
target_compile_definitions(${t} PRIVATE UPX_CONFIG_DISABLE_WERROR=1) target_compile_definitions(${t} PRIVATE UPX_CONFIG_DISABLE_WERROR=1)
endif() endif()
if(NOT UPX_CONFIG_DISABLE_ZSTD)
target_compile_definitions(${t} PRIVATE WITH_ZSTD=1)
endif()
#upx_compile_target_debug_with_O2(${t}) #upx_compile_target_debug_with_O2(${t})
upx_sanitize_target(${t}) upx_sanitize_target(${t})
if(MSVC) if(MSVC)
@@ -253,10 +261,6 @@ if(MSVC)
else() else()
target_compile_options(${t} PRIVATE ${warn_Wall} ${warn_Werror}) target_compile_options(${t} PRIVATE ${warn_Wall} ${warn_Werror})
endif() endif()
if(NOT UPX_CONFIG_DISABLE_ZSTD)
target_compile_definitions(${t} PRIVATE WITH_ZSTD=1)
target_link_libraries(upx upx_vendor_zstd)
endif()
#*********************************************************************** #***********************************************************************
# "ctest" # "ctest"
+1
View File
@@ -14,6 +14,7 @@ CMAKE = cmake
UPX_CMAKE_BUILD_FLAGS += --parallel UPX_CMAKE_BUILD_FLAGS += --parallel
ifneq ($(VERBOSE),) ifneq ($(VERBOSE),)
UPX_CMAKE_BUILD_FLAGS += --verbose UPX_CMAKE_BUILD_FLAGS += --verbose
UPX_CMAKE_CONFIG_FLAGS += -DCMAKE_VERBOSE_MAKEFILE=ON
endif endif
# enable this if you prefer Ninja for the actual builds: # enable this if you prefer Ninja for the actual builds:
#UPX_CMAKE_CONFIG_FLAGS += -G Ninja #UPX_CMAKE_CONFIG_FLAGS += -G Ninja
+1 -1
View File
@@ -15,7 +15,7 @@ RUN dpkg --add-architecture i386 \
# the full UPX binary inside the container via CMake: # 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 \ 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 \ 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 \ screen universal-ctags unzip vim zip zlib1g-dev zsh zstd \
# extra packages for compiling with "gcc -m32" and and "gcc -mx32": # extra packages for compiling with "gcc -m32" and and "gcc -mx32":
g++-multilib gcc-multilib \ g++-multilib gcc-multilib \
+1 -1
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) #define upx_std_once_flag upx_std_atomic(size_t)
template <class NoexceptCallable> template <class NoexceptCallable>
inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) { 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 #else
#include <atomic> #include <atomic>
+24
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 { const char *prettyName(const char *n) noexcept {
if (n == nullptr) if (n == nullptr)
return "(null)"; return "(null)";
+9 -4
View File
@@ -26,8 +26,6 @@
*/ */
#pragma once #pragma once
#ifndef UPX_EXCEPT_H__
#define UPX_EXCEPT_H__ 1
const char *prettyName(const char *n) noexcept; 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 throwIOException(const char *msg = nullptr, int e = 0);
NORET void throwEOFException(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 #undef NORET
#endif /* already included */
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */
+1 -1
View File
@@ -148,7 +148,7 @@ void LeFile::readImage() {
soimage = pages * mps; soimage = pages * mps;
mb_iimage.alloc(soimage); mb_iimage.alloc(soimage);
mb_iimage.clear(); mb_iimage.clear();
iimage = mb_iimage; iimage = mb_iimage; // => now a SPAN_S
unsigned ic, jc; unsigned ic, jc;
for (ic = jc = 0; ic < pages; ic++) { for (ic = jc = 0; ic < pages; ic++) {
+2 -2
View File
@@ -241,7 +241,7 @@ bool PackExe::canPack() {
if (!readFileHeader()) if (!readFileHeader())
return false; return false;
if (file_size < 1024) if (file_size < 1024)
throwCantPack("file is too small"); throwCantPack("file is too small for dos/exe");
fi->seek(0x3c, SEEK_SET); fi->seek(0x3c, SEEK_SET);
LE32 offs; LE32 offs;
fi->readx(&offs, sizeof(offs)); fi->readx(&offs, sizeof(offs));
@@ -249,7 +249,7 @@ bool PackExe::canPack() {
if (opt->dos_exe.force_stub) if (opt->dos_exe.force_stub)
opt->overlay = opt->COPY_OVERLAY; opt->overlay = opt->COPY_OVERLAY;
else else
throwCantPack("can't pack new-exe"); throwCantPack("dos/exe: can't pack new-exe");
} }
return true; return true;
} }
+51 -47
View File
@@ -35,8 +35,6 @@
static const CLANG_FORMAT_DUMMY_STATEMENT static const CLANG_FORMAT_DUMMY_STATEMENT
#include "stub/i386-dos32.tmt.h" #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->seek(adam_offset, SEEK_SET);
fi->readx(h, sizeof(h)); 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; exe_offset = adam_offset;
adam_offset += H(2) * 512 + H(1); adam_offset += H(2) * 512 + H(1);
@@ -135,14 +133,15 @@ int PackTmt::readFileHeader() {
fi->seek(adam_offset, SEEK_SET); fi->seek(adam_offset, SEEK_SET);
fi->readx(&ih, sizeof(ih)); fi->readx(&ih, sizeof(ih));
// FIXME: should add more checks for the values in 'ih'
unsigned const imagesize = ih.imagesize; // TODO: could add more checks for the values in 'ih'
unsigned const entry = ih.entry; const unsigned imagesize = ih.imagesize;
unsigned const relocsize = ih.relocsize; const unsigned entry = ih.entry;
if (imagesize < sizeof(ih) || entry < sizeof(ih) || file_size_u <= imagesize || const unsigned rsize = ih.relocsize;
file_size_u <= entry || file_size_u <= relocsize) { if (imagesize < sizeof(ih) || imagesize >= file_size_u || entry >= file_size_u ||
printWarn(getName(), "bad header; imagesize=%#x entry=%#x relocsize=%#x", imagesize, rsize >= file_size_u) {
entry, relocsize); throwCantPack("%s: bad header: imagesize=%#x entry=%#x relocsize=%#x", getName(), imagesize,
entry, rsize);
return 0; return 0;
} }
@@ -168,44 +167,47 @@ void PackTmt::pack(OutputFile *fo) {
const unsigned usize = ih.imagesize; const unsigned usize = ih.imagesize;
const unsigned rsize = ih.relocsize; const unsigned rsize = ih.relocsize;
const unsigned relocnum = rsize / 4;
ibuf.alloc(usize + rsize + 128); ibuf.alloc(usize + rsize + 128);
obuf.allocForCompression(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->seek(adam_offset + sizeof(ih), SEEK_SET);
fi->readx(ibuf, usize); 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) if (find_le32(ibuf, UPX_MIN(128u, usize), get_le32("UPX ")) >= 0)
throwAlreadyPacked(); throwAlreadyPacked();
if (rsize == 0) if (rsize == 0)
throwCantPack("file is already compressed with another packer"); 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); checkOverlay(overlay);
unsigned relocsize = 0; for (unsigned ic = 0; ic < relocnum; ic++)
// if (rsize) set_le32(relocs + ic * 4, get_le32(relocs + ic * 4) - 4);
{
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);
}
wrkmem[relocsize++] = 0; MemBuffer mb_orelocs(4 * relocnum + 8192); // relocations + extra_info
set_le32(wrkmem + relocsize, ih.entry); // save original entry point SPAN_S_VAR(upx_byte, orelocs, mb_orelocs);
relocsize += 4; unsigned orelocsize =
set_le32(wrkmem + relocsize, relocsize + 4); optimizeReloc(relocnum, relocs, orelocs, ibuf, usize, 32, true, &big_relocs);
relocsize += 4; relocs.destroy(); // done
memcpy(raw_index_bytes(ibuf, usize, relocsize), wrkmem, relocsize); 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 // prepare packheader
ph.u_len = usize + relocsize; ph.u_len = usize + orelocsize;
// prepare filter // prepare filter
Filter ft(ph.level); Filter ft(ph.level);
ft.buf_len = usize; ft.buf_len = usize;
@@ -247,7 +249,7 @@ void PackTmt::pack(OutputFile *fo) {
fo->write(loader, e_len); fo->write(loader, e_len);
fo->write(obuf, ph.c_len); fo->write(obuf, ph.c_len);
fo->write(loader + lsize - d_len, d_len); // decompressor 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); set_le32(rel_entry, 5 + s_point);
fo->write(rel_entry, sizeof(rel_entry)); fo->write(rel_entry, sizeof(rel_entry));
@@ -281,10 +283,10 @@ void PackTmt::unpack(OutputFile *fo) {
// decompress // decompress
decompress(ibuf, obuf); decompress(ibuf, obuf);
// decode relocations // read extra_info
const unsigned osize = ph.u_len - get_le32(obuf + (ph.u_len - 4)); const unsigned orig_entry = mem_size(1, get_le32(obuf + ph.u_len - 8));
SPAN_P_VAR(upx_byte, relocs, obuf + osize); const unsigned orelocsize = mem_size(1, get_le32(obuf + ph.u_len - 4));
const unsigned origstart = get_le32(obuf + (ph.u_len - 8)); const unsigned osize = mem_size(1, ph.u_len - orelocsize);
// unfilter // unfilter
if (ph.filter) { if (ph.filter) {
@@ -292,21 +294,23 @@ void PackTmt::unpack(OutputFile *fo) {
ft.init(ph.filter, 0); ft.init(ph.filter, 0);
ft.cto = (unsigned char) ph.filter_cto; ft.cto = (unsigned char) ph.filter_cto;
if (ph.version < 11) if (ph.version < 11)
ft.cto = (unsigned char) (get_le32(obuf + (ph.u_len - 12)) >> 24); ft.cto = (unsigned char) (get_le32(obuf + ph.u_len - 12) >> 24);
ft.unfilter(obuf, ptr_udiff_bytes(relocs, obuf)); ft.unfilter(obuf, osize);
} }
// decode relocations // decode relocations
MemBuffer mb_wrkmem; SPAN_S_VAR(const upx_byte, orelocs, raw_index_bytes(obuf, osize, orelocsize), orelocsize);
const unsigned relocn = unoptimizeReloc32(relocs, obuf, mb_wrkmem, true); SPAN_S_VAR(upx_byte, reloc_image, raw_index_bytes(obuf, 0, osize), osize);
SPAN_S_VAR(upx_byte, wrkmem, mb_wrkmem); MemBuffer mb_relocs;
for (unsigned ic = 0; ic < relocn; ic++) const unsigned relocnum = unoptimizeReloc(orelocs, mb_relocs, reloc_image, osize, 32, true);
set_le32(wrkmem + ic * 4, get_le32(wrkmem + ic * 4) + 4); 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)); memcpy(&oh, &ih, sizeof(oh));
oh.imagesize = osize; oh.imagesize = osize;
oh.entry = origstart; oh.entry = orig_entry;
oh.relocsize = relocn * 4; oh.relocsize = relocnum * 4;
const unsigned overlay = file_size - adam_offset - ih.imagesize - ih.relocsize - sizeof(ih); const unsigned overlay = file_size - adam_offset - ih.imagesize - ih.relocsize - sizeof(ih);
checkOverlay(overlay); checkOverlay(overlay);
@@ -315,7 +319,7 @@ void PackTmt::unpack(OutputFile *fo) {
if (fo) { if (fo) {
fo->write(&oh, sizeof(oh)); fo->write(&oh, sizeof(oh));
fo->write(obuf, osize); fo->write(obuf, osize);
fo->write(raw_bytes(wrkmem, relocn * 4), relocn * 4); fo->write(relocs, relocnum * 4);
} }
// copy the overlay // copy the overlay
+2 -2
View File
@@ -62,8 +62,8 @@ protected:
virtual void buildLoader(const Filter *ft) override; virtual void buildLoader(const Filter *ft) override;
virtual Linker *newLinker() const override; virtual Linker *newLinker() const override;
unsigned adam_offset; unsigned adam_offset = 0;
int big_relocs; int big_relocs = 0;
struct alignas(1) tmt_header_t { struct alignas(1) tmt_header_t {
char _[16]; // signature,linkerversion,minversion,exesize,imagestart char _[16]; // signature,linkerversion,minversion,exesize,imagestart
+31 -30
View File
@@ -181,7 +181,7 @@ void PackWcle::encodeObjectTable() {
OOT(0, base_address) = IOT(0, base_address); OOT(0, base_address) = IOT(0, base_address);
ic = IOT(objects - 1, my_base_address) + IOT(objects - 1, virtual_size); 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) if (ic < jc)
ic = jc; ic = jc;
@@ -247,14 +247,14 @@ void PackWcle::preprocessFixups() {
throwCantPack("files without relocations are not supported"); throwCantPack("files without relocations are not supported");
} }
MemBuffer rl_membuf(jc); MemBuffer mb_relocs(jc);
ByteArray(srf, counts[objects + 0] + 1); ByteArray(srf, counts[objects + 0] + 1);
ByteArray(slf, counts[objects + 1] + 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, selector_fixups, srf_membuf);
SPAN_S_VAR(upx_byte, selfrel_fixups, slf_membuf); SPAN_S_VAR(upx_byte, selfrel_fixups, slf_membuf);
unsigned rc = 0; unsigned relocnum = 0;
upx_byte *fix = ifixups; upx_byte *fix = ifixups;
for (ic = jc = 0; ic < pages; ic++) { for (ic = jc = 0; ic < pages; ic++) {
@@ -295,7 +295,7 @@ void PackWcle::preprocessFixups() {
} }
dputc('p', stdout); dputc('p', stdout);
memcpy(iimage + jc + fixp2, fix + 5, (fix[1] & 0x10) ? 4 : 2); 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, set_le32(iimage + jc + fixp2,
get_le32(iimage + jc + fixp2) + IOT(fix[4] - 1, my_base_address)); 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 // work around a pmwunlite bug: remove duplicated fixups
// FIXME: fix the other cases too // FIXME: fix the other cases too
if (rc == 0 || get_le32(rl + 4 * rc - 4) != jc + fixp2) { if (relocnum == 0 || get_le32(relocs + 4 * relocnum - 4) != jc + fixp2) {
set_le32(rl + 4 * rc++, jc + fixp2); set_le32(relocs + 4 * relocnum++, jc + fixp2);
set_le32(iimage + jc + fixp2, set_le32(iimage + jc + fixp2,
get_le32(iimage + jc + fixp2) + IOT(fix[4] - 1, my_base_address)); 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 // resize ifixups if it's too small
if (sofixups < 1000) { if (sofixups < 4 * relocnum + 8192) {
delete[] ifixups; 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; has_extra_code = ptr_udiff_bytes(selector_fixups, srf) != 0;
// FIXME: this could be removed if has_extra_code = false // FIXME: this could be removed if has_extra_code = false
// but then we'll need a flag // but then we'll need a flag
@@ -380,7 +383,7 @@ void PackWcle::encodeImage(Filter *ft) {
ifixups = nullptr; ifixups = nullptr;
mb_oimage.allocForCompression(isize, RESERVED + 512); mb_oimage.allocForCompression(isize, RESERVED + 512);
oimage = mb_oimage; oimage = mb_oimage; // => now a SPAN_S
// prepare packheader // prepare packheader
ph.u_len = isize; ph.u_len = isize;
// prepare filter [already done] // prepare filter [already done]
@@ -424,7 +427,7 @@ void PackWcle::pack(OutputFile *fo) {
preprocessFixups(); 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); const unsigned text_vaddr = IOT(ih.init_cs_object - 1, my_base_address);
// attach some useful data at the end of preprocessed fixups // attach some useful data at the end of preprocessed fixups
@@ -437,7 +440,8 @@ void PackWcle::pack(OutputFile *fo) {
set_le32(ifixups + sofixups, set_le32(ifixups + sofixups,
ih.init_esp_offset + IOT(ih.init_ss_object - 1, my_base_address)); // old stack pointer 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 + 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; ifixups[sofixups + 12] = (unsigned char) (unsigned) objects;
sofixups += 13; sofixups += 13;
@@ -478,7 +482,7 @@ void PackWcle::pack(OutputFile *fo) {
linker->defineSymbol("original_entry", ih.init_eip_offset + text_vaddr); linker->defineSymbol("original_entry", ih.init_eip_offset + text_vaddr);
linker->defineSymbol("original_stack", linker->defineSymbol("original_stack",
ih.init_esp_offset + IOT(ih.init_ss_object - 1, my_base_address)); 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(); defineDecompressorSymbols();
defineFilterSymbols(&ft); defineFilterSymbols(&ft);
linker->defineSymbol("filter_buffer_start", text_vaddr); linker->defineSymbol("filter_buffer_start", text_vaddr);
@@ -518,19 +522,17 @@ void PackWcle::pack(OutputFile *fo) {
**************************************************************************/ **************************************************************************/
void PackWcle::decodeFixups() { 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(); mb_iimage.dealloc();
iimage = nullptr; iimage = nullptr;
MemBuffer tmpbuf; SPAN_S_VAR(const upx_byte, p, oimage + soimage);
unsigned const fixupn = unoptimizeReloc32(p, oimage, tmpbuf, true); MemBuffer mb_relocs;
unsigned const fixupn = unoptimizeReloc(p, mb_relocs, oimage, soimage, 32, true);
MemBuffer wrkmem(8 * fixupn + 8); MemBuffer wrkmem(8 * fixupn + 8);
unsigned ic, jc, o, r; unsigned ic, jc, o, r;
for (ic = 0; ic < fixupn; ic++) { 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); set_le32(wrkmem + ic * 8, jc);
o = soobject_table; o = soobject_table;
r = get_le32(oimage + jc); r = get_le32(oimage + jc);
@@ -539,13 +541,13 @@ void PackWcle::decodeFixups() {
set_le32(oimage + jc, r); set_le32(oimage + jc, r);
} }
set_le32(wrkmem + ic * 8, 0xFFFFFFFF); // end of 32-bit offset fixups set_le32(wrkmem + ic * 8, 0xFFFFFFFF); // end of 32-bit offset fixups
tmpbuf.dealloc(); mb_relocs.dealloc(); // done
// selector fixups then self-relative fixups // 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. // 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). // The code is a subroutine that ends in RET (0xC3).
while (*q != 0xC3) { while (*q != 0xC3) {
// Defend against tampered selector_fixups; see PackWcle::preprocessFixups(). // Defend against tampered selector_fixups; see PackWcle::preprocessFixups().
@@ -563,10 +565,9 @@ void PackWcle::decodeFixups() {
} }
// Guard against run-away. // Guard against run-away.
static unsigned char const blank[9] = {0}; static unsigned char const blank[9] = {0};
if (ptr_diff_bytes(oimage + ph.u_len - sizeof(blank), raw_bytes(q, 0)) < // catastrophic worst case or no-good early warning
0 // catastrophic worst case if (ptr_diff_bytes(oimage + ph.u_len - sizeof(blank), raw_bytes(q, 0)) < 0 ||
|| !memcmp(blank, q, sizeof(blank)) // no-good early warning !memcmp(blank, q, sizeof(blank))) {
) {
char msg[50]; char msg[50];
snprintf(msg, sizeof(msg), "bad selector_fixups %d", snprintf(msg, sizeof(msg), "bad selector_fixups %d",
ptr_diff_bytes(q, selector_fixups)); ptr_diff_bytes(q, selector_fixups));
@@ -575,7 +576,7 @@ void PackWcle::decodeFixups() {
q += 9; q += 9;
} }
unsigned selectlen = ptr_udiff_bytes(q, selector_fixups) / 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; const unsigned fbytes = fixupn * 9 + 1000 + selectlen * 5;
ofixups = New(upx_byte, fbytes); ofixups = New(upx_byte, fbytes);
@@ -611,7 +612,7 @@ void PackWcle::decodeFixups() {
dputc('s', stdout); dputc('s', stdout);
} }
// 32 bit offset fixups // 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 && if (jc > 1 &&
((get_le32(wrkmem + 4 * (jc - 2)) + 3) & (mps - 1)) < 3) // cross page fixup? ((get_le32(wrkmem + 4 * (jc - 2)) + 3) & (mps - 1)) < 3) // cross page fixup?
{ {
@@ -770,7 +771,7 @@ void PackWcle::unpack(OutputFile *fo) {
// unfilter // unfilter
if (ph.filter) { 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); const unsigned text_vaddr = OOT(oh.init_cs_object - 1, my_base_address);
Filter ft(ph.level); Filter ft(ph.level);
+8 -147
View File
@@ -60,7 +60,7 @@ void Packer::assertPacker() const {
assert(getVersion() >= 11); assert(getVersion() >= 11);
assert(getVersion() <= 14); assert(getVersion() <= 14);
assert(strlen(getName()) <= 15); 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(opt)) <= 32);
assert(strlen(getFullName(nullptr)) <= 32); assert(strlen(getFullName(nullptr)) <= 32);
if (bele == nullptr) if (bele == nullptr)
@@ -77,8 +77,9 @@ void Packer::assertPacker() const {
fprintf(stderr, "%s\n", getName()); fprintf(stderr, "%s\n", getName());
assert(bele == format_bele); assert(bele == format_bele);
} }
#if 1 #if DEBUG
Linker *l = newLinker(); Linker *l = newLinker();
assert(l != nullptr);
if (bele != l->bele) if (bele != l->bele)
fprintf(stderr, "%s\n", getName()); fprintf(stderr, "%s\n", getName());
assert(bele == l->bele); 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)) if (!checkCompressionRatio(ph.u_len, ph.c_len))
return false; return false;
// return in any case if not compressible // 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; 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 { bool Packer::checkDefaultCompressionRatio(unsigned u_len, unsigned c_len) const {
assert((int) u_len > 0); assert((int) u_len > 0);
assert((int) c_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 if (gain < 512) // need at least 512 bytes gain
return false; return false;
#if 1 #if 1
if (gain >= 4096) // ok if we have 4096 bytes gain if (gain >= 4096) // ok if we have at least 4096 bytes gain
return true;
if (gain >= u_len / 16) // ok if we have 6.25% gain
return true;
return false;
#else
return true; return true;
#endif #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 { 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; 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) // loader util (interface to linker)
**************************************************************************/ **************************************************************************/
+5 -14
View File
@@ -271,20 +271,11 @@ protected:
void checkPatch(void *b, int blen, int boff, int size); void checkPatch(void *b, int blen, int boff, int size);
// relocation util // relocation util
static unsigned optimizeReloc(SPAN_P(upx_byte) in, unsigned relocnum, SPAN_P(upx_byte) out, static unsigned optimizeReloc(unsigned relocnum, SPAN_P(upx_byte) relocs, SPAN_S(upx_byte) out,
SPAN_P(upx_byte) image, unsigned headway, bool bswap, int *big, SPAN_P(upx_byte) image, unsigned image_size, int bits, bool bswap,
int bits); int *big);
static unsigned unoptimizeReloc(SPAN_P(upx_byte) & in, SPAN_P(upx_byte) image, MemBuffer &out, static unsigned unoptimizeReloc(SPAN_S(const upx_byte) & in, MemBuffer &out,
bool bswap, int bits); SPAN_P(upx_byte) image, unsigned image_size, 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,
bool bswap); bool bswap);
// Target Endianness abstraction // Target Endianness abstraction
+144
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: */
+11 -21
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); int boff = find_le32(raw_bytes(buf, blen), blen, UPX_MAGIC_LE32);
if (boff < 0) if (boff < 0)
return false; 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); 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]; version = p[4];
format = p[5]; format = p[5];
method = p[6]; method = p[6];
@@ -201,33 +201,25 @@ bool PackHeader::decodePackHeaderFromBuf(SPAN_S(const upx_byte) buf, int blen) {
// decode the new variable length header // decode the new variable length header
// //
unsigned off_filter = 0; int off_filter = 0;
if (format < 128) { if (format < 128) {
if (headway < 16) {
throwCantUnpack("header corrupted 2");
}
u_adler = get_le32(p + 8); u_adler = get_le32(p + 8);
c_adler = get_le32(p + 12); c_adler = get_le32(p + 12);
if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS) { if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS) {
if (headway < 20) {
throwCantUnpack("header corrupted 5");
}
u_len = get_le16(p + 16); u_len = get_le16(p + 16);
c_len = get_le16(p + 18); c_len = get_le16(p + 18);
u_file_size = u_len; u_file_size = u_len;
off_filter = 20; off_filter = 20;
} else if (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH) { } else if (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH) {
if (headway < 25) { if (blen < 25)
throwCantUnpack("header corrupted 6"); throwCantUnpack("header corrupted 6");
}
u_len = get_le24(p + 16); u_len = get_le24(p + 16);
c_len = get_le24(p + 19); c_len = get_le24(p + 19);
u_file_size = get_le24(p + 22); u_file_size = get_le24(p + 22);
off_filter = 25; off_filter = 25;
} else { } else {
if (headway < (3 + 28)) { if (blen < 31)
throwCantUnpack("header corrupted 7"); throwCantUnpack("header corrupted 7");
}
u_len = get_le32(p + 16); u_len = get_le32(p + 16);
c_len = get_le32(p + 20); c_len = get_le32(p + 20);
u_file_size = get_le32(p + 24); 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; n_mru = p[30] ? 1 + p[30] : 0;
} }
} else { } else {
if (headway < (3 + 28)) { if (blen < 31)
throwCantUnpack("header corrupted 8"); throwCantUnpack("header corrupted 8");
}
u_len = get_be32(p + 8); u_len = get_be32(p + 8);
c_len = get_be32(p + 12); c_len = get_be32(p + 12);
u_adler = get_be32(p + 16); 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 (version >= 10) {
if (headway < (1 + off_filter)) { if (blen < off_filter + 1)
throwCantUnpack("header corrupted 9"); throwCantUnpack("header corrupted 9");
}
filter = p[off_filter]; filter = p[off_filter];
} else if ((level & 128) == 0) } else if ((level & 128) == 0)
filter = 0; filter = 0;
@@ -273,9 +263,9 @@ bool PackHeader::decodePackHeaderFromBuf(SPAN_S(const upx_byte) buf, int blen) {
if (version == 0xff) if (version == 0xff)
throwCantUnpack("cannot unpack UPX ;-)"); throwCantUnpack("cannot unpack UPX ;-)");
// check header_checksum // check header_checksum
if (version > 9) { if (version >= 10) {
unsigned const size = getPackHeaderSize(); // expected; based on format and version int size = getPackHeaderSize(); // expected; based on format and version
if (headway < size || p[size - 1] != get_packheader_checksum(p, size - 1)) if (size > blen || p[size - 1] != get_packheader_checksum(p, size - 1))
throwCantUnpack("header corrupted 3"); throwCantUnpack("header corrupted 3");
} }
if (c_len < 2 || u_len < 2 || !mem_size_valid_bytes(c_len) || !mem_size_valid_bytes(u_len)) if (c_len < 2 || u_len < 2 || !mem_size_valid_bytes(c_len) || !mem_size_valid_bytes(u_len))
+50 -50
View File
@@ -265,8 +265,8 @@ PeFile::Reloc::Reloc(upx_byte *s, unsigned si) : start(s), size(si), rel(nullptr
counts[type]++; counts[type]++;
} }
PeFile::Reloc::Reloc(unsigned rnum) : start(nullptr), size(0), rel(nullptr), rel1(nullptr) { PeFile::Reloc::Reloc(unsigned relocnum) : start(nullptr), size(0), rel(nullptr), rel1(nullptr) {
start = new upx_byte[mem_size(4, rnum, 8192)]; // => oxrelocs start = new upx_byte[mem_size(4, relocnum, 8192)]; // => oxrelocs
counts[0] = 0; counts[0] = 0;
} }
@@ -330,13 +330,13 @@ void PeFile32::processRelocs() // pass1
unsigned const skip1 = IDADDR(PEDIR_RELOC); unsigned const skip1 = IDADDR(PEDIR_RELOC);
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 *counts = rel.getcounts();
unsigned rnum = 0; unsigned relocnum = 0;
unsigned ic; unsigned ic;
for (ic = 1; ic < 16; 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)) { if (IDSIZE(PEDIR_RELOC)) {
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects); 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); 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 orelocs = mb_orelocs; // => orelocs now is a SPAN_S
sorelocs = optimizeReloc32((upx_byte *) fix[3], xcounts[3], orelocs, ibuf + rvamin, sorelocs = optimizeReloc(xcounts[3], (upx_byte *) fix[3], orelocs, ibuf + rvamin,
ibufgood - rvamin, true, &big_relocs); ibufgood - rvamin, 32, true, &big_relocs);
delete[] fix[3]; delete[] fix[3];
// Malware that hides behind UPX often has PE header info that is // Malware that hides behind UPX often has PE header info that is
// deliberately corrupt. Sometimes it is even tuned to cause us trouble! // deliberately corrupt. Sometimes it is even tuned to cause us trouble!
// Use an extra check to avoid AccessViolation (SIGSEGV) when appending // Use an extra check to avoid AccessViolation (SIGSEGV) when appending
// the relocs into one array. // 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"); throwCantUnpack("Invalid relocs");
// append relocs type "LOW" then "HIGH" // append relocs type "LOW" then "HIGH"
@@ -426,13 +426,13 @@ void PeFile64::processRelocs() // pass1
unsigned const skip = IDADDR(PEDIR_RELOC); unsigned const skip = IDADDR(PEDIR_RELOC);
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 rnum = 0; unsigned relocnum = 0;
unsigned ic; unsigned ic;
for (ic = 1; ic < 16; 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)) { if (IDSIZE(PEDIR_RELOC)) {
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
ih.objects = tryremove(IDADDR(PEDIR_RELOC), ih.objects); 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); 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 orelocs = mb_orelocs; // => orelocs now is a SPAN_S
sorelocs = optimizeReloc64((upx_byte *) fix[10], xcounts[10], orelocs, ibuf + rvamin, sorelocs = optimizeReloc(xcounts[10], (upx_byte *) fix[10], orelocs, ibuf + rvamin,
ibufgood - rvamin, true, &big_relocs); ibufgood - rvamin, 64, true, &big_relocs);
for (ic = 15; ic; ic--) for (ic = 15; ic; ic--)
delete[] fix[ic]; delete[] fix[ic];
@@ -500,7 +500,7 @@ void PeFile64::processRelocs() // pass1
// deliberately corrupt. Sometimes it is even tuned to cause us trouble! // deliberately corrupt. Sometimes it is even tuned to cause us trouble!
// Use an extra check to avoid AccessViolation (SIGSEGV) when appending // Use an extra check to avoid AccessViolation (SIGSEGV) when appending
// the relocs into one array. // 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"); throwCantUnpack("Invalid relocs");
// append relocs type "LOW" then "HIGH" // 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); Interval names(ibuf), iats(ibuf), lookups(ibuf);
// create the preprocessed data // 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++) { for (ic = 0; ic < dllnum; ic++) {
LEXX *tarr = idlls[ic]->lookupt; LEXX *tarr = idlls[ic]->lookupt;
set_le32(ppi, ilinker->getAddress(idlls[ic]->name)); 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; ph.u_len = newvsize + soimport + sorelocs;
// some extra data for uncompression support // some extra_info data for uncompression support
unsigned s = 0; unsigned s = 0;
upx_byte *const p1 = ibuf.subref("bad ph.u_len %#x", ph.u_len, sizeof(ih)); upx_byte *const p1 = ibuf.subref("bad ph.u_len %#x", ph.u_len, sizeof(ih));
memcpy(p1 + s, &ih, 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); set_le16(p1 + s, icondir_count);
s += 2; s += 2;
} }
// end of extra data // end of extra_info data
set_le32(p1 + s, ptr_diff_bytes(p1, ibuf) - rvamin); set_le32(p1 + s, ptr_diff_bytes(p1, ibuf) - rvamin);
s += 4; s += 4;
ph.u_len += s; ph.u_len += s;
@@ -2535,7 +2536,7 @@ void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, unsigned subsystem_mask,
// unpack // 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) { upx_uint64_t imagebase) {
assert(bits == 32 || bits == 64); assert(bits == 32 || bits == 64);
if (!ODADDR(PEDIR_RELOC) || !ODSIZE(PEDIR_RELOC) || (flags & RELOCS_STRIPPED)) 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; return;
} }
SPAN_P_VAR(upx_byte, rdata, obuf); const unsigned orig_crelocs = mem_size(1, get_le32(extra_info));
rdata += get_le32(extrainfo); const upx_byte big = extra_info[4];
const upx_byte big = extrainfo[4]; extra_info += 5;
extrainfo += 5;
SPAN_S_VAR(const upx_byte, rdata, obuf + orig_crelocs, obuf);
MemBuffer mb_wrkmem; 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; unsigned r16 = 0;
if (big & 6) // 16 bit relocations if (big & 6) // 16 bit relocations
{ {
@@ -2564,10 +2565,9 @@ void PeFile::rebuildRelocs(SPAN_S(upx_byte) & extrainfo, unsigned bits, unsigned
while (*++q) while (*++q)
r16++; r16++;
} }
Reloc rel(relocn + r16); Reloc rel(relocnum + r16);
if (big & 6) { 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) 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)
@@ -2577,7 +2577,7 @@ void PeFile::rebuildRelocs(SPAN_S(upx_byte) & extrainfo, unsigned bits, unsigned
} }
SPAN_S_VAR(upx_byte, const wrkmem, mb_wrkmem); 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)); OPTR_VAR(upx_byte, const p, obuf + get_le32(wrkmem + 4 * ic));
if (bits == 32) if (bits == 32)
set_le32(p, get_le32(p) + imagebase + rvamin); set_le32(p, get_le32(p) + imagebase + rvamin);
@@ -2610,12 +2610,12 @@ void PeFile::rebuildTls() {
// this is an easy one : just do nothing ;-) // 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) if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0)
return; return;
icondir_count = get_le16(extrainfo); icondir_count = get_le16(extra_info);
extrainfo += 2; extra_info += 2;
const unsigned vaddr = IDADDR(PEDIR_RESOURCE); 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> 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)) if (ODADDR(PEDIR_IMPORT) == 0 || ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc))
return; return;
OPTR_VAR(const upx_byte, const imdata, obuf + get_le32(extrainfo)); OPTR_VAR(const upx_byte, const imdata, obuf + mem_size(1, get_le32(extra_info)));
const unsigned inamespos = get_le32(extrainfo + 4); const unsigned inamespos = mem_size(1, get_le32(extra_info + 4));
extrainfo += 8; extra_info += 8;
unsigned sdllnames = 0; 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)); OPTR_VAR(const upx_byte, p, raw_bytes(imdata, 4));
for (; get_le32(p) != 0; ++p) { 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); const unsigned dlen = strlen(dname);
ICHECK(dname, dlen + 1); 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); decompress(ibuf, obuf);
unsigned skip = get_le32(obuf + (ph.u_len - 4)); unsigned skip = get_le32(obuf + (ph.u_len - 4));
unsigned take = sizeof(oh); unsigned take = sizeof(oh);
SPAN_S_VAR(upx_byte, extrainfo, obuf); SPAN_S_VAR(upx_byte, extra_info, obuf);
extrainfo = obuf.subref("bad extrainfo offset %#x", skip, take); extra_info = obuf.subref("bad extra_info offset %#x", skip, take);
// upx_byte * const eistart = raw_bytes(extrainfo, 0); // upx_byte * const eistart = raw_bytes(extra_info, 0);
memcpy(&oh, extrainfo, take); memcpy(&oh, extra_info, take);
extrainfo += take; extra_info += take;
skip += take; skip += take;
unsigned objs = oh.objects; 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"); throwCantUnpack("unexpected value in the PE header");
Array(pe_section_t, osection, objs); Array(pe_section_t, osection, objs);
take = sizeof(pe_section_t) * objs; take = sizeof(pe_section_t) * objs;
extrainfo = obuf.subref("bad extra section size at %#x", skip, take); extra_info = obuf.subref("bad extra section size at %#x", skip, take);
memcpy(osection, extrainfo, take); memcpy(osection, extra_info, take);
extrainfo += take; extra_info += take;
skip += take; skip += take;
rvamin = osection[0].vaddr; 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; ODSIZE(PEDIR_RELOC) = 0;
} }
rebuildImports<LEXX>(extrainfo, ord_mask, set_oft); rebuildImports<LEXX>(extra_info, ord_mask, set_oft);
rebuildRelocs(extrainfo, sizeof(ih.imagebase) * 8, oh.flags, oh.imagebase); rebuildRelocs(extra_info, sizeof(ih.imagebase) * 8, oh.flags, oh.imagebase);
rebuildTls(); rebuildTls();
rebuildExports(); 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); 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 // FIXME: this does bad things if the relocation section got removed
// during compression ... // 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 // fill the data directory
ODADDR(PEDIR_DEBUG) = 0; 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)> <ih sizeof(pe_head)>
<pe_section_t objs*sizeof(pe_section_t)> <pe_section_t objs*sizeof(pe_section_t)>
+2 -2
View File
@@ -92,7 +92,7 @@ protected:
unsigned processImports0(ord_mask_t ord_mask); unsigned processImports0(ord_mask_t ord_mask);
template <typename LEXX, typename ord_mask_t> 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 unsigned processImports() = 0;
virtual void processImports2(unsigned, unsigned); virtual void processImports2(unsigned, unsigned);
MemBuffer mb_oimport; MemBuffer mb_oimport;
@@ -365,7 +365,7 @@ protected:
public: public:
Reloc(upx_byte *, unsigned); Reloc(upx_byte *, unsigned);
Reloc(unsigned rnum); Reloc(unsigned relocnum);
// //
bool next(unsigned &pos, unsigned &type); bool next(unsigned &pos, unsigned &type);
const unsigned *getcounts() const { return counts; } const unsigned *getcounts() const { return counts; }
+9 -14
View File
@@ -1,10 +1,9 @@
# #
# UPX stub Makefile - needs GNU make 3.81 or better # UPX stub Makefile - needs GNU make 3.81 or better
# #
# You also will need a number of special build tools like various # Preferred: see misc/rebuild-stubs-with-podman how to use Podman/Docker.
# cross-assemblers and cross-compilers - please see README.SRC # Otherwise you will need a number of special build tools like various
# for details. # cross-assemblers and cross-compilers - see README.SRC.
# And see misc/rebuild-stubs-with-podman how to use Podman/Docker.
# #
# Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer # Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
# #
@@ -22,10 +21,6 @@ empty :=
space := $(empty) $(empty) space := $(empty) $(empty)
tab := $(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 ifndef srcdir
srcdir := $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))) srcdir := $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
srcdir := $(shell echo '$(srcdir)' | sed 's,/*$$,,') srcdir := $(shell echo '$(srcdir)' | sed 's,/*$$,,')
@@ -207,7 +202,7 @@ tc_objdump_disasm_options =
ECHO_e = /bin/echo -e ECHO_e = /bin/echo -e
ECHO_E = /bin/echo -E ECHO_E = /bin/echo -E
PERL = perl PERL = perl
PYTHON = python2 PYTHON2 = python2
UNIX2DOS := $(PERL) -i -pe 's/$$/\r/;' UNIX2DOS := $(PERL) -i -pe 's/$$/\r/;'
# trim (strip) trailing whitespace # trim (strip) trailing whitespace
@@ -240,15 +235,15 @@ define tc
endef endef
# default tools # 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=14,15,0
tc.default.bin2h-c = $(call tc,bin2h) --compress=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.brandelf = $(PYTHON2) $(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_inc = $(PYTHON2) $(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.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.pp-as = i386-linux-gcc-3.4.6 -E -nostdinc -x assembler-with-cpp -Wall
tc.default.sstrip = sstrip-20060518 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 # default multiarch-binutils
tc.default.m-ar = multiarch-ar-2.17 tc.default.m-ar = multiarch-ar-2.17
+45 -25
View File
@@ -179,38 +179,42 @@ void MemBuffer::fill(unsigned off, unsigned len, int value) {
void MemBuffer::checkState() const { void MemBuffer::checkState() const {
if (!ptr) if (!ptr)
throwInternalError("block not allocated"); throwInternalError("block not allocated");
assert(size_in_bytes > 0);
if (use_simple_mcheck()) { 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"); 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"); 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"); 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 // NOTE: we don't automatically free a used buffer
assert(ptr == nullptr); assert(ptr == nullptr);
assert(size_in_bytes == 0); assert(size_in_bytes == 0);
// //
assert(size > 0); assert(bytes > 0);
debug_set(debug.last_return_address_alloc, upx_return_address()); debug_set(debug.last_return_address_alloc, upx_return_address());
size_t bytes = mem_size(1, size, use_simple_mcheck() ? 32 : 0); size_t malloc_bytes = mem_size(1, bytes);
unsigned char *p = (unsigned char *) malloc(bytes); if (use_simple_mcheck())
NO_printf("MemBuffer::alloc %llu: %p\n", size, p); malloc_bytes += 32;
unsigned char *p = (unsigned char *) ::malloc(malloc_bytes);
NO_printf("MemBuffer::alloc %llu: %p\n", bytes, p);
if (!p) if (!p)
throwOutOfMemoryException(); throwOutOfMemoryException();
ptr = p; size_in_bytes = ACC_ICONV(unsigned, bytes);
size_in_bytes = ACC_ICONV(unsigned, size);
if (use_simple_mcheck()) { if (use_simple_mcheck()) {
ptr = p + 16; p += 16;
// store magic constants to detect buffer overruns // store magic constants to detect buffer overruns
set_ne32(ptr - 8, size_in_bytes); set_ne32(p - 8, size_in_bytes);
set_ne32(ptr - 4, MAGIC1(ptr)); set_ne32(p - 4, MAGIC1(p));
set_ne32(ptr + size_in_bytes, MAGIC2(ptr)); set_ne32(p + size_in_bytes, MAGIC2(p));
set_ne32(ptr + size_in_bytes + 4, stats.global_alloc_counter); set_ne32(p + size_in_bytes + 4, stats.global_alloc_counter);
} }
ptr = (pointer) (void *) p;
#if !defined(__SANITIZE_ADDRESS__) && 0 #if !defined(__SANITIZE_ADDRESS__) && 0
fill(0, size_in_bytes, (rand() & 0xff) | 1); // debug fill(0, size_in_bytes, (rand() & 0xff) | 1); // debug
(void) VALGRIND_MAKE_MEM_UNDEFINED(ptr, size_in_bytes); (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_alloc_counter += 1;
stats.global_total_bytes += size_in_bytes; stats.global_total_bytes += size_in_bytes;
stats.global_total_active_bytes += size_in_bytes; stats.global_total_active_bytes += size_in_bytes;
#if DEBUG
checkState();
#endif
} }
void MemBuffer::dealloc() { void MemBuffer::dealloc() {
if (ptr != nullptr) { if (ptr != nullptr) {
debug_set(debug.last_return_address_dealloc, upx_return_address()); debug_set(debug.last_return_address_dealloc, upx_return_address());
checkState(); checkState();
stats.global_dealloc_counter += 1;
stats.global_total_active_bytes -= size_in_bytes; stats.global_total_active_bytes -= size_in_bytes;
if (use_simple_mcheck()) { if (use_simple_mcheck()) {
unsigned char *p = (unsigned char *) ptr;
// clear magic constants // clear magic constants
set_ne32(ptr - 8, 0); set_ne32(p - 8, 0);
set_ne32(ptr - 4, 0); set_ne32(p - 4, 0);
set_ne32(ptr + size_in_bytes, 0); set_ne32(p + size_in_bytes, 0);
set_ne32(ptr + size_in_bytes + 4, 0); set_ne32(p + size_in_bytes + 4, 0);
// //
::free(ptr - 16); ::free(p - 16);
} else } else {
::free(ptr); ::free(ptr);
}
ptr = nullptr; ptr = nullptr;
size_in_bytes = 0; size_in_bytes = 0;
} else { } else {
@@ -263,16 +273,26 @@ TEST_CASE("MemBuffer") {
CHECK_NOTHROW(64 + mb); CHECK_NOTHROW(64 + mb);
CHECK_THROWS(65 + mb); CHECK_THROWS(65 + mb);
#endif #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()) { if (use_simple_mcheck()) {
upx_byte *b = raw_bytes(mb, 0); unsigned char *p = raw_bytes(mb, 0);
unsigned magic1 = get_ne32(b - 4); unsigned magic1 = get_ne32(p - 4);
set_ne32(b - 4, magic1 ^ 1); set_ne32(p - 4, magic1 ^ 1);
CHECK_THROWS(mb.checkState()); CHECK_THROWS(mb.checkState());
set_ne32(b - 4, magic1); set_ne32(p - 4, magic1);
mb.checkState(); mb.checkState();
} }
} }
TEST_CASE("MemBuffer unused") {
MemBuffer mb;
CHECK(mb.raw_ptr() == nullptr);
CHECK(mb.raw_size_in_bytes() == 0);
}
TEST_CASE("MemBuffer::getSizeForCompression") { TEST_CASE("MemBuffer::getSizeForCompression") {
CHECK_THROWS(MemBuffer::getSizeForCompression(0)); CHECK_THROWS(MemBuffer::getSizeForCompression(0));
CHECK_THROWS(MemBuffer::getSizeForDecompression(0)); CHECK_THROWS(MemBuffer::getSizeForDecompression(0));
+7 -5
View File
@@ -49,9 +49,10 @@ public:
MemBufferBase() : ptr(nullptr), size_in_bytes(0) {} MemBufferBase() : ptr(nullptr), size_in_bytes(0) {}
// NOTE: implicit conversion to underlying pointer // 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; } operator pointer() const { return ptr; }
// membuffer + n -> pointer
template <class U> template <class U>
typename std::enable_if<std::is_integral<U>::value, pointer>::type operator+(U n) const { 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 size_t bytes = mem_size(sizeof(T), n); // check mem_size
@@ -59,7 +60,7 @@ public:
} }
private: private:
// NOT allowed; use raw_bytes() instead // membuffer - n -> pointer; not allowed - use raw_bytes() if needed
template <class U> template <class U>
typename std::enable_if<std::is_integral<U>::value, pointer>::type operator-(U n) const typename std::enable_if<std::is_integral<U>::value, pointer>::type operator-(U n) const
DELETED_FUNCTION; DELETED_FUNCTION;
@@ -82,13 +83,13 @@ public: // raw access
class MemBuffer final : public MemBufferBase<unsigned char> { class MemBuffer final : public MemBufferBase<unsigned char> {
public: public:
MemBuffer() : MemBufferBase<unsigned char>() {} MemBuffer() : MemBufferBase<unsigned char>() {}
explicit MemBuffer(upx_uint64_t size_in_bytes); explicit MemBuffer(upx_uint64_t bytes);
~MemBuffer(); ~MemBuffer();
static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra = 0); static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra = 0);
static unsigned getSizeForDecompression(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 allocForCompression(unsigned uncompressed_size, unsigned extra = 0);
void allocForDecompression(unsigned uncompressed_size, unsigned extra = 0); void allocForDecompression(unsigned uncompressed_size, unsigned extra = 0);
@@ -96,7 +97,7 @@ public:
void checkState() const; void checkState() const;
unsigned getSize() const { return size_in_bytes; } unsigned getSize() const { return size_in_bytes; }
// explicit converstion // explicit conversion
void *getVoidPtr() { return (void *) ptr; } void *getVoidPtr() { return (void *) ptr; }
const void *getVoidPtr() const { return (const void *) ptr; } const void *getVoidPtr() const { return (const void *) ptr; }
@@ -119,6 +120,7 @@ private:
// static debug stats // static debug stats
struct Stats { struct Stats {
upx_std_atomic(upx_uint32_t) global_alloc_counter; 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_bytes;
upx_std_atomic(upx_uint64_t) global_total_active_bytes; upx_std_atomic(upx_uint64_t) global_total_active_bytes;
}; };
+2 -1
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_MEM == UPX_RSIZE_MAX)
ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_STR <= UPX_RSIZE_MAX / 256) 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(5ull * UPX_RSIZE_MAX < UINT_MAX)
ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX >= 8192 * 65536) ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX >= 8192 * 65536)
ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_STR >= 1024) ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_STR >= 1024)
+6
View File
@@ -95,6 +95,12 @@ forceinline pointer ensureBase() const {
public: public:
inline ~CSelf() {} inline ~CSelf() {}
void destroy() {
assertInvariants();
base = ptr;
size_in_bytes = 0;
assertInvariants();
}
// constructors from pointers // constructors from pointers
CSelf(pointer first, XSpanCount count) CSelf(pointer first, XSpanCount count)
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count.count)) { : ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count.count)) {