src: rework optimizeReloc handling; cleanups
This commit is contained in:
parent
8d364c82e2
commit
4a8efd2e2f
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@ -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 }}
|
||||
|
||||
@ -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"
|
||||
|
||||
1
Makefile
1
Makefile
@ -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
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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)";
|
||||
|
||||
13
src/except.h
13
src/except.h
@ -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: */
|
||||
|
||||
@ -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++) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
155
src/packer.cpp
155
src/packer.cpp
@ -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)
|
||||
**************************************************************************/
|
||||
|
||||
19
src/packer.h
19
src/packer.h
@ -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
144
src/packer_r.cpp
Normal 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: */
|
||||
@ -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))
|
||||
|
||||
100
src/pefile.cpp
100
src/pefile.cpp
@ -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)>
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user