                        The UPX Hacker's Guide
                        ======================


Foreword
--------

  The precompiled UPX versions are linked against the NRV compression
  library instead of the UCL library. Using the same compression algorithms,
  NRV achieves a better compression ratio. NRV is not publicly
  available, though, and probably never will be.

  While you may be disappointed that you don't have access to the
  latest state-of-the-art compression technology this is actually
  a safe guard for all of us. The UPX source code release makes
  it very easy for any evil-minded person to do all sort of bad
  things. By not providing the very best compression ratio it is much
  more difficult to create fake or otherwise disguised UPX versions (or
  similar trojans), as any end user will notice when the compression
  has gotten worse with a new "version" or "product".

  Finally please be aware that you now have your hands on the source
  code of the most sophisticated executable packer ever.
  Let's join our forces to make it even better :-)

  Share and enjoy,
  Markus & Laszlo


Short overview
--------------

  The UPX source code consists of two mainly independent parts:

  1) The src/stub directory contains the decompression stubs that
     will get added to each compressed executable.
     The stubs are mainly written in assembler and get "compiled"
     into ordinary C header files.

  2) The src directory contains the actual packer sources. The stubs
     are #included by the individual executable format handlers.


Tools needed to build/modify the UPX sources
--------------------------------------------

  - A C++ compiler that fully implements C++17: clang-5, gcc-8 or msvc-2019-16.11
    (older or other compilers may work but are unsupported, use at your own risk)

  - GNU make

  - CMake 3.13 or better; see https://cmake.org/


To compile the packer sources
-----------------------------

  - just run "make" in the top-level source directory


If you want to modify the stub sources you'll also need
-------------------------------------------------------

  - Podman/Docker: see misc/podman/rebuild-stubs - this
    is the preferred way of rebuilding the stubs

  - otherwise you will need:
    - a Linux host system with Perl, Python2 and some older compat-libs
    - upx-stubtools - a number of cross-assemblers and cross-compilers.
      Precompiled binaries for amd64-linux hosts are available from
      https://github.com/upx/upx-stubtools/releases


Developer quick start
---------------------
 1)  $ mkdir my-upx; cd my-upx  # new directory for safety and convenience
 2)  $ git clone https://github.com/upx/upx.git
 3)  $ git clone https://github.com/upx/upx-testsuite.git
 4)  # Optional for re-building stubs:
 4a)    $ pushd upx/src/stub  # my-upx/upx/src/stub
 4b)    $ wget https://github.com/upx/upx-stubtools/releases/download/v20221212/bin-upx-20221212.tar.xz
          # Extract to $HOME/bin/bin-upx or $HOME/local/bin/bin-upx.
          # See directions in: https://github.com/upx/upx-stubtools

          # Some of the pre-built tools need i386 libz.  On Ubuntu:
          #   # dpkg --add-architecture i386
          #   # apt-get update
          #   # apt-get install zlib1g-dev:i386 libc6-dev:i386
          #   # apt-get install crossbuild-essential-riscv64  # for example
          # aarch64-linux-gnu/4.9.2/cc1 needs libmpfr.so.4.  Make a symlink:
          #   # ln -s /usr/lib/x86_64-linux-gnu/libmpfr.so.6 /usr/lib/x86_64-linux-gnu/libmpfr.so.4

 4c)    $ make clean; make  # verify that you can re-build stubs
 4d)    $ popd  # my-upx
 5)  $ cd upx  # my-upx/upx
 6)  $ git submodule update --init  # compression algorithms, etc.
        # DO NOT TOUCH vendor/...
        # After a git merge/pull/etc, then use "git status"
        # to check whether the vendor directory is clean;
        # if not, then update via "git submodule update".
        # If stuck, then reset via "rm -rf vendor; git submodule update --init".
 7)  $ mkdir -p build/debug build/release
 8)  $ pushd build/debug  # my-upx/upx/build/debug

9a)  Install GNU g++ so that it is used when invoking "c++" compiler.
     On Ubuntu 24.04 with
        cmake: cmake version 3.28.3
        g++: Ubuntu clang version 18.1.3 (1ubuntu1)
        /lib/llvm-18/lib/cmake/llvm/HandleLLVMOptions.cmake:
           add_flag_if_supported("-fno-lifetime-dse" CMAKE_CXX_FLAGS)
     then cmake invoking c++ uses -fno-lifetime-dse but gets
        c++: error: unknown argument: '-fno-lifetime-dse'
     Commenting out the "add_flag_if_supported' line still uses that unknown argument.
     Installing g++ avoids the problem.
9b)  $ cmake ../..  # configure cmake
10)  $ cmake --build . --verbose  # optional "--verbose"
        # This relies on stub/*.h, which YOU must re-build if necessary.
        # When in doubt, then use "cd src/stub; make clean; make".
11)  $ popd  # my-upx/upx
12)  $ cd src  # my-upx/upx/src
12a)    On MacOS: install homebrew (https:://brew.sh), then "brew install coreutils"
        and put <some_prefix>/opt/coreutils/libexec/gnubin into PATH so that
        "readlink -en" and "sha256sum -b" work.
13)  $ make run-testsuite 2>&1  |  tee testsuite.log



Misc. notes
-----------

  As the docs say: UPX is a portable, extendable and endian neutral
  program, so if you want to add some new stuff, try not to break these
  nice properties.

  - Use the types LE16, LE32, BE16 and BE32 for fields in file headers.
  - Use [sg]et_[bl]e(16|32) for getting/setting values in the data
    stream.
  - Use gcc extensions and other compiler specific stuff only through
    macros.


Some conventions:
-----------------

  - follow our coding style
  - indent level = 4
  - expand all tabulators

  - Use throwSomeException() functions instead of throw SomeException():
    this makes the code shorter if used often.

# vim:set ts=4 sw=4 et:
