Initial commit (from git)

This commit is contained in:
convert-repo 2000-05-19 16:04:55 +00:00
commit 1a9128a473
130 changed files with 31392 additions and 0 deletions

51
BUGS Normal file
View File

@ -0,0 +1,51 @@
ooooo ooo ooooooooo. ooooooo ooooo
`888' `8' `888 `Y88. `8888 d8'
888 8 888 .d88' Y888..8P
888 8 888ooo88P' `8888'
888 8 888 .8PY888.
`88. .8' 888 d8' `888b
`YbodP' o888o o888o o88888o
The Ultimate Packer for eXecutables
Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
http://www.nexus.hu/upx
http://upx.tsx.org
Things not (yet) supported:
===========================
dos/exe
-------
* normal dos/exes with new exe headers
* max ~24000 relocation records (...should be enough for everyone ;-)
* exe + sys combined images
wc/le
-----
* 16-bit selector alias fixups
* 16-bit offset relocation for objects larger than 4 kbyte
* 16:16 fixups
If you need any of the above (they're very rare), send us an url of a
test file.
* 16-bit objects are not loaded into DOS memory
* There is still a problem with the wdosx extender: if you compress a
wc/le file which does NOT contain the wdosx extender, and after this
you bind the wdosx stub to the compressed file, then it will work.
Otherwise it won't.
* unpacked pmwlite compressed programs might not work when compressed
with upx (pmwunlite bug mainly :-)
win32/pe
--------
* writeable shared sections (`--force' *may* work)
* certificates in the image
djgpp2/coff
-----------
* all overlays (except Allegro pakfiles) are silently stripped

340
COPYING Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it 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; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

138
LICENSE Normal file
View File

@ -0,0 +1,138 @@
-----BEGIN PGP SIGNED MESSAGE-----
ooooo ooo ooooooooo. ooooooo ooooo
`888' `8' `888 `Y88. `8888 d8'
888 8 888 .d88' Y888..8P
888 8 888ooo88P' `8888'
888 8 888 .8PY888.
`88. .8' 888 d8' `888b
`YbodP' o888o o888o o88888o
The Ultimate Packer for eXecutables
Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
http://www.nexus.hu/upx
http://upx.tsx.org
PLEASE CAREFULLY READ THIS LICENSE AGREEMENT, ESPECIALLY IF YOU PLAN
TO MODIFY THE UPX SOURCE CODE OR USE A MODIFIED UPX VERSION.
ABSTRACT
========
UPX and UCL are copyrighted software distributed under the terms
of the GNU General Public License (hereinafter the "GPL").
The stub which is imbedded in each UPX compressed program is part
of UPX and UCL, and contains code that is under our copyright. The
terms of the GNU General Public License still apply as compressing
a program is a special form of linking with our stub.
As a special exception we grant the free usage of UPX for all
executables, including commercial programs.
See below for details and restrictions.
COPYRIGHT
=========
UPX and UCL are copyrighted software. All rights remain with the authors.
UPX is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
UPX is Copyright (C) 1996-2000 Laszlo Molnar
UCL is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
GNU GENERAL PUBLIC LICENSE
==========================
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.
UPX and UCL are distributed in the hope that they 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.
SPECIAL EXCEPTION FOR COMPRESSED EXECUTABLES
============================================
The stub which is imbedded in each UPX compressed program is part
of UPX and UCL, and contains code that is under our copyright. The
terms of the GNU General Public License still apply as compressing
a program is a special form of linking with our stub.
Hereby Markus F.X.J. Oberhumer and Laszlo Molnar grant you special
permission to freely use and distribute all UPX compressed programs
(including commercial ones), subject to the following restrictions:
1. You must compress your program with a completely unmodified UPX
version; either with our precompiled version, or (at your option)
with a self compiled version of the unmodified UPX sources as
distributed by us.
2. This also implies that the UPX stub must be completely unmodfied, i.e.
the stub imbedded in your compressed program must be byte-identical
to the stub that is produced by the official unmodified UPX version.
3. The decompressor and any other code from the stub must exclusively get
used by the unmodified UPX stub for decompressing your program at
program startup. No portion of the stub may get read, copied,
called or otherwise get used or accessed by your program.
ANNOTATIONS
===========
- You can use a modified UPX version or modified UPX stub only for
programs that are compatible with the GNU General Public License.
- We grant you special permission to freely use and distribute all UPX
compressed programs. But any modification of the UPX stub (such as,
but not limited to, removing our copyright string or making your
program non-decompressible) will immediately revoke your right to
use and distribute a UPX compressed program.
- UPX is not a software protection tool; by requiring that you use
the unmodified UPX version for your proprietary programs we
make sure that any user can decompress your program. This protects
both you and your users as nobody can hide malicious code -
any program that cannot be decompressed is highly suspicious
by definition.
- You can integrate all or part of UPX and UCL into projects that
are compatible with the GNU GPL, but obviously you cannot grant
any special exceptions beyond the GPL for our code in your project.
- We want to actively support manufacturers of virus scanners and
similar security software. Please contact us if you would like to
incorporate parts of UPX or UCL into such a product.
Markus F.X.J. Oberhumer Laszlo Molnar
markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
Linz, Austria, 25 Feb 2000
-----BEGIN PGP SIGNATURE-----
Version: 2.6.3ia
Charset: noconv
iQCVAwUBOLaLS210fyLu8beJAQFYVAP/ShzENWKLTvedLCjZbDcwaBEHfUVcrGMI
wE7frMkbWT2zmkdv9hW90WmjMhOBu7yhUplvN8BKOtLiolEnZmLCYu8AGCwr5wBf
dfLoClxnzfTtgQv5axF1awp4RwCUH3hf4cDrOVqmAsWXKPHtm4hx96jF6L4oHhjx
OO03+ojZdO8=
=CS52
-----END PGP SIGNATURE-----

89
LOADER.TXT Normal file
View File

@ -0,0 +1,89 @@
This documentation was written for those brave souls who want to
understand and/or modify the UPX assembly stubs - the small snippets
that do the runtime decompression when a compressed program is started.
So, how the runtime stub/loader generation works?
You might have already noticed that for some file formats the loaders
are quite simple (linux/i386 & tos) while in the other cases the
loaders look very suspicious: they're full of `%ifdef's and contain
loads of cryptic comments like `__PERELOC2__'.
If you look at the C++ source files, however you can notice that these
comment strings (without the leading and trailing underscores) are used
in the following way (they are all 8 character length strings):
addLoader("PEMAIN20",
ih.entry ? "PEDOJUMP" : "PERETURN",
"IDENTSTR""UPX1HEAD",
NULL
);
Basically that's all you have to know: when you want to add a section
of assembly code to the runtime loader, you just write
l_foo.asm
---------
;__FOOBAR00__
xor eax, eax
label1:
jmps label1
;__FOOBARZZ__
p_foo.cpp
---------
addLoader("FOOBAR00", NULL);
This will add the assembly section starting from __FOOBAR00__ and ending
before __FOOBARZZ__ to the loader. You can add an %ifdef - %endif pair
before these comments if you wish - but these conditionals will NOT be
seen by the assembler, they are just syntactic sugar to make the code a
little bit more readable and understandable. (Note however, that only
%ifdefs which are started on the 1st column are removed by the upx
assembly preprocessor program, so you can still use preprocessor
conditionals if you wish - just write them starting from the 2nd
column.)
That's nice, you could say, but how cross section jumps and calls are
handled? Well, that is the nicest part of this stuff - they are handled
automatically. All you have to do is to add the required sections to the
loader using `addLoader()' and the rest is done by upx. It will resolve
every conditional or unconditional jumps or subrutine calls for you.
This functionality (we could say it's a simple linker) is achived by the
assembly preprocessor (src/stub/scripts/app.pl) and a little C++ module
(src/linker.cpp). And of course NASM - the Netwide Assembler. You can
see what's going on behind the scenes - just do:
cd src/stubs
make maintainer-clean
make all
This will rebuild all the loaders - and keep the temporary files (*.as[xy])
which are seen by the assembler.
Currently this loader/stub building method only works with ix86
assembly - both app.pl and linker.cpp heavily rely on this when dealing
with cross section references.
And finally some important features/requirements you should be aware of:
- as previously stated - preprocessor conditionals starting on the 1st
column are removed by app.pl
- sections are separated by comments in the form `;__X1234567__'
- jumps are recognized by searching for a word which starts with `j'
and followed by a label - this also means that `jmp short label1'
will NOT be recognized (but you can use a macro called `jmps' for it
by adding `%define jmps jmp short' to the beginning of the file)
- at the end of the file you need something like this
eof:
; __XTHEENDX__
section .data
dd -1
dw eof
That's all for now.

21
Makefile Normal file
View File

@ -0,0 +1,21 @@
# Toplevel Makefile for UPX
all:
$(MAKE) -C src/stub
$(MAKE) -C src
$(MAKE) -C doc
clean:
$(MAKE) -C src/stub $@
$(MAKE) -C src $@
$(MAKE) -C doc $@
distclean: clean
dist:
sh ./maint/util/laszlo.sh
.PHONY: all clean distclean dist
.NOEXPORT:

197
NEWS Normal file
View File

@ -0,0 +1,197 @@
============================================================================
User visible changes for UPX
============================================================================
Changes in 1.01 (09 Apr 2000)
* win32/pe: fixed an uncompression problem in DLLs with empty
fixup sections
* win32/pe: fixed another rare uncompression problem - a field in the
PE header was set incorrectly
Changes in 1.00 (26 Mar 2000)
* documentation updates
* watcom/le: do not duplicate the non-resident name table
* win32/pe: fixed an import handling problem: sometimes too much data
could be deleted from a file -> the uncompressed file would not work
anymore
Changes in 0.99.3 (07 Mar 2000)
* win32/pe: fixed a rare problem in the stub string handling part
Changes in 0.99.2 (02 Mar 2000)
* dos/exe: fixed a typo causing an internal error (introduced in 0.99.1)
Changes in 0.99.1 (29 Feb 2000)
* win32/pe: fixed some object alignments which were causing
problems when loading compressed DLLs under Windows NT/2000
Changes in 0.99 (25 Feb 2000)
* FULL SOURCE CODE RELEASED UNDER THE TERMS OF THE GNU GPL
* win32/pe: changed default to `--strip-relocs=1'
* dos/com and dos/sys: fixed a bad decompressor problem
* linux/i386: the counter for the progress indicator was off by one
Changes in 0.94 (06 Dec 1999)
* win32/pe: the stub now calls ExitProcess in case of import errors
* under DOS and Windows, the environment variable UPX now accepts
a '#' as replacement for '=' because of a COMMAND.COM limitation
Changes in 0.93 (22 Nov 1999)
* win32/pe: fixed --strip-relocs problem with uncompression
* win32/pe: fixed a bug which could produce a broken decompressor stub
* linux/i386: yet another FreeBSD compatibility fix
Changes in 0.92 (14 Nov 1999)
* win32/pe: really fixed that one line (see below)
Changes in 0.91 (13 Nov 1999)
* win32/pe: an important one-line fix for the newly introduced problems
* dos/com and dos/sys: fixed an internal error
* dos/exe: correctly restore cs when uncompressing
Changes in 0.90 (10 Nov 1999)
* all formats: `--overlay=copy' now is the default overlay mode
* improved compression ratio for most files
* win32/pe: uncompression is finally supported
* win32/pe: never compress REGISTRY resources
* win32/pe: headersize was not set in PE header
* win32/pe: resource handling is rewritten
* win32/pe: the last :-) TLS problem is fixed
* win32/pe: somewhat less memory is required during compression
* linux/i386: fixed compression of scripts which was broken since 0.71
* linux/i386: more FreeBSD compatibility issues
* changed option: `-i' now prints some more details during compression
(not finished yet)
Changes in 0.84 (04 Oct 1999)
* dos/exe: fixed a rare problem where the decompressor could crash
* some other minor fixes
Changes in 0.83 (17 Sep 1999)
* dos/exe: fixed minimal memory requirement problem for some files
* win32/pe: fixed a bug which caused a crash in some compressed files
* linux/i386: various improvements in the stub; also, for the sake
of FreeBSD users, the stub is now branded as Linux/ELF
Changes in 0.82 (16 Aug 1999)
* dos/exe: fixed a decompressor bug which could cause crash on some files
* linux/i386: section headers are now stripped from the stub so that
`strip' won't ruin a compressed file any longer
* wc/le: support for stack not in the last object disabled again
* win32/pe: removed some unneeded data
Changes in 0.81 (04 Aug 1999)
* win32/pe: fixed an important bug in import handling
* dos/com: fixed an internal error that could happen with very small files
Changes in 0.80 (03 Aug 1999)
* you can set some default options in the environment var `UPX'
* dos/com: the decompressor stub now checks for enough free memory
* dos/exe: decompressor rewritten, some bugs are fixed
* dos/exe: new option `--no-reloc': no relocation data is put into
the DOS header
* tmt/adam: added support for more stubs, detect already packed files
* tmt/adam: new option `--copy-overlay'
* wc/le: reduced memory requirement during uncompression
* wc/le: support files which do not contain their stack in the last object
* wc/le: fixed a bug which could cause a crash, improved relocation
handling
* wc/le: new option `--copy-overlay'
* win32/pe: `--compress-icons=2' is now the default
* win32/pe: even better TLS support
* win32/pe: versioninfo works on NT
* win32/pe: import by ordinal from kernel32.dll works
* win32/pe: other import improvements: importing a nonexistant DLL
results in a usual Windows message, importing a nonexistant function
results in program exit (instead of crash ;-)
* win32/pe: new option: `--compress-resources=0'
* win32/pe: reduced memory requirement during uncompression, some
files might even require LESS memory when they're compressed
* win32/pe: TYPELIBs should work now
* win32/pe: improved relocation handling, 16-bit relocations should work
* win32/pe: new option `--strip-relocs' (only if you know what you are doing)
* win32/pe: new option `--copy-overlay'
* important internal changes: now the stubs are built at runtime
Changes in 0.72 (12 May 1999)
* tmt/adam: fixed a serious problem in the decompressor stub; all
compressed tmt files should be recompressed
* win32/pe: fixed the 'shared sections not supported' warning:
read-only shared sections are fine
* win32/pe: never compress TYPELIB resources
* win32/pe: compressed files are hopefully less suspicious to heuristic
virus scanners now
* linux/i386: minor decompressor stub updates, nicer progress bar
Changes in 0.71 (19 Apr 1999)
* dos/exe: added option `--no-overlay'
* linux/i386: various improvements in the stub, most notably the
overhead for an extra cleanup process has been removed
* win32/pe: added support for export forwarders
* win32/pe: added support for DLLs without entry point or imports
* win32/pe: yet another .bss fix
* win32/pe: new option `--compress-icons=2': compress all icons
which are not in the first icon directory
* win32/pe: rearranged stub to avoid false alerts from some virus scanners
Changes in 0.70 (30 Mar 1999)
* added support for linux/i386 executables
* improved compression ratio quite a bit
* added new compression level `--best' to squeeze out even some more bytes
* win32/pe: TLS support is much better now
* win32/pe: --compress-icons=0 should now work as well
* the usual minor fixes for win32/pe
Changes in 0.62 (16 Mar 1999)
* win32/pe: --compress-icons and --compress-exports are on now by default
* win32/pe: --compress-icons should really work now
* win32/pe: fixed a problem with embedded .bss sections
Changes in 0.61 (08 Mar 1999)
* atari/tos: fixed a problem where the bss segment could become too small
Changes in 0.60 (06 Mar 1999)
* win32/pe: fixed file corruption when the size of the export data is invalid
* win32/pe: fixed a problem with empty resource data
* win32/pe: compressed file alignment set to minimum value
* win32/pe: made all compressed sections writeable
* fixed some other win32/pe bugs
* fixed an address optimization problem for some not Watcom LE files
* fixed a bug which could make UPX hang when an exe header contained
an illegal value
* added some compression flags for the win32/pe format
* added support for Atari ST executables (atari/tos)
* improved compression ratio
* improved compression speed
Changes in 0.51 (14 Jan 1999)
* fixed a small bug in the PE header that would prevent some compressed
win32/pe executables from running under Windows NT and WINE
Changes in 0.50 (03 Jan 1999)
* added support for PE format executables (win32/pe & rtm32/pe)
* added support for TMT executables (tmt/adam)
* fixed a dos/sys bug that affected OpenDOS
Changes in 0.40 (05 Oct 1998)
* improved compression ratio
* fixed a small but fatal bug in dos/sys introduced in 0.30
* fixed a rare bug in dos/exe
* worked around a bug in djgpp's strip 2.8
* Allegro packfile support should work now
* added dos/exeh compression method (works on 386+)
Changes in 0.30 (27 Jul 1998)
* fixed a serious bug in the 32-bit compressors - please don't use
djgpp/coff and watcom/le compressed files from previous versions,
some of them are possibly damaged !
* the 16-bit uncompressors are a little bit shorter & faster
* fixed progress indicator for VESA and SVGA text modes
Changes in 0.20 (05 Jul 1998)
* second public beta release
* too many changes to list here
Changes in 0.05 (26 May 1998)
* first public beta release

92
PROJECTS Normal file
View File

@ -0,0 +1,92 @@
ooooo ooo ooooooooo. ooooooo ooooo
`888' `8' `888 `Y88. `8888 d8'
888 8 888 .d88' Y888..8P
888 8 888ooo88P' `8888'
888 8 888 .8PY888.
`88. .8' 888 d8' `888b
`YbodP' o888o o888o o88888o
The Ultimate Packer for eXecutables
Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
http://www.nexus.hu/upx
http://upx.tsx.org
Here are some possible projects from which you can choose if you'd like to
contribute to UPX. Be sure to get in touch with us first to avoid
duplicate efforts.
User interface:
---------------
- Write a nifty Win32 GUI (in C++), but try to keep the size of the
final executable small. Compression should be in a separate
thread that calls do_one_file() [see src/work.cpp].
- Draw a nice UPX icon.
More formats:
-------------
- add more file formats / platforms (there were volunteers for FreeBSD,
BeOS, Windows CE, Amiga, C64, ...)
- add support for Linux kernels
- add support for self-extracting HTML pages using a Javascript stub
(like the AlgART HTML Packer "AHP")
Existing formats:
-----------------
- dos/com: add support for very long files - convert to exe if necessary
- dos/sys: add support for sys/exe combos
- dos/exe: implement filter support
- djgpp2/coff: add support for DLX dynamic loading
(see SEAL http://www.home.sk/public/seal/ )
- linux/i386:
- add support for compressed kernels
- use the new assembly preprocessor stuff (ie. process the file
headers internally)
- UPX uncompressor daemon
- rewrite the stub in assembly (not sure if this is a good idea...)
- etc...
- linux/i386: add a special elf/i386 format that understands
ELF files and has filter support
- watcom/le: add support for per section compression, LX support, VXD
- win32/pe: display a nice dialog box in the stub in case
of problems (like importing a DLL or function fails)
- win32/pe: finer control over resource compression, per section
compression
- win32/pe: compressing screensavers looses the description - probably
should not compress a special resource type
Compression ratio:
------------------
- invent more effective filters
- I (Markus) will continue to work on better compression algorithms,
so be sure to do better than me if you plan working on this ;-)
Other:
------
- anything else you think that could improve UPX...
Thanks for your contribution.

143
README Normal file
View File

@ -0,0 +1,143 @@
ooooo ooo ooooooooo. ooooooo ooooo
`888' `8' `888 `Y88. `8888 d8'
888 8 888 .d88' Y888..8P
888 8 888ooo88P' `8888'
888 8 888 .8PY888.
`88. .8' 888 d8' `888b
`YbodP' o888o o888o o88888o
The Ultimate Packer for eXecutables
Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
http://www.nexus.hu/upx
http://upx.tsx.org
WELCOME
=======
Welcome to UPX 1.00, the first production release (after almost two years
of beta testing).
Please don't forget to read the new LICENSE - UPX is now distributed
under the GNU General Public License (GPL) with special exceptions
allowing the distribution of all compressed executables, including
commercial programs.
INTRODUCTION
============
UPX is an advanced executable file compressor. UPX will typically
reduce the file size of programs and DLLs by around 50%-70%, thus
reducing disk space, network load times, download times and
other distribution and storage costs.
Programs and libraries compressed by UPX are completely self-contained
and run exactly as before, with no runtime or memory penalty for most
of the supported formats.
UPX supports a number of different executable formats, including
Win95/98/2000/NT programs and DLLs, DOS programs, and Linux executables.
UPX is free software distributed under the term of the GNU General
Public License. Full source code is available.
UPX may be distributed and used freely, even with commercial applications.
See the UPX License Agreement for details.
UPX is rated number one in the well known Archive Comparison Test. Visit
http://web.act.by.net/~act/act-exepack.html
UPX aims to be Commercial Quality Freeware.
SHORT DOCUMENTATION
===================
`upx program.exe' will compress a program or DLL. For best compression
results try `upx --best program.exe'.
Please see the file UPX.DOC for the full documentation. The files
NEWS and BUGS also contain various tidbits of information.
DISCLAIMER
==========
UPX comes with ABSOLUTELY NO WARRANTY; for details see the file LICENSE.
Having said that, we think that UPX is quite stable now. Indeed we
have compressed lots of files without any problems. Also, the
current version has undergone several months of beta testing -
actually it's almost 2 years since our first public beta.
This is the first production quality release, and we plan that future
releases will be backward compatible with this version.
Please report all problems or suggestions to the authors. Thanks.
THE FUTURE
==========
- We'd really love to support handheld systems like the PalmPilot because
compression makes a lot of sense here. And - because of the atari/tos
format - we already have a working decompressor in 68000 assembly.
Unfortunately we know next to nothing about the operating system
architecture of such handhelds, so we need some information from
an expert. Please contact us if you think you can help.
- The Linux approach could probably get ported to a lot of other Unix
variants, at least for other i386 architectures it shouldn't be too
much work. If someone sends me a fresh hard disk and an official
FreeBSD/OpenBSD/NetBSD/Solaris/BeOS... CD I might take a look at it ;-)
- We will *NOT* add any sort of protection and/or encryption.
This only gives people a false feeling of security because
by definition all protectors/compressors can be broken.
And don't trust any advertisment of authors of other executable
compressors about this topic - just do a websearch on something
like "procdump"...
- Fix all remaining bugs - keep your reports coming ;-)
- See the file PROJECTS in the source code distribution if you want
to contribute.
COPYRIGHT
=========
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
This program may be used freely, and you are welcome to
redistribute it under certain conditions.
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
UPX License Agreement for more details.
You should have received a copy of the UPX License Agreement along
with this program; see the file LICENSE. If not, visit the UPX home page.
Share and enjoy,
Markus & Laszlo
Markus F.X.J. Oberhumer Laszlo Molnar
markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
[ The term UPX is a shorthand for the Ultimate Packer for eXecutables
and holds no connection with potential owners of registered trademarks
or other rights. ]
[ Feel free to contact us if you have commercial compression requirements
or interesting job offers. ]

153
README.SRC Normal file
View File

@ -0,0 +1,153 @@
The UPX Hacker's Guide
======================
Foreword
--------
The precompiled UPX versions are linked against the NRV compression
library instead of the UCL library. Using 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
Introduction
------------
Welcome to the UPX source code release!
UPX is not a toy for kids. Apart from basic knowledge about executables
and data compression you will need to be firm in C++, assembler,
Perl and Makefiles. Probably some other things as well.
If you cant't manage to compile it then the sources are
probably not for you. Don't email us for help.
The authors use Linux for development. You might want to as well.
Short overview
--------------
The UPX source code consists of two mainly independent parts:
1) The src/stubs 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.
Prerequisites
-------------
- first of all you need to build the UCL compression library
http://wildsau.idv.uni-linz.ac.at/mfx/ucl.html
Tools needed to build/modify the UPX sources
--------------------------------------------
- A modern C++ compiler like gcc 2.95.2 or Visual C++ 6
(egcs 1.1.x may work, half-baked implementations like Borland C++ 5.5 won't)
- GNU make 3.77 for Win32
ftp://agnes.dida.physik.uni-essen.de/home/janjaap/mingw32/newnew/
- GNU make 3.77 for DOS
ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/
To compile the packer sources
-----------------------------
set the environment variable UCLDIR to point to your UCL installation, e.g.
set UCLDIR=c:\src\ucl-0.90 (DOS)
export UCLDIR=$HOME/local/src/ucl-0.90 (Unix)
then type
make target=linux # on linux
make target=djgpp2 # for djgpp2
make target=mingw32 # for mingw32
make target=no-cygwin # for mingw32 as of cygwin b20.1
make target=msc # for Visual C++ 6.0
If you want to modify the stub sources you'll also need
-------------------------------------------------------
- Nasm - the Netwide Assembler 0.98
http://www.cryogen.com/Nasm
- Perl 5.004 or better
ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/perl*b.zip
- A68K - a 68000 macro assembler
http://wildsau.idv.uni-linz.ac.at/mfx/download/upx/tools/
- djasm - an assembler for the djgpp stub
http://wildsau.idv.uni-linz.ac.at/mfx/download/upx/tools/
ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2/djdev203.zip
- Linux (for the linux/i386 stubs)
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.
- Keep in mind that it should be possible to build UPX on braindead
file systems (FAT). Don't use long file names or other things
that break building under plain DOS.
***
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.
***
Patches/Contributions
- Please send us bug fixes/contributions only using
diff -u oldfile newfile
or
diff -uNr olddirectory newdirectory

55
THANKS Normal file
View File

@ -0,0 +1,55 @@
ooooo ooo ooooooooo. ooooooo ooooo
`888' `8' `888 `Y88. `8888 d8'
888 8 888 .d88' Y888..8P
888 8 888ooo88P' `8888'
888 8 888 .8PY888.
`88. .8' 888 d8' `888b
`YbodP' o888o o888o o88888o
The Ultimate Packer for eXecutables
Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
http://www.nexus.hu/upx
http://upx.tsx.org
.___.. .
| |_ _.._ ;_/ __
| [ )(_][ )| \_)
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
Adam Ierymenko <api@one.net>
for severals ideas for the Linux version
Andi Kleen <ak@muc.de> and Jamie Lokier <nospam@cern.ch>
for the /proc/self/fd/X and other Linux suggestions
Atli Mar Gudmundsson <amg@complex.is>
for several comments on the win32/pe stub
Charles W. Sandmann <sandmann@clio.rice.edu>
for the idea with the stubless decompressor in djgpp2/coff
Ice
for debugging the PE headersize problem down
Joergen Ibsen <jibz@hotmail.com> and d'b
for the relocation & address optimization ideas
John S. Fine <johnfine@erols.com>
for the new version of the dos/exe decompressor
Lukundoo <Lukundoo@softhome.net>
for beta testing
Oleg V. Volkov <rover@lglobus.ru>
for various FreeBSD specific informations
The Owl & G-RoM
for the --compress-icons fix
Ralph Roth <RalphRoth@gmx.net>
for reporting several bugs
Salvador Eduardo Tropea
for beta testing
The WINE project (http://www.winehq.com/)
for lots of useful information found in their PE loader sources
DJ Delorie <dj@delorie.com> for djgpp
Linus for Linux
Natascha
Everybody else who was kind enough to spend time testing UPX, use it in
their packages and report bugs, who are too numerous to mention here.
UPX would not be what it is today without your invaluable help.

186
TODO Normal file
View File

@ -0,0 +1,186 @@
- The UCL license is GPL, this will cause problems for the antivirus
programs which can't use the uncompressor because of this. Or am I wrong?
- Rearrange this TODO list, sort by categories, add a priority (1-5)
For 0.95:
- FIXME: what do we want in 1.00 ???
- add NRV2D for dos/exe (use by default when >= 400 kB)
- implement switch `-m' for method: 1 NRV2B, 2 NRV2D
- DLL problem under NT ? is this fixed ???
PE
==
2 - easy - mfx + ml) new switch(es) : do not compress resource types x,y,z
or resource names a,b,c
3 - medium - ml) rebuild exports
3 - difficult) don't compress the BSS section and other holes.
4 - medium - ml) fix when objectalign < 0x1000
4 - easy - ml) put the original offset of moved resources somewhere into
the res.dir. (if it's safe to do)
4 - ??? - ml) fix FIXMEs
5 - medium - ml) try to put the preprocessed imports & relocs back to their
original section if possible this could save some virtual memory
address space
COM
===
EXE
===
LE
==
4 - easy - ml) the decompressors are already aligned, no need for an
extra alignment
4 - difficult - ml) handle holes in the file
TMT
===
4 - easy - ml) the decompressors are already aligned, no need for an
extra alignment
LINUX
=====
4 - ???)
- test with AOUT binaries
- test with Java binaries
- make a compressed program suid. what happens ?
5 - difficult) rewrite the whole stub in assembly
SPARC
=====
3 - easy - ml) finish support - should generate byte-identical versions
for all formats (except those which are using Packer::getRandomId())
DJGPP2
======
1 - ???) do we support overlays at all ???
5 - ???) fix file extension handling when the --coff option is set
FOR 0.95
========
- enable automatic dependency tracking
1 - mfx) determine when to use NRV2D, find best c_flags values for
NRV2B & NRV2D (see util/runtest.sh)
5 - boring - mfx) Finally fix all screen and UI problems. How boring...
Probably should think about the whole system (printf vs. fprintf vs.
con_fprintf...)
5 - policy - ml+mfx) Discuss a default C++ style (GNU indent 2.2.3)
with Laszlo and use it. Or maybe Artistic Style?
10) Examine why pod2text breaks lines within something like `B<--coff>'.
(pod sucks anyway. unfortunately all alternatives as well.)
MISC
====
3 - difficult ml) The first two sentences of the README look too much like
those from the aspack docs. Laszlo, could you rewrite this ?
1 - easy - mfx) Check whether the compressed size of the executable is
really smaller than the uncompressed
1 - ??? - mfx) Implement a more informational interface.
Probably add some global functions in msg.cpp.
Should think about the requirements first, i.e. should there be
some simple hierarchies (header1, header2, ...) etc. ?
Could use the `-v' switch for enabling this (or `-i' ??).
- Something like this would be fine: (with colors :-)
[Processing kernel32.dll]
[Import]
3 DLL.
Original size: 12345 bytes.
Preprocessed size: 6789 bytes.
[Relocations]
Original size: 50000 bytes.
Preprocessed size: 25000 bytes.
[Exports]
<warning> exports compressed (try --compress-export=0 if needed)
[TLS]
Added 56 bytes TLS data.
Added 5 fixup records.
[Resources]
Directory size: 1234 bytes.
Resource data size: 100000 bytes.
Compressed resources: 8 (99900 bytes).
Not compressed resources: 1 (100 bytes).
3 - ???) delete temporary files when something wrong happens
4 - easy - ml) Add a `--486' option to use bswap on the 32-bit formats.
4 - easy - ml) consider removing 'sbb bp,bp' or "or ebp,-1" when not needed
5 - ???) idea: --subfile=xx compress xx. subfile: we'd need a list_subfiles
for this...
FIXME: classify
GOALS FOR 0.90
==============
- Provide additional NRV2D stubs for all 32-bit formats. Try to do this
in a generic way so that we can possibly add more algorithms.
Start by adding a `--nrv2d' switch.
FOR 0.90
========
/ update the output of `--help'
- filters: implement the missing scan() function for f_cto32.
Maybe could use this to try to find an optimal filter (e.g.
if level >= 9) based on the counts.
- filters: could we have use for a f->firstcall info field ?
TODO
====
- all formats: more thoroughly test the exe-header in canPack()
and throw exceptions when encountering bad values.
- experiment with filters
- for small programs (e.g. < 64k) try an additional algorithm (like
the non yet finished NRV2C) to see if it gives better compression ?
/ make checkerg++ work -> test
- fix file extension handling when the --coff option is set
- set up an "official" test suite
- finish documentation

63
doc/Makefile Normal file
View File

@ -0,0 +1,63 @@
SHELL = /bin/sh
top_srcdir = ..
PACKAGE = upx
VERSION_DATE = 10 May 2000
VERSION := $(shell sed -n 's/^.*UPX_VERSION_STRING.*"\(.*\)".*/\1/p' $(top_srcdir)/src/version.h)
TRIMSPACE = cat
TRIMSPACE = sed -e 's/ *$$//'
BUILT_SOURCES = upx.1 upx.doc upx.html upx.man upx.ps upx.tex
###
###
###
all: $(BUILT_SOURCES)
clean:
-rm -f $(BUILT_SOURCES) pod2html*cache
distclean: clean
.SUFFIXES: .1 .doc .html .man .pod .ps .tex .texi
.PHONY: all clean distclean
###
### rules
###
.pod.1:
pod2man --center=" " --release="$(PACKAGE) $(VERSION)" --date="$(VERSION_DATE)" $< | $(TRIMSPACE) > $@
.pod.html:
### pod2html $< | $(TRIMSPACE) > $@
pod2html --noindex $< | $(TRIMSPACE) > $@
@-rm -f pod2html*cache
.pod.tex:
pod2latex $<
.pod.doc:
pod2text < $< | $(TRIMSPACE) > $@
.1.man:
nroff -man $< | $(TRIMSPACE) > $@
.1.ps:
groff -man $< | $(TRIMSPACE) > $@
###
### dependencies
###
$(BUILT_SOURCES): $(top_srcdir)/src/version.h Makefile
.NOEXPORT:

612
doc/upx.pod Normal file
View File

@ -0,0 +1,612 @@
=head1 NAME
upx - compress or expand executable files
=head1 SYNOPSIS
B<upx> S<[ I<command> ]> S<[ I<options> ]> I<filename>...
=head1 ABSTRACT
The Ultimate Packer for eXecutables
Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar
http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
http://www.nexus.hu/upx
http://upx.tsx.org
B<UPX> is a portable, extendable, high-performance executable packer for
several different executable formats. It achieves an excellent compression
ratio and offers I<*very*> fast decompression. Your executables suffer
no memory overhead or other drawbacks for most of the formats supported.
While you may use UPX freely for both non-commercial and commercial
executables (for details see the file LICENSE), we would highly
appreciate if you credit UPX and ourselves in the documentation,
possibly including a reference to the UPX home page. Thanks.
[ Using UPX in non-OpenSource applications without proper credits
is considered not politically correct ;-) ]
=head1 DISCLAIMER
UPX comes with ABSOLUTELY NO WARRANTY; for details see the file LICENSE.
Having said that, we think that UPX is quite stable now. Indeed we
have compressed lots of files without any problems. Also, the
current version has undergone several months of beta testing -
actually it's almost 2 years since our first public beta.
This is the first production quality release, and we plan that future 1.xx
releases will be backward compatible with this version.
Please report all problems or suggestions to the authors. Thanks.
=head1 DESCRIPTION
B<UPX> is a versatile executable packer with the following features:
- excellent compression ratio: compresses better than zip/gzip,
use UPX to decrease the size of your distribution !
- very fast decompression: about 10 MB/sec even on my old Pentium 133
- no memory overhead for your compressed executables for most of the
supported formats
- safe: you can list, test and unpack your executables
Also, a checksum of both the compressed and uncompressed file is
maintained internally.
- universal: UPX can pack a number of executable formats:
* dos/exe
* dos/sys
* dos/com
* djgpp2/coff
* watcom/le (supporting DOS4G, PMODE/W, DOS32a and CauseWay)
* win32/pe
* rtm32/pe
* tmt/adam
* linux/i386
* atari/tos
- portable: UPX is written in portable endian-neutral C++
- extendable: because of the class layout it's very easy to support
new executable formats or add new compression algorithms
- free: UPX can be distributed and used freely. And from version 0.99
the full source code of UPX is released under the GNU General Public
License (GPL) !
You probably understand now why we call UPX the "I<ultimate>"
executable packer.
=head1 COMMANDS
=head2 Compress
This is the default operation, eg. B<upx yourfile.exe> will compress the file
specified on the command line.
=head2 Decompress
All UPX supported file formats can be unpacked using the B<-d> switch, eg.
B<upx -d yourfile.exe> will uncompress the file you've just compressed.
=head2 Test
The B<-t> command tests the integrity of the compressed and uncompressed
data, eg. B<upx -t yourfile.exe> check whether your file can be safely
decompressed. Note, that this command doesn't check the whole file, only
the part that will be uncompressed during program execution. This means
that you should not use this command instead of a virus checker.
=head2 List
The B<-l> command prints out some information about the compressed files
specified on the command line as parameters, eg B<upx -l yourfile.exe>
shows the compressed / uncompressed size and the compression ratio of
I<yourfile.exe>.
=head1 OPTIONS
B<-q>: be quiet, suppress warnings
B<-q -q> (or B<-qq>): be very quiet, suppress errors
B<-q -q -q> (or B<-qqq>): produce no output at all
B<--help>: prints the help
B<--version>: print the version of UPX
B<--stdout>: writes all output to stdout
[ ...to be written... - type `B<upx --help>' for now ]
=head1 COMPRESSION LEVELS & TUNING
B<UPX> offers ten different compression levels from B<-1> to B<-9>,
and B<--best>. The default compression level is B<-7>.
=over 4
=item *
Compression levels 1, 2 and 3 are pretty fast.
=item *
Compression levels 4, 5 and 6 achieve a good time/ratio performance.
=item *
Compression levels 7, 8 and 9 favor compression ratio over speed.
=item *
Compression level B<--best> may take a very long time.
=back
Note that compression level B<-9> can be quite slow for some large
files, but you definitely should use it when releasing a final version
of your program. (E.g. it took about 20 minutes to compress the almost
5 MB MAME 0.34 with B<-9> on my Pentium 133, but the resulting executable
was still ~65 kB smaller than when using B<-7>.)
Since UPX 0.70 there is also an extra compression level B<--best> which
squeezes out even some more compression ratio. While it is usually fine
to use this option with your favorite .com file it may take several hours
to compress a multi-megabyte program. You have been warned.
Tips for even better compression:
=over 4
=item *
Try if B<--overlay=strip> works.
=item *
For win32/pe programs there's B<--strip-relocs=0>. See notes below.
=back
=head1 OVERLAY HANDLING OPTIONS
B<UPX> handles overlays like many other executable packers do: it simply
copies the overlay after the compressed image. This works with some
files, but doesn't work with others.
Since version 0.90 UPX defaults to B<--overlay=copy> for
all executable formats.
--overlay=copy Copy any extra data attached to the file. [DEFAULT]
--overlay=strip Strip any overlay from the program instead of
copying it. Be warned, this may make the compressed
program crash or otherwise unusable.
--overlay=skip Refuse to compress any program which has an overlay.
=head1 ENVIRONMENT
The environment variable B<UPX> can hold a set of default
options for UPX. These options are interpreted first and
can be overwritten by explicit command line parameters.
For example:
for DOS/Windows: set UPX=-9 --compress-icons#1
for sh/ksh/zsh: UPX="-9 --compress-icons=1"; export UPX
for csh/tcsh: setenv UPX "-9 --compress-icons=1"
Under DOS/Windows you must use '#' instead of '=' when setting the
environment variable because of a command.com limitation.
On Vax/VMS, the name of the environment variable is
UPX_OPT, to avoid a conflict with the symbol set for
invocation of the program.
Not all of the options are valid in the environment variable -
UPX will tell you.
You can use the B<--no-env> option to turn this support off.
=head1 NOTES FOR THE SUPPORTED EXECUTABLE FORMATS
=head2 NOTES FOR ATARI/TOS
This is the executable format used by the Atari ST, a 68000 based
personal computer which was popular in the late '80s. Support
of this format is only because of nostalgic feelings of one of
the authors and serves no practical purpose :-).
Packed programs will be byte-identical to the original after uncompression.
All debug information will be stripped, though.
Extra options available for this executable format:
(none)
=head2 NOTES FOR DOS/COM
Obviously UPX won't work with executables that want to read data from
themselves (like some commandline utilities that ship with Win95/98).
Compressed programs only work on a 286+.
Packed programs will be byte-identical to the original after uncompression.
Maximum uncompressed size: ~65100 bytes.
Extra options available for this executable format:
--8086 Create an executable that works on any 8086 CPU.
=head2 NOTES FOR DOS/EXE
dos/exe stands for all "normal" 16-bit DOS executables.
Obviously UPX won't work with executables that want to read data from
themselves (like some command line utilities that ship with Win95/98).
Compressed programs only work on a 286+.
Extra options available for this executable format:
--8086 Create an executable that works on any 8086 CPU.
--no-reloc Use no relocation records in the exe header.
=head2 NOTES FOR DOS/SYS
You can only compress plain sys files, sys/exe (two in one)
combos are not supported.
Compressed programs only work on a 286+.
Packed programs will be byte-identical to the original after uncompression.
Maximum uncompressed size: ~65350 bytes.
Extra options available for this executable format:
--8086 Create an executable that works on any 8086 CPU.
=head2 NOTES FOR DJGPP2/COFF
First of all, it is recommended to use UPX *instead* of B<strip>. strip has
the very bad habit of replacing your stub with its own (outdated) version.
Additionally UPX corrects a bug/feature in strip v2.8.x: it
will fix the 4 KByte aligment of the stub.
UPX includes the full functionality of stubify. This means it will
automatically stubify your COFF files. Use the option B<--coff> to
disable this behaviour (see below).
UPX automatically handles Allegro packfiles.
The DLM format (a rather exotic shared library extension) is not supported.
Packed programs will be byte-identical to the original after uncompression.
All debug information and trailing garbage will be stripped, though.
BTW, UPX is the successor of the DJP executable packer.
Extra options available for this executable format:
--coff Produce COFF output instead of EXE. By default
UPX keeps your current stub.
=head2 NOTES FOR LINUX/i386
How it works:
For ELF executables, UPX decompresses directly to memory, simulating
the mapping that the operating system kernel uses during exec(),
including the PT_INTERP program interpreter (if any).
The brk() is set by a special PT_LOAD segment in the compressed
executable itself. UPX then wipes the stack clean except for
arguments, environment variables, and Elf_auxv entries (this is
required by bugs in the startup code of /lib/ld-linux.so as of
May 2000), and transfers control to the program interpreter or
the e_entry address of the original executable.
For shell script executables (files beginning with "#!/" or "#! /")
where the shell is known to accept "-c <command>", UPX decompresses
the file into low memory, then maps the shell (and its PT_INTERP),
and passes control to the shell with the entire decompressed file
as the argument after "-c". Known shells are sh, ash, bsh, csh,
ksh, tcsh, pdksh. Restriction: UPX 1.10 cannot use this method
for shell scripts which use the one optional string argument after
the shell name in the script (example: "#! /bin/sh option3\n".)
For files which are not ELF and not a script for a known "-c" shell,
UPX uses kernel exec(), which first requires decompressing to a
file in the filesystem. Interestingly -
because of the good memory management of the Linux kernel - this
often does not introduce a noticable delay, and in fact there
will be no disk access at all if you have enough free memory as
the entire process takes places within the filesystem buffers.
A compressed executable consists of the UPX stub and an overlay
which contains the original program in a compressed form.
The UPX stub is a statically linked ELF executable and does
the following at program startup:
1) decompress the overlay to a temporary location in /tmp
2) open the temporary file for reading
3) try to delete the temporary file and start (execve)
the uncompressed program in /tmp using /proc/<pid>/fd/X as
attained by step 2)
4) if that fails, fork off a subprocess to clean up and
start the program in /tmp in the meantime
The UPX stub is about 1700 bytes long, partly written in assembler
and only uses kernel syscalls. It is not linked against any libc.
Benefits:
- UPX can compress all executables, be it AOUT, ELF, libc4, libc5,
libc6, Shell/Perl/Python/... scripts, standalone Java .class
binaries, or whatever...
All scripts and programs will work just as before.
- Compressed programs are completely self-contained. No need for
any external program.
- UPX keeps your original program untouched. This means that
after decompression you will have a byte-identical version,
and you can use UPX as a file compressor just like gzip.
[ Note that UPX maintains a checksum of the file internally,
so it is indeed a reliable alternative. ]
- As the stub only uses syscalls and isn't linked against libc it
should run under any Linux configuration that can run ELF
binaries and has working /proc support.
- For the same reason compressed executables should run under
FreeBSD and other systems which can run Linux binaries.
[ Please send feedback on this topic ]
Drawbacks:
- For non-ELF, non-shell executables, you need additional free disk
space for the uncompressed program
in your /tmp directory. This program is deleted immediately after
decompression, but you still need it for the full execution time
of the program.
- For non-ELF, non-shell executables, you must have /proc filesystem
support as the stub wants to open
/proc/<pid>/exe and needs /proc/<pid>/fd/X. This also means that you
cannot compress programs that are used during the boot sequence
before /proc is mounted, unless those programs are ELF or are
scripts for known "-c" shells.
- `ldd' and `size' won't show anything useful because all they
see is the statically linked stub (since version 0.82 the section
headers are stripped from the UPX stub and `size' doesn't even
recognize the file format any longer - looks like a binutils bug).
- For non-ELF, non-shell executables, utilities like `top' will
display numerical values in the process
name field. This is because Linux computes the process name from
the first argument of the last execve syscall (which is typically
something like /proc/<pid>/fd/3).
- For non-ELF, non-shell executables, to reduce memory requirements
during uncompression UPX splits the
original file into blocks, so the compression ratio is a little bit
worse than with the other executable formats (but still quite nice).
[ Advise from kernel experts which can tell me more about the
execve memory semantics is welcome. Maybe this shortcoming
could be removed. ]
- For non-ELF, non-shell executables, because of temporary decompression
to disk the decompression speed
is not as fast as with the other executable formats. Still, I can see
no noticable delay when starting programs like my ~3 MB emacs (which
is less than 1 MB when compressed :-).
Notes:
- As UPX leaves your original program untouched it is advantageous
to strip it before compression.
- It is not advisable to compress programs which usually have many
instances running (like `make') because the common segments of
compressed programs won't be shared any longer between different
processes.
- If you compress a script you will lose platform independence -
this could be a problem if you are using NFS mounted disks.
- Compression of suid, guid and sticky-bit programs is rejected
because of possible security implications.
- For the same reason there is no sense in making any compressed
program suid.
- Obviously UPX won't work with executables that want to read data
from themselves. E.g., this might be a problem for Perl scripts
which access their __DATA__ lines.
- In case of internal errors the stub will abort with exitcode 127.
Typical reasons for this to happen are that the program has somehow
been modified after compression, you have run out of disk space
or your /proc filesystem is not yet mounted.
Running `strace -o strace.log compressed_exe' will tell you more.
Extra options available for this executable format:
(none)
=head2 NOTES FOR RTM32/PE
Same as win32/pe.
=head2 NOTES FOR TMT/ADAM
This format is used by the TMT Pascal compiler - see http://www.tmt.com/ .
Extra options available for this executable format:
(none)
=head2 NOTES FOR WATCOM/LE
UPX has been successfully tested with the following extenders:
DOS4G, DOS4GW, PMODE/W, DOS32a, CauseWay.
The WDOS/X extender is partly supported (for details
see the file bugs BUGS).
Yes, you can use your compressed executables with DOS4GW.
The LX format is not yet supported.
DLLs are not supported.
Extra options available for this executable format:
--le Produce an unbound LE output instead of
keeping the current stub.
=head2 NOTES FOR WIN32/PE
The PE support in UPX is quite stable now, but definitely there are
still some incompabilities with some files.
Because of the way UPX (and other packers for this format) works, you
can see increased memory usage of your compressed files. If you start
several instances of huge compressed programs you're wasting memory
because the common segements of the program won't get shared
across the instances.
On the other hand if you're compressing only smaller programs, or
running only one instance of larger programs, then this penalty is
smaller, but it's still there.
If you're running executables from network, then compressed programs
will load faster, and require less bandwidth during execution.
DLLs are supported.
Extra options available for this executable format:
--compress-exports=0 Don't compress the export section.
Use this if you plan to run the compressed
program under Wine.
--compress-exports=1 Compress the export section. [DEFAULT]
Compression of the export section can improve the
compression ratio quite a bit but may not work
with all programs (like winword.exe).
UPX never compresses the export section of a DLL
regardless of this option.
--compress-icons=0 Don't compress any icons.
--compress-icons=1 Compress all but the first icon.
--compress-icons=2 Compress all icons which are not in the
first icon directory. [DEFAULT]
--compress-resources=0 Don't compress any resources at all.
--force Force compression even when there is an
unexpected value in a header field.
Use with care.
--strip-relocs=0 Don't strip relocation records.
--strip-relocs=1 Strip relocation records. [DEFAULT]
This option only works on executables with base
address greater or equal to 0x400000. Usually the
compressed files becomes smaller, but some files
may become larger. Note that the resulting file will
not work under Win32s.
UPX never strips relocations from a DLL
regardless of this option.
=head1 DIAGNOSTICS
Exit status is normally 0; if an error occurs, exit status
is 1. If a warning occurs, exit status is 2.
B<UPX>'s diagnostics are intended to be self-explanatory.
=head1 BUGS
Please report all bugs immediately to the authors.
=head1 AUTHORS
Markus F.X.J. Oberhumer <markus.oberhumer@jk.uni-linz.ac.at>
http://wildsau.idv.uni-linz.ac.at/mfx/upx.html
Laszlo Molnar <ml1050@cdata.tvnet.hu>
http://www.nexus.hu/upx
=head1 COPYRIGHT
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
This program may be used freely, and you are welcome to
redistribute it under certain conditions.
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
UPX License Agreement for more details.
You should have received a copy of the UPX License Agreement along
with this program; see the file LICENSE. If not, visit the UPX home page.

476
src/Makefile Normal file
View File

@ -0,0 +1,476 @@
# UPX Makefile (GNU make) - works with djgpp2/win32/unix
#
# usage:
# `make target=linux' # linux
# `make target=djggp2' # djggp2
# `make target=mingw32' # mingw32
# `make target=no-cygwin' # mingw32 as of cygwin b20.1
# `make target=msc' # Visual C++ 6.0
#
# configuration section
ifeq ($(strip $(UCLDIR)),)
# change this to reflect where the UCL library is
UCLDIR = $(HOME)/local/src/ucl-0.90
endif
DEBUG = 1
# -------------------------------------------------------
# You should not have to change anything below this line.
# -------------------------------------------------------
SHELL = /bin/sh
.SUFFIXES:
.SUFFIXES: .a .c .cpp .exe .lib .o .obj
srcdir = .
top_srcdir = ..
# auto-detect the target unless given on the commandline
target = djgpp2
ifneq ($(strip $(wildcard /usr/include/linux)),)
target = linux
endif
ifneq ($(strip $(wildcard /platform/sun4?/kernel/unix)),)
target = sparc
endif
# /***********************************************************************
# // object files
# ************************************************************************/
# these use exceptions & RTTI
OBJECTS1 = \
compress$o except$o file$o lefile$o \
filter$o mem$o msg$o stdcxx$o work$o ui$o \
packer$o packhead$o packmast$o \
p_com$o p_djgpp2$o p_exe$o p_lx_elf$o p_lx_sep$o p_lx_sh$o \
p_sys$o p_tmt$o p_tos$o \
p_unix$o p_vmlinux$o p_w32pe$o p_wcle$o
# no exceptions or RTTI
OBJECTS2 = \
filteri$o help$o main$o mygetopt$o util$o linker$o \
c_init$o c_file$o c_none$o c_screen$o \
s_object$o s_djgpp2$o s_vcsa$o s_win32$o
# pure C sources
OBJECTS3 =
OBJECTS = $(OBJECTS1) $(OBJECTS2) $(OBJECTS3)
# /***********************************************************************
# // compiler settings
# ************************************************************************/
# default to a unix-type compiler
CC = gcc
CXX = $(CC)
DEFS =
INCLUDES = -I$(srcdir)
CFLAGS_OUTPUT = -o $@
CXXFLAGS_OUTPUT = $(CFLAGS_OUTPUT)
LINK_EXE = $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
STUBEDIT_EXE =
o = .o
a = .a
e = .exe
###
### gcc defaults
###
##CFLAGS_O = -Os
CFLAGS_O = -O2
##CFLAGS_WERROR = -Werror
CFLAGS_W = $(CFLAGS_WERROR)
CFLAGS_W += -Wall -W -Wcast-align -Wcast-qual -Wmissing-declarations -Wmissing-prototypes -Wshadow -Wwrite-strings
##CFLAGS_M = -fno-builtin
## CFLAGS_M += -malign-functions=0 -malign-jumps=0 -malign-loops=0
CFLAGS = $(CFLAGS_W) $(CFLAGS_O) $(CFLAGS_M)
CXXFLAGS = $(CFLAGS) -Wsynth -fconserve-space
CXXFLAGS1 = $(CXXFLAGS)
CXXFLAGS2 = $(CXXFLAGS) -fno-exceptions -fno-rtti
ifeq ($(DEBUG),1)
DEFS += -DDEBUG
## DEFS += -DTESTING
endif
ifeq ($(DEBUG),1)
LDFLAGS = -g
else
LDFLAGS = -s
endif
LDFLAGS += -Wl,-Map,$(basename $@).map
LDLIBS = -lz
LIBDIRS =
###
### compression library
###
UCLDIR:=$(strip $(subst \,/,$(UCLDIR)))
NRVDIR:=$(strip $(subst \,/,$(NRVDIR)))
ifeq ($(strip $(wildcard $(NRVDIR)/include/nrv)),)
u = ucl
U = UCL
upx_exe = upx$e
else
u = nrv
U = NRV
upx_exe = upx_$u$e
endif
UDIR := $($(U)DIR)
DEFS += -DWITH_$(U)
ifneq ($(strip $(wildcard $(UDIR)/include)),)
INCLUDES += -I$(UDIR)/include
endif
ifneq ($(strip $(wildcard $(UDIR)/src/.libs)),)
LIBDIRS += $(UDIR)/src/.libs
endif
ifeq ($(DEBUG),1)
ifneq ($(strip $(wildcard $(UDIR)/build/debug/src/.libs)),)
LIBDIRS += $(UDIR)/build/debug/src/.libs
endif
endif
ifneq ($(strip $(wildcard $(UDIR)/build/release/src/.libs)),)
LIBDIRS += $(UDIR)/build/release/src/.libs
endif
ifneq ($(strip $(wildcard $(UDIR)/build/src/.libs)),)
LIBDIRS += $(UDIR)/build/src/.libs
endif
ifneq ($(strip $(wildcard $(UDIR))),)
LIBDIRS += $(UDIR)
endif
tmp := -Wl,--rpath,
LDRPATH := $(addprefix $(tmp),$(LIBDIRS))
LIBDIRS += .
LDLIBDIRS := $(addprefix -L,$(LIBDIRS))
##LDFLAGS += $(LDRPATH)
LDFLAGS += $(LDLIBDIRS)
LDLIBS += -l$(u)
###
### linux
###
ifeq ($(target),linux)
e =
DEFS += '-DUPX_CONFIG_H="config_h/linux.h"'
CFLAGS_M += -mno-schedule-prologue
CFLAGS_M += -march=i386 -mcpu=pentium
CFLAGS_WERROR = -Werror
LDLIBS += -lmcheck
ifeq (1,2) # checkergcc
CC = checkergcc
CXX = checkerg++
else
ifeq ($(DEBUG),1)
##CFLAGS += -O0 -gstabs+3
CFLAGS += -O0 -gstabs+3
else
##LDFLAGS += -static
STUBEDIT_EXE = objcopy -S -R .comment -R .note $@ && perl $(srcdir)/stub/scripts/brandelf.pl $@ && chmod 755 $@
endif
endif
endif # linux
###
### djgpp2
###
ifeq ($(target),djgpp2)
CFLAGS_M += -mno-schedule-prologue
CFLAGS_M += -march=i386 -mcpu=pentium
CFLAGS_WERROR = -Werror
STUBEDIT_EXE = stubedit $@ bufsize=0xfc00
endif # djgpp2
###
### cygwin / mingw32
###
ifeq ($(target),cygwin)
CFLAGS_M += -mno-schedule-prologue
CFLAGS_M += -march=i386 -mcpu=pentium
endif
ifeq ($(target),mingw32)
CFLAGS_M += -mno-schedule-prologue
CFLAGS_M += -march=i386 -mcpu=pentium
endif
# mingw32 as included in cygwin b20.1
ifeq ($(target),no-cygwin)
CC = gcc -mno-cygwin
CFLAGS_M += -mno-schedule-prologue
CFLAGS_M += -march=i386 -mcpu=pentium
endif
###
### Microsoft 32-bit C/C++ Compiler 12.00 (aka Visual C++ 6)
###
ifeq ($(target),msc)
o = .obj
a = .lib
CC = cl -nologo
CFLAGS = -W4
CXXFLAGS1 = $(CFLAGS) -GX -GR
CXXFLAGS2 = $(CFLAGS)
LDFLAGS =
LINK_LDFLAGS = /link /map:$(basename $@).map
ifneq ($(strip $(wildcard $(UDIR))),)
LIB := $(UDIR);$(LIB)
endif
export LIB
ifeq (1,2)
# statically link libc
CC += -ML
LDLIBS = $(u)_s.lib zlib_s.lib setargv.obj
else
# link against msvcrt.dll
CC += -MD
LDLIBS = $(u).lib zlib.lib setargv.obj
endif
ifeq ($(DEBUG),1)
CFLAGS += -Od -ZI
LINK_LDFLAGS += /debug
else
CFLAGS += -O2 -Gs -GF
LINK_LDFLAGS += /release
endif
##LINK_LDFLAGS += /verbose
LINK_EXE = $(CC) $(LDFLAGS) -Fe$@ $^ $(LDLIBS) $(LINK_LDFLAGS)
endif # msc
###
### sparc
###
ifeq ($(target),sparc)
e =
DEFS += '-DUPX_CONFIG_H="config_h/sparc.h"'
INCLUDES += -I/home/ethmola/local/include
ifeq (1,2) # native compiler
CFLAGS = -O0 -g
CXXFLAGS1 =
CXXFLAGS2 =
CFLAGS_M =
DEFS += -DUSE_STDNAMESPACE
else # gcc
CFLAGS += -O0 -gstabs+
endif
ifeq (1,2) # purify
DEFS += -D__PURIFY__
LDFLAGS = -g -L/home/ethmola/local/lib
LINK_EXE = purify $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
else
LDFLAGS += -g -L/home/ethmola/local/lib
LINK_EXE = $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
endif
endif # sparc
###
### Borland C++ 5.5 (DOES NOT WORK - INCOMPLETE C++ IMPLEMENTATION)
###
ifeq ($(target),bcc)
o = .obj
a = .lib
CC = bcc32
CFLAGS = -w -w-par
CXXFLAGS1 = $(CFLAGS)
CXXFLAGS2 = $(CFLAGS)
CFLAGS_OUTPUT = -o$@
LDFLAGS =
LDLIBS = $(u).lib zlib.lib
ifneq ($(strip $(wildcard $(UDIR))),)
LIB := $(UDIR);$(LIB)
endif
export LIB
ifeq ($(DEBUG),1)
CFLAGS +=
else
CFLAGS += -O2
endif
LINK_EXE = $(CC) $(LDFLAGS) -e$@ $^ $(LDLIBS)
endif # bcc
###
### malloc debuggers (Linux only)
###
ifeq (1,2)
LDLIBS += -lefence
endif
ifeq (1,2)
CFLAGS += -DWITH_DMALLOC
LDLIBS += -ldmalloc
endif
ifeq (1,2)
CFLAGS += -DWITH_GC -DLINUX_THREADS -D_REENTRANT
LDLIBS += -lgc -lpthread
# only needed when using -static:
##LDFLAGS += -Wl,-defsym,_DYNAMIC=0
endif
ifeq (1,2)
CFLAGS += -DWITH_MSS
LDLIBS += -lmss
endif
# /***********************************************************************
# // main targets
# ************************************************************************/
all: $(upx_exe)
.PHONY: all unupx mostlyclean clean distclean maintainer-clean untabify tags
$(upx_exe): $(OBJECTS) $(LIBS)
$(LINK_EXE)
$(STUBEDIT_EXE)
unupx:
$(MAKE) target=msc unupx.dll
unupx.dll: $(OBJECTS) $(LIBS)
$(LINK_DLL)
mostlyclean:
-rm -f *.d *.err *.i *.log *.map *~ gdb-trans*
clean: mostlyclean
-rm -f *.a *.lib *.o *.obj tags TAGS ID
-rm -f upx upx.exe upx_nrv upx_nrv.exe upx_ucl upx_ucl.exe
distclean: clean
maintainer-clean: distclean
untabify:
mfxtu -d4 -t *.h *.cpp *.ch
mfxtu -d8 -t stub/[ln]*.asm stub/*.ash stub/*.[cs]
tags TAGS:
ctags *.h *.cpp *.ch
ID:
mkid *.h *.cpp *.ch
# /***********************************************************************
# // rules
# ************************************************************************/
.c$o:
$(CC) $(DEFS) $(INCLUDES) $(CFLAGS) $(CFLAGS_OUTPUT) -c $<
.cpp$o:
$(CXX) $(DEFS) $(INCLUDES) $(CXXFLAGS1) $(CXXFLAGS_OUTPUT) -c $<
$(OBJECTS1): %$o : %.cpp
$(CXX) $(DEFS) $(INCLUDES) $(CXXFLAGS1) $(CXXFLAGS_OUTPUT) -c $<
$(OBJECTS2): %$o : %.cpp
$(CXX) $(DEFS) $(INCLUDES) $(CXXFLAGS2) $(CXXFLAGS_OUTPUT) -c $<
ifneq ($(strip $(OBJECTS3)),)
$(OBJECTS3): %$o : %.c
$(CC) $(DEFS) $(INCLUDES) $(CFLAGS) $(CFLAGS_OUTPUT) -c $<
endif
# /***********************************************************************
# // dependencies
# ************************************************************************/
# FIXME: use automated dependencies
main$o: mygetopt.h version.h
filter$o: filter.h
filteri$o: filter.h fcto_ml.ch fcto_ml2.ch
help$o: version.h
msg$o: ui.h
lefile$o: lefile.h
linker$o: linker.h
mygetopt$o: mygetopt.h
packer$o: packer.h filter.h linker.h ui.h version.h
packhead$o: packer.h
packmast$o: packmast.h packer.h lefile.h \
p_com.h p_djgpp2.h p_exe.h p_lx_elf.h p_lx_sep.h p_lx_sh.h \
p_sys.h p_tmt.h p_tos.h \
p_unix.h p_vxd.h p_w32pe.h p_wcle.h
ui$o: packer.h ui.h
work$o: packer.h ui.h packmast.h
p_com$o: packer.h p_com.h stub/l_com.h
p_djgpp2$o: packer.h p_djgpp2.h stub/stubify.h \
stub/l_djgpp2.h
p_exe$o: packer.h p_exe.h stub/l_exe.h
p_lx_elf$o: packer.h p_lx_elf.h p_unix.h p_elf.h \
stub/l_le_n2b.h stub/l_le_n2d.h
p_lx_sep$o: packer.h p_lx_sep.h
p_lx_sh$o: packer.h p_lx_elf.h p_unix.h p_elf.h \
stub/l_sh_n2b.h stub/l_sh_n2d.h
p_sys$o: packer.h p_sys.h p_com.h stub/l_sys.h
p_tmt$o: packer.h p_tmt.h \
stub/l_tmt.h
p_tos$o: packer.h p_tos.h \
stub/l_t_n2b.h stub/l_t_n2bs.h \
stub/l_t_n2d.h stub/l_t_n2ds.h
p_unix$o: packer.h p_unix.h p_elf.h \
stub/l_lx_n2b.h stub/l_lx_n2d.h
p_vmlinux$o: packer.h p_unix.h p_elf.h \
stub/l_lx_n2b.h stub/l_lx_n2d.h
p_w32pe$o: packer.h p_w32pe.h \
stub/l_w32pe.h
p_wcle$o: packer.h p_wcle.h lefile.h \
stub/l_wcle.h
# vi:nowrap

261
src/bele.h Normal file
View File

@ -0,0 +1,261 @@
/* bele.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_BELE_H
#define __UPX_BELE_H
/*************************************************************************
// access memory in BigEndian and LittleEndian byte order
**************************************************************************/
inline unsigned short get_be16(const void * bb, int off=0)
{
const upx_bytep b = reinterpret_cast<const upx_bytep>(bb) + off;
unsigned v;
v = (unsigned) b[1] << 0;
v |= (unsigned) b[0] << 8;
return (unsigned short) v;
}
inline void set_be16(void * bb, unsigned v, int off=0)
{
upx_bytep b = reinterpret_cast<upx_bytep>(bb) + off;
b[1] = (unsigned char) (v >> 0);
b[0] = (unsigned char) (v >> 8);
}
inline unsigned get_be32(const void * bb, int off=0)
{
const upx_bytep b = reinterpret_cast<const upx_bytep>(bb) + off;
unsigned v;
v = (unsigned) b[3] << 0;
v |= (unsigned) b[2] << 8;
v |= (unsigned) b[1] << 16;
v |= (unsigned) b[0] << 24;
return v;
}
inline void set_be32(void * bb, unsigned v, int off=0)
{
upx_bytep b = reinterpret_cast<upx_bytep>(bb) + off;
b[3] = (unsigned char) (v >> 0);
b[2] = (unsigned char) (v >> 8);
b[1] = (unsigned char) (v >> 16);
b[0] = (unsigned char) (v >> 24);
}
inline unsigned short get_le16(const void * bb, int off=0)
{
const upx_bytep b = reinterpret_cast<const upx_bytep>(bb) + off;
unsigned v;
#if defined(__i386__)
v = * (const unsigned short *) b;
#else
v = (unsigned) b[0] << 0;
v |= (unsigned) b[1] << 8;
#endif
return (unsigned short) v;
}
inline void set_le16(void * bb, unsigned v, int off=0)
{
upx_bytep b = reinterpret_cast<upx_bytep>(bb) + off;
#if defined(__i386__)
(* (unsigned short *) b) = (unsigned short) v;
#else
b[0] = (unsigned char) (v >> 0);
b[1] = (unsigned char) (v >> 8);
#endif
}
inline unsigned get_le24(const void * bb, int off=0)
{
const upx_bytep b = reinterpret_cast<const upx_bytep>(bb) + off;
unsigned v;
v = (unsigned) b[0] << 0;
v |= (unsigned) b[1] << 8;
v |= (unsigned) b[2] << 16;
return v;
}
inline void set_le24(void * bb, unsigned v, int off=0)
{
upx_bytep b = reinterpret_cast<upx_bytep>(bb) + off;
b[0] = (unsigned char) (v >> 0);
b[1] = (unsigned char) (v >> 8);
b[2] = (unsigned char) (v >> 16);
}
inline unsigned get_le32(const void * bb, int off=0)
{
const upx_bytep b = reinterpret_cast<const upx_bytep>(bb) + off;
unsigned v;
#if defined(__i386__)
v = * (const unsigned *) b;
#else
v = (unsigned) b[0] << 0;
v |= (unsigned) b[1] << 8;
v |= (unsigned) b[2] << 16;
v |= (unsigned) b[3] << 24;
#endif
return v;
}
inline void set_le32(void * bb, unsigned v, int off=0)
{
upx_bytep b = reinterpret_cast<upx_bytep>(bb) + off;
#if defined(__i386__)
(* (unsigned *) b) = v;
#else
b[0] = (unsigned char) (v >> 0);
b[1] = (unsigned char) (v >> 8);
b[2] = (unsigned char) (v >> 16);
b[3] = (unsigned char) (v >> 24);
#endif
}
/*************************************************************************
// classes for portable unaligned access
**************************************************************************/
class BE16
{
unsigned char d[2];
public:
BE16& operator = (const BE16 &v) { memcpy(d, v.d, sizeof(d)); return *this; }
BE16& operator = (unsigned v) { set_be16(d, v); return *this; }
BE16& operator += (unsigned v) { set_be16(d, get_be16(d) + v); return *this; }
BE16& operator -= (unsigned v) { set_be16(d, get_be16(d) - v); return *this; }
BE16& operator &= (unsigned v) { set_be16(d, get_be16(d) & v); return *this; }
BE16& operator |= (unsigned v) { set_be16(d, get_be16(d) | v); return *this; }
operator const unsigned () const { return get_be16(d); }
};
class BE32
{
unsigned char d[4];
public:
BE32& operator = (const BE32 &v) { memcpy(d, v.d, sizeof(d)); return *this; }
BE32& operator = (unsigned v) { set_be32(d, v); return *this; }
BE32& operator += (unsigned v) { set_be32(d, get_be32(d) + v); return *this; }
BE32& operator -= (unsigned v) { set_be32(d, get_be32(d) - v); return *this; }
BE32& operator &= (unsigned v) { set_be32(d, get_be32(d) & v); return *this; }
BE32& operator |= (unsigned v) { set_be32(d, get_be32(d) | v); return *this; }
operator const unsigned () const { return get_be32(d); }
};
class LE16
{
unsigned char d[2];
public:
LE16& operator = (const LE16 &v) { memcpy(d, v.d, sizeof(d)); return *this; }
LE16& operator = (unsigned v) { set_le16(d, v); return *this; }
LE16& operator += (unsigned v) { set_le16(d, get_le16(d) + v); return *this; }
LE16& operator -= (unsigned v) { set_le16(d, get_le16(d) - v); return *this; }
LE16& operator &= (unsigned v) { set_le16(d, get_le16(d) & v); return *this; }
LE16& operator |= (unsigned v) { set_le16(d, get_le16(d) | v); return *this; }
operator const unsigned () const { return get_le16(d); }
};
class LE32
{
unsigned char d[4];
public:
LE32& operator = (const LE32 &v) { memcpy(d, v.d, sizeof(d)); return *this; }
LE32& operator = (unsigned v) { set_le32(d, v); return *this; }
LE32& operator += (unsigned v) { set_le32(d, get_le32(d) + v); return *this; }
LE32& operator -= (unsigned v) { set_le32(d, get_le32(d) - v); return *this; }
LE32& operator &= (unsigned v) { set_le32(d, get_le32(d) & v); return *this; }
LE32& operator |= (unsigned v) { set_le32(d, get_le32(d) | v); return *this; }
operator const unsigned () const { return get_le32(d); }
};
/*************************************************************************
// global operators
**************************************************************************/
inline bool operator < (const BE16& v1, const BE16& v2)
{
return (const unsigned)v1 < (const unsigned)v2;
}
inline bool operator < (const BE32& v1, const BE32& v2)
{
return (const unsigned)v1 < (const unsigned)v2;
}
inline bool operator < (const LE16& v1, const LE16& v2)
{
return (const unsigned)v1 < (const unsigned)v2;
}
inline bool operator < (const LE32& v1, const LE32& v2)
{
return (const unsigned)v1 < (const unsigned)v2;
}
/*************************************************************************
// misc
**************************************************************************/
// for use with qsort()
int be16_compare(const void *e1, const void *e2);
int be32_compare(const void *e1, const void *e2);
int le16_compare(const void *e1, const void *e2);
int le32_compare(const void *e1, const void *e2);
#endif /* already included */
/*
vi:ts=4:et:nowrap
*/

95
src/c_file.cpp Normal file
View File

@ -0,0 +1,95 @@
/* c_file.cpp -- file console output
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#if defined(USE_CONSOLE)
/*************************************************************************
//
**************************************************************************/
static int init(FILE *f, int o, int now)
{
UNUSED(f);
UNUSED(o);
UNUSED(now);
return CON_FILE;
}
static int set_fg(FILE *f, int fg)
{
UNUSED(f);
UNUSED(fg);
return -1;
}
static void print0(FILE *f, const char *s)
{
#if 1
fputs(s,f);
#else
/* filter out all ANSI sequences */
int c;
while ((c = *s++) != 0)
{
if (c == '\033' && *s == ']')
{
while (*s && *s != 'm')
s++;
}
else
fputc(c,f);
}
#endif
}
static upx_bool intro(FILE *f)
{
UNUSED(f);
return 0;
}
console_t console_file =
{
init,
set_fg,
print0,
intro
};
#endif /* USE_CONSOLE */
/*
vi:ts=4:et
*/

165
src/c_init.cpp Normal file
View File

@ -0,0 +1,165 @@
/* c_init.cpp -- console initialization
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
FILE *con_term = NULL;
#if defined(USE_CONSOLE)
/*************************************************************************
//
**************************************************************************/
static console_t * const me = &console_init;
console_t * con = &console_init;
int con_mode = CON_INIT;
static void try_init(console_t *c, FILE *f)
{
int k;
assert(c);
assert(c->init);
k = c->init(f,opt->console,con_mode);
if (k == CON_INIT)
return;
#if 0
if (con_mode != CON_INIT && opt->console != CON_INIT)
if (k != opt->console)
return;
#endif
if (k > con_mode)
{
con_mode = k;
con = c;
con->init = 0;
if (!con->set_fg)
con->set_fg = console_none.set_fg;
if (!con->print0)
con->print0 = console_none.print0;
if (!con->intro)
con->intro = console_none.intro;
}
}
static int do_init(FILE *f)
{
assert(con_mode == CON_INIT);
try_init(&console_none,f);
assert(con != me);
assert(con == &console_none);
if (opt->console == CON_NONE || opt->to_stdout)
return con_mode;
try_init(&console_file,f);
if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO))
return con_mode;
#if defined(USE_ANSI)
try_init(&console_ansi_mono,f);
try_init(&console_ansi_color,f);
#endif
#if defined(USE_SCREEN)
try_init(&console_screen,f);
#endif
#if defined(USE_AALIB)
try_init(&console_aalib,f);
#endif
return con_mode;
}
/*************************************************************************
//
**************************************************************************/
static int init(FILE *f, int o, int now)
{
if (con != me)
return con_mode;
assert(o == -1);
assert(now == -1);
UNUSED(o);
UNUSED(now);
return do_init(f);
}
static int set_fg(FILE *f, int fg)
{
if (con == me)
init(f,-1,-1);
assert(con != me);
return con->set_fg(f,fg);
}
static upx_bool intro(FILE *f)
{
if (con == me)
init(f,-1,-1);
assert(con != me);
return con->intro(f);
}
console_t console_init =
{
init,
set_fg,
0,
intro
};
void con_fprintf(FILE *f, const char *format, ...)
{
va_list args;
char buf[80*25];
va_start(args,format);
upx_vsnprintf(buf,sizeof(buf),format,args);
va_end(args);
if (con == me)
init(f,-1,-1);
assert(con != me);
con->print0(f,buf);
}
#endif /* USE_CONSOLE */
/*
vi:ts=4:et
*/

81
src/c_none.cpp Normal file
View File

@ -0,0 +1,81 @@
/* c_none.cpp -- dummy console output
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#if defined(USE_CONSOLE)
/*************************************************************************
//
**************************************************************************/
static int init(FILE *f, int o, int now)
{
UNUSED(f);
UNUSED(o);
UNUSED(now);
return CON_NONE;
}
static int set_fg(FILE *f, int fg)
{
UNUSED(f);
UNUSED(fg);
return -1;
}
static void print0(FILE *f, const char *s)
{
UNUSED(f);
UNUSED(s);
}
static upx_bool intro(FILE *f)
{
UNUSED(f);
return 0;
}
console_t console_none =
{
init,
set_fg,
print0,
intro
};
#endif /* USE_CONSOLE */
/*
vi:ts=4:et
*/

286
src/c_screen.cpp Normal file
View File

@ -0,0 +1,286 @@
/* c_screen.cpp -- screen driver console output
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#if defined(USE_SCREEN)
#include "screen.h"
#define mask_fg 0x0f
#define mask_bg 0xf0
/*************************************************************************
//
**************************************************************************/
static screen_t *do_construct(screen_t *s, int fd)
{
if (!s)
return NULL;
if (s->init(s,fd) != 0)
{
s->destroy(s);
return NULL;
}
return s;
}
static screen_t *screen = NULL;
static void do_destroy(void)
{
if (screen)
{
screen->destroy(screen);
screen = NULL;
}
}
static int mode = -1;
static int init_fg = -1;
static int init_bg = -1;
static int cur_fg = -1;
static int cur_bg = -1;
static int init(FILE *f, int o, int now)
{
int fd = fileno(f);
int n = CON_INIT;
UNUSED(now);
assert(screen == NULL);
atexit(do_destroy);
#if defined(__DJGPP__)
if (!screen)
screen = do_construct(screen_djgpp2_construct(),fd);
#endif
#if defined(__MFX_WIN32)
if (!screen)
screen = do_construct(screen_win32_construct(),fd);
#endif
#if defined(USE_SCREEN_VCSA)
if (!screen)
screen = do_construct(screen_vcsa_construct(),fd);
#endif
#if defined(USE_SCREEN_CURSES)
if (!screen && o == CON_SCREEN)
screen = do_construct(screen_curses_construct(),fd);
#endif
if (!screen)
return CON_INIT;
mode = screen->getMode(screen);
init_fg = cur_fg = screen->getFg(screen);
init_bg = cur_bg = screen->getBg(screen);
if (screen->isMono(screen))
cur_fg = -1;
if (screen->getCols(screen) < 80 || screen->getCols(screen) > 256)
return CON_INIT;
if (screen->getRows(screen) < 24)
return CON_INIT;
if (cur_fg == (cur_bg >> 4))
return CON_INIT;
if (cur_bg != BG_BLACK)
if (!screen->isMono(screen))
{
/* return CON_ANSI_MONO; */ /* we could emulate ANSI mono */
return CON_INIT;
}
if (o == CON_SCREEN)
n = CON_SCREEN;
if (o == CON_INIT) /* use by default */
n = CON_SCREEN;
if (o == CON_ANSI_COLOR) /* can emulate ANSI color */
n = CON_ANSI_COLOR;
if (o == CON_ANSI_MONO) /* can emulate ANSI mono */
n = CON_ANSI_MONO;
if (screen->atExit)
atexit(screen->atExit);
return n;
}
static int set_fg(FILE *f, int fg)
{
const int last_fg = cur_fg;
int f1 = fg & mask_fg;
int f2 = init_fg & mask_fg;
UNUSED(f);
cur_fg = fg;
if (screen->isMono(screen))
{
const int b = (init_bg & mask_bg) >> 4;
if (fg == -1) /* restore startup fg */
f1 = f2;
else if (b == 0)
f1 = (f2 <= 8) ? 15 : 8;
else if (b <= 8)
f1 = (f2 == 0) ? 15 : 0;
else
f1 = (f2 == 0) ? 8 : 0;
}
else if (con_mode == CON_ANSI_MONO && f1 != f2)
{
f1 = f2 ^ 0x08;
}
screen->setFg(screen,f1 & mask_fg);
return last_fg;
}
static void print0(FILE *f, const char *ss)
{
int cx, cy;
int c_cx, c_cy;
char p[256+1];
int pi = 0, px = -1, py = -1;
const int sx = screen->getCols(screen);
const int sy = screen->getRows(screen);
int pass;
// Note:
// We use 2 passes to avoid unnecessary system calls because
// scrollScreen() under Win32 is *extremely* slow.
UNUSED(f);
screen->getCursor(screen,&cx,&cy);
c_cx = cx; c_cy = cy;
for (pass = 0; pass < 2; pass++)
{
const char *s = ss;
int scroll_y = 0;
while (*s)
{
for ( ; *s; s++)
{
if (*s == '\n')
{
c_cy++;
c_cx = 0;
}
else if (*s == '\r')
{
c_cx = 0;
#if 1
if (pass > 0 && c_cy < sy)
screen->clearLine(screen,c_cy);
#endif
}
else
break;
}
if (c_cx >= sx)
{
c_cy++;
c_cx = 0;
}
if (pass > 0 && pi > 0 && py != c_cy)
{
screen->putString(screen,p,px,py);
pi = 0;
}
if (c_cy >= sy)
{
int l = c_cy - sy + 1;
if (pass > 0)
c_cy -= screen->scrollUp(screen,l);
else
{
scroll_y += l;
c_cy -= l;
}
if (c_cy < 0)
c_cy = 0;
c_cx = 0;
}
if (*s)
{
if (pass > 0)
{
if (pi == 0)
px = c_cx, py = c_cy;
p[pi++] = *s;
p[pi] = 0;
}
c_cx++;
s++;
}
}
if (pass == 0)
{
c_cx = cx;
if (scroll_y > 0)
{
c_cy -= screen->scrollUp(screen,scroll_y);
if (c_cy < 0)
c_cy = 0;
}
else
c_cy = cy;
}
}
if (pi > 0)
screen->putString(screen,p,px,py);
screen->setCursor(screen,c_cx,c_cy);
screen->refresh(screen);
}
static upx_bool intro(FILE *f)
{
UNUSED(f);
#if defined(USE_FRAMES)
if (screen->intro)
return screen->intro(screen,screen_show_frames);
#endif
return 0;
}
console_t console_screen =
{
init,
set_fg,
print0,
intro
};
#endif /* USE_SCREEN */
/*
vi:ts=4:et
*/

269
src/compress.cpp Normal file
View File

@ -0,0 +1,269 @@
/* compress.cpp -- interface to the compression library
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#if defined(WITH_UCL) && !defined(WITH_NRV)
# define nrv2b_99_compress_internal ucl_nrv2b_99_compress
# define nrv2d_99_compress_internal ucl_nrv2d_99_compress
# if 0 && defined(__i386__)
# include <ucl/ucl_asm.h>
# define nrv2b_decompress_safe_8 ucl_nrv2b_decompress_asm_safe_8
# define nrv2b_decompress_safe_le16 ucl_nrv2b_decompress_asm_safe_le16
# define nrv2b_decompress_safe_le32 ucl_nrv2b_decompress_asm_safe_le32
# define nrv2d_decompress_safe_8 ucl_nrv2d_decompress_asm_safe_8
# define nrv2d_decompress_safe_le16 ucl_nrv2d_decompress_asm_safe_le16
# define nrv2d_decompress_safe_le32 ucl_nrv2d_decompress_asm_safe_le32
# else
# define nrv2b_decompress_safe_8 ucl_nrv2b_decompress_safe_8
# define nrv2b_decompress_safe_le16 ucl_nrv2b_decompress_safe_le16
# define nrv2b_decompress_safe_le32 ucl_nrv2b_decompress_safe_le32
# define nrv2d_decompress_safe_8 ucl_nrv2d_decompress_safe_8
# define nrv2d_decompress_safe_le16 ucl_nrv2d_decompress_safe_le16
# define nrv2d_decompress_safe_le32 ucl_nrv2d_decompress_safe_le32
# endif
#endif
#if defined(WITH_NRV)
# include <nrv/nrv2b.h>
# include <nrv/nrv2d.h>
# if !defined(NRV_VERSION) || (NRV_VERSION < 0x007300L)
# error
# endif
# if 1 && defined(__i386__)
# define nrv2b_decompress_safe_8 nrv2b_decompress_asm_safe_8
# define nrv2b_decompress_safe_le16 nrv2b_decompress_asm_safe_le16
# define nrv2d_decompress_safe_8 nrv2d_decompress_asm_safe_8
# define nrv2d_decompress_safe_le16 nrv2d_decompress_asm_safe_le16
# if (NRV_VERSION < 0x008000L)
# define nrv2b_decompress_safe_le32 nrv2b_decompress_asm_safe
# define nrv2d_decompress_safe_le32 nrv2d_decompress_asm_safe
# else
# define nrv2b_decompress_safe_le32 nrv2b_decompress_asm_safe_le32
# define nrv2d_decompress_safe_le32 nrv2d_decompress_asm_safe_le32
# endif
# endif
NRV_EXTERN_CDECL(int) nrv2b_99_compress_internal(...);
NRV_EXTERN_CDECL(int) nrv2d_99_compress_internal(...);
NRV_EXTERN_CDECL(int) nrv2b_decompress_safe_8(...);
NRV_EXTERN_CDECL(int) nrv2b_decompress_safe_le16(...);
NRV_EXTERN_CDECL(int) nrv2b_decompress_safe_le32(...);
NRV_EXTERN_CDECL(int) nrv2d_decompress_safe_8(...);
NRV_EXTERN_CDECL(int) nrv2d_decompress_safe_le16(...);
NRV_EXTERN_CDECL(int) nrv2d_decompress_safe_le32(...);
#endif
#if 0 && defined(WITH_ZLIB) && defined(M_ZLIB)
# include <zlib.h>
#endif
/*************************************************************************
//
**************************************************************************/
int upx_compress ( const upx_byte *src, upx_uint src_len,
upx_byte *dst, upx_uint *dst_len,
upx_progress_callback_t *cb,
int method, int level,
const struct upx_compress_config_t *conf_parm,
upx_uintp result)
{
struct upx_compress_config_t conf;
upx_uint result_buffer[16];
int r = UPX_E_ERROR;
assert(level > 0);
memset(&conf, 0xff, sizeof(conf));
if (conf_parm)
conf = *conf_parm; // struct copy
if (!result)
result = result_buffer;
// assume no info available - fill in worst case results
//result[0] = 1; // min_offset_found - NOT USED
result[1] = src_len - 1; // max_offset_found
//result[2] = 2; // min_match_found - NOT USED
result[3] = src_len - 1; // max_match_found
//result[4] = 1; // min_run_found - NOT USED
result[5] = src_len; // max_run_found
result[6] = 1; // first_offset_found
//result[7] = 999999; // same_match_offsets_found - NOT USED
#if 0 && defined(WITH_ZLIB) && defined(M_ZLIB)
if (method == M_ZLIB)
{
uLong destLen = src_len + src_len / 8 + 256;
r = compress2(dst, &destLen, src, src_len, UPX_MIN(level, 9));
*dst_len = destLen;
if (r == Z_MEM_ERROR)
return UPX_E_OUT_OF_MEMORY;
if (r != Z_OK)
return UPX_E_ERROR;
return UPX_E_OK;
}
#endif
// prepare bit-buffer settings
conf.bb_endian = 0;
conf.bb_size = 0;
if (method == M_NRV2B_LE32 || method == M_NRV2D_LE32)
conf.bb_size = 32;
else if (method == M_NRV2B_8 || method == M_NRV2D_8)
conf.bb_size = 8;
else if (method == M_NRV2B_LE16 || method == M_NRV2D_LE16)
conf.bb_size = 16;
else
throwInternalError("unknown compression method");
#if 1 && defined(WITH_NRV)
if (level == 1 && conf.bb_size == 32 &&
conf.max_offset == UPX_UINT_MAX && conf.max_match == UPX_UINT_MAX)
{
if (method == M_NRV2B_LE32)
{
upx_byte wrkmem[NRV2B_1_16_MEM_COMPRESS];
#if defined(__CHECKER__) || defined(__PURIFY__)
memset(wrkmem,0,NRV2B_1_16_MEM_COMPRESS);
#endif
r = nrv2b_1_16_compress(src, src_len, dst, dst_len, wrkmem);
}
else if (method == M_NRV2D_LE32)
{
upx_byte wrkmem[NRV2D_1_16_MEM_COMPRESS];
#if defined(__CHECKER__) || defined(__PURIFY__)
memset(wrkmem,0,NRV2D_1_16_MEM_COMPRESS);
#endif
r = nrv2d_1_16_compress(src, src_len, dst, dst_len, wrkmem);
}
else
throwInternalError("unknown compression method");
return r;
}
#endif
// optimize compression parms
if (level <= 3 && conf.max_offset == UPX_UINT_MAX)
conf.max_offset = 8*1024-1;
else if (level == 4 && conf.max_offset == UPX_UINT_MAX)
conf.max_offset = 32*1024-1;
#if defined(WITH_NRV)
else if (level <= 7 && conf.max_offset == UPX_UINT_MAX)
conf.max_offset = 1024*1024-1;
else if (level <= 8 && conf.max_offset == UPX_UINT_MAX)
conf.max_offset = 2048*1024-1;
else if (level <= 10 && conf.max_offset == UPX_UINT_MAX)
conf.max_offset = 4096*1024-1;
#endif
if M_IS_NRV2B(method)
r = nrv2b_99_compress_internal(src, src_len, dst, dst_len,
cb, level, &conf, result);
else if M_IS_NRV2D(method)
r = nrv2d_99_compress_internal(src, src_len, dst, dst_len,
cb, level, &conf, result);
else
throwInternalError("unknown compression method");
return r;
}
/*************************************************************************
//
**************************************************************************/
int upx_decompress ( const upx_byte *src, upx_uint src_len,
upx_byte *dst, upx_uint *dst_len,
int method )
{
int r = UPX_E_ERROR;
#if 0 && defined(WITH_ZLIB) && defined(M_ZLIB)
if (method == M_ZLIB)
{
uLong destLen = *dst_len;
r = uncompress(dst, &destLen, src, src_len);
*dst_len = destLen;
if (r == Z_MEM_ERROR)
return UPX_E_OUT_OF_MEMORY;
if (r != Z_OK)
return UPX_E_ERROR;
return UPX_E_OK;
}
#endif
if (method == M_NRV2B_LE32)
r = nrv2b_decompress_safe_le32(src,src_len,dst,dst_len,NULL);
else if (method == M_NRV2B_8)
r = nrv2b_decompress_safe_8(src,src_len,dst,dst_len,NULL);
else if (method == M_NRV2B_LE16)
r = nrv2b_decompress_safe_le16(src,src_len,dst,dst_len,NULL);
else if (method == M_NRV2D_LE32)
r = nrv2d_decompress_safe_le32(src,src_len,dst,dst_len,NULL);
else if (method == M_NRV2D_8)
r = nrv2d_decompress_safe_8(src,src_len,dst,dst_len,NULL);
else if (method == M_NRV2D_LE16)
r = nrv2d_decompress_safe_le16(src,src_len,dst,dst_len,NULL);
else
throwInternalError("unknown decompression method");
return r;
}
/*************************************************************************
//
**************************************************************************/
int upx_test_overlap ( const upx_byte *buf, upx_uint src_off,
upx_uint src_len, upx_uint *dst_len,
int method )
{
int r = UPX_E_ERROR;
if (method == M_NRV2B_LE32)
r = ucl_nrv2b_test_overlap_le32(buf,src_off,src_len,dst_len,NULL);
else if (method == M_NRV2B_8)
r = ucl_nrv2b_test_overlap_8(buf,src_off,src_len,dst_len,NULL);
else if (method == M_NRV2B_LE16)
r = ucl_nrv2b_test_overlap_le16(buf,src_off,src_len,dst_len,NULL);
else if (method == M_NRV2D_LE32)
r = ucl_nrv2d_test_overlap_le32(buf,src_off,src_len,dst_len,NULL);
else if (method == M_NRV2D_8)
r = ucl_nrv2d_test_overlap_8(buf,src_off,src_len,dst_len,NULL);
else if (method == M_NRV2D_LE16)
r = ucl_nrv2d_test_overlap_le16(buf,src_off,src_len,dst_len,NULL);
else
throwInternalError("unknown decompression method");
return r;
}
/*
vi:ts=4:et:nowrap
*/

613
src/conf.h Normal file
View File

@ -0,0 +1,613 @@
/* conf.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_CONF_H
#define __UPX_CONF_H
#if 0 && defined(__EMX__)
# include <sys/emx.h>
#endif
#if defined(UPX_CONFIG_H)
# include UPX_CONFIG_H
#endif
#include <limits.h>
#include "version.h"
#include "tailor.h"
#if !defined(__i386__)
# if defined(__386__) || defined(_M_IX86)
# define __i386__ 1
# endif
#endif
#if defined(__linux__) && !defined(__unix__)
# define __unix__ 1
#endif
// just in case
#undef dos
#undef linux
#undef tos
#undef unix
#if defined(WITH_UCL)
# include <ucl/uclconf.h>
# include <ucl/ucl.h>
# if !defined(UPX_UINT_MAX)
# define UPX_UINT_MAX UCL_UINT_MAX
# define upx_uint ucl_uint
# define upx_voidp ucl_voidp
# define upx_uintp ucl_uintp
# define upx_byte ucl_byte
# define upx_bytep ucl_bytep
# define upx_bool ucl_bool
# define upx_progress_callback_t ucl_progress_callback_t
# define upx_adler32 ucl_adler32
# define UPX_E_OK UCL_E_OK
# define UPX_E_ERROR UCL_E_ERROR
# define UPX_E_OUT_OF_MEMORY UCL_E_OUT_OF_MEMORY
# define __UPX_ENTRY __UCL_ENTRY
# endif
#endif
#if defined(WITH_NRV)
# include <nrv/nrvconf.h>
# if !defined(UPX_UINT_MAX)
# define UPX_UINT_MAX NRV_UINT_MAX
# define upx_uint nrv_uint
# define upx_voidp nrv_voidp
# define upx_uintp nrv_uintp
# define upx_byte nrv_byte
# define upx_bytep nrv_bytep
# define upx_bool nrv_bool
# define upx_progress_callback_t nrv_progress_callback_t
# define upx_adler32 nrv_adler32
# define UPX_E_OK NRV_E_OK
# define UPX_E_ERROR NRV_E_ERROR
# define UPX_E_OUT_OF_MEMORY NRV_E_OUT_OF_MEMORY
# define __UPX_ENTRY __NRV_ENTRY
# endif
#endif
#ifndef WITH_ZLIB
# define WITH_ZLIB 1
#endif
#if !defined(UPX_UINT_MAX) || (UINT_MAX < 0xffffffffL)
# error "you lose"
#endif
#if !defined(WITH_UCL)
# error "you lose"
#endif
#if !defined(UCL_VERSION) || (UCL_VERSION < 0x009100L)
# error "please upgrade your UCL installation"
#endif
/*************************************************************************
// system includes
**************************************************************************/
#if !defined(NO_SYS_TYPES_H)
# include <sys/types.h>
#endif
#define NDEBUG
#undef NDEBUG
#include <assert.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#if !defined(NO_FCNTL_H)
# include <fcntl.h>
#endif
#if !defined(NO_SYS_STAT_H)
# include <sys/stat.h>
#endif
#if defined(HAVE_IO_H) && !defined(NO_IO_H)
# include <io.h>
#endif
#if defined(HAVE_DOS_H) && !defined(NO_DOS_H)
# include <dos.h>
#endif
#if defined(HAVE_MALLOC_H) && !defined(NO_MALLOC_H)
# include <malloc.h>
#endif
#if defined(HAVE_ALLOCA_H) && !defined(NO_ALLOCA_H)
# include <alloca.h>
#endif
#if defined(HAVE_SIGNAL_H)
# include <signal.h>
#endif
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined(TIME_WITH_SYS_TIME)
# include <sys/time.h>
# include <time.h>
#else
# include <time.h>
#endif
#if defined(HAVE_UTIME_H)
# include <utime.h>
#elif defined(HAVE_SYS_UTIME_H)
# include <sys/utime.h>
#endif
#if defined(HAVE_SHARE_H)
# include <share.h>
#endif
// malloc debuggers
#if defined(WITH_DMALLOC)
# define DMALLOC_FUNC_CHECK
# include <dmalloc.h>
#elif defined(WITH_GC)
# define GC_DEBUG
# include <gc/gc.h>
# undef malloc
# undef realloc
# undef free
# define malloc GC_MALLOC
# define realloc GC_REALLOC
# define free GC_FREE
#elif defined(WITH_MSS)
# define MSS
# include <mss.h>
#endif
/*************************************************************************
// portab
**************************************************************************/
#if defined(NO_BOOL)
typedef int bool;
enum { false, true };
#endif
#if !defined(PATH_MAX)
# define PATH_MAX 512
#elif (PATH_MAX < 512)
# undef PATH_MAX
# define PATH_MAX 512
#endif
#ifndef RETSIGTYPE
# define RETSIGTYPE void
#endif
#ifndef SIGTYPEENTRY
# define SIGTYPEENTRY
#endif
typedef RETSIGTYPE (SIGTYPEENTRY *sig_type)(int);
#undef MODE_T
#if defined(HAVE_MODE_T)
# define MODE_T mode_t
#else
# define MODE_T int
#endif
#if !defined(HAVE_STRCHR)
# if defined(HAVE_INDEX)
# define strchr index
# endif
#endif
#if !defined(HAVE_STRCASECMP)
# if defined(HAVE_STRICMP)
# define strcasecmp stricmp
# else
# define strcasecmp strcmp
# endif
#endif
#if !defined(HAVE_STRNCASECMP)
# if defined(HAVE_STRNICMP)
# define strncasecmp strnicmp
# else
# define strncasecmp strncmp
# endif
#endif
#ifndef STDIN_FILENO
# define STDIN_FILENO (fileno(stdin))
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO (fileno(stdout))
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO (fileno(stderr))
#endif
#if !defined(S_IFMT) && defined(_S_IFMT)
# define S_IFMT _S_IFMT
#endif
#if !defined(S_IFREG) && defined(_S_IFREG)
# define S_IFREG _S_IFREG
#endif
#if !defined(S_IFDIR) && defined(_S_IFDIR)
# define S_IFDIR _S_IFDIR
#endif
#if !defined(S_IFCHR) && defined(_S_IFCHR)
# define S_IFCHR _S_IFCHR
#endif
#if !defined(S_ISREG)
# if defined(S_IFMT) && defined(S_IFREG)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
# else
# error S_ISREG
# endif
#endif
#if !defined(S_ISDIR)
# if defined(S_IFMT) && defined(S_IFDIR)
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
# else
# error S_ISDIR
# endif
#endif
#if !defined(S_ISCHR)
# if defined(S_IFMT) && defined(S_IFCHR)
# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
# endif
#endif
// avoid warnings about shadowing that obsolete index() function
#define index upx_index
/*************************************************************************
// file io
**************************************************************************/
#if defined(HAVE_SETMODE)
# if !defined(O_BINARY)
# error "setmode without O_BINARY"
# endif
# define USE_SETMODE 1
#endif
#if !defined(O_BINARY)
# define O_BINARY 0
#endif
#if defined(__DJGPP__)
# undef sopen
# undef USE_SETMODE
#endif
/*************************************************************************
// memory util
**************************************************************************/
#undef FREE
#define FREE(ptr) if (ptr) { free(ptr); ptr = NULL; }
#undef UNUSED
#if defined(__BORLANDC__)
#define UNUSED(parm) ((void)(parm))
#else
#define UNUSED(parm) (parm = parm)
#endif
#define HIGH(array) ((unsigned) (sizeof(array)/sizeof((array)[0])))
#define ALIGN_DOWN(a,b) (((a) / (b)) * (b))
#define ALIGN_UP(a,b) ALIGN_DOWN((a) + ((b) - 1), b)
#define UPX_MAX(a,b) ((a) >= (b) ? (a) : (b))
#define UPX_MIN(a,b) ((a) <= (b) ? (a) : (b))
#define UPX_MAX3(a,b,c) ((a) >= (b) ? UPX_MAX(a,c) : UPX_MAX(b,c))
#define UPX_MIN3(a,b,c) ((a) <= (b) ? UPX_MIN(a,c) : UPX_MIN(b,c))
#if 0 && defined(__cplusplus)
// global operators - debug
inline void *operator new(size_t l)
{
void *p = malloc(l);
printf("new %6ld %p\n",(long)l,p);
fflush(stdout);
return p;
}
inline void *operator new[](size_t l)
{
void *p = malloc(l);
printf("new %6ld %p\n",(long)l,p);
fflush(stdout);
return p;
}
inline void operator delete(void *p)
{
printf("delete %p\n",p);
fflush(stdout);
if (p) free(p);
}
inline void operator delete[](void *p)
{
printf("delete %p\n",p);
fflush(stdout);
if (p) free(p);
}
#endif
// A autoheap_array allocates memory on the heap, but automatically
// gets destructed when leaving scope or on exceptions.
// "var" is declared as a read-only reference to a pointer
// and behaves exactly like an array "var[]".
#if 0
# define autoheap_array(type, var, size) \
assert((int)(size) > 0); \
vector<type> var ## _autoheap_vec((size)); \
type * const & var = & var ## _autoheap_vec[0]
#else
# define autoheap_array(type, var, size) \
assert((int)(size) > 0); \
MemBuffer var ## _autoheap_buf((size)*(sizeof(type))); \
type * const & var = (type *) (unsigned char *) var ## _autoheap_buf
#endif
/*************************************************************************
//
**************************************************************************/
/* exit codes of this program: 0 ok, 1 error, 2 warning */
#define EXIT_OK 0
#define EXIT_ERROR 1
#define EXIT_WARN 2
#define EXIT_USAGE 1
#define EXIT_FILE_READ 1
#define EXIT_FILE_WRITE 1
#define EXIT_MEMORY 1
#define EXIT_CHECKSUM 1
#define EXIT_INIT 1
#define EXIT_INTERNAL 1
// compression methods - DO NOT CHANGE
#define M_NRV2B_LE32 2
#define M_NRV2B_8 3
#define M_NRV2B_LE16 4
#define M_NRV2D_LE32 5
#define M_NRV2D_8 6
#define M_NRV2D_LE16 7
#define M_IS_NRV2B(x) ((x) >= M_NRV2B_LE32 && (x) <= M_NRV2B_LE16)
#define M_IS_NRV2D(x) ((x) >= M_NRV2D_LE32 && (x) <= M_NRV2D_LE16)
/*************************************************************************
// globals
**************************************************************************/
#include "unupx.h"
#if defined(__cplusplus)
#include "stdcxx.h"
#include "except.h"
#include "bele.h"
#include "util.h"
#include "console.h"
// options
enum {
CMD_NONE,
CMD_COMPRESS, CMD_DECOMPRESS, CMD_TEST, CMD_LIST, CMD_FILEINFO,
CMD_HELP, CMD_LICENSE, CMD_VERSION
};
struct options_t {
int cmd;
int method;
int level; // compression level 1..10
int mem_level; // memory level 1..9
int filter; // preferred filter from Packer::getFilters()
bool all_filters; // try all filters ?
int console;
int debug;
int force;
int info_mode;
bool ignorewarn;
int backup;
bool no_env;
bool no_progress;
const char *output_name;
const char *script_name;
int small;
int verbose;
bool to_stdout;
// overlay handling
enum {
SKIP_OVERLAY = 0,
COPY_OVERLAY = 1,
STRIP_OVERLAY = 2
};
int overlay;
// compression runtime parameters - see struct ucl_compress_config_t
struct {
upx_uint max_offset;
upx_uint max_match;
int s_level;
int h_level;
int p_level;
int c_flags;
upx_uint m_size;
} crp;
// CPU
enum {
CPU_DEFAULT = 0,
CPU_8086 = 1,
CPU_286 = 2,
CPU_386 = 3,
CPU_486 = 4,
CPU_586 = 5,
CPU_686 = 6
};
int cpu;
// options for various executable formats
struct {
bool force_stub;
bool no_reloc;
} dos;
struct {
bool coff;
} djgpp2;
struct {
bool split_segments;
} tos;
struct {
unsigned blocksize;
} unix;
struct {
bool le;
} wcle;
struct {
bool compress_exports;
int compress_icons;
bool compress_resources;
int strip_relocs;
} w32pe;
};
extern struct options_t * volatile opt;
// main.cpp
extern const char *progname;
bool set_ec(int ec);
#if defined(__GNUC__)
void e_exit(int ec) __attribute__((noreturn));
#else
void e_exit(int ec);
#endif
// msg.cpp
void printSetNl(int need_nl);
void printClearLine(FILE *f = NULL);
void printErr(const char *iname, const Throwable *e);
#if defined(__GNUC__)
void printErr(const char *iname, const char *format, ...)
__attribute__((format(printf,2,3)));
void printWarn(const char *iname, const char *format, ...)
__attribute__((format(printf,2,3)));
#else
void printErr(const char *iname, const char *format, ...);
void printWarn(const char *iname, const char *format, ...);
#endif
#if defined(__GNUC__)
void infoWarning(const char *format, ...)
__attribute__((format(printf,1,2)));
void infoHeader(const char *format, ...)
__attribute__((format(printf,1,2)));
void info(const char *format, ...)
__attribute__((format(printf,1,2)));
#else
void infoWarning(const char *format, ...);
void infoHeader(const char *format, ...);
void info(const char *format, ...);
#endif
void infoHeader();
void infoWriting(const char *what, long size);
// work.cpp
void do_one_file(const char *iname, char *oname);
void do_files(int i, int argc, char *argv[]);
// help.cpp
void show_head(void);
void show_help(int x = 0);
void show_license(void);
void show_usage(void);
void show_version(int);
// compress.cpp
#if defined(WITH_UCL)
#define upx_compress_config_t ucl_compress_config_t
#elif defined(WITH_NRV)
struct nrv_compress_config_t;
struct nrv_compress_config_t
{
int bb_endian;
int bb_size;
nrv_uint max_offset;
nrv_uint max_match;
int s_level;
int h_level;
int p_level;
int c_flags;
nrv_uint m_size;
};
#define upx_compress_config_t nrv_compress_config_t
#endif
int upx_compress ( const upx_byte *src, upx_uint src_len,
upx_byte *dst, upx_uint *dst_len,
upx_progress_callback_t *cb,
int method, int level,
const struct upx_compress_config_t *conf,
upx_uintp result);
int upx_decompress ( const upx_byte *src, upx_uint src_len,
upx_byte *dst, upx_uint *dst_len,
int method );
int upx_test_overlap ( const upx_byte *buf, upx_uint src_off,
upx_uint src_len, upx_uint *dst_len,
int method );
#endif /* __cplusplus */
#define SCRIPT_MAX 32
#endif /* already included */
/*
vi:ts=4:et
*/

240
src/config_h/linux.h Normal file
View File

@ -0,0 +1,240 @@
/* pseudo <config.h> for Linux */
#ifndef __UPX_CONFIG_H
#define __UPX_CONFIG_H
/* $TOP$ */
/* Define to empty if the keyword does not work. */
/* #undef const */
/* Define if your C compiler doesn't accept -c and -o together. */
/* #undef NO_MINUS_C_MINUS_O */
/* Define as the return type of signal handlers (int or void). */
#define RETSIGTYPE void
/* Define to `unsigned' if <sys/types.h> doesn't define. */
/* #undef size_t */
/* Define if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1
/* Define if your memcmp is broken. */
/* #undef NO_MEMCMP */
/* Define to `long' if <stddef.h> doesn't define. */
/* #undef ptrdiff_t */
/* The number of bytes in a ptrdiff_t. */
#define SIZEOF_PTRDIFF_T 4
/* The number of bytes in a size_t. */
#define SIZEOF_SIZE_T 4
/* Define when using the dmalloc package. */
/* #undef WITH_DMALLOC */
/* Define if you have the access function. */
#define HAVE_ACCESS 1
/* Define if you have the atoi function. */
#define HAVE_ATOI 1
/* Define if you have the chmod function. */
#define HAVE_CHMOD 1
/* Define if you have the chown function. */
#define HAVE_CHOWN 1
/* Define if you have the ctime function. */
#define HAVE_CTIME 1
/* Define if you have the difftime function. */
#define HAVE_DIFFTIME 1
/* Define if you have the fchmod function. */
#define HAVE_FCHMOD 1
/* Define if you have the fileno function. */
#define HAVE_FILENO 1
/* Define if you have the fstat function. */
#define HAVE_FSTAT 1
/* Define if you have the XXX function. */
#define HAVE_GETPID 1
/* Define if you have the XXX function. */
#define HAVE_GETTIMEOFDAY 1
/* Define if you have the getumask function. */
/* #undef HAVE_GETUMASK */
/* Define if you have the gmtime function. */
#define HAVE_GMTIME 1
/* Define if you have the index function. */
#define HAVE_INDEX 1
/* Define if you have the isatty function. */
#define HAVE_ISATTY 1
/* Define if you have the lstat function. */
#define HAVE_LSTAT 1
/* Define if you have the localtime function. */
#define HAVE_LOCALTIME 1
/* Define if you have the memcmp function. */
#define HAVE_MEMCMP 1
/* Define if you have the memcpy function. */
#define HAVE_MEMCPY 1
/* Define if you have the memmove function. */
#define HAVE_MEMMOVE 1
/* Define if you have the memset function. */
#define HAVE_MEMSET 1
/* Define if you have the mktime function. */
#define HAVE_MKTIME 1
/* Define if you have the setmode function. */
/* #undef HAVE_SETMODE */
/* Define if you have the stat function. */
#define HAVE_STAT 1
/* Define if you have the strcasecmp function. */
#define HAVE_STRCASECMP 1
/* Define if you have the strchr function. */
#define HAVE_STRCHR 1
/* Define if you have the strdup function. */
#define HAVE_STRDUP 1
/* Define if you have the strftime function. */
#define HAVE_STRFTIME 1
/* Define if you have the stricmp function. */
/* #undef HAVE_STRICMP */
/* Define if you have the strncasecmp function. */
#define HAVE_STRNCASECMP 1
/* Define if you have the strnicmp function. */
/* #undef HAVE_STRNICMP */
/* Define if you have the strstr function. */
#define HAVE_STRSTR 1
/* Define if you have the tzset function. */
#define HAVE_TZSET 1
/* Define if you have the umask function. */
#define HAVE_UMASK 1
/* Define if you have the utime function. */
#define HAVE_UTIME 1
/* Define if you have the vsnprintf function. */
#define HAVE_VSNPRINTF 1
/* Define if you have the <assert.h> header file. */
#define HAVE_ASSERT_H 1
/* Define if you have the <ctype.h> header file. */
#define HAVE_CTYPE_H 1
/* Define if you have the <curses.h> header file. */
#define HAVE_CURSES_H 1
/* Define if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define if you have the <linux/kd.h> header file. */
#define HAVE_LINUX_KD_H 1
/* Define if you have the <linux/kdev_t.h> header file. */
#define HAVE_LINUX_KDEV_T_H 1
/* Define if you have the <linux/major.h> header file. */
#define HAVE_LINUX_MAJOR_H 1
/* Define if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define if you have the <ncurses.h> header file. */
#define HAVE_NCURSES_H 1
/* Define if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define if you have the <stddef.h> header file. */
#define HAVE_STDDEF_H 1
/* Define if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define if you have the <sys/resource.h> header file. */
#define HAVE_SYS_RESOURCE_H 1
/* Define if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define if you have the <sys/times.h> header file. */
#define HAVE_SYS_TIMES_H 1
/* Define if you have the <sys/utime.h> header file. */
/* #undef HAVE_SYS_UTIME_H */
/* Define if you have the <time.h> header file. */
#define HAVE_TIME_H 1
/* Define if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define if you have the <utime.h> header file. */
#define HAVE_UTIME_H 1
/* $BOTTOM$ */
#if defined(HAVE_GMTIME) && !defined(TIME_WITH_SYS_TIME)
# undef /**/ HAVE_GMTIME
#endif
#if defined(HAVE_LOCALTIME) && !defined(TIME_WITH_SYS_TIME)
# undef /**/ HAVE_LOCALTIME
#endif
#if defined(HAVE_STRFTIME) && !defined(TIME_WITH_SYS_TIME)
# undef /**/ HAVE_STRFTIME
#endif
#if defined(HAVE_SYS_RESOURCE_H) && !defined(TIME_WITH_SYS_TIME)
# undef /**/ HAVE_SYS_RESOURCE_H
#endif
#if defined(HAVE_SYS_TIMES_H) && !defined(TIME_WITH_SYS_TIME)
# undef /**/ HAVE_SYS_TIMES_H
#endif
#if (SIZEOF_PTRDIFF_T <= 0)
# undef /**/ SIZEOF_PTRDIFF_T
#endif
#if (SIZEOF_SIZE_T <= 0)
# undef /**/ SIZEOF_SIZE_T
#endif
#endif /* already included */
/*
vi:ts=4
*/

186
src/console.h Normal file
View File

@ -0,0 +1,186 @@
/* console.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
/*************************************************************************
//
**************************************************************************/
#undef USE_CONSOLE
#undef USE_ANSI
#undef USE_SCREEN
#undef USE_SCREEN_VCSA
#undef USE_SCREEN_CURSES
#undef USE_FRAMES
#if 1 && defined(__linux__)
# define USE_SCREEN
# define USE_SCREEN_VCSA
# if !defined(HAVE_LINUX_KD_H)
# undef USE_SCREEN
# undef USE_SCREEN_VCSA
# endif
# if !defined(HAVE_LINUX_KDEV_T_H) || !defined(HAVE_LINUX_MAJOR_H)
# undef USE_SCREEN
# undef USE_SCREEN_VCSA
# endif
#endif
#if 1 && defined(__DJGPP__)
# define USE_SCREEN
#endif
#if 1 && defined(__MFX_WIN32)
# define USE_SCREEN
#endif
#if 0 || defined(NO_ANSI)
# undef USE_ANSI
#endif
#if 0 || defined(NO_SCREEN)
# undef USE_SCREEN
#endif
#if 0 || defined(NO_FRAMES) || !defined(USE_SCREEN)
# undef USE_FRAMES
#endif
#if 1
# undef USE_FRAMES
#endif
#if 0 || defined(USE_ANSI) || defined(USE_SCREEN)
# define USE_CONSOLE
#endif
#if 0 || defined(NO_CONSOLE) || !defined(USE_CONSOLE)
# undef USE_CONSOLE
# undef USE_ANSI
# undef USE_SCREEN
# undef USE_SCREEN_VCSA
# undef USE_SCREEN_CURSES
# undef USE_FRAMES
#endif
/*************************************************************************
//
**************************************************************************/
enum {
CON_INIT,
CON_NONE,
CON_FILE,
CON_ANSI_MONO,
CON_ANSI_COLOR,
CON_SCREEN,
CON_UNUSED
};
#if defined(USE_CONSOLE)
typedef struct
{
int (*init)(FILE *f, int, int);
int (*set_fg)(FILE *f, int fg);
void (*print0)(FILE *f, const char *s);
upx_bool (*intro)(FILE *f);
}
console_t;
#if defined(__GNUC__)
void con_fprintf(FILE *f, const char *format, ...)
__attribute__((format(printf,2,3)));
#else
void con_fprintf(FILE *f, const char *format, ...);
#endif
#define FG_BLACK 0x00
#define FG_BLUE 0x01
#define FG_GREEN 0x02
#define FG_CYAN 0x03
#define FG_RED 0x04
#define FG_VIOLET 0x05
#define FG_ORANGE 0x06
#define FG_LTGRAY 0x07
#define FG_DKGRAY 0x08
#define FG_BRTBLUE 0x09
#define FG_BRTGREEN 0x0a
#define FG_BRTCYAN 0x0b
#define FG_BRTRED 0x0c
#define FG_BRTVIOLET 0x0d
#define FG_YELLOW 0x0e
#define FG_WHITE 0x0f
#define BG_BLACK 0x00
#define BG_BLUE 0x10
#define BG_GREEN 0x20
#define BG_CYAN 0x30
#define BG_RED 0x40
#define BG_VIOLET 0x50
#define BG_ORANGE 0x60
#define BG_WHITE 0x70
#endif /* USE_CONSOLE */
/*************************************************************************
//
**************************************************************************/
extern FILE *con_term;
#if defined(USE_CONSOLE)
extern int con_mode;
extern console_t *con;
extern console_t console_init;
extern console_t console_none;
extern console_t console_file;
extern console_t console_ansi_mono;
extern console_t console_ansi_color;
extern console_t console_screen;
#define con_fg(f,x) con->set_fg(f,x)
#else
#define con_fg(f,x) 0
#define con_fprintf fprintf
#endif /* USE_CONSOLE */
/*
vi:ts=4:et
*/

138
src/except.cpp Normal file
View File

@ -0,0 +1,138 @@
/* except.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
/*************************************************************************
// compression
**************************************************************************/
void throwCantPack(const char *msg)
{
// UGLY, but makes things easier
if (opt->cmd == CMD_COMPRESS)
throw CantPackException(msg);
else if (opt->cmd == CMD_FILEINFO)
throw CantPackException(msg);
else
throw CantUnpackException(msg);
}
void throwFilterException()
{
throwCantPack("filter problem");
}
void throwUnknownExecutableFormat(const char *msg, bool warn)
{
throw UnknownExecutableFormatException(msg, warn);
}
void throwNotCompressible(const char *msg)
{
throw NotCompressibleException(msg);
}
void throwAlreadyPacked(const char *msg)
{
throw AlreadyPackedException(msg);
}
/*************************************************************************
// decompression
**************************************************************************/
void throwCantUnpack(const char *msg)
{
// UGLY, but makes things easier
throwCantPack(msg);
}
void throwNotPacked(const char *msg)
{
if (msg == NULL)
msg = "not packed by UPX";
throw NotPackedException(msg);
}
void throwChecksumError()
{
throw Exception("checksum error");
}
void throwCompressedDataViolation()
{
throw Exception("compressed data violation");
}
/*************************************************************************
// other
**************************************************************************/
void throwInternalError(const char *msg)
{
throw InternalError(msg);
}
void throwBadLoader()
{
throwInternalError("bad loader");
}
void throwIOException(const char *msg, int e)
{
throw IOException(msg,e);
}
/*************************************************************************
//
**************************************************************************/
const char *prettyName(const char *n)
{
while (*n >= '0' && *n <= '9') // gcc / egcs
n++;
if (strlen(n) > 6 && memcmp(n, "class ", 6) == 0) // Visual C++
n += 6;
return n;
}
const char *prettyName(const type_info &ti)
{
return prettyName(ti.name());
}
/*
vi:ts=4:et
*/

226
src/except.h Normal file
View File

@ -0,0 +1,226 @@
/* except.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_EXCEPT_H
#define __UPX_EXCEPT_H
#ifdef __cplusplus
const char *prettyName(const char *n);
const char *prettyName(const type_info &ti);
/*************************************************************************
// exceptions
**************************************************************************/
class Throwable : public exception
{
protected:
Throwable(const char *m = 0, int e = 0, bool w = false)
: msg(m), err(e), is_warning(w) { }
public:
virtual ~Throwable() { }
const char *getMsg() const { return msg; }
int getErrno() const { return err; }
bool isWarning() const { return is_warning; }
private:
//Throwable(const Throwable &);
private:
// void * operator new(size_t); // ...
const char *msg;
int err;
protected:
bool is_warning; // can be set by subclasses
};
// Exceptions can/should be caught
class Exception : public Throwable
{
typedef Throwable super;
public:
Exception(const char *m = 0, int e = 0, bool w = false) : super(m,e,w) { }
};
// Errors should not be caught (or re-thrown)
class Error : public Throwable
{
typedef Throwable super;
public:
Error(const char *m = 0, int e = 0) : super(m,e) { }
};
/*************************************************************************
// system exception
**************************************************************************/
class OutOfMemoryException : public Exception
{
typedef Exception super;
public:
OutOfMemoryException(const char *m = 0, int e = 0) : super(m,e) { }
};
class IOException : public Exception
{
typedef Exception super;
public:
IOException(const char *m = 0, int e = 0) : super(m,e) { }
};
class EOFException : public IOException
{
typedef IOException super;
public:
EOFException(const char *m = 0, int e = 0) : super(m,e) { }
};
class FileNotFoundException : public IOException
{
typedef IOException super;
public:
FileNotFoundException(const char *m = 0, int e = 0) : super(m,e) { }
};
class FileAlreadyExistsException : public IOException
{
typedef IOException super;
public:
FileAlreadyExistsException(const char *m = 0, int e = 0) : super(m,e) { }
};
/*************************************************************************
// application execptions
**************************************************************************/
class OverlayException : public Exception
{
typedef Exception super;
public:
OverlayException(const char *m = 0, bool w = false) : super(m,0,w) { }
};
class CantPackException : public Exception
{
typedef Exception super;
public:
CantPackException(const char *m = 0, bool w = false) : super(m,0,w) { }
};
class UnknownExecutableFormatException : public CantPackException
{
typedef CantPackException super;
public:
UnknownExecutableFormatException(const char *m = 0, bool w = false) : super(m,w) { }
};
class AlreadyPackedException : public CantPackException
{
typedef CantPackException super;
public:
AlreadyPackedException(const char *m = 0) : super(m) { is_warning = true; }
};
class NotCompressibleException : public CantPackException
{
typedef CantPackException super;
public:
NotCompressibleException(const char *m = 0) : super(m) { }
};
class CantUnpackException : public Exception
{
typedef Exception super;
public:
CantUnpackException(const char *m = 0, bool w = false) : super(m,0,w) { }
};
class NotPackedException : public CantUnpackException
{
typedef CantUnpackException super;
public:
NotPackedException(const char *m = 0) : super(m,true) { }
};
/*************************************************************************
// errors
**************************************************************************/
class InternalError : public Error
{
typedef Error super;
public:
InternalError(const char *m = 0) : super(m,0) { }
};
/*************************************************************************
// util
**************************************************************************/
#if 0 && defined(__GNUC__)
// (noreturn) is probably not the correct semantics
#define NORET __attribute__((noreturn))
#else
#define NORET
#endif
void throwCantPack(const char *msg) NORET;
void throwUnknownExecutableFormat(const char *msg = 0, bool warn = false) NORET;
void throwNotCompressible(const char *msg = 0) NORET;
void throwAlreadyPacked(const char *msg = 0) NORET;
void throwCantUnpack(const char *msg) NORET;
void throwNotPacked(const char *msg = 0) NORET;
void throwFilterException() NORET;
void throwBadLoader() NORET;
void throwChecksumError() NORET;
void throwCompressedDataViolation() NORET;
void throwInternalError(const char *msg) NORET;
void throwIOException(const char *msg = 0, int e = 0) NORET;
#undef NORET
#endif /* __cplusplus */
#endif /* already included */
/*
vi:ts=4:et
*/

105
src/fcto_ml.ch Normal file
View File

@ -0,0 +1,105 @@
/* fctl_ml.ch -- filter CTO implementation by ML1050
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
/*************************************************************************
// these are not implemented here
**************************************************************************/
// filter: e8, e9, e8e9
#define f_cto32_e8 NULL
#define f_cto32_e9 NULL
#define f_cto32_e8e9 NULL
// unfilter: e8, e9, e8e9
#define u_cto32_e8 NULL
#define u_cto32_e9 NULL
#define u_cto32_e8e9 NULL
// scan: e8, e9, e8e9
#define s_cto32_e8 NULL
#define s_cto32_e9 NULL
#define s_cto32_e8e9 NULL
// filter: e8, e9, e8e9 with bswap be->le
#define f_cto32_e8_bswap_be NULL
#define f_cto32_e9_bswap_be NULL
#define f_cto32_e8e9_bswap_be NULL
// unfilter: e8, e9, e8e9 with bswap be->le
#define u_cto32_e8_bswap_be NULL
#define u_cto32_e9_bswap_be NULL
#define u_cto32_e8e9_bswap_be NULL
// scan: e8, e9, e8e9 with bswap be->le
#define s_cto32_e8_bswap_be NULL
#define s_cto32_e9_bswap_be NULL
#define s_cto32_e8e9_bswap_be NULL
/*************************************************************************
//
**************************************************************************/
#define COND(b,x) (b[x] == 0xe8)
#define F f_cto32_e8_bswap_le
#define U u_cto32_e8_bswap_le
#include "fcto_ml2.ch"
#undef U
#undef F
#define F s_cto32_e8_bswap_le
#include "fcto_ml2.ch"
#undef F
#undef COND
#define COND(b,x) (b[x] == 0xe9)
#define F f_cto32_e9_bswap_le
#define U u_cto32_e9_bswap_le
#include "fcto_ml2.ch"
#undef U
#undef F
#define F s_cto32_e9_bswap_le
#include "fcto_ml2.ch"
#undef F
#undef COND
#define COND(b,x) (b[x] == 0xe8 || b[x] == 0xe9)
#define F f_cto32_e8e9_bswap_le
#define U u_cto32_e8e9_bswap_le
#include "fcto_ml2.ch"
#undef U
#undef F
#define F s_cto32_e8e9_bswap_le
#include "fcto_ml2.ch"
#undef F
#undef COND
/*
vi:ts=4:et
*/

191
src/fcto_ml2.ch Normal file
View File

@ -0,0 +1,191 @@
/* fctl_ml2.ch -- filter CTO implementation by ML1050
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
/*************************************************************************
//
**************************************************************************/
static int F(filter_t *f)
{
#ifdef U
// filter
upx_byte *b = f->buf;
const unsigned addvalue = f->addvalue;
#else
// scan
const upx_byte *b = f->buf;
#endif
const unsigned size = f->buf_len;
unsigned ic, jc, kc;
unsigned cto;
unsigned char cto8;
unsigned calls = 0, noncalls = 0, noncalls2 = 0;
unsigned lastnoncall = size, lastcall = 0;
// find a 16MB large empty address space
if (f->forced_cto >= 0 && f->forced_cto <= 255)
cto8 = (unsigned char) f->forced_cto;
else
{
unsigned char buf[256];
memset(buf,0,256);
#if 1
for (ic = 0; ic < size - 5; ic++)
if (COND(b,ic) && get_le32(b+ic+1)+ic+1 >= size)
{
buf[b[ic+1]] |= 1;
}
#else
{
int i = size - 6;
do {
if (COND(b,i) && get_le32(b+i+1)+i+1 >= size)
buf[b[i+1]] |= 1;
} while (--i >= 0);
}
#endif
ic = 256;
if (f->preferred_ctos)
{
for (const int *pc = f->preferred_ctos; *pc >= 0; pc++)
{
if (buf[*pc & 255] == 0)
{
ic = *pc & 255;
break;
}
}
}
#if 0
// just a test to see if certain ctos would improve compression
if (ic >= 256)
for (ic = 0; ic < 256; ic += 16)
if (buf[ic] == 0)
break;
#endif
if (ic >= 256)
for (ic = 0; ic < 256; ic++)
if (buf[ic] == 0)
break;
if (ic >= 256)
//throwCantPack("call trick problem");
return -1;
cto8 = (unsigned char) ic;
}
cto = (unsigned)cto8 << 24;
for (ic = 0; ic < size - 5; ic++)
{
if (!COND(b,ic))
continue;
jc = get_le32(b+ic+1)+ic+1;
// try to detect 'real' calls only
if (jc < size)
{
#ifdef U
set_be32(b+ic+1,jc+addvalue+cto);
#endif
if (ic - lastnoncall < 5)
{
// check the last 4 bytes before this call
for (kc = 4; kc; kc--)
if (COND(b,ic-kc) && b[ic-kc+1] == cto8)
break;
if (kc)
{
#ifdef U
// restore original
set_le32(b+ic+1,jc-ic-1);
#endif
if (b[ic+1] == cto8)
return 1; // fail - buffer not restored
lastnoncall = ic;
noncalls2++;
continue;
}
}
calls++;
ic += 4;
lastcall = ic+1;
}
else
{
assert(b[ic+1] != cto8); // this should not happen
lastnoncall = ic;
noncalls++;
}
}
f->cto = cto8;
f->calls = calls;
f->noncalls = noncalls;
f->lastcall = lastcall;
#ifdef TESTING
printf("\ncalls=%d noncalls=%d noncalls2=%d text_size=%x calltrickoffset=%x\n",calls,noncalls,noncalls2,size,cto);
#endif
return 0;
}
#ifdef U
static int U(filter_t *f)
{
upx_byte *b = f->buf;
const unsigned size5 = f->buf_len - 5;
const unsigned addvalue = f->addvalue;
const unsigned cto = f->cto << 24;
unsigned ic, jc;
for (ic = 0; ic < size5; ic++)
if (COND(b,ic))
{
jc = get_be32(b+ic+1);
if (b[ic+1] == f->cto)
{
set_le32(b+ic+1,jc-ic-1-addvalue-cto);
f->calls++;
ic += 4;
f->lastcall = ic+1;
}
else
f->noncalls++;
}
return 0;
}
#endif
/*
vi:ts=4:et
*/

379
src/file.cpp Normal file
View File

@ -0,0 +1,379 @@
/* file.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
/*************************************************************************
//
**************************************************************************/
void File::chmod(const char *name, int mode)
{
#if defined(HAVE_CHMOD)
if (::chmod(name,mode) != 0)
throwIOException(name,errno);
#endif
}
void File::rename(const char *old_, const char *new_)
{
#if 1 && defined(__DJGPP__)
if (::_rename(old_,new_) != 0)
#else
if (::rename(old_,new_) != 0)
#endif
throwIOException("rename error",errno);
}
void File::unlink(const char *name)
{
if (::unlink(name) != 0)
throwIOException(name,errno);
}
/*************************************************************************
//
**************************************************************************/
FileBase::FileBase() :
_fd(-1), _flags(0), _shflags(0), _mode(0), _name(0)
{
memset(&st,0,sizeof(st));
}
FileBase::~FileBase()
{
#if 0 && defined(__GNUC__) // debug
if (isOpen())
fprintf(stderr,"%s: %s\n", _name, __PRETTY_FUNCTION__);
#endif
// FIXME: we should use close() during exception unwinding but
// closex() otherwise
closex();
}
bool FileBase::close()
{
bool ok = true;
if (isOpen() && _fd != STDIN_FILENO && _fd != STDOUT_FILENO && _fd != STDERR_FILENO)
if (::close(_fd) == -1)
ok = false;
_fd = -1;
_flags = 0;
_mode = 0;
_name = 0;
return ok;
}
void FileBase::closex()
{
if (!close())
throwIOException("close failed",errno);
}
int FileBase::read(void *buf, int len)
{
int l;
if (!isOpen() || len < 0)
throwIOException("bad read");
if (len == 0)
return 0;
for (;;)
{
#if 1 && defined(__DJGPP__)
l = ::_read(_fd,buf,len);
#else
l = ::read(_fd,buf,len);
#endif
if (l < 0)
{
#if defined(EINTR)
if (errno == EINTR)
continue;
#endif
throwIOException("read error",errno);
}
break;
}
return l;
}
int FileBase::readx(void *buf, int len)
{
int l = this->read(buf,len);
if (l != len)
throw EOFException();
return l;
}
void FileBase::write(const void *buf, int len)
{
int l;
if (!isOpen() || len < 0)
throwIOException("bad write");
if (len == 0)
return;
for (;;)
{
#if 1 && defined(__DJGPP__)
l = ::_write(_fd,buf,len);
#else
l = ::write(_fd,buf,len);
#endif
#if defined(EINTR)
if (l < 0 && errno == EINTR)
continue;
#endif
if (l != len)
throwIOException("write error",errno);
break;
}
}
void FileBase::seek(off_t off, int whence)
{
if (!isOpen())
throwIOException("bad seek");
if (::lseek(_fd,off,whence) < 0)
throwIOException("seek error",errno);
}
off_t FileBase::tell()
{
if (!isOpen())
throwIOException("bad tell");
off_t l = ::lseek(_fd,0,SEEK_CUR);
if (l < 0)
throwIOException("tell error",errno);
return l;
}
/*************************************************************************
//
**************************************************************************/
InputFile::InputFile()
{
}
InputFile::~InputFile()
{
}
void InputFile::sopen(const char *name, int flags, int shflags)
{
close();
_name = name;
_flags = flags;
_shflags = shflags;
_mode = 0;
if (shflags < 0)
_fd = ::open(_name,_flags);
else
#if defined(__DJGPP__)
_fd = ::open(_name,_flags | _shflags);
#elif defined(SH_DENYRW)
_fd = ::sopen(_name,_flags,_shflags);
#else
assert(0);
#endif
if (!isOpen())
{
if (errno == ENOENT)
throw FileNotFoundException(_name,errno);
else if (errno == EEXIST)
throw FileAlreadyExistsException(_name,errno);
else
throwIOException(_name,errno);
}
}
int InputFile::read(void * buf, int len)
{
return super::read(buf,len);
}
int InputFile::readx(void * buf, int len)
{
return super::readx(buf,len);
}
void InputFile::seek(off_t off, int whence)
{
super::seek(off,whence);
}
off_t InputFile::tell()
{
return super::tell();
}
/*************************************************************************
//
**************************************************************************/
OutputFile::OutputFile() :
bytes_written(0)
{
}
OutputFile::~OutputFile()
{
}
void OutputFile::sopen(const char *name, int flags, int shflags, int mode)
{
close();
_name = name;
_flags = flags;
_shflags = shflags;
_mode = mode;
if (shflags < 0)
_fd = ::open(_name,_flags,_mode);
else
#if defined(__DJGPP__)
_fd = ::open(_name,_flags | _shflags, _mode);
#elif defined(SH_DENYRW)
_fd = ::sopen(_name,_flags,_shflags,_mode);
#else
assert(0);
#endif
if (!isOpen())
{
#if 0
// don't throw FileNotFound here - confusing
if (errno == ENOENT)
throw FileNotFoundException(_name,errno);
else
#endif
if (errno == EEXIST)
throw FileAlreadyExistsException(_name,errno);
else
throwIOException(_name,errno);
}
}
bool OutputFile::openStdout(int flags, bool force)
{
close();
if (!force)
{
if (!isafile(STDOUT_FILENO))
return false;
}
_fd = STDOUT_FILENO;
_name = "<stdout>";
_flags = flags;
_shflags = -1;
_mode = 0;
if (flags != 0)
{
assert(flags == O_BINARY);
#if defined(HAVE_SETMODE) && defined(USE_SETMODE)
if (setmode(_fd, O_BINARY) == -1)
throwIOException(_name,errno);
#if defined(__DJGPP__)
__djgpp_set_ctrl_c(1);
#endif
#endif
}
return true;
}
void OutputFile::write(const void * buf, int len)
{
super::write(buf,len);
bytes_written += len;
}
void OutputFile::dump(const char *name, const void *buf, int len, int flags)
{
if (flags < 0)
flags = O_CREAT | O_BINARY | O_TRUNC;
flags |= O_WRONLY;
OutputFile f;
f.open(name, flags, 0666);
f.write(buf, len);
f.close();
}
/*************************************************************************
//
**************************************************************************/
MemoryOutputFile::MemoryOutputFile() :
b(NULL), b_size(0), b_pos(0), bytes_written(0)
{
}
void MemoryOutputFile::write(const void * buf, int len)
{
if (!isOpen() || len < 0)
throwIOException("bad write");
if (len == 0)
return;
if (b_pos + len > b_size)
throwIOException("write error",ENOSPC);
memcpy(b + b_pos, buf, len);
b_pos += len;
bytes_written += len;
}
/*
vi:ts=4:et
*/

174
src/file.h Normal file
View File

@ -0,0 +1,174 @@
/* file.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_FILE_H
#define __UPX_FILE_H
/*************************************************************************
//
**************************************************************************/
class File
{
public:
static void chmod(const char *name, int mode);
static void rename(const char *old_, const char *new_);
static void unlink(const char *name);
};
class FileBase : public File
{
protected:
FileBase();
virtual ~FileBase();
public:
virtual bool close();
virtual void closex();
virtual bool isOpen() const { return _fd >= 0; }
int getFd() const { return _fd; }
const char *getName() const { return _name; }
protected:
virtual int read(void *buf, int len);
virtual int readx(void *buf, int len);
virtual void write(const void *buf, int len);
virtual void seek(off_t off, int whence);
virtual off_t tell();
int _fd;
int _flags;
int _shflags;
int _mode;
const char *_name;
public:
struct stat st;
};
/*************************************************************************
//
**************************************************************************/
class InputFile : public FileBase
{
typedef FileBase super;
public:
InputFile();
virtual ~InputFile();
virtual void sopen(const char *name, int flags, int shflags);
virtual void open(const char *name, int flags)
{
sopen(name, flags, -1);
}
virtual int read(void * buf, int len);
virtual int readx(void * buf, int len);
virtual void seek(off_t off, int whence);
virtual off_t tell();
};
/*************************************************************************
//
**************************************************************************/
class OutputFile : public FileBase
{
typedef FileBase super;
public:
OutputFile();
virtual ~OutputFile();
virtual void sopen(const char *name, int flags, int shflags, int mode);
virtual void open(const char *name, int flags, int mode)
{
sopen(name, flags, -1, mode);
}
virtual bool openStdout(int flags=0, bool force=false);
virtual void write(const void *buf, int len);
off_t getBytesWritten() const { return bytes_written; }
// FIXME - won't work with `--stdout' option
virtual void seek(off_t off, int whence)
{
super::seek(off,whence);
}
virtual void rewrite(const void *buf, int len)
{
write(buf, len);
bytes_written -= len;
}
// util
static void dump(const char *name, const void *buf, int len, int flags=-1);
protected:
off_t bytes_written;
};
/*************************************************************************
//
**************************************************************************/
class MemoryOutputFile : public FileBase
{
typedef FileBase super;
public:
MemoryOutputFile();
virtual ~MemoryOutputFile() { b = NULL; }
virtual bool close() { b = NULL; return true; }
virtual bool isOpen() const { return b != NULL; }
virtual void open(void *buf, unsigned size)
{ b = (upx_bytep) buf; b_size = size; }
virtual void write(const void *buf, int len);
off_t getBytesWritten() const { return bytes_written; }
protected:
upx_bytep b;
unsigned b_size;
unsigned b_pos;
off_t bytes_written;
};
#endif /* already included */
/*
vi:ts=4:et
*/

206
src/filter.cpp Normal file
View File

@ -0,0 +1,206 @@
/* filter.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "filter.h"
/*************************************************************************
// util
**************************************************************************/
static //inline
void initFilter(Filter *f, upx_byte *buf, unsigned buf_len)
{
f->buf = buf;
f->buf_len = buf_len;
// clear output parameters
f->calls = f->wrongcalls = f->noncalls = f->lastcall = 0;
}
/*************************************************************************
// implementation
**************************************************************************/
const FilterImp::f_t *FilterImp::getFilter(int id)
{
static bool done = false;
static unsigned filter_id[256];
if (id < 0 || id > 255)
return NULL;
if (!done)
{
memset(filter_id, 0xff, sizeof(filter_id));
for (int i = 0; i < n_filters; i++)
filter_id[filters[i].id] = i;
done = true;
}
unsigned index = filter_id[id];
if (index > 255)
return NULL;
assert(filters[index].id == id);
return &filters[index];
}
/*************************************************************************
// high level API
**************************************************************************/
void Filter::init(int id_, unsigned addvalue_)
{
this->id = id_;
initFilter(this, NULL, 0);
// clear input parameters
this->addvalue = addvalue_;
this->forced_cto = -1;
this->preferred_ctos = NULL;
// clear input/output parameters
this->cto = 0;
}
bool Filter::filter(upx_byte *buf_, unsigned buf_len_)
{
initFilter(this, buf_, buf_len_);
const FilterImp::f_t *ft = FilterImp::getFilter(id);
if (ft == NULL)
throwInternalError("filter-1");
if (ft->id == 0)
return true;
if (buf_len < ft->min_buf_len)
return false;
if (ft->max_buf_len && buf_len > ft->max_buf_len)
return false;
if (!ft->f)
throwInternalError("filter-2");
// setChecksum
if (clevel != 1)
{
this->adler = upx_adler32(0,NULL,0);
this->adler = upx_adler32(this->adler, this->buf, this->buf_len);
}
//printf("filter: %02x %p %d\n", this->id, this->buf, this->buf_len);
int r = (*ft->f)(this);
//printf("filter: %02x %d\n", ft->id, r);
if (r > 0)
throwFilterException();
if (r == 0)
return true;
return false;
}
bool Filter::unfilter(upx_byte *buf_, unsigned buf_len_, bool vc)
{
initFilter(this, buf_, buf_len_);
const FilterImp::f_t *ft = FilterImp::getFilter(id);
if (ft == NULL)
throwInternalError("unfilter-1");
if (ft->id == 0)
return true;
if (buf_len < ft->min_buf_len)
return false;
if (ft->max_buf_len && buf_len > ft->max_buf_len)
return false;
if (!ft->u)
throwInternalError("unfilter-2");
//printf("unfilter: %02x %p %d\n", this->id, this->buf, this->buf_len);
int r = (*ft->u)(this);
//printf("unfilter: %02x %d\n", ft->id, r);
if (r != 0)
throwInternalError("unfilter-3");
// verifyChecksum
if (vc && clevel != 1)
{
unsigned a = upx_adler32(0,NULL,0);
if (this->adler != upx_adler32(a, this->buf, this->buf_len))
throwInternalError("unfilter-4");
}
return true;
}
bool Filter::verifyUnfilter()
{
// Note:
// This verify is just because of complete paranoia that there
// could be a hidden bug in the filter implementation, and
// it should not be necessary at all.
// Maybe we will remove it at some future point.
//
// See also:
// Packer::verifyOverlappingDecompression()
//printf("verifyUnfilter: %02x %p %d\n", this->id, this->buf, this->buf_len);
if (clevel == 1)
return true;
return unfilter(this->buf, this->buf_len, true);
}
bool Filter::scan(const upx_byte *buf_, unsigned buf_len_)
{
// Note: must use const_cast here. This is fine as the scan
// implementations (f->s) actually don't change the buffer.
upx_byte *b = const_cast<upx_byte *>(buf_);
initFilter(this, b, buf_len_);
const FilterImp::f_t *ft = FilterImp::getFilter(id);
if (ft == NULL)
throwInternalError("filter-1");
if (ft->id == 0)
return true;
if (buf_len < ft->min_buf_len)
return false;
if (ft->max_buf_len && buf_len > ft->max_buf_len)
return false;
if (!ft->s)
throwInternalError("filter-2");
//printf("filter: %02x %p %d\n", this->id, this->buf, this->buf_len);
int r = (*ft->s)(this);
//printf("filter: %02x %d\n", ft->id, r);
if (r > 0)
throwFilterException();
if (r == 0)
return true;
return false;
}
/*
vi:ts=4:et
*/

129
src/filter.h Normal file
View File

@ -0,0 +1,129 @@
/* filter.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_FILTER_H
#define __UPX_FILTER_H
class Filter;
class FilterImp;
/*************************************************************************
// A filter is a reversible operation that modifies a given
// block of memory.
//
// A filter can fail and return false. In this case the buffer
// must be unmodified (or otherwise restored).
//
// If a filter fails and somehow cannot restore the block it must
// call throwFilterException() - this will cause the compression
// to fail.
//
// The return value of unfilters can/should be ignored. They throw
// exceptions in case of errors.
//
// The main idea behind filters is to convert relative jumps and calls
// to absolute addresses so that the buffer compresses better.
**************************************************************************/
class Filter
{
public:
Filter(int level) { clevel = level; init(); }
void init(int id=0, unsigned addvalue=0);
bool filter(upx_byte *buf, unsigned buf_len);
bool unfilter(upx_byte *buf, unsigned buf_len, bool verify_checksum=false);
bool verifyUnfilter();
bool scan(const upx_byte *buf, unsigned buf_len);
public:
// Will be set by each call to filter()/unfilter().
// Read-only afterwards.
upx_byte *buf;
unsigned buf_len;
// Checksum of the buffer before applying the filter
// or after un-applying the filter.
unsigned adler;
// Input parameters used by various filters.
unsigned addvalue;
int forced_cto;
const int *preferred_ctos;
// Input/output parameters used by various filters
unsigned char cto; // call trick offset
// Output used by various filters. Read only.
unsigned calls;
unsigned noncalls;
unsigned wrongcalls;
unsigned lastcall;
// Read only.
int id;
private:
int clevel; // compression level
};
/*************************************************************************
// We don't want a full OO interface here because of
// certain implementation speed reasons.
//
// This class is strictly private to Filter - don't look.
**************************************************************************/
class FilterImp
{
friend class Filter;
private:
struct f_t {
int id;
unsigned min_buf_len;
unsigned max_buf_len;
int (*f)(Filter *);
int (*u)(Filter *);
int (*s)(Filter *);
};
static const f_t filters[];
static const int n_filters;
static const f_t *getFilter(int id);
};
#endif /* already included */
/*
vi:ts=4:et
*/

453
src/filteri.cpp Normal file
View File

@ -0,0 +1,453 @@
/* filteri.cpp -- filter implementation (low-level)
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "filter.h"
#define filter_t Filter
#define set_dummy(p, v) ((void)0)
/*************************************************************************
// 16-bit calltrick ("naive")
**************************************************************************/
#define CT16(f, cond, addvalue, get, set) \
upx_byte *b = f->buf; \
upx_byte *b_end = b + f->buf_len - 3; \
do { \
if (cond) \
{ \
b += 1; \
unsigned a = (unsigned) (b - f->buf); \
f->lastcall = a; \
set(b, get(b) + (addvalue)); \
f->calls++; \
b += 2 - 1; \
} \
} while (++b < b_end); \
if (f->lastcall) f->lastcall += 2; \
return 0;
// filter: e8, e9, e8e9
static int f_ct16_e8(filter_t *f)
{
CT16(f, (*b == 0xe8), a + f->addvalue, get_le16, set_le16)
}
static int f_ct16_e9(filter_t *f)
{
CT16(f, (*b == 0xe9), a + f->addvalue, get_le16, set_le16)
}
static int f_ct16_e8e9(filter_t *f)
{
CT16(f, (*b == 0xe8 || *b == 0xe9), a + f->addvalue, get_le16, set_le16)
}
// unfilter: e8, e9, e8e9
static int u_ct16_e8(filter_t *f)
{
CT16(f, (*b == 0xe8), 0 - a - f->addvalue, get_le16, set_le16)
}
static int u_ct16_e9(filter_t *f)
{
CT16(f, (*b == 0xe9), 0 - a - f->addvalue, get_le16, set_le16)
}
static int u_ct16_e8e9(filter_t *f)
{
CT16(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_le16, set_le16)
}
// scan: e8, e9, e8e9
static int s_ct16_e8(filter_t *f)
{
CT16(f, (*b == 0xe8), 0 - a - f->addvalue, get_le16, set_dummy)
}
static int s_ct16_e9(filter_t *f)
{
CT16(f, (*b == 0xe9), 0 - a - f->addvalue, get_le16, set_dummy)
}
static int s_ct16_e8e9(filter_t *f)
{
CT16(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_le16, set_dummy)
}
// filter: e8, e9, e8e9 with bswap le->be
static int f_ct16_e8_bswap_le(filter_t *f)
{
CT16(f, (*b == 0xe8), a + f->addvalue, get_le16, set_be16)
}
static int f_ct16_e9_bswap_le(filter_t *f)
{
CT16(f, (*b == 0xe9), a + f->addvalue, get_le16, set_be16)
}
static int f_ct16_e8e9_bswap_le(filter_t *f)
{
CT16(f, (*b == 0xe8 || *b == 0xe9), a + f->addvalue, get_le16, set_be16)
}
// unfilter: e8, e9, e8e9 with bswap le->be
static int u_ct16_e8_bswap_le(filter_t *f)
{
CT16(f, (*b == 0xe8), 0 - a - f->addvalue, get_be16, set_le16)
}
static int u_ct16_e9_bswap_le(filter_t *f)
{
CT16(f, (*b == 0xe9), 0 - a - f->addvalue, get_be16, set_le16)
}
static int u_ct16_e8e9_bswap_le(filter_t *f)
{
CT16(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_be16, set_le16)
}
// scan: e8, e9, e8e9 with bswap le->be
static int s_ct16_e8_bswap_le(filter_t *f)
{
CT16(f, (*b == 0xe8), 0 - a - f->addvalue, get_be16, set_dummy)
}
static int s_ct16_e9_bswap_le(filter_t *f)
{
CT16(f, (*b == 0xe9), 0 - a - f->addvalue, get_be16, set_dummy)
}
static int s_ct16_e8e9_bswap_le(filter_t *f)
{
CT16(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_be16, set_dummy)
}
// filter: e8, e9, e8e9 with bswap be->le
static int f_ct16_e8_bswap_be(filter_t *f)
{
CT16(f, (*b == 0xe8), a + f->addvalue, get_be16, set_le16)
}
static int f_ct16_e9_bswap_be(filter_t *f)
{
CT16(f, (*b == 0xe9), a + f->addvalue, get_be16, set_le16)
}
static int f_ct16_e8e9_bswap_be(filter_t *f)
{
CT16(f, (*b == 0xe8 || *b == 0xe9), a + f->addvalue, get_be16, set_le16)
}
// unfilter: e8, e9, e8e9 with bswap be->le
static int u_ct16_e8_bswap_be(filter_t *f)
{
CT16(f, (*b == 0xe8), 0 - a - f->addvalue, get_le16, set_be16)
}
static int u_ct16_e9_bswap_be(filter_t *f)
{
CT16(f, (*b == 0xe9), 0 - a - f->addvalue, get_le16, set_be16)
}
static int u_ct16_e8e9_bswap_be(filter_t *f)
{
CT16(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_le16, set_be16)
}
// scan: e8, e9, e8e9 with bswap be->le
static int s_ct16_e8_bswap_be(filter_t *f)
{
CT16(f, (*b == 0xe8), 0 - a - f->addvalue, get_le16, set_dummy)
}
static int s_ct16_e9_bswap_be(filter_t *f)
{
CT16(f, (*b == 0xe9), 0 - a - f->addvalue, get_le16, set_dummy)
}
static int s_ct16_e8e9_bswap_be(filter_t *f)
{
CT16(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_le16, set_dummy)
}
#undef CT16
/*************************************************************************
// 32-bit calltrick ("naive")
**************************************************************************/
#define CT32(f, cond, addvalue, get, set) \
upx_byte *b = f->buf; \
upx_byte *b_end = b + f->buf_len - 5; \
do { \
if (cond) \
{ \
b += 1; \
unsigned a = (unsigned) (b - f->buf); \
f->lastcall = a; \
set(b, get(b) + (addvalue)); \
f->calls++; \
b += 4 - 1; \
} \
} while (++b < b_end); \
if (f->lastcall) f->lastcall += 4; \
return 0;
// filter: e8, e9, e8e9
static int f_ct32_e8(filter_t *f)
{
CT32(f, (*b == 0xe8), a + f->addvalue, get_le32, set_le32)
}
static int f_ct32_e9(filter_t *f)
{
CT32(f, (*b == 0xe9), a + f->addvalue, get_le32, set_le32)
}
static int f_ct32_e8e9(filter_t *f)
{
CT32(f, (*b == 0xe8 || *b == 0xe9), a + f->addvalue, get_le32, set_le32)
}
// unfilter: e8, e9, e8e9
static int u_ct32_e8(filter_t *f)
{
CT32(f, (*b == 0xe8), 0 - a - f->addvalue, get_le32, set_le32)
}
static int u_ct32_e9(filter_t *f)
{
CT32(f, (*b == 0xe9), 0 - a - f->addvalue, get_le32, set_le32)
}
static int u_ct32_e8e9(filter_t *f)
{
CT32(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_le32, set_le32)
}
// scan: e8, e9, e8e9
static int s_ct32_e8(filter_t *f)
{
CT32(f, (*b == 0xe8), 0 - a - f->addvalue, get_le32, set_dummy)
}
static int s_ct32_e9(filter_t *f)
{
CT32(f, (*b == 0xe9), 0 - a - f->addvalue, get_le32, set_dummy)
}
static int s_ct32_e8e9(filter_t *f)
{
CT32(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_le32, set_dummy)
}
// filter: e8, e9, e8e9 with bswap le->be
static int f_ct32_e8_bswap_le(filter_t *f)
{
CT32(f, (*b == 0xe8), a + f->addvalue, get_le32, set_be32)
}
static int f_ct32_e9_bswap_le(filter_t *f)
{
CT32(f, (*b == 0xe9), a + f->addvalue, get_le32, set_be32)
}
static int f_ct32_e8e9_bswap_le(filter_t *f)
{
CT32(f, (*b == 0xe8 || *b == 0xe9), a + f->addvalue, get_le32, set_be32)
}
// unfilter: e8, e9, e8e9 with bswap le->be
static int u_ct32_e8_bswap_le(filter_t *f)
{
CT32(f, (*b == 0xe8), 0 - a - f->addvalue, get_be32, set_le32)
}
static int u_ct32_e9_bswap_le(filter_t *f)
{
CT32(f, (*b == 0xe9), 0 - a - f->addvalue, get_be32, set_le32)
}
static int u_ct32_e8e9_bswap_le(filter_t *f)
{
CT32(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_be32, set_le32)
}
// scan: e8, e9, e8e9 with bswap le->be
static int s_ct32_e8_bswap_le(filter_t *f)
{
CT32(f, (*b == 0xe8), 0 - a - f->addvalue, get_be32, set_dummy)
}
static int s_ct32_e9_bswap_le(filter_t *f)
{
CT32(f, (*b == 0xe9), 0 - a - f->addvalue, get_be32, set_dummy)
}
static int s_ct32_e8e9_bswap_le(filter_t *f)
{
CT32(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_be32, set_dummy)
}
// filter: e8, e9, e8e9 with bswap be->le
static int f_ct32_e8_bswap_be(filter_t *f)
{
CT32(f, (*b == 0xe8), a + f->addvalue, get_be32, set_le32)
}
static int f_ct32_e9_bswap_be(filter_t *f)
{
CT32(f, (*b == 0xe9), a + f->addvalue, get_be32, set_le32)
}
static int f_ct32_e8e9_bswap_be(filter_t *f)
{
CT32(f, (*b == 0xe8 || *b == 0xe9), a + f->addvalue, get_be32, set_le32)
}
// unfilter: e8, e9, e8e9 with bswap be->le
static int u_ct32_e8_bswap_be(filter_t *f)
{
CT32(f, (*b == 0xe8), 0 - a - f->addvalue, get_le32, set_be32)
}
static int u_ct32_e9_bswap_be(filter_t *f)
{
CT32(f, (*b == 0xe9), 0 - a - f->addvalue, get_le32, set_be32)
}
static int u_ct32_e8e9_bswap_be(filter_t *f)
{
CT32(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_le32, set_be32)
}
// scan: e8, e9, e8e9 with bswap be->le
static int s_ct32_e8_bswap_be(filter_t *f)
{
CT32(f, (*b == 0xe8), 0 - a - f->addvalue, get_le32, set_dummy)
}
static int s_ct32_e9_bswap_be(filter_t *f)
{
CT32(f, (*b == 0xe9), 0 - a - f->addvalue, get_le32, set_dummy)
}
static int s_ct32_e8e9_bswap_be(filter_t *f)
{
CT32(f, (*b == 0xe8 || *b == 0xe9), 0 - a - f->addvalue, get_le32, set_dummy)
}
#undef CT32
/*************************************************************************
// 32-bit calltrick with cto ("clever")
//
// This version is more sophisticated because it only
// tries to change actual calls and/or jumps.
**************************************************************************/
#if 1
// use Laszlo's implementation
#include "fcto_ml.ch"
#else
// use Marco's implementation
#include "fcto_mfx.ch"
#endif
/*************************************************************************
// database for class Filter
**************************************************************************/
const FilterImp::f_t FilterImp::filters[] = {
// no filter
{ 0x00, 0, 0, NULL, NULL, NULL },
// 16-bit calltrick
{ 0x01, 4, 0, f_ct16_e8, u_ct16_e8, s_ct16_e8,},
{ 0x02, 4, 0, f_ct16_e9, u_ct16_e9, s_ct16_e9 },
{ 0x03, 4, 0, f_ct16_e8e9, u_ct16_e8e9, s_ct16_e8e9 },
{ 0x04, 4, 0, f_ct16_e8_bswap_le, u_ct16_e8_bswap_le, s_ct16_e8_bswap_le },
{ 0x05, 4, 0, f_ct16_e9_bswap_le, u_ct16_e9_bswap_le, s_ct16_e9_bswap_le },
{ 0x06, 4, 0, f_ct16_e8e9_bswap_le, u_ct16_e8e9_bswap_le, s_ct16_e8e9_bswap_le },
{ 0x07, 4, 0, f_ct16_e8_bswap_be, u_ct16_e8_bswap_be, s_ct16_e8_bswap_be },
{ 0x08, 4, 0, f_ct16_e9_bswap_be, u_ct16_e9_bswap_be, s_ct16_e9_bswap_be },
{ 0x09, 4, 0, f_ct16_e8e9_bswap_be, u_ct16_e8e9_bswap_be, s_ct16_e8e9_bswap_be },
// 32-bit calltrick
{ 0x11, 6, 0, f_ct32_e8, u_ct32_e8, s_ct32_e8 },
{ 0x12, 6, 0, f_ct32_e9, u_ct32_e9, s_ct32_e9 },
{ 0x13, 6, 0, f_ct32_e8e9, u_ct32_e8e9, s_ct32_e8e9 },
{ 0x14, 6, 0, f_ct32_e8_bswap_le, u_ct32_e8_bswap_le, s_ct32_e8_bswap_le },
{ 0x15, 6, 0, f_ct32_e9_bswap_le, u_ct32_e9_bswap_le, s_ct32_e9_bswap_le },
{ 0x16, 6, 0, f_ct32_e8e9_bswap_le, u_ct32_e8e9_bswap_le, s_ct32_e8e9_bswap_le },
{ 0x17, 6, 0, f_ct32_e8_bswap_be, u_ct32_e8_bswap_be, s_ct32_e8_bswap_be },
{ 0x18, 6, 0, f_ct32_e9_bswap_be, u_ct32_e9_bswap_be, s_ct32_e9_bswap_be },
{ 0x19, 6, 0, f_ct32_e8e9_bswap_be, u_ct32_e8e9_bswap_be, s_ct32_e8e9_bswap_be },
// 32-bit cto calltrick
{ 0x21, 6, 0x00ffffff, f_cto32_e8, u_cto32_e8, s_cto32_e8 },
{ 0x22, 6, 0x00ffffff, f_cto32_e9, u_cto32_e9, s_cto32_e9 },
{ 0x23, 6, 0x00ffffff, f_cto32_e8e9, u_cto32_e8e9, s_cto32_e8e9 },
{ 0x24, 6, 0x00ffffff, f_cto32_e8_bswap_le, u_cto32_e8_bswap_le, s_cto32_e8_bswap_le },
{ 0x25, 6, 0x00ffffff, f_cto32_e9_bswap_le, u_cto32_e9_bswap_le, s_cto32_e9_bswap_le },
{ 0x26, 6, 0x00ffffff, f_cto32_e8e9_bswap_le, u_cto32_e8e9_bswap_le, s_cto32_e8e9_bswap_le },
{ 0x27, 6, 0x00ffffff, f_cto32_e8_bswap_be, u_cto32_e8_bswap_be, s_cto32_e8_bswap_be },
{ 0x28, 6, 0x00ffffff, f_cto32_e9_bswap_be, u_cto32_e9_bswap_be, s_cto32_e9_bswap_be },
{ 0x29, 6, 0x00ffffff, f_cto32_e8e9_bswap_be, u_cto32_e8e9_bswap_be, s_cto32_e8e9_bswap_be },
};
const int FilterImp::n_filters = HIGH(filters);
/*
vi:ts=4:et:nowrap
*/

278
src/help.cpp Normal file
View File

@ -0,0 +1,278 @@
/* help.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
/*************************************************************************
//
**************************************************************************/
static bool head_done = 0;
void show_head(void)
{
FILE *f = con_term;
int fg;
if (head_done)
return;
head_done = 1;
fg = con_fg(f,FG_GREEN);
con_fprintf(f,
" Ultimate Packer for eXecutables\n"
" Copyright (C) 1996, 1997, 1998, 1999, 2000\n"
"UPX v%-12sMarkus F.X.J. Oberhumer & Laszlo Molnar%21s\n\n",
UPX_VERSION_STRING, UPX_VERSION_DATE);
fg = con_fg(f,fg);
}
/*************************************************************************
//
**************************************************************************/
void show_usage(void)
{
FILE *f = con_term;
con_fprintf(f,"Usage: %s [-123456788dlsthVL] [-qvfk] [-o file] %sfile..\n", progname,
#if defined(__DJGPP__) || defined(__EMX__)
"[@]");
#else
"");
#endif
}
/*************************************************************************
//
**************************************************************************/
void show_help(int x)
{
FILE *f = con_term;
int fg;
show_head();
show_usage();
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"\nCommands:\n");
fg = con_fg(f,fg);
con_fprintf(f,
" -1 compress faster -9 compress better\n"
"%s"
" -d decompress -l list compressed file\n"
" -t test compressed file -V display version number\n"
" -h give %s help -L display software license\n%s",
x == 0 ? "" : " --best compress best (can be very slow for big files)\n",
x == 0 ? "more" : "this", x == 0 ? "" : "\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options:\n");
fg = con_fg(f,fg);
con_fprintf(f,
" -q be quiet -v be verbose\n"
//" -oFILE write output to `FILE' -c write output to stdout\n"
" -oFILE write output to `FILE'\n"
//" -f force overwrite of output files and compression of suspicious files\n"
" -f force compression of suspicious files\n"
"%s%s"
, (x == 0) ? " -k keep backup files\n" : ""
#if 1
, (x > 0) ? " --no-color, --mono, --color, --no-progress change look\n" : ""
#else
, ""
#endif
);
if (x > 0)
{
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"\nBackup options:\n");
fg = con_fg(f,fg);
con_fprintf(f,
" -k, --backup keep backup files\n"
" --no-backup no backup files [default]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Overlay options:\n");
fg = con_fg(f,fg);
con_fprintf(f,
" --overlay=skip don't compress a file with an overlay\n"
" --overlay=copy copy any extra data attached to the file [default]\n"
" --overlay=strip strip any extra data attached to the file [dangerous]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for dos/exe:\n");
fg = con_fg(f,fg);
con_fprintf(f,
" --8086 make compressed exe work on any 8086\n"
" --no-reloc put no relocations in to the exe header\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for dos/com:\n");
fg = con_fg(f,fg);
con_fprintf(f,
" --8086 make compressed com work on any 8086\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for dos/sys:\n");
fg = con_fg(f,fg);
con_fprintf(f,
" --8086 make compressed sys work on any 8086\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for djgpp2/coff:\n");
fg = con_fg(f,fg);
con_fprintf(f,
" --coff produce COFF output [default: EXE]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for watcom/le:\n");
fg = con_fg(f,fg);
con_fprintf(f,
" --le produce LE output [default: EXE]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for win32/pe & rtm32/pe:\n");
fg = con_fg(f,fg);
con_fprintf(f,
" --compress-exports=0 do not compress the export section\n"
" --compress-exports=1 compress the export section [default]\n"
" --compress-icons=0 do not compress any icons\n"
" --compress-icons=1 compress all but the first icon\n"
" --compress-icons=2 compress all but the first icon directory [default]\n"
" --compress-resources=0 do not compress any resources\n"
" --strip-relocs=0 do not strip relocations\n"
" --strip-relocs=1 strip relocations [default]\n"
"\n");
fg = con_fg(f,FG_YELLOW);
con_fprintf(f,"Options for linux/i386\n");
fg = con_fg(f,fg);
con_fprintf(f,
" -s use /usr/local/lib/upx[bd] as decompressor\n"
" -s=path/upxX use path/upxX as decompressor\n"
"\n");
}
con_fprintf(f,
" file.. executables to (de)compress\n"
"\n"
"This version supports: dos/exe, dos/com, dos/sys, djgpp2/coff, watcom/le,\n"
" win32/pe, rtm32/pe, tmt/adam, atari/tos\n"
" linux/elf386, linux/sh386, linux/386\n"
"%s",
"\nUPX comes with ABSOLUTELY NO WARRANTY; for details visit http://upx.tsx.org\n"
//"\nUPX comes with ABSOLUTELY NO WARRANTY; for details type `upx -L'.\n"
"");
#if defined(DEBUG) || defined(TESTING)
fg = con_fg(f,FG_RED);
con_fprintf(f,"\nWARNING: this version is compiled with"
#if defined(DEBUG)
" -DDEBUG"
#endif
#if defined(TESTING)
" -DTESTING"
#endif
"\n");
fg = con_fg(f,fg);
#endif
}
/*************************************************************************
//
**************************************************************************/
void show_license(void)
{
FILE *f = con_term;
show_head();
con_fprintf(f,
" This program may be used freely, and you are welcome to\n"
" redistribute it under certain conditions.\n"
"\n"
" This program is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" UPX License Agreement for more details.\n"
"\n"
" You should have received a copy of the UPX License Agreement\n"
" along with this program; see the file LICENSE.\n"
" If not, visit one of the following pages:\n"
"\n"
);
int fg = con_fg(f,FG_CYAN);
con_fprintf(f,
" http://upx.tsx.org\n"
" http://wildsau.idv.uni-linz.ac.at/mfx/upx.html\n"
" http://www.nexus.hu/upx\n"
);
(void)con_fg(f,FG_ORANGE);
con_fprintf(f,
"\n"
" Markus F.X.J. Oberhumer Laszlo Molnar\n"
" markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu\n"
);
fg = con_fg(f,fg);
}
/*************************************************************************
//
**************************************************************************/
void show_version(int x)
{
FILE *f = stdout;
UNUSED(x);
fprintf(f,"upx %s\n",UPX_VERSION_STRING);
#if defined(WITH_UCL)
fprintf(f,"UCL data compression library %s\n", ucl_version_string());
#elif defined(WITH_NRV)
fprintf(f,"NRV data compression library %s\n", nrv_version_string());
#endif
fprintf(f,"Copyright (C) 1996,1997,1998,1999,2000 Markus Franz Xaver Johannes Oberhumer\n");
fprintf(f,"Copyright (C) 1996,1997,1998,1999,2000 Laszlo Molnar\n");
fprintf(f,"Copyright (C) 2000 John F. Reiser\n");
fprintf(f,"UPX comes with ABSOLUTELY NO WARRANTY; for details type `%s -L'.\n", progname);
}
/*
vi:ts=4:et:nowrap
*/

349
src/lefile.cpp Normal file
View File

@ -0,0 +1,349 @@
/* lefile.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "mem.h"
#include "lefile.h"
LeFile::LeFile(InputFile *f) : fif(f)
{
memset(&ih,0,sizeof ih);
memset(&oh,0,sizeof oh);
iobject_table = oobject_table = NULL;
ifpage_table = ofpage_table = NULL;
ipm_entries = opm_entries = NULL;
ires_names = ores_names = NULL;
ifixups = ofixups = NULL;
inonres_names = ononres_names = NULL;
ientries = oentries = NULL;
le_offset = exe_offset = 0;
}
LeFile::~LeFile()
{
delete [] iobject_table;
delete [] oobject_table;
delete [] ifpage_table;
delete [] ofpage_table;
delete [] ipm_entries;
delete [] opm_entries;
delete [] ires_names;
delete [] ores_names;
delete [] ifixups;
delete [] ofixups;
delete [] inonres_names;
delete [] ononres_names;
delete [] ientries;
delete [] oentries;
}
#define objects ih.object_table_entries
#define pages ih.memory_pages
#define mps ih.memory_page_size
void LeFile::readObjectTable()
{
iobject_table = new le_object_table_entry_t[soobject_table = objects];
fif->seek(le_offset + ih.object_table_offset,SEEK_SET);
fif->readx(iobject_table,sizeof(*iobject_table)*objects);
}
void LeFile::writeObjectTable()
{
if (fof && oobject_table)
fof->write(oobject_table,sizeof(*iobject_table)*soobject_table);
}
void LeFile::readPageMap()
{
ipm_entries = new le_pagemap_entry_t[sopm_entries = pages];
fif->seek(le_offset + ih.object_pagemap_offset,SEEK_SET);
fif->readx(ipm_entries,sizeof(*ipm_entries)*pages);
for (unsigned ic = 0; ic < pages; ic++)
if ((ipm_entries[ic].type & 0xC0) != 0 && (ipm_entries[ic].type & 0xC0) != 0xC0)
throwCantPack("unexpected value in page map table");
}
void LeFile::writePageMap()
{
if (fof && opm_entries)
fof->write(opm_entries,sizeof(*ipm_entries)*sopm_entries);
}
void LeFile::readResidentNames()
{
sores_names = ih.entry_table_offset - ih.resident_names_offset;
ires_names = new upx_byte[sores_names];
fif->seek(le_offset+ih.resident_names_offset,SEEK_SET);
fif->readx(ires_names,sores_names);
}
void LeFile::writeResidentNames()
{
if (fof && ores_names)
fof->write(ores_names,sores_names);
}
void LeFile::readEntryTable()
{
soentries = ih.fixup_page_table_offset - ih.entry_table_offset;
fif->seek(le_offset + ih.entry_table_offset,SEEK_SET);
ientries = new upx_byte[soentries];
fif->readx(ientries,soentries);
}
void LeFile::writeEntryTable()
{
if (fof && oentries)
fof->write(oentries,soentries);
}
void LeFile::readFixupPageTable()
{
ifpage_table = new unsigned[sofpage_table = 1+pages];
fif->seek(le_offset + ih.fixup_page_table_offset,SEEK_SET);
fif->readx(ifpage_table,4*sofpage_table);
}
void LeFile::writeFixupPageTable()
{
if (fof && ofpage_table)
fof->write(ofpage_table,4*sofpage_table);
}
void LeFile::readFixups()
{
sofixups = get_le32(ifpage_table+pages)-get_le32(ifpage_table);
ifixups = new upx_byte[sofixups];
fif->seek(le_offset + ih.fixup_record_table_offset,SEEK_SET);
fif->readx(ifixups,sofixups);
}
void LeFile::writeFixups()
{
if (fof && ofixups)
fof->write(ofixups,sofixups);
}
void LeFile::readImage()
{
soimage = pages*mps;
iimage.alloc(soimage);
memset(iimage,0,soimage);
unsigned ic,jc;
for (ic = jc = 0; ic < pages; ic++)
{
if ((ipm_entries[ic].type & 0xC0) == 0)
{
fif->seek(ih.data_pages_offset + exe_offset +
(ipm_entries[ic].m*0x100 + ipm_entries[ic].l-1) * mps,SEEK_SET);
fif->readx(iimage+jc,ic != pages-1 ? mps : ih.bytes_on_last_page);
}
jc += mps;
}
}
void LeFile::writeImage()
{
if (fof && oimage != NULL)
fof->write(oimage, soimage);
}
void LeFile::readNonResidentNames()
{
if (ih.non_resident_name_table_length)
{
inonres_names = new upx_byte[sononres_names = ih.non_resident_name_table_length];
fif->seek(exe_offset+ih.non_resident_name_table_offset,SEEK_SET);
fif->readx(inonres_names,sononres_names);
}
}
void LeFile::writeNonResidentNames()
{
if (fof && ononres_names)
fof->write(ononres_names,sononres_names);
}
bool LeFile::readFileHeader()
{
#define H(x) get_le16(header+2*(x))
upx_byte header[0x40];
le_offset = exe_offset = 0;
int ic;
for (ic = 0; ic < 20; ic++)
{
fif->seek(le_offset,SEEK_SET);
fif->readx(header,sizeof(header));
if (memcmp(header,"MZ",2) == 0) // normal dos exe
{
exe_offset = le_offset;
if (H(0x18/2) >= 0x40
&& memcmp(header+0x19,"TIPPACH",7)) // new format exe
le_offset += H(0x3c/2)+H(0x3e/2)*65536;
else
{
le_offset += H(2)*512+H(1);
if (H(1))
le_offset -= 512;
else if (H(2) == 0)
return false;
}
}
else if (memcmp(header,"BW",2) == 0) // used in dos4gw.exe
le_offset += H(2)*512+H(1);
else if (memcmp(header,"LE",2) == 0)
break;
else if (memcmp(header,"PMW1",4) == 0)
throwCantPack("already packed with PMWLITE");
else
return false;
}
if (ic == 20)
return false;
fif->seek(le_offset,SEEK_SET);
fif->readx(&ih,sizeof(ih));
return true;
#undef H
}
void LeFile::writeFile(OutputFile *f, bool le)
{
fof = f;
memcpy (&oh,&ih,(char*)&oh.memory_pages-(char*)&oh); // copy some members of the orig. header
oh.memory_page_size = mps;
oh.object_table_offset = sizeof(oh);
oh.object_table_entries = soobject_table;
oh.object_pagemap_offset = oh.object_table_offset + soobject_table*sizeof(*iobject_table);
oh.resident_names_offset = oh.object_pagemap_offset + sopm_entries*sizeof(*ipm_entries);
oh.entry_table_offset = oh.resident_names_offset + sores_names;
oh.fixup_page_table_offset = oh.entry_table_offset + soentries;
oh.fixup_record_table_offset = oh.fixup_page_table_offset + sofpage_table*4;
oh.imported_modules_name_table_offset = oh.fixup_record_table_offset + sofixups - FIXUP_EXTRA;
oh.imported_procedures_name_table_offset = oh.imported_modules_name_table_offset;
oh.data_pages_offset = oh.fixup_record_table_offset + sofixups + (le ? 0 : le_offset-exe_offset);
if (ih.non_resident_name_table_length)
{
oh.non_resident_name_table_offset = oh.data_pages_offset + soimage;
oh.non_resident_name_table_length = sononres_names;
}
oh.fixup_size = sofixups + 4*sofpage_table;
oh.loader_size = oh.fixup_size + oh.fixup_page_table_offset - sizeof(oh);
fof->write(&oh,sizeof(oh));
writeObjectTable();
writePageMap();
writeResidentNames();
writeEntryTable();
writeFixupPageTable();
writeFixups();
writeImage();
writeNonResidentNames();
}
void LeFile::countFixups(unsigned *counts) const
{
memset(counts,0,sizeof(unsigned)*(objects+2));
// counts[0..objects-1] - # of 32-bit offset relocations in for that objects
// counts[objects] - # of selector fixups
// counts[objects+1] - # of self-relative fixups
const upx_byte *fix = ifixups;
const unsigned sfixups = get_le32(ifpage_table+pages);
unsigned ll;
while ((unsigned)(fix - ifixups) < sfixups)
{
if ((fix[1] & ~0x10) != 0)
throwCantPack("unsupported fixup record");
switch (*fix)
{
case 2: // selector fixup
counts[objects] += 9;
fix += 5;
break;
case 0x12: // alias selector
throwCantPack("16-bit selector alias fixup not yet supported");
case 5: // 16-bit offset
fix += (fix[1] & 0x10) ? 9 : 7;
break;
case 6: // 16:32 pointer
counts[objects] += 9;
case 7: // 32-bit offset
counts[fix[4]-1] += 4;
fix += (fix[1] & 0x10) ? 9 : 7;
break;
case 0x27: // 32-bit offset list
ll = fix[2];
counts[fix[3]-1] += ll*4;
fix += (fix[1] & 0x10) ? 6 : 4;
fix += ll*2;
break;
case 8: // 32-bit self relative fixup
counts[objects+1] += 4;
fix += (fix[1] & 0x10) ? 9 : 7;
break;
default:
throwCantPack("unsupported fixup record");
}
}
counts[objects]++; // extra space for 'ret'
counts[objects+1] += 4; // extra space for 0xFFFFFFFF
}
/*
vi:ts=4:et
*/

223
src/lefile.h Normal file
View File

@ -0,0 +1,223 @@
/* lefile.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_LEFILE_H
#define __UPX_LEFILE_H
class InputFile;
class OutputFile;
/*************************************************************************
//
**************************************************************************/
class LeFile
{
public:
LeFile(InputFile *);
virtual ~LeFile();
virtual bool readFileHeader();
virtual void writeFile(OutputFile *, bool);
protected:
enum { FIXUP_EXTRA = 3 };
struct le_header_t
{ // 0x00
char _[2]; // signature: 'LE' || 'LX'
char byte_order; // 0 little endian
char word_order; // 0 little endian
LE32 exe_format_level; // 0
LE16 cpu_type; // 1->286..4->586
LE16 target_os; // 1->OS2
char _0[4]; // module_version = 0
// 0x10
LE32 module_type; // 0x200->compatible with PM windowing
LE32 memory_pages;
LE32 init_cs_object;
LE32 init_eip_offset;
// 0x20
LE32 init_ss_object;
LE32 init_esp_offset;
LE32 memory_page_size;
LE32 bytes_on_last_page;
// 0x30
LE32 fixup_size;
char _1[4]; // fixup_checksum = 0
LE32 loader_size;
char _2[4]; // loader_checksum = 0
// 0x40
LE32 object_table_offset;
LE32 object_table_entries;
LE32 object_pagemap_offset;
LE32 object_iterate_data_map_offset;
// 0x50
char _3[4]; // resource_offset
LE32 resource_entries;
LE32 resident_names_offset;
LE32 entry_table_offset;
// 0x60
char _4[4]; // module_directives_table_offset = 0
LE32 module_directives_entries;
LE32 fixup_page_table_offset;
LE32 fixup_record_table_offset;
// 0x70
LE32 imported_modules_name_table_offset;
LE32 imported_modules_count;
LE32 imported_procedures_name_table_offset;
char _5[4]; // per_page_checksum_table_offset = 0
// 0x80
LE32 data_pages_offset;
char _6[4]; // preload_page_count = 0
LE32 non_resident_name_table_offset;
LE32 non_resident_name_table_length;
// 0x90
#if 1
char _7[52];
#else
LE32 non_resident_names_checksum;
LE32 automatic_data_object;
LE32 debug_info_offset;
LE32 debug_info_length;
// 0xA0
LE32 preload_instance_pages;
LE32 demand_instance_pages;
LE32 extra_heap_alloc;
char reserved[12];
LE32 versioninfo;
LE32 unkown;
// 0xC0
LE16 device_id;
LE16 ddk_version;
#endif
};
struct le_object_table_entry_t
{
LE32 virtual_size;
LE32 base_address;
LE32 flags;
LE32 pagemap_index;
LE32 npages;
LE32 reserved;
};
struct le_pagemap_entry_t
{
upx_byte h;
upx_byte m;
upx_byte l;
upx_byte type; // 0x00-legal;0x40-iterated;0x80-invalid;0xC0-zeroed
};
virtual void readObjectTable();
virtual void writeObjectTable();
//virtual void encodeObjectTable(){oobject_table = iobject_table; iobject_table = NULL;}
//virtual void decodeObjectTable(){encodeObjectTable();}
virtual void readFixupPageTable();
virtual void writeFixupPageTable();
//virtual void encodeFixupPageTable(){ofpage_table = ifpage_table; ifpage_table = NULL;}
//virtual void decodeFixupPageTable(){encodeFixupPageTable();}
virtual void readPageMap();
virtual void writePageMap();
virtual void encodePageMap(){opm_entries = ipm_entries; ipm_entries = NULL;}
virtual void decodePageMap(){encodePageMap();}
virtual void readResidentNames();
virtual void writeResidentNames();
virtual void encodeResidentNames(){ores_names = ires_names; ires_names = NULL;}
virtual void decodeResidentNames(){encodeResidentNames();}
virtual void readNonResidentNames();
virtual void writeNonResidentNames();
virtual void encodeNonResidentNames(){ononres_names = inonres_names; inonres_names = NULL;}
virtual void decodeNonResidentNames(){encodeNonResidentNames();}
virtual void readEntryTable();
virtual void writeEntryTable();
//virtual void encodeEntryTable(){oentries = ientries; ientries = NULL;}
//virtual void decodeEntryTable(){encodeEntryTable();}
virtual void readFixups();
virtual void writeFixups();
//virtual void encodeFixups(){ofixups = ifixups; ifixups = NULL;}
//virtual void decodeFixups(){encodeFixups();}
virtual void readImage();
virtual void writeImage();
//virtual void encodeImage(){oimage = iimage; iimage = NULL;}
//virtual void decodeImage(){encodeImage();}
void countFixups(unsigned *) const;
InputFile *fif;
OutputFile *fof;
long le_offset;
long exe_offset;
le_header_t ih;
le_header_t oh;
le_object_table_entry_t *iobject_table;
le_object_table_entry_t *oobject_table;
unsigned *ifpage_table;
unsigned *ofpage_table;
le_pagemap_entry_t *ipm_entries;
le_pagemap_entry_t *opm_entries;
upx_byte *ires_names;
upx_byte *ores_names;
upx_byte *ifixups;
upx_byte *ofixups;
upx_byte *inonres_names;
upx_byte *ononres_names;
MemBuffer iimage;
MemBuffer oimage;
upx_byte *ientries;
upx_byte *oentries;
unsigned soobject_table;
unsigned sofpage_table;
unsigned sopm_entries;
unsigned sores_names;
unsigned sofixups;
unsigned sononres_names;
unsigned soimage;
unsigned soentries;
};
#endif /* already included */
/*
vi:ts=4:et
*/

204
src/linker.cpp Normal file
View File

@ -0,0 +1,204 @@
/* linker.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "linker.h"
struct Linker::section
{
int istart;
int ostart;
int len;
char name[8];
};
struct Linker::jump
{
int pos;
int len;
char tsect[8];
int toffs;
};
Linker::Linker(const void *pdata, int plen, int pinfo)
{
iloader = new char[(ilen = plen) + 4096];
memcpy(iloader,pdata,plen);
oloader = new char[plen];
olen = 0;
align_hack = 0;
info = pinfo;
njumps = nsections = frozen = 0;
jumps = new jump [200];
sections = new section[200];
char *p = iloader + info;
while (get_le32(p) != (unsigned)(-1))
{
if (get_le32(p))
{
memcpy(sections[nsections].name,p,8);
sections[nsections].istart = get_le32(p+8);
sections[nsections++].ostart = -1;
p += 12;
assert(nsections < 200);
}
else
{
int l;
for (l = get_le32(p+4) - 1; iloader[l] == 0; l--)
;
jumps[njumps].pos = l+1;
jumps[njumps].len = get_le32(p+4)-jumps[njumps].pos;
memcpy(jumps[njumps].tsect,p+8,8);
jumps[njumps++].toffs = get_le32(p+16);
p += 20;
assert(njumps < 200);
}
}
int ic;
for (ic = 0; ic < nsections - 1; ic++)
sections[ic].len = sections[ic+1].istart - sections[ic].istart;
sections[ic].len = 0;
}
Linker::~Linker()
{
delete [] iloader;
delete [] oloader;
delete [] jumps;
delete [] sections;
}
void Linker::addSection(const char *sect)
{
int ic;
while (*sect)
{
if (*sect == '+') // alignment
{
if (sect[1] == '0')
align_hack = olen;
else
{
ic = (sect[1] & 0xf) + (sect[1] > '9' ? 9 : 0);
ic = (ic + (sect[2] & 0xf) + (sect[2] > '9' ? 9 : 0)
- (olen - align_hack) % ic) % ic;
memset(oloader+olen,sect[3] == 'C' ? 0x90 : 0,ic);
olen += ic;
}
}
else
{
for (ic = 0; ic < nsections; ic++)
if (memcmp(sect,sections[ic].name,8) == 0)
{
memcpy(oloader+olen,iloader+sections[ic].istart,sections[ic].len);
sections[ic].ostart = olen;
olen += sections[ic].len;
break;
}
//printf("%8.8s",section);
assert(ic!=nsections);
}
sect += 8;
}
}
void Linker::addSection(const char *sname, const void *sdata, unsigned len)
{
// add a new section - can be used for adding stuff like ident or header
memcpy(sections[nsections].name,sname,8);
sections[nsections].istart = ilen;
sections[nsections].len = len;
sections[nsections++].ostart = olen;
assert(nsections < 200);
memcpy(iloader+ilen,sdata,len);
ilen += len;
}
const char *Linker::getLoader(int *llen)
{
if (!frozen)
{
int ic,jc,kc;
for (ic = 0; ic < njumps; ic++)
{
for (jc = 0; jc < nsections-1; jc++)
if (jumps[ic].pos >= sections[jc].istart
&& jumps[ic].pos < sections[jc+1].istart)
break;
assert(jc!=nsections-1);
if (sections[jc].ostart < 0)
continue;
for (kc = 0; kc < nsections-1; kc++)
if (memcmp(jumps[ic].tsect,sections[kc].name,8) == 0)
break;
assert(kc!=nsections-1);
int offs = sections[kc].ostart+jumps[ic].toffs -
(jumps[ic].pos+jumps[ic].len -
sections[jc].istart+sections[jc].ostart);
set_le32(&offs,offs);
memcpy(oloader+sections[jc].ostart+jumps[ic].pos-sections[jc].istart,&offs,jumps[ic].len);
}
frozen=1;
}
if (llen) *llen = olen;
return oloader;
}
int Linker::getSection(const char *name, int *slen) const
{
if (!frozen)
return -1;
for (int ic = 0; ic < nsections; ic++)
if (memcmp(name,sections[ic].name,8) == 0)
{
if (slen)
*slen = sections[ic].len;
return sections[ic].ostart;
}
return -1;
}
/*
vi:ts=4:et
*/

65
src/linker.h Normal file
View File

@ -0,0 +1,65 @@
/* linker.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_LINKER_H
#define __UPX_LINKER_H
class Linker
{
public:
Linker(const void *pdata, int plen, int pinfo);
~Linker();
void addSection(const char *sect);
void addSection(const char *sname, const void *sdata, unsigned len);
const char *getLoader(int *llen);
int getSection(const char *name, int *slen) const;
private:
struct section;
struct jump;
char *iloader, *oloader;
int ilen, olen;
int info;
jump *jumps;
int njumps;
section *sections;
int nsections;
int frozen;
int align_hack;
};
#endif /* already included */
/*
vi:ts=4:et
*/

1134
src/main.cpp Normal file

File diff suppressed because it is too large Load Diff

115
src/mem.cpp Normal file
View File

@ -0,0 +1,115 @@
/* mem.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "mem.h"
/*************************************************************************
//
**************************************************************************/
MemBuffer::MemBuffer(unsigned size=0) :
ptr(NULL), alloc_ptr(NULL), alloc_size(0)
{
if (size > 0)
alloc(size, 0);
}
MemBuffer::~MemBuffer()
{
free();
}
void MemBuffer::free()
{
if (alloc_ptr)
::free(alloc_ptr);
alloc_ptr = ptr = NULL;
alloc_size = 0;
}
unsigned MemBuffer::getSize() const
{
if (!alloc_ptr)
return 0;
unsigned size = alloc_size - (ptr - alloc_ptr);
assert((int)size > 0);
return size;
}
void MemBuffer::alloc(unsigned size, unsigned base_offset)
{
assert(alloc_ptr == NULL);
//free();
assert((int)size > 0);
size = base_offset + size;
alloc_ptr = (unsigned char *) malloc(size);
if (!alloc_ptr)
{
throwCantPack("out of memory");
//exit(1);
}
alloc_size = size;
ptr = alloc_ptr + base_offset;
}
void MemBuffer::alloc(unsigned size)
{
alloc(size, 0);
}
void MemBuffer::allocForCompression(unsigned uncompressed_size)
{
// Idea:
// We allocate the buffer at an offset of 4096 so
// that we could do an in-place decompression for
// verifying our overlap overhead at the end
// of packing.
//
// See Packer::verifyOverlappingDecompression().
alloc(uncompressed_size + uncompressed_size/8 + 256, MAX_OVERLAP_OVERHEAD);
}
void MemBuffer::allocForUncompression(unsigned uncompressed_size)
{
alloc(uncompressed_size + 512, 0); // 512 safety bytes
}
/*
vi:ts=4:et
*/

82
src/mem.h Normal file
View File

@ -0,0 +1,82 @@
/* mem.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_MEM_H
#define __UPX_MEM_H
/*************************************************************************
//
**************************************************************************/
class MemBuffer
{
public:
MemBuffer(unsigned size=0);
~MemBuffer();
void alloc(unsigned size);
void allocForCompression(unsigned uncompressed_size);
void allocForUncompression(unsigned uncompressed_size);
void free();
const unsigned char *getBuf() const { return ptr; }
unsigned getSize() const ;
operator unsigned char * () { return ptr; }
//operator const unsigned char * () const { return ptr; }
enum { MAX_OVERLAP_OVERHEAD = 4096 };
private:
void alloc(unsigned size, unsigned base_offset);
unsigned char *ptr;
unsigned char *alloc_ptr;
unsigned alloc_size;
private:
// disable copy and assignment
MemBuffer(MemBuffer const &); // {}
MemBuffer& operator= (MemBuffer const &); // { return *this; }
// disable dynamic allocation
static void *operator new (size_t); // {}
static void *operator new[] (size_t); // {}
//static void operator delete (void *) {}
//static void operator delete[] (void *) {}
};
#endif /* already included */
/*
vi:ts=4:et
*/

10
src/merge.sh Normal file
View File

@ -0,0 +1,10 @@
#!/bin/bash
set -x
for i in *.h *.cpp
do
diff3 -m ./$i ../../upx-ancestor/src/$i ../../upx-1.10/src/$i > tmp.$$
mv tmp.$$ ./$i
read junk
done

232
src/msg.cpp Normal file
View File

@ -0,0 +1,232 @@
/* msg.cpp -- info and error messages
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
/*************************************************************************
// FIXME: if stdout is redirected to a file and stderr is not, should
// we write all error messages to both stderr and stdout ?
**************************************************************************/
static int pr_need_nl = 0;
void printSetNl(int need_nl)
{
pr_need_nl = need_nl;
}
void printClearLine(FILE *f)
{
static char clear_line_msg[1+79+1+1];
if (!clear_line_msg[0])
{
char *msg = clear_line_msg;
msg[0] = '\r';
memset(msg+1,' ',79);
msg[80] = '\r';
msg[81] = 0;
}
fflush(stdout); fflush(stderr);
if (f == NULL)
f = stdout;
con_fprintf(f,clear_line_msg);
fflush(f);
printSetNl(0);
}
static void pr_print(bool c, const char *msg)
{
if (c && !opt->to_stdout)
con_fprintf(stderr,msg);
else
fprintf(stderr,msg);
}
static void pr_error(const char *iname, const char *msg, bool is_warning)
{
set_ec(EXIT_ERROR);
fflush(stdout); fflush(stderr);
char buf[1024];
buf[0] = 0;
if (pr_need_nl == 2)
printClearLine(stdout);
else if (pr_need_nl)
{
buf[0] = '\n';
buf[1] = 0;
printSetNl(0);
}
// This hack is needed, otherwise error messages may get lost
// when the cursor is not yet at the bottom of the screen.
// At least I can use some colors then...
bool c = isatty(STDERR_FILENO) ? 1 : 0;
int fg = con_fg(stderr,FG_BRTRED);
upx_snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),"%s: ", progname);
pr_print(c,buf);
//(void)con_fg(stderr,FG_RED);
upx_snprintf(buf,sizeof(buf),"%s: ", iname);
pr_print(c,buf);
//(void)con_fg(stderr,FG_BRTRED);
pr_print(c,msg);
pr_print(c,"\n");
fflush(stdout); fflush(stderr);
fg = con_fg(stderr,fg);
UNUSED(is_warning);
}
void printErr(const char *iname, const Throwable *e)
{
char buf[1024];
upx_snprintf(buf, sizeof(buf), "%s", prettyName(typeid(*e)));
if (e->getMsg())
upx_snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),": %s", e->getMsg());
if (e->getErrno())
upx_snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),": %s", strerror(e->getErrno()));
pr_error(iname,buf,e->isWarning());
}
void printErr(const char *iname, const char *format, ...)
{
va_list args;
char buf[1024];
va_start(args,format);
upx_vsnprintf(buf,sizeof(buf),format,args);
va_end(args);
pr_error(iname,buf,false);
}
void printWarn(const char *iname, const char *format, ...)
{
va_list args;
char buf[1024];
va_start(args,format);
upx_vsnprintf(buf,sizeof(buf),format,args);
va_end(args);
pr_error(iname,buf,true);
}
/*************************************************************************
// FIXME: should use colors and a consistent layout here
**************************************************************************/
static int info_header = 0;
static void info_print(const char *msg)
{
if (opt->info_mode <= 0)
return;
FILE *f = opt->to_stdout ? stderr : stdout;
if (pr_need_nl)
{
printClearLine(f);
con_fprintf(f,"%s\n",msg);
}
else if (pr_need_nl)
con_fprintf(f,"\n%s\n",msg);
else
con_fprintf(f,"%s\n",msg);
fflush(f);
printSetNl(0);
}
void infoHeader()
{
info_header = 0;
}
void infoHeader(const char *format, ...)
{
if (opt->info_mode <= 0)
return;
va_list args;
char buf[1024];
va_start(args,format);
upx_vsnprintf(buf,sizeof(buf),format,args);
va_end(args);
info_print(buf);
info_header = 1;
}
void info(const char *format, ...)
{
if (opt->info_mode <= 0)
return;
va_list args;
char buf[1024];
const int n = 4 * info_header;
memset(buf, ' ', n);
va_start(args,format);
upx_vsnprintf(buf+n,sizeof(buf)-n,format,args);
va_end(args);
info_print(buf);
}
void infoWarning(const char *format, ...)
{
if (opt->info_mode <= 0)
return;
va_list args;
char buf[1024];
va_start(args,format);
upx_vsnprintf(buf,sizeof(buf),format,args);
va_end(args);
info("[WARNING] %s\n", buf);
}
void infoWriting(const char *what, long size)
{
if (opt->info_mode <= 0)
return;
info("Writing %s: %ld bytes", what, size);
}
/*
vi:ts=4:et:nowrap
*/

696
src/mygetopt.cpp Normal file
View File

@ -0,0 +1,696 @@
/* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
before changing it!
Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, 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; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "tailor.h"
#ifndef EOF
#include <stdio.h>
#include <string.h>
#endif
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
long-named option. Because this is not POSIX.2 compliant, it is
being phased out. */
/* #define GETOPT_COMPAT */
#undef GETOPT_COMPAT
/* This version of `getopt' appears to the caller like standard Unix `getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of ARGV so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable POSIXLY_CORRECT disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
#include "mygetopt.h"
#define option mfx_option
#define optarg mfx_optarg
#define optind mfx_optind
#define opterr mfx_opterr
#define optopt mfx_optopt
#define my_index strchr
#define my_strlen strlen
#undef BAD_OPTION
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = NULL;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* XXX 1003.2 says this must be 1 before any call. */
int optind = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Set to an option character which was unrecognized.
This must be initialized on some systems to avoid linking in the
system's own getopt implementation. */
#define BAD_OPTION '\0'
int optopt = BAD_OPTION;
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
POSIXLY_CORRECT is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIXLY_CORRECT, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
static int first_nonopt;
static int last_nonopt;
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved.
To perform the swap, we first reverse the order of all elements. So
all options now come before all non options, but they are in the
wrong order. So we put back the options and non options in original
order by reversing them again. For example:
original input: a b c -x -y
reverse all: -y -x c b a
reverse options: -x -y c b a
reverse non options: -x -y a b c
*/
static void exchange (char **argv)
{
char *temp, **first, **last;
/* Reverse all the elements [first_nonopt, optind) */
first = &argv[first_nonopt];
last = &argv[optind-1];
while (first < last) {
temp = *first; *first = *last; *last = temp; first++; last--;
}
/* Put back the options in order */
first = &argv[first_nonopt];
first_nonopt += (optind - last_nonopt);
last = &argv[first_nonopt - 1];
while (first < last) {
temp = *first; *first = *last; *last = temp; first++; last--;
}
/* Put back the non options in order */
first = &argv[first_nonopt];
last_nonopt = optind;
last = &argv[last_nonopt-1];
while (first < last) {
temp = *first; *first = *last; *last = temp; first++; last--;
}
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns `EOF'.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return BAD_OPTION after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return BAD_OPTION.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.
LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */
static int _getopt_internal (int argc, char **argv, const char *optstring,
const struct option *longopts, int *longind,
int long_only)
{
static char empty_string[1];
int option_index;
if (longind != NULL)
*longind = -1;
optarg = 0;
/* Initialize the internal data when the first call is made.
Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
if (optind == 0)
{
first_nonopt = last_nonopt = optind = 1;
nextchar = NULL;
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
#if 0
else if (getenv ("POSIXLY_CORRECT") != NULL)
ordering = REQUIRE_ORDER;
#endif
else
ordering = PERMUTE;
}
if (nextchar == NULL || *nextchar == '\0')
{
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange (argv);
else if (last_nonopt != optind)
first_nonopt = optind;
/* Now skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc
&& (argv[optind][0] != '-' || argv[optind][1] == '\0')
#ifdef GETOPT_COMPAT
&& (longopts == NULL
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
#endif /* GETOPT_COMPAT */
)
optind++;
last_nonopt = optind;
}
/* Special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange (argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return EOF;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
#ifdef GETOPT_COMPAT
&& (longopts == NULL
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
#endif /* GETOPT_COMPAT */
)
{
if (ordering == REQUIRE_ORDER)
return EOF;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Start decoding its characters. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
if (longopts != NULL
&& ((argv[optind][0] == '-'
&& (argv[optind][1] == '-' || long_only))
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
#endif /* GETOPT_COMPAT */
))
{
const struct option *p;
char *s = nextchar;
int exact = 0;
int ambig = 0;
const struct option *pfound = NULL;
int indfound = 0;
int needexact = 0;
#if defined(DOSISH)
/* allow `--option#value' because you cannout assign a '='
to an environment variable under DOS command.com */
while (*s && *s != '=' && * s != '#')
s++;
#else
while (*s && *s != '=')
s++;
#endif
/* Test all options for either exact match or abbreviated matches. */
for (p = longopts, option_index = 0; p->name;
p++, option_index++)
if (!strncmp (p->name, nextchar, (unsigned) (s - nextchar)))
{
if (p->has_arg & 0x10)
needexact = 1;
if ((unsigned) (s - nextchar) == my_strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second nonexact match found. */
ambig = 1;
}
/* don't allow nonexact longoptions */
if (needexact && !exact)
{
if (opterr)
fprintf (stderr, "%s: unrecognized option `%s'\n",
argv[0], argv[optind]);
nextchar += my_strlen (nextchar);
optind++;
return BAD_OPTION;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, "%s: option `%s' is ambiguous\n",
argv[0], argv[optind]);
nextchar += my_strlen (nextchar);
optind++;
return BAD_OPTION;
}
if (pfound != NULL)
{
int have_arg = (s[0] != '\0');
if (have_arg && (pfound->has_arg & 0xf))
have_arg = (s[1] != '\0');
option_index = indfound;
optind++;
if (have_arg)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg & 0xf)
optarg = s + 1;
else
{
if (opterr)
{
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
"%s: option `--%s' doesn't allow an argument\n",
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
"%s: option `%c%s' doesn't allow an argument\n",
argv[0], argv[optind - 1][0], pfound->name);
}
nextchar += my_strlen (nextchar);
return BAD_OPTION;
}
}
else if ((pfound->has_arg & 0xf) == 1)
{
#if 0
if (optind < argc)
#else
if (optind < argc && (pfound->has_arg & 0x20) == 0)
#endif
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr, "%s: option `--%s%s' requires an argument\n",
argv[0], pfound->name,
(pfound->has_arg & 0x20) ? "=" : "");
nextchar += my_strlen (nextchar);
return optstring[0] == ':' ? ':' : BAD_OPTION;
}
}
nextchar += my_strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
#ifdef GETOPT_COMPAT
|| argv[optind][0] == '+'
#endif /* GETOPT_COMPAT */
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, "%s: unrecognized option `--%s'\n",
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
argv[0], argv[optind][0], nextchar);
}
nextchar = empty_string;
optind++;
return BAD_OPTION;
}
ambig = ambig;
}
/* Look at and handle the next option-character. */
{
char c = *nextchar++;
char *temp = my_index (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*nextchar == '\0')
++optind;
if (temp == NULL || c == ':')
{
if (opterr)
{
#if 0
if (c < 040 || c >= 0177)
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
argv[0], c);
else
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
#else
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
#endif
}
optopt = c;
return BAD_OPTION;
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = 0;
nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
{
#if 0
fprintf (stderr, "%s: option `-%c' requires an argument\n",
argv[0], c);
#else
/* 1003.2 specifies the format of this message. */
fprintf (stderr, "%s: option requires an argument -- %c\n",
argv[0], c);
#endif
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = BAD_OPTION;
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}
int mfx_getopt(int argc, char **argv, const char *optstring)
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}
int mfx_getopt_long(int argc, char **argv, const char *options,
const struct option *long_options, int *opt_index)
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of `getopt'. */
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
if (c == EOF)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case BAD_OPTION:
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

102
src/mygetopt.h Normal file
View File

@ -0,0 +1,102 @@
/* Declarations for getopt.
Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, 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; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef __MFX_GETOPT_H
#define __MFX_GETOPT_H 1
#ifdef __cplusplus
//extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *mfx_optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns EOF, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int mfx_optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int mfx_opterr;
/* Set to an option character which was unrecognized. */
extern int mfx_optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct mfx_option
{
const char *name;
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define mfx_no_argument 0
#define mfx_required_argument 1
#define mfx_optional_argument 2
#define mfx_exact_argument 0x10 /* no abbrev. */
int mfx_getopt(int argc, char **argv, const char *shortopts);
int mfx_getopt_long(int argc, char **argv, const char *shortopts,
const struct mfx_option *longopts, int *longind);
#ifdef __cplusplus
//}
#endif
#endif /* _GETOPT_H */

268
src/p_com.cpp Normal file
View File

@ -0,0 +1,268 @@
/* p_com.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "filter.h"
#include "packer.h"
#include "p_com.h"
static const
#include "stub/l_com.h"
#define STACKSIZE 0x60
//#define TESTING
/*************************************************************************
//
**************************************************************************/
int PackCom::getCompressionMethod() const
{
if (M_IS_NRV2B(opt->method))
return M_NRV2B_LE16;
#if 0
// NOT IMPLEMENTED
if (M_IS_NRV2D(opt->method))
return M_NRV2D_LE16;
#endif
return M_NRV2B_LE16;
}
const int *PackCom::getFilters() const
{
static const int filters[] = { 0x06, 0x03, 0x04, 0x01, 0x05, 0x02, -1 };
return filters;
}
/*************************************************************************
//
**************************************************************************/
bool PackCom::canPack()
{
unsigned char buf[128];
fi->readx(buf,128);
if (memcmp(buf,"MZ",2) == 0 || memcmp(buf,"ZM",2) == 0 // .exe
|| memcmp (buf,"\xff\xff\xff\xff",4) == 0) // .sys
return false;
if (!fn_has_ext(fi->getName(),"com"))
return false;
if (find_le32(buf,128,UPX_MAGIC_LE32))
throwAlreadyPacked();
if (file_size < 1024)
throwCantPack("file is too small");
if (file_size > 0xFF00)
throwCantPack("file is too big for dos/com");
return true;
}
/*************************************************************************
//
**************************************************************************/
void PackCom::patchLoader(OutputFile *fo,
upx_byte *loader, int lsize,
unsigned calls, unsigned overlapoh)
{
const int filter_id = ph.filter;
const int e_len = getLoaderSection("COMCUTPO");
const int d_len = lsize - e_len;
assert(e_len > 0 && e_len < 256);
assert(d_len > 0 && d_len < 256);
const unsigned upper_end = ph.u_len + overlapoh + d_len + 0x100;
if (upper_end + STACKSIZE > 0xfffe)
throwNotCompressible();
if (filter_id)
{
assert(calls > 0);
patch_le16(loader,lsize,"CT",calls);
}
// NOTE: Depends on: decompr_start == cutpoint+1 !!!
patch_le16(loader,e_len,"JM",upper_end - 0xff - d_len - getLoaderSection("UPX1HEAD"));
loader[getLoaderSection("COMSUBSI") - 1] = (upx_byte) -e_len;
patch_le16(loader,e_len,"DI",upper_end);
patch_le16(loader,e_len,"SI",ph.c_len + lsize + 0x100);
patch_le16(loader,e_len,"CX",ph.c_len + lsize);
patch_le16(loader,e_len,"SP",upper_end + STACKSIZE);
// write loader + compressed file
fo->write(loader,e_len); // entry
fo->write(obuf,ph.c_len);
fo->write(loader+e_len,d_len); // decompressor
}
int PackCom::buildLoader(const Filter *ft)
{
const int filter_id = ft->id;
initLoader(nrv2b_loader,sizeof(nrv2b_loader));
addLoader("COMMAIN1""COMSUBSI",
filter_id ? "COMCALLT" : "",
"COMMAIN2""UPX1HEAD""COMCUTPO""NRV2B160",
filter_id ? "NRVDDONE" : "NRVDRETU",
"NRVDECO1",
ph.max_offset_found <= 0xd00 ? "NRVLED00" : "NRVGTD00",
"NRVDECO2""NRV2B169",
NULL
);
if (filter_id)
addFilter16(filter_id);
return getLoaderSize();
}
void PackCom::addFilter16(int filter_id)
{
assert(filter_id > 0);
assert(isValidFilter(filter_id));
if (filter_id % 3 == 0)
addLoader("CALLTR16",
filter_id < 4 ? "CT16SUB0" : "",
filter_id < 4 ? "" : (opt->cpu == opt->CPU_8086 ? "CT16I086" : "CT16I286""CT16SUB0"),
"CALLTRI2",
getFormat() == UPX_F_DOS_COM ? "CORETURN" : "",
NULL
);
else
addLoader(filter_id%3 == 1 ? "CT16E800" : "CT16E900",
"CALLTRI5",
getFormat() == UPX_F_DOS_COM ? "CT16JEND" : "CT16JUL2",
filter_id < 4 ? "CT16SUB1" : "",
filter_id < 4 ? "" : (opt->cpu == opt->CPU_8086 ? "CT16I087" : "CT16I287""CT16SUB1"),
"CALLTRI6",
NULL
);
}
/*************************************************************************
//
**************************************************************************/
void PackCom::pack(OutputFile *fo)
{
// read file
ibuf.alloc(file_size);
obuf.allocForCompression(file_size);
fi->seek(0,SEEK_SET);
fi->readx(ibuf,file_size);
// prepare packheader
ph.u_len = file_size;
ph.filter = 0;
// prepare filter
Filter ft(opt->level);
ft.addvalue = getCallTrickOffset();
// prepare other settings
const unsigned overlap_range = ph.u_len < 0xFE00 - ft.addvalue ? 32 : 0;
unsigned overlapoh;
int strategy = -1; // try the first working filter
if (opt->filter >= 0 && isValidFilter(opt->filter))
// try opt->filter or 0 if that fails
strategy = -2;
else if (opt->all_filters || opt->level > 9)
// choose best from all available filters
strategy = 0;
else if (opt->level == 9)
// choose best from the first 4 filters
strategy = 4;
compressWithFilters(&ft, &overlapoh, overlap_range, strategy);
const int lsize = getLoaderSize();
MemBuffer loader(lsize);
memcpy(loader,getLoader(),lsize);
putPackHeader(loader,lsize);
const unsigned calls = ft.id % 3 ? ft.lastcall - 2 * ft.calls : ft.calls;
patchLoader(fo, loader, lsize, calls, overlapoh);
// verify
verifyOverlappingDecompression(&obuf, overlapoh);
}
/*************************************************************************
//
**************************************************************************/
bool PackCom::canUnpack()
{
if (!readPackHeader(128, 0))
return false;
if (file_size <= (off_t) ph.c_len)
return false;
return true;
}
/*************************************************************************
//
**************************************************************************/
void PackCom::unpack(OutputFile *fo)
{
ibuf.alloc(file_size);
obuf.allocForUncompression(ph.u_len);
// read whole file
fi->seek(0,SEEK_SET);
fi->readx(ibuf,file_size);
// get compressed data offset
int e_len = ph.buf_offset + ph.getPackHeaderSize();
if (file_size <= e_len + (off_t)ph.c_len)
throwCantUnpack("file damaged");
// decompress
decompress(ibuf+e_len,obuf);
// unfilter
Filter ft(ph.level);
ft.init(ph.filter, getCallTrickOffset());
ft.unfilter(obuf,ph.u_len);
// write decompressed file
if (fo)
fo->write(obuf,ph.u_len);
}
/*
vi:ts=4:et
*/

69
src/p_com.h Normal file
View File

@ -0,0 +1,69 @@
/* p_com.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_COM_H
#define __UPX_P_COM_H
/*************************************************************************
// dos/com
**************************************************************************/
class PackCom : public Packer
{
typedef Packer super;
public:
PackCom(InputFile *f) : super(f) { }
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_DOS_COM; }
virtual const char *getName() const { return "dos/com"; }
virtual int getCompressionMethod() const;
virtual const int *getFilters() const;
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canPack();
virtual bool canUnpack();
protected:
virtual const unsigned getCallTrickOffset() const { return 0x100; }
protected:
virtual int buildLoader(const Filter *ft);
virtual void patchLoader(OutputFile *fo, upx_byte *, int, unsigned, unsigned);
virtual void addFilter16(int filter_id);
};
#endif /* already included */
/*
vi:ts=4:et
*/

433
src/p_djgpp2.cpp Normal file
View File

@ -0,0 +1,433 @@
/* p_djgpp2.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "filter.h"
#include "packer.h"
#include "p_djgpp2.h"
static const unsigned char stubify_stub[] = {
#include "stub/stubify.h"
};
static const
#include "stub/l_djgpp2.h"
/*************************************************************************
//
**************************************************************************/
PackDjgpp2::PackDjgpp2(InputFile *f) :
super(f), coff_offset(0)
{
assert(sizeof(coff_hdr) == 0xa8);
assert(sizeof(stubify_stub) == 2048);
}
int PackDjgpp2::getCompressionMethod() const
{
if (M_IS_NRV2B(opt->method))
return M_NRV2B_LE32;
if (M_IS_NRV2D(opt->method))
return M_NRV2D_LE32;
return opt->level > 1 && file_size >= 512*1024 ? M_NRV2D_LE32 : M_NRV2B_LE32;
}
const int *PackDjgpp2::getFilters() const
{
static const int filters[] = { 0x26, 0x24, 0x11, 0x14, 0x13, 0x16,
0x25, 0x15, 0x12, -1 };
return filters;
}
int PackDjgpp2::buildLoader(const Filter *ft)
{
// prepare loader
initLoader(nrv_loader,sizeof(nrv_loader));
addLoader("IDENTSTR""DJ2MAIN1",
ft->id ? "DJCALLT1" : "",
"DJ2MAIN2",
getDecompressor(),
"DJ2BSS00",
NULL
);
if (ft->id)
{
addLoader("DJCALLT2",NULL);
addFilter32(ft->id);
}
addLoader("DJRETURN+40DXXXXUPX1HEAD",NULL);
return getLoaderSize();
}
/*************************************************************************
// util
**************************************************************************/
void PackDjgpp2::handleStub(OutputFile *fo)
{
if (fo && !opt->djgpp2.coff)
{
if (coff_offset > 0)
{
// copy stub from exe
Packer::handleStub(fi,fo,coff_offset);
}
else
{
// "stubify" stub
info("Adding stub: %ld bytes", (long)sizeof(stubify_stub));
fo->write(stubify_stub,sizeof(stubify_stub));
}
}
}
static bool is_dlm(InputFile *fi,long coff_offset)
{
unsigned char buf[4];
long off;
try {
fi->seek(coff_offset,SEEK_SET);
fi->readx(buf,4);
off = get_le32(buf);
if (off < 0 || off > coff_offset + 4)
return false;
fi->seek(off,SEEK_SET);
fi->readx(buf,4);
if (memcmp(buf,"DLMF",4) == 0)
return true;
} catch (IOException&) {
}
return false;
}
static void handle_allegropak(InputFile *fi,OutputFile *fo)
{
unsigned char buf[0x4000];
unsigned pfsize=0, ic;
try {
fi->seek(-8,SEEK_END);
fi->readx(buf,8);
if (memcmp(buf,"slh+",4) != 0)
return;
pfsize = get_be32(buf+4);
fi->seek(-(off_t)pfsize,SEEK_END);
} catch (IOException&) {
return;
}
while (pfsize)
{
ic = pfsize < sizeof(buf) ? pfsize : sizeof(buf);
fi->readx(buf,ic);
fo->write(buf,ic);
pfsize -= ic;
}
}
bool PackDjgpp2::readFileHeader()
{
unsigned char hdr[0x1c];
unsigned char magic[8];
fi->seek(0,SEEK_SET);
fi->readx(hdr,sizeof(hdr));
if (get_le16(hdr) == 0x5a4d) // MZ exe signature, stubbed?
{
coff_offset = 512 * get_le16(hdr+4);
if (get_le16(hdr+2) != 0)
coff_offset += get_le16(hdr+2) - 512;
fi->seek(512,SEEK_SET);
fi->readx(magic,8);
if (memcmp("go32stub",magic,8) != 0)
return false; // not V2 image
fi->seek(coff_offset,SEEK_SET);
if (fi->read(&coff_hdr,sizeof(coff_hdr)) != sizeof(coff_hdr))
throwCantPack("skipping djgpp symlink");
}
else
{
fi->seek(coff_offset,SEEK_SET);
fi->readx(&coff_hdr,0xa8);
}
if (coff_hdr.f_magic != 0x014c) // I386MAGIC
return false;
if ((coff_hdr.f_flags & 2) == 0) // F_EXEC - COFF executable
return false;
if (coff_hdr.a_magic != 0413) // ZMAGIC - demand load format
return false;
// FIXME: check for Linux etc.
text = coff_hdr.sh;
data = text + 1;
bss = data + 1;
return true;
}
// "strip" debug info
void PackDjgpp2::stripDebug()
{
coff_hdr.f_symptr = 0;
coff_hdr.f_nsyms = 0;
coff_hdr.f_flags = 0x10f; // 0x100: "32 bit machine: LSB first"
memset(text->misc,0,12);
}
/*************************************************************************
//
**************************************************************************/
bool PackDjgpp2::canPack()
{
if (!readFileHeader())
return false;
if (is_dlm(fi,coff_offset))
throwCantPack("can't handle DLM");
if (opt->force == 0)
if (text->size != coff_hdr.a_tsize || data->size != coff_hdr.a_dsize)
throwAlreadyPacked();
if (text->vaddr + text->size != data->vaddr
|| data->vaddr + data->size != bss->vaddr)
{
if (text->vaddr + text->size < data->vaddr &&
data->vaddr - text->vaddr == data->scnptr - text->scnptr)
{
// This hack is needed to compress Quake 1!
text->size = coff_hdr.a_tsize = data->vaddr - text->vaddr;
}
else
throwAlreadyPacked();
}
// FIXME: check for Linux etc.
return true;
}
/*************************************************************************
//
**************************************************************************/
void PackDjgpp2::pack(OutputFile *fo)
{
handleStub(fo);
// patch coff header #1: "strip" debug info
stripDebug();
// read file
const unsigned size = text->size + data->size;
const unsigned tpos = text->scnptr;
const unsigned usize = size + (tpos & 0x1ff);
const unsigned hdrsize = 20 + 28 + (40 * coff_hdr.f_nscns);
if (hdrsize < sizeof(coff_hdr) || hdrsize > tpos)
throwCantPack("coff header error");
ibuf.alloc(usize);
obuf.allocForCompression(usize);
fi->seek(coff_offset,SEEK_SET);
fi->readx(ibuf,hdrsize); // orig. coff header
memset(ibuf + hdrsize, 0, tpos - hdrsize);
fi->seek(coff_offset+tpos,SEEK_SET);
fi->readx(ibuf + (tpos & 0x1ff),size);
#if 0
// filter
Filter ft(opt->level);
tryFilters(&ft, ibuf, usize - data->size, text->vaddr & ~0x1ff);
// compress
ph.filter = ft.id;
ph.filter_cto = ft.cto;
ph.u_len = usize;
if (!compress(ibuf,obuf))
throwNotCompressible();
unsigned overlapoh = findOverlapOverhead(obuf,ibuf,512);
overlapoh = (overlapoh + 0x3ff) & ~0x1ff;
// verify filter
ft.verifyUnfilter();
#else
// new version using compressWithFilters()
// prepare packheader
ph.u_len = usize;
ph.filter = 0;
// prepare filter
Filter ft(opt->level);
ft.buf_len = usize - data->size;
ft.addvalue = text->vaddr & ~0x1ff;
// prepare other settings
const unsigned overlap_range = 512;
unsigned overlapoh;
int strategy = -1; // try the first working filter
if (opt->filter >= 0 && isValidFilter(opt->filter))
// try opt->filter or 0 if that fails
strategy = -2;
else if (opt->all_filters)
// choose best from all available filters
strategy = 0;
compressWithFilters(&ft, &overlapoh, overlap_range, strategy);
overlapoh = (overlapoh + 0x3ff) & ~0x1ff;
#endif
// patch coff header #2
const unsigned lsize = getLoaderSize();
text->size = lsize; // new size of .text
data->size = ph.c_len; // new size of .data
if (bss->size < overlapoh) // give it a .bss
bss->size = overlapoh;
text->scnptr = sizeof(coff_hdr);
data->scnptr = text->scnptr + text->size;
data->vaddr = bss->vaddr + ((data->scnptr + data->size) & 0x1ff) - data->size + overlapoh - 0x200;
coff_hdr.f_nscns = 3;
// prepare loader
MemBuffer loader(lsize);
memcpy(loader,getLoader(),lsize);
// patch loader
putPackHeader(loader,lsize);
patch_le32(loader,lsize,"ENTR",coff_hdr.a_entry);
if (ft.id)
{
assert(ft.calls > 0);
if (ft.id > 0x20)
patch_le16(loader,lsize,"??",'?' + (ft.cto << 8));
patch_le32(loader,lsize,"TEXL",(ft.id & 0xf) % 3 == 0 ? ft.calls :
ft.lastcall - ft.calls * 4);
}
patch_le32(loader,lsize,"BSSL",overlapoh/4);
assert(bss->vaddr == ((size + 0x1ff) &~ 0x1ff) + (text->vaddr &~ 0x1ff));
patch_le32(loader,lsize,"OUTP",text->vaddr &~ 0x1ff);
patch_le32(loader,lsize,"INPP",data->vaddr);
// patch coff header #3
text->vaddr = sizeof(coff_hdr);
coff_hdr.a_entry = sizeof(coff_hdr) + getLoaderSection("DJ2MAIN1");
bss->vaddr += overlapoh;
bss->size -= overlapoh;
// because of a feature (bug?) in stub.asm we need some padding
memcpy(obuf+data->size,"UPX",3);
data->size = ALIGN_UP(data->size,4);
// write coff header, loader and compressed file
fo->write(&coff_hdr,sizeof(coff_hdr));
fo->write(loader,lsize);
fo->write(obuf,data->size);
// verify
verifyOverlappingDecompression(&obuf, overlapoh);
// handle overlay
// FIXME: only Allegro pakfiles are supported
handle_allegropak(fi,fo);
}
/*************************************************************************
//
**************************************************************************/
bool PackDjgpp2::canUnpack()
{
if (!readFileHeader())
return false;
if (is_dlm(fi,coff_offset))
throwCantUnpack("can't handle DLM");
return readPackHeader(1024, coff_offset);
}
/*************************************************************************
//
**************************************************************************/
void PackDjgpp2::unpack(OutputFile *fo)
{
handleStub(fo);
ibuf.alloc(ph.c_len);
obuf.allocForUncompression(ph.u_len);
fi->seek(coff_offset + ph.buf_offset + ph.getPackHeaderSize(),SEEK_SET);
fi->readx(ibuf,ph.c_len);
// decompress
decompress(ibuf,obuf);
// unfilter
if (ph.filter)
{
memcpy(&coff_hdr,obuf,sizeof(coff_hdr));
Filter ft(ph.level);
ft.init(ph.filter, text->vaddr &~ 0x1ff);
ft.cto = (unsigned char) ph.filter_cto;
if (ph.version < 11)
{
unsigned char ctobuf[4];
fi->readx(ctobuf, 4);
ft.cto = (unsigned char) (get_le32(ctobuf) >> 24);
}
ft.unfilter(obuf, ph.u_len - data->size);
}
// fixup for the aligning bug in strip 2.8+
text = ((coff_header_t*) (unsigned char *) obuf)->sh;
data = text + 1;
text->scnptr &= 0x1ff;
data->scnptr = text->scnptr + text->size;
// write decompressed file
if (fo)
{
fo->write(obuf,ph.u_len);
handle_allegropak(fi,fo);
}
}
/*
vi:ts=4:et
*/

107
src/p_djgpp2.h Normal file
View File

@ -0,0 +1,107 @@
/* p_djgpp2.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_DJGPP2_H
#define __UPX_P_DJGPP2_H
/*************************************************************************
// djgpp2/coff
**************************************************************************/
class PackDjgpp2 : public Packer
{
typedef Packer super;
public:
PackDjgpp2(InputFile *f);
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_DJGPP2_COFF; }
virtual const char *getName() const { return "djgpp2/coff"; }
virtual int getCompressionMethod() const;
virtual const int *getFilters() const;
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canPack();
virtual bool canUnpack();
protected:
virtual int buildLoader(const Filter *ft);
virtual void handleStub(OutputFile *fo);
long coff_offset;
struct external_scnhdr_t
{
char _[12]; // name, paddr
LE32 vaddr;
LE32 size;
LE32 scnptr;
char misc[12]; // relptr, lnnoptr, nreloc, nlnno
char __[4]; // flags
};
struct coff_header_t
{
// ext_file_hdr
LE16 f_magic;
LE16 f_nscns;
char _[4]; // f_timdat
LE32 f_symptr;
LE32 f_nsyms;
char __[2]; // f_opthdr
LE16 f_flags;
// aout_hdr
LE16 a_magic;
char ___[2]; // a_vstamp
LE32 a_tsize;
LE32 a_dsize;
char ____[4]; // a_bsize
LE32 a_entry;
char _____[8]; // a_text_start a_data_start
// section headers
external_scnhdr_t sh[3];
} coff_hdr;
external_scnhdr_t *text,*data,*bss;
bool readFileHeader();
void stripDebug();
};
#endif /* already included */
/*
vi:ts=4:et
*/

83
src/p_elf.h Normal file
View File

@ -0,0 +1,83 @@
/* p_elf.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_ELF_H
#define __UPX_P_ELF_H
/*************************************************************************
// Some ELF type definitinons
**************************************************************************/
// The ELF file header. This appears at the start of every ELF file.
struct Elf_LE32_Ehdr
{
unsigned char e_ident[16]; /* Magic number and other info */
LE16 e_type; /* Object file type */
LE16 e_machine; /* Architecture */
LE32 e_version; /* Object file version */
LE32 e_entry; /* Entry point virtual address */
LE32 e_phoff; /* Program header table file offset */
LE32 e_shoff; /* Section header table file offset */
LE32 e_flags; /* Processor-specific flags */
LE16 e_ehsize; /* ELF header size in bytes */
LE16 e_phentsize; /* Program header table entry size */
LE16 e_phnum; /* Program header table entry count */
LE16 e_shentsize; /* Section header table entry size */
LE16 e_shnum; /* Section header table entry count */
LE16 e_shstrndx; /* Section header string table index */
};
// Program segment header.
struct Elf_LE32_Phdr
{
LE32 p_type; /* Segment type */
LE32 p_offset; /* Segment file offset */
LE32 p_vaddr; /* Segment virtual address */
LE32 p_paddr; /* Segment physical address */
LE32 p_filesz; /* Segment size in file */
LE32 p_memsz; /* Segment size in memory */
LE32 p_flags; /* Segment flags */
LE32 p_align; /* Segment alignment */
};
// Values for p_type
#define PT_LOAD 1 /* Loadable program segment */
// Values for p_flags
#define PF_X (1 << 0) /* Segment is executable */
#define PF_W (1 << 1) /* Segment is writable */
#define PF_R (1 << 2) /* Segment is readable */
#endif /* already included */
/*
vi:ts=4:et
*/

658
src/p_exe.cpp Normal file
View File

@ -0,0 +1,658 @@
/* p_exe.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "filter.h"
#include "packer.h"
#include "p_exe.h"
static const
#include "stub/l_exe.h"
#define RSFCRI 4096 // reserved space for compressed relocation info
#define MAXMATCH 0x2000
#define MAXRELOCS (0x8000-MAXMATCH)
/*************************************************************************
//
**************************************************************************/
PackExe::PackExe(InputFile *f) :
super(f)
{
assert(sizeof(exe_header_t) == 32);
ih_exesize = ih_imagesize = ih_overlay = 0;
}
int PackExe::getCompressionMethod() const
{
if (M_IS_NRV2B(opt->method))
return M_NRV2B_8;
if (M_IS_NRV2D(opt->method))
return M_NRV2D_8;
return opt->level > 1 && ih_imagesize >= 300000 ? M_NRV2D_8 : M_NRV2B_8;
}
const int *PackExe::getFilters() const
{
return NULL;
}
/*************************************************************************
//
**************************************************************************/
bool PackExe::readExeHeader()
{
ih_exesize = ih_imagesize = ih_overlay = 0;
fi->readx(&ih,sizeof(ih));
if (ih.ident != 'M' + 'Z'*256 && ih.ident != 'Z' + 'M'*256)
return false;
ih_exesize = ih.m512 + ih.p512*512 - (ih.m512 ? 512 : 0);
ih_imagesize = ih_exesize - ih.headsize16*16;
ih_overlay = file_size - ih_exesize;
if (ih.m512+ih.p512*512u < sizeof (ih))
throwCantPack("illegal exe header");
if (file_size < (off_t)ih_exesize || ih_imagesize <= 0 || ih_imagesize > ih_exesize)
throwCantPack("exe header corrupted");
#if 0
printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay);
#endif
return true;
}
bool PackExe::canPack()
{
if (fn_has_ext(fi->getName(),"sys"))
return false;
if (!readExeHeader())
return false;
if (file_size < 1024)
throwCantPack("file is too small");
fi->seek(0x3c,SEEK_SET);
LE32 offs;
fi->readx(&offs,sizeof (offs));
if (ih.relocoffs >= 0x40 && offs)
{
if (opt->dos.force_stub)
opt->overlay = opt->COPY_OVERLAY;
else
throwCantPack("can't pack new-exe");
}
return true;
}
/*************************************************************************
//
**************************************************************************/
static
unsigned optimize_relocs(upx_byte *b, const unsigned size,
const upx_byte *relocs, const unsigned nrelocs,
upx_byte *crel,bool *has_9a)
{
upx_byte *crel_save = crel;
unsigned i;
unsigned seg_high = 0;
#if 0
unsigned seg_low = 0xffffffff;
unsigned off_low = 0xffffffff;
unsigned off_high = 0;
unsigned linear_low = 0xffffffff;
unsigned linear_high = 0;
#endif
// pass 1 - find 0x9a bounds
for (i = 0; i < nrelocs; i++)
{
unsigned addr = get_le32(relocs+4*i);
if (addr >= size - 1)
throwCantPack("unexpected relocation 1");
if (addr >= 3 && b[addr-3] == 0x9a)
{
unsigned seg = get_le16(b+addr);
if (seg > seg_high)
seg_high = seg;
#if 0
if (seg < seg_low)
seg_low = seg;
unsigned off = get_le16(b+addr-2);
if (off < off_low)
off_low = off;
if (off > off_high)
off_high = off;
unsigned l = (seg << 4) + off;
if (l < linear_low)
linear_low = l;
if (l > linear_high)
linear_high = l;
#endif
}
}
//printf("%d %d\n", seg_low, seg_high);
//printf("%d %d\n", off_low, off_high);
//printf("%d %d\n", linear_low, linear_high);
// pass 2 - reloc
crel += 4; // to be filled in later
unsigned ones = 0;
unsigned es = 0,di,t;
i = 0;
do
{
unsigned addr = get_le32(relocs+4*i);
set_le16(crel,di = addr & 0x0f);
set_le16(crel+2,(addr >> 4) - es);
es = addr >> 4;
crel += 4;
for (++i; i < nrelocs; i++)
{
addr = get_le32(relocs+4*i);
//printf ("%x\n",es*16+di);
if (addr - es*16 > 0xfffe)
{
// segment change
t = 1+(0xffff-di)/254;
memset(crel,1,t);
crel += t;
ones += t-1; // -1 is used to help the assembly stuff
break;
}
unsigned offs = addr - es*16;
if (offs >= 3 && b[es*16 + offs-3] == 0x9a)
{
for (t = di; t < offs-3; t++)
if (b[es*16+t] == 0x9a && get_le16(b+es*16+t+3) <= seg_high)
break;
if (t == offs-3)
{
// code 0: search for 0x9a
*crel++ = 0;
di = offs;
*has_9a = true;
continue;
}
}
t = offs - di;
if (t < 2)
throwCantPack("unexpected relocation 1");
while (t >= 256)
{
// code 1: add 254, don't reloc
*crel++ = 1;
t -= 254;
ones++;
}
*crel++ = (unsigned char) t;
di = offs;
}
} while (i < nrelocs);
*crel++ = 1;
ones++;
set_le16 (crel_save,ones);
set_le16 (crel_save+2,seg_high);
#if 0 // def TESTING
//if (opt->debug >= 3)
{
FILE *f1=fopen ("x.rel","wb");
fwrite (crel_save,crel-crel_save,1,f1);
fclose (f1);
}
#endif
return crel - crel_save;
}
/*************************************************************************
//
**************************************************************************/
void PackExe::pack(OutputFile *fo)
{
unsigned ic;
unsigned char flag = 0;
char extra_info[32];
unsigned eisize = 0;
//
const unsigned exesize = ih_exesize;
const unsigned imagesize = ih_imagesize;
const unsigned overlay = ih_overlay;
if (ih.relocs > MAXRELOCS)
throwCantPack("too many relocations");
checkOverlay(overlay);
// alloc buffers
unsigned relocsize = RSFCRI + 4*ih.relocs;
ibuf.alloc(imagesize+16+relocsize+2);
obuf.allocForCompression(imagesize+16+relocsize+2);
// read image
fi->seek(ih.headsize16*16,SEEK_SET);
fi->readx(ibuf,imagesize);
if (find_le32(ibuf,imagesize < 127 ? imagesize : 127,UPX_MAGIC_LE32))
throwAlreadyPacked();
// relocations
has_9a = false;
upx_byte *w = ibuf + imagesize;
if (ih.relocs)
{
upx_byte *wr = w + RSFCRI;
fi->seek(ih.relocoffs,SEEK_SET);
fi->readx(wr,4*ih.relocs);
for (ic = 0; ic < ih.relocs; ic++)
{
unsigned jc = get_le32(wr+4*ic);
set_le32(wr+4*ic, (jc>>16)*16+(jc&0xffff));
}
qsort(wr,ih.relocs,4,le32_compare);
relocsize = optimize_relocs(ibuf, imagesize, wr, ih.relocs, w, &has_9a);
set_le16(w+relocsize, relocsize+2);
relocsize += 2;
if (relocsize > MAXRELOCS)
throwCantPack("too many relocations");
#if 0
upx_byte out[9*relocsize/8+1024];
unsigned in_len = relocsize;
unsigned out_len = 0;
ucl_nrv2b_99_compress(w, in_len, out, &out_len, NULL, 9, NULL, NULL);
printf("reloc compress: %d -> %d\n", in_len, out_len);
#endif
}
else
{
flag |= NORELOC;
relocsize = 0;
}
ph.u_len = imagesize+relocsize;
if (!compress(ibuf,obuf,0,MAXMATCH))
throwNotCompressible();
const unsigned overlapoh = findOverlapOverhead(obuf,32);
if (ph.max_run_found + ph.max_match_found > 0x8000)
throwCantPack("decompressor limit exceeded, send a bugreport");
#ifdef TESTING
if (opt->debug)
{
printf("image+relocs %d -> %d\n",imagesize+relocsize,ph.c_len);
printf("offsets: %d - %d\nmatches: %d - %d\nruns: %d - %d\n",
ph.min_offset_found,ph.max_offset_found,
ph.min_match_found,ph.max_match_found,
ph.min_run_found,ph.max_run_found);
}
#endif
const unsigned packedsize = ph.c_len;
if (!opt->dos.no_reloc)
flag |= USEJUMP;
// fill new exe header
memset(&oh,0,sizeof(oh));
oh.ident = 'M' + 'Z' * 256;
unsigned destpara = (ph.u_len+overlapoh-packedsize+31)/16;
oh.ss = packedsize/16+destpara;
if (ih.ss*16 + ih.sp < 0x100000 && ih.ss > oh.ss && ih.sp > 0x200)
oh.ss = ih.ss;
oh.sp = ih.sp > 0x200 ? ih.sp : 0x200;
if (oh.ss*16u + 0x50 < ih.ss*16u + ih.sp
&& oh.ss*16u + 0x200 > ih.ss*16u + ih.sp)
oh.ss += 0x20;
destpara = oh.ss - packedsize/16;
if (oh.ss != ih.ss)
{
set_le16(extra_info+eisize,ih.ss);
eisize += 2;
flag |= SS;
}
if (oh.sp != ih.sp)
{
set_le16(extra_info+eisize,ih.sp);
eisize += 2;
flag |= SP;
}
#define DI_LIMIT 0xff00 // see the assembly why
// prepare loader
initLoader(nrv_loader,sizeof(nrv_loader));
addLoader("EXEENTRY",
relocsize ? "EXERELPU" : "",
"EXEMAIN4""+G5DXXXX""UPX1HEAD""EXECUTPO",
NULL
);
if (ph.method == M_NRV2B_8)
addLoader("NRV2B16S", // decompressor
ph.u_len > DI_LIMIT ? "NDIGT64K" : "",
"NRV2BEX1",
opt->cpu == opt->CPU_8086 ? "N2BX8601" : "N2B28601",
"NRV2BEX2",
opt->cpu == opt->CPU_8086 ? "N2BX8602" : "N2B28602",
"NRV2BEX3",
packedsize > 0xffff ? "NSIGT64K" : "",
"NRV2BEX9""NRV2B16E",
NULL
);
else if (ph.method == M_NRV2D_8)
addLoader("NRV2D16S",
ph.u_len > DI_LIMIT ? "NDIGT64D" : "",
"NRV2DEX1",
opt->cpu == opt->CPU_8086 ? "N2DX8601" : "N2D28601",
"NRV2DEX2",
opt->cpu == opt->CPU_8086 ? "N2DX8602" : "N2D28602",
"NRV2DEX3",
packedsize > 0xffff ? "NSIGT64D" : "",
"NRV2DEX9""NRV2D16E",
NULL
);
else
throwInternalError("unknown compression method");
addLoader("EXEMAIN5", NULL);
if (relocsize)
addLoader(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? "EXENOADJ" : "EXEADJUS",
"EXERELO1",
has_9a ? "EXEREL9A" : "",
"EXERELO2",
exesize > 0xFE00 ? "EXEREBIG" : "",
"EXERELO3",
NULL
);
addLoader("EXEMAIN8",
(flag & SS) ? "EXESTACK" : "",
(flag & SP) ? "EXESTASP" : "",
(flag & USEJUMP) ? "EXEJUMPF" : "",
NULL
);
if (!(flag & USEJUMP))
addLoader(ih.cs ? "EXERCSPO" : "",
"EXERETIP",
NULL
);
const unsigned lsize = getLoaderSize();
MemBuffer loader(lsize);
memcpy(loader,getLoader(),lsize);
//OutputFile::dump("xxloader.dat", loader, lsize);
// patch loader
putPackHeader(loader,lsize);
const unsigned e_len = getLoaderSection("EXECUTPO");
const unsigned d_len = lsize - e_len;
assert((e_len&15) == 0);
const unsigned copysize = (1+packedsize+d_len) & ~1;
const unsigned firstcopy = copysize%0x10000 ? copysize%0x10000 : 0x10000;
oh.headsize16 = 2;
oh.ip = 0;
ic = ih.min*16+imagesize;
if (ic < oh.ss*16u + oh.sp)
ic = oh.ss*16u + oh.sp;
oh.min = (ic - (packedsize + lsize)) / 16;
ic = ((unsigned) oh.min) + (ih.max - ih.min);
oh.max = ic < 0xffff && ih.max != 0xffff ? ic : 0xffff;
if (ih.min != oh.min)
{
set_le16(extra_info+eisize,ih.min);
eisize += 2;
flag |= MINMEM;
}
if (ih.max != oh.max)
{
set_le16(extra_info+eisize,ih.max);
eisize += 2;
flag |= MAXMEM;
}
putPackHeader(loader,lsize);
upx_bytep p = find_le32(loader,lsize,get_le32("IPCS"));
if (p == NULL && (flag & USEJUMP))
throwBadLoader();
if (flag & USEJUMP)
memcpy(p,&ih.ip,4);
else
{
patch_le16(loader,lsize,"IP",ih.ip);
if (ih.cs)
patch_le16(loader,lsize,"CS",ih.cs);
}
if (flag & SP)
patch_le16(loader,lsize,"SP",ih.sp);
if (flag & SS)
patch_le16(loader,lsize,"SS",ih.ss);
if (relocsize)
patch_le16(loader,lsize,"RS",(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? 0 : MAXRELOCS) - relocsize);
patch_le16(loader,e_len,"BX",0x800F + 0x10*((packedsize&15)+1) - 0x10);
patch_le16(loader,e_len,"BP",(packedsize&15)+1);
patch_le16(loader,e_len,"ES",destpara-e_len/16);
patch_le16(loader,e_len,"DS",e_len/16+(copysize-firstcopy)/16);
patch_le16(loader,e_len,"SI",firstcopy-2);
patch_le16(loader,e_len,"CX",firstcopy/2);
// finish --stub support
//if (ih.relocoffs >= 0x40 && memcmp(&ih.relocoffs,">TIPPACH",8))
// throwCantPack("FIXME");
// I use a relocation entry to set the original cs
oh.relocs = (flag & USEJUMP) ? 1 : 0;
oh.relocoffs = (char*)(&oh.firstreloc)-(char*)&oh;
oh.firstreloc = (p-loader) + packedsize + 2;
oh.firstreloc = (oh.firstreloc&0xf)+((oh.firstreloc>>4)<<16);
if (!(flag & USEJUMP))
oh.firstreloc = ih.cs*0x10000 + ih.ip;
extra_info[eisize++] = flag;
const unsigned outputlen = sizeof(oh)+lsize+packedsize+eisize;
oh.m512 = outputlen & 511;
oh.p512 = (outputlen + 511) >> 9;
//fprintf(stderr,"\ne_len=%x d_len=%x clen=%x oo=%x ulen=%x destp=%x copys=%x images=%x",e_len,d_len,packedsize,overlapoh,ph.u_len,destpara,copysize,imagesize);
// write header + write loader + compressed file
#ifdef TESTING
if (opt->debug)
printf("\n%d %d %d %d\n",(int)sizeof(oh),e_len,packedsize,d_len);
#endif
fo->write(&oh,sizeof(oh));
fo->write(loader,e_len); // entry
fo->write(obuf,packedsize);
fo->write(loader+e_len,d_len); // decompressor
fo->write(extra_info,eisize);
// verify
verifyOverlappingDecompression(&obuf, overlapoh);
// copy the overlay
copyOverlay(fo, overlay, &obuf);
//fprintf (stderr,"%x %x\n",relocsize,ph.u_len);
}
/*************************************************************************
//
**************************************************************************/
bool PackExe::canUnpack()
{
if (!readExeHeader())
return false;
const off_t off = ih.headsize16*16;
bool b = readPackHeader(128, off);
return b && (off + (off_t) ph.c_len <= file_size);
}
/*************************************************************************
//
**************************************************************************/
void PackExe::unpack(OutputFile *fo)
{
ibuf.alloc(file_size);
obuf.allocForUncompression(ph.u_len);
// read the file
unsigned imagesize = ih_imagesize;
const unsigned overlay = ih_overlay;
fi->seek(ih.headsize16*16,SEEK_SET);
fi->readx(ibuf,imagesize);
// get compressed data offset
unsigned e_len = ph.buf_offset + ph.getPackHeaderSize();
if (imagesize <= e_len + ph.c_len)
throwCantUnpack("file damaged");
checkOverlay(overlay);
// decompress
decompress(ibuf+e_len,obuf);
const unsigned char flag = ibuf[imagesize-1];
unsigned relocn = 0;
upx_byte *relocs = obuf + ph.u_len;
MemBuffer wrkmem;
if (!(flag & NORELOC))
{
relocs -= get_le16(obuf+ph.u_len-2);
ph.u_len -= 2;
upx_byte *p;
wrkmem.alloc(4*MAXRELOCS);
unsigned es = 0,ones = get_le16(relocs);
unsigned seghi = get_le16(relocs+2);
p = relocs + 4;
while (ones)
{
unsigned di = get_le16(p);
es += get_le16(p+2);
bool dorel = true;
for (p += 4; ones && di < 0x10000; p++)
{
if (dorel)
{
set_le16(wrkmem+4*relocn,di);
set_le16(wrkmem+2+4*relocn++,es);
//printf ("%x\n",es*16+di);
}
dorel = true;
if (*p == 0)
{
upx_byte *q;
for (q = obuf+es*16+di; !(*q == 0x9a && get_le16(q+3) <= seghi); q++)
;
di = q - (obuf+es*16) + 3;
}
else if (*p == 1)
{
di += 254;
if (di < 0x10000)
ones--;
dorel = false;
}
else
di += *p;
}
}
}
// fill new exe header
memset(&oh,0,sizeof(oh));
oh.ident = 'M' + 'Z'*256;
oh.relocs = relocn;
while (relocn&3)
set_le32(wrkmem+4*relocn++,0);
unsigned outputlen = sizeof(oh)+relocn*4+relocs-obuf;
oh.m512 = outputlen & 511;
oh.p512 = (outputlen + 511) >> 9;
oh.headsize16 = 2+relocn/4;
imagesize--;
oh.max = ih.max;
oh.min = ih.min;
oh.sp = ih.sp;
oh.ss = ih.ss;
if (flag & MAXMEM)
imagesize -= 2, oh.max = get_le16(ibuf+imagesize);
if (flag & MINMEM)
imagesize -= 2, oh.min = get_le16(ibuf+imagesize);
if (flag & SP)
imagesize -= 2, oh.sp = get_le16(ibuf+imagesize);
if (flag & SS)
imagesize -= 2, oh.ss = get_le16(ibuf+imagesize);
unsigned ip = (flag & USEJUMP) ? get_le32(ibuf+imagesize-4) : ih.firstreloc;
oh.ip = ip & 0xffff;
oh.cs = ip >> 16;
oh.relocoffs = sizeof(oh);
oh.firstreloc = 0;
if (!fo)
return;
// write header + relocations + uncompressed file
fo->write(&oh,sizeof(oh));
fo->write(wrkmem,relocn*4);
fo->write(obuf,relocs-obuf);
// copy the overlay
copyOverlay(fo, overlay, &obuf);
}
/*
vi:ts=4:et
*/

109
src/p_exe.h Normal file
View File

@ -0,0 +1,109 @@
/* p_exe.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_EXE_H
#define __UPX_P_EXE_H
/*************************************************************************
// dos/exe
**************************************************************************/
class PackExe : public Packer
{
typedef Packer super;
public:
PackExe(InputFile *f);
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_DOS_EXE; }
virtual const char *getName() const { return "dos/exe"; }
virtual int getCompressionMethod() const;
virtual const int *getFilters() const;
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canPack();
virtual bool canUnpack();
// unpacker capabilities
virtual bool canUnpackVersion(int version) const
{
// NOTE: could adapt p_exe.cpp to support (version >= 8)
return (version >= 10);
}
virtual bool canUnpackFormat(int format) const
{
return (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH);
}
protected:
virtual bool readExeHeader(void);
struct exe_header_t
{
LE16 ident;
LE16 m512;
LE16 p512;
LE16 relocs;
LE16 headsize16;
LE16 min;
LE16 max;
LE16 ss;
LE16 sp;
char _[2]; // checksum
LE16 ip;
LE16 cs;
LE16 relocoffs;
char __[2]; // overlnum
LE32 firstreloc;
} ih, oh;
unsigned ih_exesize;
unsigned ih_imagesize;
unsigned ih_overlay;
bool has_9a;
enum {
NORELOC = 1,
USEJUMP = 2,
SS = 4,
SP = 8,
MINMEM = 16,
MAXMEM = 32
};
};
#endif /* already included */
/*
vi:ts=4:et
*/

504
src/p_lx_elf.cpp Normal file
View File

@ -0,0 +1,504 @@
/* p_lx_elf.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Copyright (C) 2000 John F. Reiser. 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
John F. Reiser
jreiser@BitWagon.com
*/
#include "conf.h"
#include "file.h"
#include "packer.h"
#include "p_elf.h"
#include "p_unix.h"
#include "p_lx_elf.h"
static const
#include "stub/l_le_n2b.h"
static const
#include "stub/l_le_n2d.h"
PackLinuxI386elf::~PackLinuxI386elf()
{
}
PackLinuxI386elf::PackLinuxI386elf(InputFile *f)
:super(f)
,phdri(0)
{
}
const upx_byte *PackLinuxI386elf::getLoader() const
{
if (M_IS_NRV2B(opt->method))
return linux_i386elf_nrv2b_loader;
if (M_IS_NRV2D(opt->method))
return linux_i386elf_nrv2d_loader;
return NULL;
}
int PackLinuxI386elf::getLoaderSize() const
{
if (0 != lsize) {
return lsize;
}
if (M_IS_NRV2B(opt->method))
return sizeof(linux_i386elf_nrv2b_loader);
if (M_IS_NRV2D(opt->method))
return sizeof(linux_i386elf_nrv2d_loader);
return 0;
}
static inline off_t min_off_t(off_t a, off_t b)
{
return a < b ? a : b;
}
static inline off_t max_off_t(off_t a, off_t b)
{
return a > b ? a : b;
}
static off_t getbrk(Elf_LE32_Phdr const *phdr, int e_phnum)
{
off_t brka = 0;
for (int j = 0; j < e_phnum; ++phdr, ++j) if (PT_LOAD==phdr->p_type) {
brka = max_off_t(brka, phdr->p_vaddr + phdr->p_memsz);
}
return brka;
}
void PackLinuxI386elf::updateLoader(OutputFile *fo)
{
#define PAGE_MASK (~0<<12)
Elf_LE32_Phdr *const phdro = (Elf_LE32_Phdr *)(sizeof(Elf_LE32_Ehdr)+loader);
off_t const totlen = fo->getBytesWritten();
phdro->p_filesz = totlen;
// pre-calculate for benefit of runtime disappearing act via munmap()
phdro->p_memsz = PAGE_MASK & (~PAGE_MASK + totlen);
patchLoaderChecksum();
fo->seek(0, SEEK_SET);
fo->rewrite(loader, 0x80);
#undef PAGE_MASK
}
void PackLinuxI386elf::patchLoader()
{
lsize = getLoaderSize();
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)(void *)loader;
Elf_LE32_Phdr *const phdr = (Elf_LE32_Phdr *)(1+ehdr);
// stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset
off_t const fold_begin = phdr[1].p_offset + 0x80;
upx_byte *cprLoader = new upx_byte[lsize];
// compress compiled C-code portion of loader
upx_compress_config_t conf; memset(&conf, 0xff, sizeof(conf));
conf.c_flags = 0;
upx_uint result_buffer[16];
size_t cprLsize;
upx_compress(
loader + fold_begin, lsize - fold_begin,
cprLoader, &cprLsize,
0, // progress_callback_t ??
getCompressionMethod(), 9,
&conf,
result_buffer
);
set_le32(0+fold_begin+loader, lsize - fold_begin);
set_le32(4+fold_begin+loader, cprLsize);
memcpy( 8+fold_begin+loader, cprLoader, cprLsize);
lsize = 8 + fold_begin + cprLsize;
patchVersion(loader,lsize);
// Info for OS kernel to set the brk()
unsigned const brka = getbrk(phdri, ehdri.e_phnum);
phdr[1].p_offset = 0xfff&brka;
phdr[1].p_vaddr = brka;
phdr[1].p_paddr = brka;
phdr[1].p_filesz = 0;
phdr[1].p_memsz = 0;
// The beginning of our loader consists of a elf_hdr (52 bytes) and
// two sections elf_phdr (2 * 32 byte), so we have 12 free bytes
// from offset 116 to the program start at offset 128.
assert(ehdr->e_phoff == sizeof(*ehdr));
assert(ehdr->e_ehsize == sizeof(*ehdr));
assert(ehdr->e_phentsize == sizeof(Elf_LE32_Phdr));
assert(ehdr->e_phnum == 2);
assert(ehdr->e_shnum == 0);
assert(lsize > 128 && lsize < 4096);
patchLoaderChecksum();
}
bool PackLinuxI386elf::canPack()
{
unsigned char buf[512];
fi->readx(buf,512);
fi->seek(0,0);
if (0==memcmp(buf, "\x7f\x45\x4c\x46\x01\x01\x01", 7)) { // ELF 32-bit LSB
Elf_LE32_Ehdr const *const ehdr = (Elf_LE32_Ehdr const *)buf;
Elf_LE32_Phdr const *phdr = (Elf_LE32_Phdr const *)(ehdr->e_phoff +
(char const *)ehdr);
if (ehdr->e_phoff != sizeof(*ehdr)) {// Phdrs not contiguous with Ehdr
return false;
}
// The first PT_LOAD must cover the beginning of the file (0==p_offset).
for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) {
if (PT_LOAD==phdr->p_type) {
if (phdr->p_offset!=0) {
return false;
}
break;
}
}
return super::canPack();
}
return false;
}
void PackLinuxI386elf::packExtent(
Extent const &x,
OutputFile *fo,
unsigned &total_in,
unsigned &total_out
)
{
blocksize = opt->unix.blocksize;
if ((off_t)blocksize > x.size)
blocksize = x.size;
fi->seek(x.offset, SEEK_SET);
for (off_t rest = x.size; 0!=rest; )
{
int l = fi->readx(ibuf, min_off_t(rest, blocksize));
rest -= l;
if (l == 0)
break;
// Note: compression for a block can fail if the
// file is e.g. blocksize + 1 bytes long
// compress
ph.u_len = l;
compress(ibuf, obuf); // ignore return value
if (ph.c_len < ph.u_len)
{
if (!testOverlappingDecompression(obuf, OVERHEAD))
throwNotCompressible();
}
else
{
ph.c_len = ph.u_len;
// must update checksum of compressed data
ph.c_adler = upx_adler32(ph.c_adler, ibuf, ph.u_len);
}
// write block sizes
unsigned char size[8];
set_native32(size+0, ph.u_len);
set_native32(size+4, ph.c_len);
fo->write(size, 8);
// write compressed data
if (ph.c_len < ph.u_len)
{
fo->write(obuf, ph.c_len);
verifyOverlappingDecompression(&obuf, OVERHEAD);
}
else
fo->write(ibuf, ph.u_len);
total_in += ph.u_len;
total_out += ph.c_len;
}
}
void PackLinuxI386elf::pack(OutputFile *fo)
{
// set options
opt->unix.blocksize = file_size;
blocksize = file_size;
progid = 0; // not used
fi->readx(&ehdri, sizeof(ehdri));
off_t const sz_phdrs = ehdri.e_phnum * ehdri.e_phentsize;
phdri = new Elf_LE32_Phdr[ehdri.e_phnum];
fi->seek(ehdri.e_phoff, SEEK_SET);
fi->readx(phdri, sz_phdrs);
// prepare loader
lsize = getLoaderSize();
loader.alloc(lsize + sizeof(p_info));
memcpy(loader,getLoader(),lsize);
// patch loader, prepare header info, write loader + header info
patchLoader(); // can change lsize by packing upx_main
p_info *const hbuf = (p_info *)(loader + lsize);
set_native32(&hbuf->p_progid, progid);
set_native32(&hbuf->p_filesize, file_size);
set_native32(&hbuf->p_blocksize, blocksize);
fo->write(loader, lsize + sizeof(p_info));
// init compression buffers
ibuf.alloc(blocksize);
obuf.allocForCompression(blocksize);
assert(ehdri.e_phoff == sizeof(Elf_LE32_Ehdr)); // checked by canPack()
Extent x;
unsigned k;
// count
total_passes = 0;
off_t ptload0hi=0, ptload1lo=0;
int nx = 0;
for (k = 0; k < ehdri.e_phnum; ++k) {
if (PT_LOAD==phdri[k].p_type) {
x.offset = phdri[k].p_offset;
x.size = phdri[k].p_filesz;
if (0==ptload0hi) {
ptload0hi = x.size + x.offset;
}
else if (0==ptload1lo) {
ptload1lo = x.offset;
}
total_passes++;
} else {
if (nx++ == 0)
total_passes++;
}
}
if (ptload0hi < ptload1lo)
total_passes++;
// compress extents
unsigned total_in = 0;
unsigned total_out = 0;
x.offset = 0;
x.size = sizeof(Elf_LE32_Ehdr) + sz_phdrs;
pass = -1;
packExtent(x, fo, total_in, total_out);
pass = 0;
nx = 0;
for (k = 0; k < ehdri.e_phnum; ++k) if (PT_LOAD==phdri[k].p_type) {
x.offset = phdri[k].p_offset;
x.size = phdri[k].p_filesz;
if (0==nx) {
x.offset += sizeof(Elf_LE32_Ehdr) + sz_phdrs;
x.size -= sizeof(Elf_LE32_Ehdr) + sz_phdrs;
}
packExtent(x, fo, total_in, total_out);
++nx;
}
if (ptload0hi < ptload1lo) { // alignment hole?
x.offset = ptload0hi;
x.size = ptload1lo - ptload0hi;
packExtent(x, fo, total_in, total_out);
}
if ((off_t)total_in < file_size) { // non-PT_LOAD stuff
x.offset = total_in;
x.size = file_size - total_in;
packExtent(x, fo, total_in, total_out);
}
if ((off_t)total_in != file_size)
throw EOFException();
// write block end marker (uncompressed size 0)
fo->write("\x00\x00\x00\x00", 4);
// update header with totals
ph.u_len = total_in;
ph.c_len = total_out;
// write header
const int hsize = ph.getPackHeaderSize();
set_le32(obuf, ph.magic); // note: always le32
putPackHeader(obuf, hsize);
fo->write(obuf, hsize);
// write overlay offset (needed for decompression)
set_native32(obuf, lsize);
fo->write(obuf, 4);
updateLoader(fo);
// finally check compression ratio
if (!super::checkCompressionRatio(fo->getBytesWritten(), ph.u_len))
throwNotCompressible();
}
void PackLinuxI386elf::unpackExtent(unsigned wanted, OutputFile *fo,
unsigned &total_in, unsigned &total_out,
unsigned &c_adler, unsigned &u_adler)
{
while (wanted) {
fi->readx(ibuf, 8);
int const sz_unc = ph.u_len = get_native32(ibuf+0);
int const sz_cpr = ph.c_len = get_native32(ibuf+4);
if (sz_unc == 0) { // must never happen while 0!=wanted
throwCompressedDataViolation();
break;
}
if (sz_unc <= 0 || sz_cpr <= 0)
throwCompressedDataViolation();
if (sz_cpr > sz_unc || sz_unc > (int)blocksize)
throwCompressedDataViolation();
int j = blocksize + OVERHEAD - sz_cpr;
fi->readx(ibuf+j, sz_cpr);
// update checksum of compressed data
c_adler = upx_adler32(c_adler, ibuf + j, sz_cpr);
// decompress
if (sz_cpr < sz_unc)
{
decompress(ibuf+j, ibuf, false);
j = 0;
}
// update checksum of uncompressed data
u_adler = upx_adler32(u_adler, ibuf + j, sz_unc);
total_in += sz_cpr;
total_out += sz_unc;
// write block
if (fo)
fo->write(ibuf + j, sz_unc);
wanted -= sz_unc;
}
}
bool PackLinuxI386elf::canUnpackFormat(int format) const
{
return UPX_F_LINUX_ELF_i386==format || UPX_F_LINUX_SEP_i386==format;
}
void PackLinuxI386elf::unpack(OutputFile *fo)
{
#define MAX_ELF_HDR 512
char bufehdr[MAX_ELF_HDR];
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)bufehdr;
Elf_LE32_Phdr const *phdr = (Elf_LE32_Phdr *)(1+ehdr);
fi->seek(overlay_offset, SEEK_SET);
p_info hbuf;
fi->readx(&hbuf, sizeof(hbuf));
unsigned orig_file_size = get_native32(&hbuf.p_filesize);
blocksize = get_native32(&hbuf.p_blocksize);
if (file_size > (off_t)orig_file_size || blocksize > orig_file_size)
throwCantUnpack("file header corrupted");
ibuf.alloc(blocksize + OVERHEAD);
fi->readx(ibuf, 2*4);
ph.u_len = get_native32(0+ibuf);
ph.c_len = get_native32(4+ibuf);
// Uncompress Ehdr and Phdrs.
fi->readx(ibuf, ph.c_len);
decompress(ibuf, (upx_byte *)ehdr, false);
unsigned total_in = 0;
unsigned total_out = 0;
unsigned c_adler = upx_adler32(0, NULL, 0);
unsigned u_adler = upx_adler32(0, NULL, 0);
off_t ptload0hi=0, ptload1lo=0;
// decompress PT_LOAD
fi->seek(-(2*4 + ph.c_len), SEEK_CUR);
for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) {
if (PT_LOAD==phdr->p_type) {
if (0==ptload0hi) {
ptload0hi = phdr->p_filesz + phdr->p_offset;
}
else if (0==ptload1lo) {
ptload1lo = phdr->p_offset;
}
if (fo)
fo->seek(phdr->p_offset, SEEK_SET);
unpackExtent(phdr->p_filesz, fo, total_in, total_out, c_adler, u_adler);
}
}
if (ptload0hi < ptload1lo) { // alignment hole?
if (fo)
fo->seek(ptload0hi, SEEK_SET);
unpackExtent(ptload1lo - ptload0hi, fo, total_in, total_out, c_adler, u_adler);
}
if (total_out != orig_file_size) { // non-PT_LOAD stuff
if (fo)
fo->seek(0, SEEK_END);
unpackExtent(orig_file_size - total_out, fo, total_in, total_out, c_adler, u_adler);
}
// check for end-of-file
fi->readx(ibuf, 2*4);
unsigned const sz_unc = ph.u_len = get_native32(ibuf+0);
if (sz_unc == 0) { // uncompressed size 0 -> EOF
// note: magic is always stored le32
unsigned const sz_cpr = get_le32(ibuf+4);
if (sz_cpr != UPX_MAGIC_LE32) // sz_cpr must be h->magic
throwCompressedDataViolation();
}
else { // extra bytes after end?
throwCompressedDataViolation();
}
// update header with totals
ph.c_len = total_in;
ph.u_len = total_out;
// all bytes must be written
if (total_out != orig_file_size)
throw EOFException();
// finally test the checksums
if (ph.c_adler != c_adler || ph.u_adler != u_adler)
throwChecksumError();
#undef MAX_ELF_HDR
}
/*
vi:ts=4:et
*/

84
src/p_lx_elf.h Normal file
View File

@ -0,0 +1,84 @@
/* p_lx_elf.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Copyright (C) 2000 John F. Reiser. 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
John F. Reiser
jreiser@BitWagon.com
*/
#ifndef __UPX_P_LX_ELF_H //{
#define __UPX_P_LX_ELF_H
#include "p_unix.h"
#include "p_elf.h"
class PackLinuxI386elf : public PackLinuxI386
{
typedef PackLinuxI386 super;
public:
PackLinuxI386elf(InputFile *f);
virtual ~PackLinuxI386elf();
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_LINUX_ELF_i386; }
virtual const char *getName() const { return "linux/elf386"; }
virtual const int *getFilters() const { return NULL; }
virtual bool canPack();
virtual bool canUnpackFormat(int format) const;
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canUnpackVersion(int version) const
{ return (version >= 11); }
struct Extent {
off_t offset;
off_t size;
};
virtual void packExtent(Extent const &x, OutputFile *fo,
unsigned &total_in, unsigned &total_out);
virtual void unpackExtent(unsigned wanted, OutputFile *fo,
unsigned &total_in, unsigned &total_out,
unsigned &c_adler, unsigned &u_adler);
protected:
virtual const upx_byte *getLoader() const;
virtual int getLoaderSize() const;
virtual void patchLoader();
virtual void updateLoader(OutputFile *);
Elf_LE32_Ehdr ehdri; // from input file
Elf_LE32_Phdr *phdri; // for input file
};
#endif //}__UPX_P_LX_ELF_H
/*
vi:ts=4:et
*/

85
src/p_lx_sep.cpp Normal file
View File

@ -0,0 +1,85 @@
/* p_lxsep.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Copyright (C) 2000 John F. Reiser. 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
John F. Reiser
jreiser@BitWagon.com
*/
#include "conf.h"
#include "file.h"
#include "packer.h"
#include "p_lx_sep.h"
/*************************************************************************
//
**************************************************************************/
const upx_byte *PackLinuxI386sep::getLoader() const
{
static char script[SCRIPT_MAX + sizeof(l_info)];
memset(script, 0, sizeof(script));
char const *name = opt->script_name;
if (0==name) {
name = "/usr/local/lib/upxX";
}
sprintf(script, "#!%s\n", name);
if (M_IS_NRV2B(opt->method)) {
script[strlen(script)-2] = 'b';
return (upx_byte const *)script;
}
if (M_IS_NRV2D(opt->method)) {
script[strlen(script)-2] = 'd';
return (upx_byte const *)script;
}
return NULL;
}
int PackLinuxI386sep::getLoaderSize() const
{
if (M_IS_NRV2B(opt->method))
return SCRIPT_MAX + sizeof(l_info);
if (M_IS_NRV2D(opt->method))
return SCRIPT_MAX + sizeof(l_info);
return 0;
}
int PackLinuxI386sep::getLoaderPrefixSize() const
{
return SCRIPT_MAX;
}
void PackLinuxI386sep::patchLoader()
{
patchLoaderChecksum();
}
/*
vi:ts=4:et
*/

55
src/p_lx_sep.h Normal file
View File

@ -0,0 +1,55 @@
/* p_lx_sep.h --
This file is part of the UPX executable compressor.
Copyright (C) 2000 John F. Reiser
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.
John F. Reiser
jreiser@BitWagon.com
*/
#ifndef __UPX_P_LX_SEP_H // {
#define __UPX_P_LX_SEP_H
#include "p_lx_elf.h"
class PackLinuxI386sep : public PackLinuxI386elf
{
typedef PackLinuxI386elf super;
public:
PackLinuxI386sep(InputFile *f) : super(f) { }
virtual int getFormat() const { return UPX_F_LINUX_SEP_i386; }
virtual const char *getName() const { return "linux/sep386"; }
protected:
virtual const upx_byte *getLoader() const;
virtual int getLoaderSize() const;
virtual int getLoaderPrefixSize() const;
virtual void patchLoader();
virtual void updateLoader(OutputFile *) {}
};
#endif __UPX_P_LX_SEP_H //}
#define __UPX_P_LX_SEP_H
/*
vi:ts=4:et
*/

223
src/p_lx_sh.cpp Normal file
View File

@ -0,0 +1,223 @@
/* p_lx_sh.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Copyright (C) 2000 John F. Reiser. 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
John F. Reiser
jreiser@BitWagon.com
*/
#include "conf.h"
#include "file.h"
#include "packer.h"
#include "p_elf.h"
#include "p_unix.h"
#include "p_lx_sh.h"
static const
#include "stub/l_sh_n2b.h"
static const
#include "stub/l_sh_n2d.h"
PackLinuxI386sh::~PackLinuxI386sh()
{
}
PackLinuxI386sh::PackLinuxI386sh(InputFile *f)
:super(f)
,o_shname(0)
,l_shname(0)
{
}
const upx_byte *PackLinuxI386sh::getLoader() const
{
if (M_IS_NRV2B(opt->method))
return linux_i386sh_nrv2b_loader;
if (M_IS_NRV2D(opt->method))
return linux_i386sh_nrv2d_loader;
return NULL;
}
int PackLinuxI386sh::getLoaderSize() const
{
if (0 != lsize) {
return lsize;
}
if (M_IS_NRV2B(opt->method))
return sizeof(linux_i386sh_nrv2b_loader);
if (M_IS_NRV2D(opt->method))
return sizeof(linux_i386sh_nrv2d_loader);
return 0;
}
static inline off_t max_off_t(off_t a, off_t b)
{
return a > b ? a : b;
}
static off_t getbrk(Elf_LE32_Phdr const *phdr, int e_phnum)
{
off_t brka = 0;
for (int j = 0; j < e_phnum; ++phdr, ++j) if (PT_LOAD==phdr->p_type) {
brka = max_off_t(brka, phdr->p_vaddr + phdr->p_memsz);
}
return brka;
}
void PackLinuxI386sh::patchLoader()
{
lsize = getLoaderSize();
ehdri = (Elf_LE32_Ehdr *)(void *)loader;
Elf_LE32_Phdr *const phdri = (Elf_LE32_Phdr *)(1+ehdri);
patch_le32(loader,lsize,"UPX3",l_shname);
patch_le32(loader,lsize,"UPX2",o_shname);
// stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset
off_t const fold_begin = phdri[1].p_offset + 0x80;
MemBuffer cprLoader(lsize);
// compress compiled C-code portion of loader
upx_compress_config_t conf; memset(&conf, 0xff, sizeof(conf));
conf.c_flags = 0;
upx_uint result_buffer[16];
size_t cprLsize;
upx_compress(
loader + fold_begin, lsize - fold_begin,
cprLoader, &cprLsize,
0, // progress_callback_t ??
getCompressionMethod(), 9,
&conf,
result_buffer
);
set_le32(0+fold_begin+loader, lsize - fold_begin);
set_le32(4+fold_begin+loader, cprLsize);
memcpy( 8+fold_begin+loader, cprLoader, cprLsize);
lsize = 8 + fold_begin + cprLsize;
patchVersion(loader,lsize);
unsigned const brka = getbrk(phdri, ehdri->e_phnum);
phdri[1].p_offset = 0xfff&brka;
phdri[1].p_vaddr = brka;
phdri[1].p_paddr = brka;
phdri[1].p_filesz = 0;
phdri[1].p_memsz = 0;
// The beginning of our loader consists of a elf_hdr (52 bytes) and
// two sections elf_phdr (2 * 32 byte), so we have 12 free bytes
// from offset 116 to the program start at offset 128.
assert(ehdri->e_phoff == sizeof(Elf_LE32_Ehdr));
assert(ehdri->e_ehsize == sizeof(Elf_LE32_Ehdr));
assert(ehdri->e_phentsize == sizeof(Elf_LE32_Phdr));
assert(ehdri->e_phnum == 2);
assert(ehdri->e_shnum == 0);
assert(lsize > 128 && lsize < 4096);
patchLoaderChecksum();
}
bool PackLinuxI386sh::getShellName(char *buf)
{
exetype = -1;
l_shname = strcspn(buf, " \t\n\v\f\r");
buf[l_shname] = 0;
char const *const basename = 1+strrchr(buf, '/');
static char const *const shname[] = { // known shells that accept "-c" arg
"sh", "ash", "bsh", "csh", "ksh", "bash", "tcsh", "pdksh",
0
};
for (int j=0; 0 != shname[j]; ++j) {
if (0==strcmp(shname[j], basename)) {
o_shname += 3; // space for "-c\x00"
return super::canPack();
}
}
return false;
}
bool PackLinuxI386sh::canUnpackFormat(int format) const
{
return UPX_F_LINUX_SH_i386==format;
}
bool PackLinuxI386sh::canPack()
{
#if defined(__linux__) //{
// only compress i386sh scripts when running under Linux
char buf[512];
fi->readx(buf, 512);
fi->seek(0, SEEK_SET);
buf[511] = 0;
if (!memcmp(buf, "#!/", 3)) { // #!/bin/sh
o_shname = 2;
return getShellName(&buf[o_shname]);
}
else if (!memcmp(buf, "#! /", 4)) { // #! /bin/sh
o_shname = 3;
return getShellName(&buf[o_shname]);
}
#endif //}
return false;
}
void PackLinuxI386sh::pack(OutputFile *fo)
{
#define PAGE_MASK (~0<<12)
opt->unix.blocksize = file_size;
PackUnix::pack(fo);
// update loader
Elf_LE32_Phdr *const phdro = (Elf_LE32_Phdr *)(sizeof(Elf_LE32_Ehdr)+loader);
off_t const totlen = fo->getBytesWritten();
phdro[0].p_filesz = totlen;
phdro[0].p_memsz = PAGE_MASK & (~PAGE_MASK + totlen);
// Try to make brk() work by faking it for exec().
unsigned const brka = 0x08048000;
phdro[1].p_offset = 0xfff&brka;
phdro[1].p_vaddr = brka;
phdro[1].p_paddr = brka;
phdro[1].p_filesz = 0;
phdro[1].p_memsz = 0;
patchLoaderChecksum();
fo->seek(0, SEEK_SET);
fo->rewrite(loader, 0x80);
#undef PAGE_MASK
}
/*
vi:ts=4:et
*/

73
src/p_lx_sh.h Normal file
View File

@ -0,0 +1,73 @@
/* p_lx_sh.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Copyright (C) 2000 John F. Reiser. 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
John F. Reiser
jreiser@BitWagon.com
*/
#ifndef __UPX_P_LX_SH_H //{
#define __UPX_P_LX_SH_H
class PackLinuxI386sh : public PackLinuxI386
{
typedef PackLinuxI386 super;
public:
PackLinuxI386sh(InputFile *f);
virtual ~PackLinuxI386sh();
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_LINUX_SH_i386; }
virtual const char *getName() const { return "linux/sh386"; }
virtual const int *getFilters() const { return NULL; }
virtual bool canPack();
virtual void pack(OutputFile *fo);
// virtual void unpack(OutputFile *fo) { super::unpack(fo); }
virtual bool canUnpackFormat(int format) const;
virtual bool canUnpackVersion(int version) const
{ return (version >= 11); }
protected:
virtual const upx_byte *getLoader() const;
virtual int getLoaderSize() const;
virtual bool getShellName(char *buf);
virtual void patchLoader();
Elf_LE32_Ehdr *ehdri; // from input file
int o_shname; // offset to name_of_shell
int l_shname; // length of name_of_shell
};
#endif //}__UPX_P_LX_SH_H
/*
vi:ts=4:et
*/

132
src/p_sys.cpp Normal file
View File

@ -0,0 +1,132 @@
/* p_sys.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "filter.h"
#include "packer.h"
#include "p_com.h"
#include "p_sys.h"
static const
#include "stub/l_sys.h"
/*************************************************************************
//
**************************************************************************/
bool PackSys::canPack()
{
unsigned char buf[128];
fi->readx(buf,128);
if (memcmp (buf,"\xff\xff\xff\xff",4) != 0)
return false;
if (!fn_has_ext(fi->getName(),"sys"))
return false;
if (find_le32(buf,128,UPX_MAGIC_LE32))
throwAlreadyPacked();
if (file_size < 1024)
throwCantPack("file is too small");
if (file_size > 0x10000)
throwCantPack("file is too big for dos/sys");
return true;
}
/*************************************************************************
//
**************************************************************************/
void PackSys::patchLoader(OutputFile *fo,
upx_byte *loader, int lsize,
unsigned calls, unsigned overlapoh)
{
const int filter_id = ph.filter;
const int e_len = getLoaderSection("SYSCUTPO");
const int d_len = lsize - e_len;
assert(e_len > 0 && e_len < 256);
assert(d_len > 0 && d_len < 256);
if (ph.u_len + d_len + overlapoh > 0xfffe)
throwNotCompressible();
memcpy(loader,ibuf,6); // copy from orig. header
memcpy(loader+8,ibuf+8,2); // opendos wants this word too
unsigned copy_to = ph.u_len + d_len + overlapoh;
patch_le16(loader,lsize,"JO",get_le16(ibuf+6)-copy_to-1);
if (filter_id)
{
assert(calls > 0);
patch_le16(loader,lsize,"CT",calls);
}
unsigned jmp_pos;
jmp_pos = find_le16(loader,e_len,get_le16("JM")) - loader;
patch_le16(loader,e_len,"JM",ph.u_len+overlapoh+2-jmp_pos-2);
loader[getLoaderSection("SYSSUBSI") - 1] = (upx_byte) -e_len;
patch_le16(loader,e_len,"DI",copy_to);
patch_le16(loader,e_len,"SI",ph.c_len+e_len+d_len-1);
// write loader + compressed file
fo->write(loader,e_len); // entry
fo->write(obuf,ph.c_len);
fo->write(loader+e_len,d_len); // decompressor
}
int PackSys::buildLoader(const Filter *ft)
{
const int filter_id = ft->id;
initLoader(nrv2b_loader,sizeof(nrv2b_loader));
addLoader("SYSMAIN1",
opt->cpu == opt->CPU_8086 ? "SYSI0861" : "SYSI2861",
"SYSMAIN2""SYSSUBSI",
filter_id ? "SYSCALLT" : "",
"SYSMAIN3""UPX1HEAD""SYSCUTPO""NRV2B160""NRVDDONE""NRVDECO1",
ph.max_offset_found <= 0xd00 ? "NRVLED00" : "NRVGTD00",
"NRVDECO2""NRV2B169",
NULL
);
if (filter_id)
addFilter16(filter_id);
addLoader("SYSMAIN5",
opt->cpu == opt->CPU_8086 ? "SYSI0862" : "SYSI2862",
"SYSJUMP1",
NULL
);
return getLoaderSize();
}
/*
vi:ts=4:et
*/

62
src/p_sys.h Normal file
View File

@ -0,0 +1,62 @@
/* p_sys.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_SYS_H
#define __UPX_P_SYS_H
/*************************************************************************
// dos/sys
**************************************************************************/
class PackSys : public PackCom
{
typedef PackCom super;
public:
PackSys(InputFile *f) : super(f) { }
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_DOS_SYS; }
virtual const char *getName() const { return "dos/sys"; }
virtual bool canPack();
protected:
virtual const unsigned getCallTrickOffset() const { return 0; }
protected:
virtual int buildLoader(const Filter *ft);
virtual void patchLoader(OutputFile *fo, upx_byte *, int, unsigned, unsigned);
};
#endif /* already included */
/*
vi:ts=4:et
*/

333
src/p_tmt.cpp Normal file
View File

@ -0,0 +1,333 @@
/* p_tmt.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "filter.h"
#include "packer.h"
#include "p_tmt.h"
static const
#include "stub/l_tmt.h"
#define EXTRA_INFO 4 // original entry point
/*************************************************************************
//
**************************************************************************/
int PackTmt::getCompressionMethod() const
{
if (M_IS_NRV2B(opt->method))
return M_NRV2B_LE32;
if (M_IS_NRV2D(opt->method))
return M_NRV2D_LE32;
return opt->level > 1 && file_size >= 512*1024 ? M_NRV2D_LE32 : M_NRV2B_LE32;
}
const int *PackTmt::getFilters() const
{
static const int filters[] = { 0x26, 0x24, 0x11, 0x14, 0x13, 0x16,
0x25, 0x12, 0x15, -1 };
return filters;
}
/*************************************************************************
// util
**************************************************************************/
bool PackTmt::readFileHeader()
{
#define H(x) get_le16(h,2*(x))
#define H4(x) get_le32(h,x)
upx_byte h[0x40];
int ic;
unsigned exe_offset = 0;
adam_offset = 0;
for (ic = 0; ic < 20; ic++)
{
fi->seek(adam_offset,SEEK_SET);
fi->readx(h,sizeof(h));
if (memcmp(h,"MZ",2) == 0) // dos exe
{
exe_offset = adam_offset;
adam_offset += H(2)*512+H(1);
if (H(1))
adam_offset -= 512;
if (H(0x18/2) == 0x40 && H4(0x3c))
adam_offset = H4(0x3c);
}
else if (memcmp(h,"BW",2) == 0)
adam_offset += H(2)*512+H(1);
else if (memcmp(h,"PMW1",4) == 0)
{
fi->seek(adam_offset + H4(0x18),SEEK_SET);
adam_offset += H4(0x24);
int objs = H4(0x1c);
while (objs--)
{
fi->readx(h,0x18);
adam_offset += H4(4);
}
}
else if (memcmp(h,"LE",2) == 0)
{
// + (memory_pages-1)*memory_page_size+bytes_on_last_page
unsigned offs = exe_offset + (H4(0x14) - 1) * H4(0x28) + H4(0x2c);
fi->seek(adam_offset+0x80,SEEK_SET);
fi->readx(h,4);
// + data_pages_offset
adam_offset = offs + H4(0);
}
else if (memcmp(h,"Adam",4) == 0)
break;
else
return false;
}
if (ic == 20)
return false;
fi->seek(adam_offset,SEEK_SET);
fi->readx(&ih,sizeof(ih));
return true;
#undef H4
#undef H
}
bool PackTmt::canPack()
{
return PackTmt::readFileHeader();
}
/*************************************************************************
//
**************************************************************************/
void PackTmt::pack(OutputFile *fo)
{
Packer::handleStub(fi,fo,adam_offset);
const unsigned usize = ih.imagesize;
const unsigned rsize = ih.relocsize;
ibuf.alloc(usize+rsize+128);
obuf.allocForCompression(usize+rsize+128);
MemBuffer wrkmem;
wrkmem.alloc(rsize+EXTRA_INFO); // relocations
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,128,get_le32("UPX ")))
throwAlreadyPacked();
if (rsize == 0)
throwCantPack("file is already compressed with another packer");
checkOverlay(overlay);
unsigned relocsize = 0;
int big;
//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,1,&big)-wrkmem;
}
// filter
Filter ft(opt->level);
tryFilters(&ft, ibuf, usize);
wrkmem[relocsize++] = 0;
set_le32(wrkmem+relocsize,ih.entry); // save original entry point
relocsize += 4;
set_le32(wrkmem+relocsize,relocsize+4);
relocsize += 4;
memcpy(ibuf+usize,wrkmem,relocsize);
ph.filter = ft.id;
ph.filter_cto = ft.cto;
ph.u_len = usize+relocsize;
if (!compress(ibuf,obuf))
throwNotCompressible();
// make sure the decompressor will be paragraph aligned
const unsigned overlapoh = ((findOverlapOverhead(obuf,512)+0x20)
&~ 0xf) - (ph.u_len & 0xf);
// verify filter
ft.verifyUnfilter();
// prepare loader
initLoader(nrv_loader,sizeof(nrv_loader));
addLoader("IDENTSTR""TMTMAIN1",
ft.id ? "TMTCALT1" : "",
"TMTMAIN2""UPX1HEAD""TMTCUTPO""+0XXXXXX",
getDecompressor(),
"TMTMAIN5",
NULL
);
if (ft.id)
{
assert(ft.calls > 0);
addLoader("TMTCALT2",NULL);
addFilter32(ft.id);
}
addLoader("TMTRELOC""RELOC320",
big ? "REL32BIG" : "",
"RELOC32J""TMTJUMP1",
NULL
);
const unsigned lsize = getLoaderSize();
MemBuffer loader(lsize);
memcpy(loader,getLoader(),lsize);
const unsigned s_point = getLoaderSection("TMTMAIN1");
int e_len = getLoaderSection("TMTCUTPO");
const unsigned d_len = lsize - e_len;
assert(e_len > 0 && s_point > 0);
// patch loader
patch_le32(loader,lsize,"JMPO",ih.entry-(ph.u_len+overlapoh+d_len));
if (ft.id)
{
assert(ft.calls > 0);
if (ft.id > 0x20)
patch_le16(loader,lsize,"??",'?'+(ph.filter_cto << 8));
patch_le32(loader,lsize,"TEXL",(ft.id & 0xf) % 3 == 0 ? ft.calls :
ft.lastcall - ft.calls * 4);
}
unsigned jmp_pos;
jmp_pos = find_le32(loader,e_len,get_le32("JMPD")) - loader;
patch_le32(loader,e_len,"JMPD",ph.u_len+overlapoh-jmp_pos-4);
patch_le32(loader,e_len,"ECX0",ph.c_len+d_len);
patch_le32(loader,e_len,"EDI0",ph.u_len+overlapoh+d_len-1);
patch_le32(loader,e_len,"ESI0",ph.c_len+e_len+d_len-1);
putPackHeader(loader,e_len);
//fprintf(stderr,"\nelen=%x dlen=%x copy_len=%x copy_to=%x oo=%x jmp_pos=%x ulen=%x clen=%x \n\n",
// e_len,d_len,copy_len,copy_to,overlapoh,jmp_pos,ph.u_len,ph.c_len);
memcpy(&oh,&ih,sizeof(oh));
oh.imagesize = ph.c_len+e_len+d_len; // new size
oh.entry = s_point; // new entry point
oh.relocsize = 4;
// write loader + compressed file
fo->write(&oh,sizeof(oh));
fo->write(loader,e_len);
fo->write(obuf,ph.c_len);
fo->write(loader+lsize-d_len,d_len); // decompressor
char rel_entry[4];
set_le32(rel_entry,5 + s_point);
fo->write(rel_entry,sizeof (rel_entry));
// verify
verifyOverlappingDecompression(&obuf, overlapoh);
// copy the overlay
copyOverlay(fo, overlay, &obuf);
}
bool PackTmt::canUnpack()
{
if (!PackTmt::readFileHeader())
return false;
return readPackHeader(512,adam_offset);
}
void PackTmt::unpack(OutputFile *fo)
{
Packer::handleStub(fi,fo,adam_offset);
ibuf.alloc(ph.c_len);
obuf.allocForUncompression(ph.u_len);
fi->seek(adam_offset + ph.buf_offset + ph.getPackHeaderSize(),SEEK_SET);
fi->readx(ibuf,ph.c_len);
// decompress
decompress(ibuf,obuf);
// decode relocations
const unsigned osize = ph.u_len - get_le32(obuf+ph.u_len-4);
upx_byte *relocs = obuf + osize;
const unsigned origstart = get_le32(obuf+ph.u_len-8);
// unfilter
if (ph.filter)
{
Filter ft(ph.level);
ft.init(ph.filter, 0);
ft.cto = (unsigned char) (ph.version < 11 ? (get_le32(obuf+ph.u_len-12) >> 24) : ph.filter_cto);
ft.unfilter(obuf, relocs-obuf);
}
// decode relocations
MemBuffer wrkmem;
unsigned relocn = unoptimizeReloc32(&relocs,obuf,&wrkmem,1);
for (unsigned ic = 0; ic < relocn; ic++)
set_le32(wrkmem+ic*4,get_le32(wrkmem+ic*4)+4);
memcpy(&oh,&ih,sizeof(oh));
oh.imagesize = osize;
oh.entry = origstart;
oh.relocsize = relocn*4;
const unsigned overlay = file_size - adam_offset - ih.imagesize
- ih.relocsize - sizeof(ih);
checkOverlay(overlay);
// write decompressed file
if (fo)
{
fo->write(&oh,sizeof(oh));
fo->write(obuf,osize);
fo->write(wrkmem,relocn*4);
}
// copy the overlay
copyOverlay(fo, overlay, &obuf);
}
/*
vi:ts=4:et
*/

76
src/p_tmt.h Normal file
View File

@ -0,0 +1,76 @@
/* p_tmt.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_TMT_H
#define __UPX_P_TMT_H
/*************************************************************************
// tmt/adam
**************************************************************************/
class PackTmt : public Packer
{
typedef Packer super;
public:
PackTmt(InputFile *f) : super(f) { assert(sizeof(tmt_header_t) == 44); }
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_TMT_ADAM; }
virtual const char *getName() const { return "tmt/adam"; }
virtual int getCompressionMethod() const;
virtual const int *getFilters() const;
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canPack();
virtual bool canUnpack();
protected:
bool readFileHeader();
unsigned adam_offset;
struct tmt_header_t
{
char _[16]; // signature,linkerversion,minversion,exesize,imagestart
LE32 imagesize;
char __[4]; // initial memory
LE32 entry;
char ___[12]; // esp,numfixups,flags
LE32 relocsize;
} ih,oh;
};
#endif /* already included */
/*
vi:ts=4:et
*/

544
src/p_tos.cpp Normal file
View File

@ -0,0 +1,544 @@
/* p_tos.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "packer.h"
#include "p_tos.h"
static const
#include "stub/l_t_n2b.h"
static const
#include "stub/l_t_n2bs.h"
static const
#include "stub/l_t_n2d.h"
static const
#include "stub/l_t_n2ds.h"
// #define TESTING
/*************************************************************************
//
**************************************************************************/
#define FH_SIZE sizeof(tos_header_t)
PackTos::PackTos(InputFile *f) :
super(f)
{
assert(FH_SIZE == 28);
}
int PackTos::getCompressionMethod() const
{
if (M_IS_NRV2B(opt->method))
return M_NRV2B_8;
if (M_IS_NRV2D(opt->method))
return M_NRV2D_8;
return opt->level > 1 && file_size >= 512*1024 ? M_NRV2D_8 : M_NRV2B_8;
}
const int *PackTos::getFilters() const
{
return NULL;
}
const upx_byte *PackTos::getLoader() const
{
if (M_IS_NRV2B(opt->method))
return opt->small ? nrv2b_loader_small : nrv2b_loader;
if (M_IS_NRV2D(opt->method))
return opt->small ? nrv2d_loader_small : nrv2d_loader;
return NULL;
}
int PackTos::getLoaderSize() const
{
if (M_IS_NRV2B(opt->method))
return opt->small ? sizeof(nrv2b_loader_small) : sizeof(nrv2b_loader);
if (M_IS_NRV2D(opt->method))
return opt->small ? sizeof(nrv2d_loader_small) : sizeof(nrv2d_loader);
return 0;
}
/*************************************************************************
//
**************************************************************************/
/* flags for curproc->memflags */
/* also used for program headers fh_flag */
#define F_FASTLOAD 0x01 // don't zero heap
#define F_ALTLOAD 0x02 // OK to load in alternate ram
#define F_ALTALLOC 0x04 // OK to malloc from alt. ram
#define F_RESERVED 0x08 // reserved for future use
#define F_MEMFLAGS 0xf0 // reserved for future use
#define F_SHTEXT 0x800 // program's text may be shared
#define F_MINALT 0xf0000000 // used to decide which type of RAM to load in
/* Bit in Mxalloc's arg for "don't auto-free this memory" */
#define F_KEEP 0x4000
#define F_OS_SPECIAL 0x8000 // mark as a special process
/* flags for curproc->memflags (that is, fh_flag) and also Mxalloc mode. */
/* (Actually, when users call Mxalloc, they add 0x10 to what you see here) */
#define F_PROTMODE 0xf0 // protection mode bits
#define F_PROT_P 0x00 // no read or write
#define F_PROT_G 0x10 // any access OK
#define F_PROT_S 0x20 // any super access OK
#define F_PROT_PR 0x30 // any read OK, no write
#define F_PROT_I 0x40 // invalid page
/*************************************************************************
// util
**************************************************************************/
bool PackTos::readExeHeader()
{
fi->seek(0,SEEK_SET);
fi->readx(&ih, FH_SIZE);
if (ih.fh_magic != 0x601a)
return false;
if (FH_SIZE + ih.fh_text + ih.fh_data + ih.fh_sym > (unsigned) file_size)
return false;
return true;
}
bool PackTos::checkExeHeader()
{
const unsigned f = ih.fh_flag;
//printf("flags: 0x%x, text: %d, data: %d, bss: %d, sym: %d\n", f, (int)ih.fh_text, (int)ih.fh_data, (int)ih.fh_bss, (int)ih.fh_sym);
if ((ih.fh_text & 1) || (ih.fh_data & 1))
throwCantPack("odd size values in text/data");
if (f & F_OS_SPECIAL)
throwCantPack("I won't pack F_OS_SPECIAL programs");
if ((f & F_PROTMODE) > F_PROT_I)
throwCantPack("invalid protection mode");
if (ih.fh_reserved != 0)
{
if (opt->force < 1)
throwCantPack("reserved header field set; use option `-f' to force packing");
}
if ((f & F_PROTMODE) != F_PROT_P)
{
if (opt->force < 1)
throwCantPack("no private memory protection; use option `-f' to force packing");
}
if (f & F_SHTEXT)
{
if (opt->force < 1)
throwCantPack("shared text segment; use option `-f' to force packing");
}
return true;
}
void PackTos::patch_d0_subq(void *l, int llen,
const char *d0_old, const char *subq_old,
unsigned d0_new)
{
void *p;
// patch "subq.l #1,d0" or "subq.w #1,d0"
p = find_be16(l, llen, get_be16(subq_old));
checkPatch(l, p, 2);
set_be16(p, d0_new > 65535 ? 0x5380 : 0x5340);
//
p = find_be32(l, llen, get_be32(d0_old));
checkPatch(l, p, 4);
set_be32(p, d0_new);
assert(get_be16(p, -2) == 0x203c); // move.l #XXXXXXXX,d0
}
/*************************************************************************
// relocs
**************************************************************************/
// Check relocation for errors to make sure our loader can handle it.
static int check_relocs(const upx_byte *relocs, unsigned rsize, unsigned isize,
unsigned *relocsize, unsigned *overlay)
{
unsigned fixup = get_be32(relocs);
unsigned last_fixup = fixup;
unsigned i = 4;
assert(isize >= 4);
assert(fixup > 0);
for (;;)
{
if (fixup & 1) // must be word-aligned
return -1;
if (fixup + 4 > isize) // too far
return -1;
if (i >= rsize) // premature EOF in relocs
return -1;
int c = relocs[i++];
if (c == 0) // end marker
break;
else if (c == 1) // increase fixup, no reloc
fixup += 254;
else if (c & 1) // must be word-aligned
return -1;
else // next reloc is here
{
fixup += c;
if (fixup - last_fixup < 4) // overlapping relocation
return -1;
last_fixup = fixup;
}
}
*relocsize = i;
*overlay = rsize - i;
return 0;
}
/*************************************************************************
//
**************************************************************************/
bool PackTos::canPack()
{
if (!readExeHeader())
return false;
unsigned char buf[512];
fi->readx(buf,sizeof(buf));
if (find_le32(buf,sizeof(buf),UPX_MAGIC_LE32))
throwAlreadyPacked();
if (!checkExeHeader())
throwCantPack("unsupported header flags");
if (file_size < 256)
throwCantPack("program too small");
return true;
}
void PackTos::fileInfo()
{
if (!readExeHeader())
return;
con_fprintf(stdout, " text: %d, data: %d, sym: %d, bss: %d, flags=0x%x\n",
(int)ih.fh_text, (int)ih.fh_data, (int)ih.fh_sym, (int)ih.fh_bss, (int)ih.fh_flag);
}
/*************************************************************************
//
**************************************************************************/
void PackTos::pack(OutputFile *fo)
{
unsigned t;
unsigned relocsize = 0;
unsigned overlay = 0;
const unsigned lsize = getLoaderSize();
const unsigned e_len = get_be16(getLoader()+lsize-4);
const unsigned d_len = get_be16(getLoader()+lsize-2);
assert(e_len + d_len == lsize - 4);
assert((e_len & 3) == 0 && (d_len & 1) == 0);
const unsigned i_text = ih.fh_text;
const unsigned i_data = ih.fh_data;
const unsigned i_sym = ih.fh_sym;
const unsigned i_bss = ih.fh_bss;
// read file
const unsigned isize = file_size - i_sym;
ibuf.alloc(isize);
fi->seek(FH_SIZE, SEEK_SET);
// read text + data
t = i_text + i_data;
fi->readx(ibuf,t);
// skip symbols
fi->seek(i_sym,SEEK_CUR);
// read relocations + overlay
overlay = file_size - (FH_SIZE + i_text + i_data + i_sym);
fi->readx(ibuf+t,overlay);
#if 0 || defined(TESTING)
printf("text: %d, data: %d, sym: %d, bss: %d, flags=0x%x\n",
i_text, i_data, i_sym, i_bss, (int)fh_flag);
printf("xx1 reloc: %d, overlay: %d, fixup: %d\n", relocsize, overlay, overlay >= 4 ? (int)get_be32(ibuf+t) : -1);
#endif
// Check relocs (see load_and_reloc() in mint/src/mem.c).
// Must work around TOS bugs and lots of broken programs.
int r = 0;
if (overlay < 4)
{
// Bug workaround: Whatever this is, silently keep it in
// the (unused) relocations for byte-identical unpacking.
relocsize = overlay;
overlay = 0;
}
else if (get_be32(ibuf+t) == 0)
{
// Bug workaround - check the empty fixup before testing fh_reloc.
relocsize = 4;
overlay -= 4;
}
else if (ih.fh_reloc != 0)
relocsize = 0;
else
r = check_relocs(ibuf+t, overlay, t, &relocsize, &overlay);
#if 0 || defined(TESTING)
printf("xx2 reloc: %d, overlay: %d, t: %d\n", relocsize, overlay, t);
#endif
if (r != 0)
throwCantPack("bad relocation table");
checkOverlay(overlay);
// Append original fileheader.
t += relocsize;
ih.fh_sym = 0; // we stripped all symbols
memcpy(ibuf+t, &ih, FH_SIZE);
t += FH_SIZE;
#if 0 || defined(TESTING)
printf("xx3 reloc: %d, overlay: %d, t: %d\n", relocsize, overlay, t);
#endif
assert(t <= isize);
// Now the data in ibuf[0..t] looks like this:
// text + data + relocs + original file header
// After compression this will become the first part of the
// data segement. The second part will be the decompressor.
// alloc buffer
obuf.allocForCompression(t + d_len + 512);
// compress (max_match = 65535)
ph.u_len = t;
if (!compress(ibuf,obuf,0,65535))
throwNotCompressible();
// The decompressed data will now get placed at this offset:
const unsigned overlapoh = findOverlapOverhead(obuf, 512);
unsigned offset = (ph.u_len + overlapoh) - ph.c_len;
// compute addresses
unsigned o_text, o_data, o_bss;
o_text = e_len;
o_data = ph.c_len;
o_bss = i_bss;
// word align len of compressed data
while (o_data & 1)
{
obuf[o_data++] = 0;
offset++;
}
// append decompressor (part 2 of loader)
const unsigned d_off = o_data;
memcpy(obuf+d_off, getLoader()+e_len, d_len);
o_data += d_len;
// dword align the len of the final data segment
while (o_data & 3)
{
obuf[o_data++] = 0;
offset++;
}
// dword align offset
while (offset & 3)
offset++;
// new bss
if (i_text + i_data + i_bss > o_text + o_data + o_bss)
o_bss = (i_text + i_data + i_bss) - (o_text + o_data);
// dirty bss
unsigned dirty_bss = (o_data + offset) - (i_text + i_data);
//printf("real dirty_bss: %d\n", dirty_bss);
// dword align (or 16 - for speedup when clearing the dirty bss)
const unsigned dirty_bss_align = opt->small ? 4 : 16;
while (dirty_bss & (dirty_bss_align - 1))
dirty_bss++;
// adjust bss, assert room for some stack
if (dirty_bss + 256 > o_bss)
o_bss = dirty_bss + 256;
// dword align the len of the final bss segment
while (o_bss & 3)
o_bss++;
// prepare loader
MemBuffer loader(o_text);
memcpy(loader,getLoader(),o_text);
// patch loader
// patch "subq.l #1,d0" or "subq.w #1,d0" - see "up41" below
if (!opt->small)
patchVersion(loader,o_text);
patch_be16(loader,o_text,"u4",
dirty_bss / dirty_bss_align > 65535 ? 0x5380 : 0x5340);
patch_be32(loader,o_text,"up31",d_off + offset);
if (opt->small)
patch_d0_subq(loader,o_text,"up22","u1", o_data/4);
else
{
if (o_data <= 160)
throwNotCompressible();
unsigned loop1 = o_data / 160;
unsigned loop2 = o_data % 160;
if (loop2 == 0)
{
loop1--;
loop2 = 160;
}
patch_be16(loader,o_text,"u2", 0x7000 + loop2/4-1); // moveq.l #X,d0
patch_d0_subq(loader,o_text,"up22","u1", loop1);
}
patch_be32(loader,o_text,"up21",o_data + offset);
patch_be32(loader,o_text,"up13",i_bss); // p_blen
patch_be32(loader,o_text,"up12",i_data); // p_dlen
patch_be32(loader,o_text,"up11",i_text); // p_tlen
putPackHeader(loader,o_text);
// patch decompressor
upx_byte *p = obuf + d_off;
patch_be32(p,d_len,"up41", dirty_bss / dirty_bss_align);
patch_be16(p,d_len,"u3", 0x7600 + (relocsize > 4)); // moveq.l #X,d3
// set new file_hdr
memcpy(&oh, &ih, FH_SIZE);
if (opt->tos.split_segments)
{
oh.fh_text = o_text;
oh.fh_data = o_data;
}
else
{
// put everything into the text segment
oh.fh_text = o_text + o_data;
oh.fh_data = 0;
}
oh.fh_bss = o_bss;
oh.fh_sym = 0;
oh.fh_reserved = 0;
// only keep the following flags:
oh.fh_flag = ih.fh_flag & (F_FASTLOAD | F_ALTALLOC | F_KEEP);
// add an empty relocation fixup to workaround a bug in some TOS versions
oh.fh_reloc = 0;
#if 0 || defined(TESTING)
printf("old text: %6d, data: %6d, bss: %6d, reloc: %d, overlay: %d\n",
i_text, i_data, i_bss, relocsize, overlay);
printf("new text: %6d, data: %6d, bss: %6d, dirty_bss: %d, flag=0x%x\n",
o_text, o_data, o_bss, dirty_bss, (int)fh_flag);
#endif
// write new file header, loader and compressed file
fo->write(&oh, FH_SIZE);
fo->write(loader, o_text); // entry
fo->write(obuf, o_data); // compressed + decompressor
// write empty relocation fixup
fo->write("\x00\x00\x00\x00",4);
// verify
verifyOverlappingDecompression(&obuf, overlapoh);
// copy the overlay
copyOverlay(fo, overlay, &obuf);
}
/*************************************************************************
//
**************************************************************************/
bool PackTos::canUnpack()
{
if (!readPackHeader(512, 0))
return false;
if (!readExeHeader())
return false;
// check header as set by packer
if ((ih.fh_text & 3) != 0 || (ih.fh_data & 3) != 0 || (ih.fh_bss & 3) != 0
|| ih.fh_sym != 0 || ih.fh_reserved != 0 || ih.fh_reloc > 1)
throwCantUnpack("file damaged");
if (!checkExeHeader())
throwCantUnpack("unsupported header flags");
return true;
}
/*************************************************************************
//
**************************************************************************/
void PackTos::unpack(OutputFile *fo)
{
ibuf.alloc(ph.c_len);
obuf.allocForUncompression(ph.u_len);
fi->seek(ph.buf_offset + ph.getPackHeaderSize(),SEEK_SET);
fi->readx(ibuf,ph.c_len);
// decompress
decompress(ibuf,obuf);
// write original header & decompressed file
if (fo)
{
unsigned overlay = file_size - (FH_SIZE + ih.fh_text + ih.fh_data);
if (ih.fh_reloc == 0 && overlay >= 4)
overlay -= 4; // this is our empty fixup
checkOverlay(overlay);
fo->write(obuf+ph.u_len-FH_SIZE, FH_SIZE); // orig. file_hdr
fo->write(obuf, ph.u_len-FH_SIZE); // orig. text+data+relocs
// copy any overlay
copyOverlay(fo, overlay, &obuf);
}
}
/*
vi:ts=4:et
*/

85
src/p_tos.h Normal file
View File

@ -0,0 +1,85 @@
/* p_tos.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_TOS_H
#define __UPX_P_TOS_H
/*************************************************************************
// atari/tos
**************************************************************************/
class PackTos : public Packer
{
typedef Packer super;
public:
PackTos(InputFile *f);
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_ATARI_TOS; }
virtual const char *getName() const { return "atari/tos"; }
virtual int getCompressionMethod() const;
virtual const int *getFilters() const;
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canPack();
virtual bool canUnpack();
virtual void fileInfo();
protected:
virtual const upx_byte *getLoader() const;
virtual int getLoaderSize() const;
bool readExeHeader();
bool checkExeHeader();
struct tos_header_t
{
BE16 fh_magic;
BE32 fh_text;
BE32 fh_data;
BE32 fh_bss;
BE32 fh_sym;
BE32 fh_reserved;
BE32 fh_flag;
BE16 fh_reloc;
} ih, oh;
protected:
void patch_d0_subq(void *l, int llen, const char*, const char*, unsigned);
};
#endif /* already included */
/*
vi:ts=4:et
*/

460
src/p_unix.cpp Normal file
View File

@ -0,0 +1,460 @@
/* p_unix.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "packer.h"
#include "p_unix.h"
#include "p_elf.h"
// do not change
#define BLOCKSIZE (512*1024)
/*************************************************************************
//
**************************************************************************/
PackUnix::PackUnix(InputFile *f) :
super(f), exetype(0), blocksize(0), overlay_offset(0), lsize(0)
{
assert(sizeof(Elf_LE32_Ehdr) == 52);
assert(sizeof(Elf_LE32_Phdr) == 32);
}
// common part of canPack(), enhanced by subclasses
bool PackUnix::canPack()
{
if (exetype == 0)
return false;
#if defined(__unix__)
// must be executable by owner
if ((fi->st.st_mode & S_IXUSR) == 0)
throwCantPack("file not executable; try `chmod +x'");
#endif
if (file_size < 4096)
throwCantPack("file is too small");
// info: currently the header is 36 (32+4) bytes before EOF
unsigned char buf[256];
fi->seek(-(long)sizeof(buf), SEEK_END);
fi->readx(buf,sizeof(buf));
if (find_le32(buf,sizeof(buf),UPX_MAGIC_LE32)) // note: always le32
throwAlreadyPacked();
return true;
}
/*************************************************************************
// Generic Unix pack(). Subclasses must provide patchLoader().
//
// A typical compressed Unix executable looks like this:
// - loader stub
// - 12 bytes header info
// - the compressed blocks, each with a 8 byte header for block sizes
// - 4 bytes block end marker (uncompressed size 0)
// - 32 bytes UPX packheader
// - 4 bytes overlay offset (needed for decompression)
**************************************************************************/
// see note below and Packer::compress()
bool PackUnix::checkCompressionRatio(unsigned, unsigned) const
{
return true;
}
void PackUnix::pack(OutputFile *fo)
{
// set options
blocksize = opt->unix.blocksize;
if (blocksize <= 0)
blocksize = BLOCKSIZE;
if ((off_t)blocksize > file_size)
blocksize = file_size;
// create a pseudo-unique program id for our paranoid stub
progid = getRandomId();
// prepare loader
lsize = getLoaderSize();
loader.alloc(lsize + sizeof(p_info));
memcpy(loader,getLoader(),lsize);
// patch loader, prepare header info
patchLoader(); // can change lsize by packing C-code of upx_main etc.
p_info *const hbuf = (p_info *)(loader + lsize);
set_native32(&hbuf->p_progid, progid);
set_native32(&hbuf->p_filesize, file_size);
set_native32(&hbuf->p_blocksize, blocksize);
fo->write(loader, lsize + sizeof(p_info));
// init compression buffers
ibuf.alloc(blocksize);
obuf.allocForCompression(blocksize);
// compress blocks
unsigned total_in = 0;
unsigned total_out = 0;
this->total_passes = (file_size + blocksize - 1) / blocksize;
if (this->total_passes == 1)
this->total_passes = 0;
fi->seek(0, SEEK_SET);
for (;;)
{
int l = fi->read(ibuf, blocksize);
if (l == 0)
break;
// Note: compression for a block can fail if the
// file is e.g. blocksize + 1 bytes long
// compress
ph.u_len = l;
(void) compress(ibuf, obuf); // ignore return value
if (ph.c_len < ph.u_len)
{
if (!testOverlappingDecompression(obuf, OVERHEAD))
throwNotCompressible();
}
else
{
// block is not compressible
ph.c_len = ph.u_len;
// must manually update checksum of compressed data
ph.c_adler = upx_adler32(ph.c_adler, ibuf, ph.u_len);
}
// write block sizes
unsigned char size[8];
set_native32(size+0, ph.u_len);
set_native32(size+4, ph.c_len);
fo->write(size, 8);
// write compressed data
if (ph.c_len < ph.u_len)
{
fo->write(obuf, ph.c_len);
verifyOverlappingDecompression(&obuf, OVERHEAD);
}
else
fo->write(ibuf, ph.u_len);
total_in += ph.u_len;
total_out += ph.c_len;
}
if ((off_t)total_in != file_size)
throw EOFException();
// write block end marker (uncompressed size 0)
fo->write("\x00\x00\x00\x00", 4);
// update header with totals
ph.u_len = total_in;
ph.c_len = total_out;
// write packheader
const int hsize = ph.getPackHeaderSize();
set_le32(obuf, ph.magic); // note: always le32
putPackHeader(obuf, hsize);
fo->write(obuf, hsize);
// write overlay offset (needed for decompression)
set_native32(obuf, lsize);
fo->write(obuf, 4);
// finally check compression ratio
if (!Packer::checkCompressionRatio(fo->getBytesWritten(), ph.u_len))
throwNotCompressible();
}
/*************************************************************************
// Generic Unix canUnpack().
**************************************************************************/
bool PackUnix::canUnpack()
{
upx_byte buf[128];
const int bufsize = sizeof(buf);
fi->seek(-bufsize, SEEK_END);
if (!readPackHeader(128, -1, buf))
return false;
int l = ph.buf_offset + ph.getPackHeaderSize();
if (l < 0 || l + 4 > bufsize)
throwCantUnpack("file corrupted");
overlay_offset = get_native32(buf+l);
if ((off_t)overlay_offset >= file_size)
throwCantUnpack("file corrupted");
return true;
}
/*************************************************************************
// Generic Unix unpack().
//
// This code looks much like the one in stub/l_linux.c
// See notes there.
**************************************************************************/
void PackUnix::unpack(OutputFile *fo)
{
unsigned c_adler = upx_adler32(0, NULL, 0);
unsigned u_adler = upx_adler32(0, NULL, 0);
// defaults for ph.version == 8
unsigned orig_file_size = 0;
blocksize = 512 * 1024;
fi->seek(overlay_offset, SEEK_SET);
if (ph.version > 8)
{
p_info hbuf;
fi->readx(&hbuf, sizeof(hbuf));
orig_file_size = get_native32(&hbuf.p_filesize);
blocksize = get_native32(&hbuf.p_blocksize);
if (file_size > (off_t)orig_file_size || blocksize > orig_file_size)
throwCantUnpack("file header corrupted");
}
else
{
// skip 4 bytes (program id)
fi->seek(4, SEEK_CUR);
}
ibuf.alloc(blocksize + OVERHEAD);
// decompress blocks
unsigned total_in = 0;
unsigned total_out = 0;
for (;;)
{
#define buf ibuf
int i;
int size[2];
fi->readx(buf, 8);
ph.u_len = size[0] = get_native32(buf+0);
ph.c_len = size[1] = get_native32(buf+4);
if (size[0] == 0) // uncompressed size 0 -> EOF
{
// note: must reload size[1] as magic is always stored le32
size[1] = get_le32(buf+4);
if (size[1] != UPX_MAGIC_LE32) // size[1] must be h->magic
throwCompressedDataViolation();
break;
}
if (size[0] <= 0 || size[1] <= 0)
throwCompressedDataViolation();
if (size[1] > size[0] || size[0] > (int)blocksize)
throwCompressedDataViolation();
i = blocksize + OVERHEAD - size[1];
fi->readx(buf+i, size[1]);
// update checksum of compressed data
c_adler = upx_adler32(c_adler, buf + i, size[1]);
// decompress
if (size[1] < size[0])
{
decompress(buf+i, buf, false);
i = 0;
}
// update checksum of uncompressed data
u_adler = upx_adler32(u_adler, buf + i, size[0]);
total_in += size[1];
total_out += size[0];
// write block
if (fo)
fo->write(buf + i, size[0]);
#undef buf
}
// update header with totals
ph.c_len = total_in;
ph.u_len = total_out;
// all bytes must be written
if (ph.version > 8 && total_out != orig_file_size)
throw EOFException();
// finally test the checksums
if (ph.c_adler != c_adler || ph.u_adler != u_adler)
throwChecksumError();
}
/*************************************************************************
// Linux/i386 specific (execve format)
**************************************************************************/
static const
#include "stub/l_lx_n2b.h"
static const
#include "stub/l_lx_n2d.h"
int PackLinuxI386::getCompressionMethod() const
{
if (M_IS_NRV2B(opt->method))
return M_NRV2B_LE32;
if (M_IS_NRV2D(opt->method))
return M_NRV2D_LE32;
return opt->level > 1 && file_size >= 512*1024 ? M_NRV2D_LE32 : M_NRV2B_LE32;
}
const upx_byte *PackLinuxI386::getLoader() const
{
if (M_IS_NRV2B(opt->method))
return linux_i386exec_nrv2b_loader;
if (M_IS_NRV2D(opt->method))
return linux_i386exec_nrv2d_loader;
return NULL;
}
int PackLinuxI386::getLoaderSize() const
{
if (0!=lsize) {
return lsize;
}
if (M_IS_NRV2B(opt->method))
return sizeof(linux_i386exec_nrv2b_loader);
if (M_IS_NRV2D(opt->method))
return sizeof(linux_i386exec_nrv2d_loader);
return 0;
}
int PackLinuxI386::getLoaderPrefixSize() const
{
return 116;
}
bool PackLinuxI386::canPack()
{
Elf_LE32_Ehdr ehdr;
unsigned char *buf = ehdr.e_ident;
fi->readx(&ehdr, sizeof(ehdr));
fi->seek(0, SEEK_SET);
exetype = 0;
const unsigned l = get_le32(buf);
if (!memcmp(buf, "\x7f\x45\x4c\x46\x01\x01\x01", 7)) // ELF 32-bit LSB
{
exetype = 1;
// now check the ELF header
if (!memcmp(buf+8, "FreeBSD", 7)) // branded
exetype = 0;
if (ehdr.e_type != 2) // executable
exetype = 0;
if (ehdr.e_machine != 3 && ehdr.e_machine != 6) // Intel 80[34]86
exetype = 0;
if (ehdr.e_version != 1) // version
exetype = 0;
}
else if (l == 0x00640107 || l == 0x00640108 || l == 0x0064010b || l == 0x006400cc)
{
// OMAGIC / NMAGIC / ZMAGIC / QMAGIC
exetype = 2;
// FIXME: N_TRSIZE, N_DRSIZE
// FIXME: check for aout shared libraries
}
#if defined(__linux__)
// only compress scripts when running under Linux
else if (!memcmp(buf, "#!/", 3)) // #!/bin/sh
exetype = -1;
else if (!memcmp(buf, "#! /", 4)) // #! /bin/sh
exetype = -1;
else if (!memcmp(buf, "\xca\xfe\xba\xbe", 4)) // Java bytecode
exetype = -2;
#endif
return super::canPack();
}
void PackLinuxI386::patchLoader()
{
lsize = getLoaderSize();
// mmapsize is (blocksize + OVERHEAD) rounded up to next PAGE_SIZE
const unsigned pagesize = 4096;
const unsigned mmapsize = ALIGN_UP(blocksize + OVERHEAD, pagesize);
// patch loader
// note: we only can use /proc/<pid>/fd when exetype > 0.
// also, we sleep much longer when compressing a script.
patch_le32(loader,lsize,"UPX5",mmapsize);
patch_le32(loader,lsize,"UPX4",exetype > 0 ? 3 : 15); // sleep time
patch_le32(loader,lsize,"UPX3",exetype > 0 ? 0 : 0x7fffffff);
patch_le32(loader,lsize,"UPX2",progid);
patch_le32(loader,lsize,"UPX1",lsize);
patchVersion(loader,lsize);
// The beginning of our loader consists of a elf_hdr (52 bytes) and
// two sections elf_phdr (2 * 32 byte), so we have 12 free bytes
// from offset 116 to the program start at offset 128.
assert(get_le32(loader + 28) == 52); // e_phoff
assert(get_le32(loader + 32) == 0); // e_shoff
assert(get_le16(loader + 40) == 52); // e_ehsize
assert(get_le16(loader + 42) == 32); // e_phentsize
assert(get_le16(loader + 44) == 2); // e_phnum
assert(get_le16(loader + 48) == 0); // e_shnum
assert(lsize > 128 && lsize < 4096);
patchLoaderChecksum();
}
void PackLinuxI386::patchLoaderChecksum()
{
l_info *const lp = (l_info *)(loader + getLoaderPrefixSize());
// checksum for loader + p_info
lp->l_checksum = 0; // (this checksum is currently unused)
lp->l_magic = UPX_ELF_MAGIC;
lp->l_lsize = lsize;
lp->l_version = (unsigned char) ph.version;
lp->l_format = (unsigned char) ph.format;
unsigned adler = upx_adler32(0,NULL,0);
adler = upx_adler32(adler, loader, lsize + sizeof(p_info));
lp->l_checksum = adler;
}
/*
vi:ts=4:et
*/

217
src/p_unix.h Normal file
View File

@ -0,0 +1,217 @@
/* p_unix.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_UNIX_H
#define __UPX_P_UNIX_H
/*************************************************************************
// Abstract class for all Unix-type packers.
// Already provides most of the functionality.
**************************************************************************/
class PackUnix : public Packer
{
typedef Packer super;
protected:
PackUnix(InputFile *f);
public:
virtual int getVersion() const { return 11; }
virtual const int *getFilters() const { return NULL; }
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canPack();
virtual bool canUnpack();
protected:
// called by the generic pack()
virtual void patchLoader() = 0;
virtual void patchLoaderChecksum() {}
// in order too share as much code as possible we introduce
// an endian abstraction here
virtual unsigned get_native32(const void *, int off=0) = 0;
virtual void set_native32(void *, unsigned, int off=0) = 0;
virtual bool checkCompressionRatio(unsigned, unsigned) const;
int exetype;
unsigned blocksize;
unsigned progid; // program id
unsigned overlay_offset; // used when decompressing
MemBuffer loader;
int lsize;
struct l_info { // 12-byte trailer in header for loader
unsigned l_checksum;
unsigned l_magic;
unsigned short l_lsize;
unsigned char l_version;
unsigned char l_format;
};
struct p_info { // 12-byte packed program header
unsigned p_progid;
unsigned p_filesize;
unsigned p_blocksize;
};
// do not change !!!
enum { OVERHEAD = 2048 };
};
/*************************************************************************
// abstract classes encapsulating endian issues
// note: UPX_MAGIC is always stored in le32 format
**************************************************************************/
class PackUnixBe32 : public PackUnix
{
typedef PackUnix super;
protected:
PackUnixBe32(InputFile *f) : super(f) { }
virtual unsigned get_native32(const void * b, int off=0)
{
return get_be32(b, off);
}
virtual void set_native32(void * b, unsigned v, int off=0)
{
set_be32(b, v, off);
}
};
class PackUnixLe32 : public PackUnix
{
typedef PackUnix super;
protected:
PackUnixLe32(InputFile *f) : super(f) { }
virtual unsigned get_native32(const void * b, int off=0)
{
return get_le32(b, off);
}
virtual void set_native32(void * b, unsigned v, int off=0)
{
set_le32(b, v, off);
}
};
/*************************************************************************
// linux/i386 (execve format)
**************************************************************************/
class PackLinuxI386 : public PackUnixLe32
{
typedef PackUnixLe32 super;
public:
PackLinuxI386(InputFile *f) : super(f) { }
virtual int getFormat() const { return UPX_F_LINUX_i386; }
virtual const char *getName() const { return "linux/386"; }
virtual int getCompressionMethod() const;
virtual bool canPack();
protected:
virtual const upx_byte *getLoader() const;
virtual int getLoaderSize() const;
virtual int getLoaderPrefixSize() const;
virtual void patchLoader();
virtual void patchLoaderChecksum();
enum {
UPX_ELF_MAGIC = 0x5850557f // "\x7fUPX"
};
};
/*************************************************************************
// bvmlinux/i386 (Linux kernel image)
// vmlinux/i386 (Linux kernel image)
**************************************************************************/
class PackBvmlinuxI386 : public Packer
{
typedef Packer super;
public:
PackBvmlinuxI386(InputFile *f);
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_BVMLINUX_i386; }
virtual const char *getName() const { return "bvmlinux/386"; }
virtual int getCompressionMethod() const;
virtual const int *getFilters() const { return NULL; }
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canPack();
virtual bool canUnpack();
protected:
// virtual const upx_byte *getLoader() const;
// virtual int getLoaderSize() const;
unsigned elf_offset;
};
/*************************************************************************
// solaris/sparc
**************************************************************************/
#if 0
class PackSolarisSparc : public PackUnixBe32
{
typedef PackUnixBe32 super;
public:
PackSolarisSparc(InputFile *f) : super(f) { }
virtual int getFormat() const { return UPX_F_SOLARIS_SPARC; }
virtual const char *getName() const { return "solaris/sparc"; }
virtual bool canPack();
protected:
virtual const upx_byte *getLoader() const;
virtual int getLoaderSize() const;
virtual void patchLoader();
};
#endif
#endif /* already included */
/*
vi:ts=4:et
*/

154
src/p_vmlinux.cpp Normal file
View File

@ -0,0 +1,154 @@
/* p_vmlinux.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "packer.h"
#include "p_unix.h"
#include "p_elf.h"
#include <zlib.h>
/*************************************************************************
//
**************************************************************************/
PackBvmlinuxI386::PackBvmlinuxI386(InputFile *f) :
super(f), elf_offset(0)
{
}
int PackBvmlinuxI386::getCompressionMethod() const
{
return M_NRV2D_LE32;
}
bool PackBvmlinuxI386::canPack()
{
Elf_LE32_Ehdr ehdr;
Elf_LE32_Phdr text;
Elf_LE32_Phdr data;
unsigned char *buf = ehdr.e_ident;
fi->seek(elf_offset, SEEK_SET);
fi->readx(&ehdr, sizeof(ehdr));
fi->readx(&text, sizeof(text));
fi->readx(&data, sizeof(data));
// check the ELF header
if (memcmp(buf, "\x7f\x45\x4c\x46\x01\x01\x01", 7)) // ELF 32-bit LSB
return false;
if (!memcmp(buf+8, "FreeBSD", 7)) // branded
return false;
if (ehdr.e_type != 2) // executable
return false;
if (ehdr.e_machine != 3 && ehdr.e_machine != 6) // Intel 80[34]86
return false;
if (ehdr.e_version != 1) // version
return false;
// now check for bvmlinux
if (ehdr.e_phoff != 52 || ehdr.e_ehsize != 52 || ehdr.e_phentsize != 32)
return false;
if (ehdr.e_entry != 0x100000 || ehdr.e_phnum != 2)
return false;
// check for bvmlinux - text segment
if (text.p_type != 1 || text.p_offset != 0x1000)
return false;
if (text.p_vaddr != 0x100000 || text.p_paddr != 0x100000)
return false;
if (text.p_flags != 5)
return false;
// check for bvmlinux - data segment
if (data.p_type != 1)
return false;
if (data.p_filesz < 200000)
return false;
if (data.p_flags != 6)
return false;
// check gzip data
unsigned char magic[2];
LE32 uncompressed_size;
off_t gzip_offset = elf_offset + data.p_offset + 472;
fi->seek(gzip_offset, SEEK_SET);
fi->readx(magic, 2);
if (memcmp(magic, "\037\213", 2))
return false;
fi->seek(data.p_filesz - 2 - 4 - 472, SEEK_CUR);
fi->readx(&uncompressed_size, 4);
if (uncompressed_size < data.p_filesz || uncompressed_size > 4*1024*1024)
return false;
// uncompress kernel with zlib
fi->seek(gzip_offset, SEEK_SET);
gzFile f = gzdopen(fi->getFd(), "r");
if (f == NULL)
return false;
ibuf.alloc(uncompressed_size);
unsigned ilen = gzread(f, ibuf, uncompressed_size);
bool ok = ilen == uncompressed_size;
gzclose(f);
printf("decompressed kernel: %d -> %d\n", (int)data.p_filesz, ilen);
return ok;
}
/*************************************************************************
//
**************************************************************************/
void PackBvmlinuxI386::pack(OutputFile *fo)
{
fo = fo;
}
/*************************************************************************
//
**************************************************************************/
bool PackBvmlinuxI386::canUnpack()
{
return false;
}
void PackBvmlinuxI386::unpack(OutputFile *fo)
{
fo = fo;
}
/*
vi:ts=4:et
*/

72
src/p_vxd.h Normal file
View File

@ -0,0 +1,72 @@
/* p_vxd.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_VXD_H
#define __UPX_P_VXD_H
/*************************************************************************
// Vxd
**************************************************************************/
class PackVxd : public PackWcle
{
typedef PackWcle super;
public:
PackVxd(InputFile *f);
~PackVxd();
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_VXD_LE; }
virtual const char *getName() const { return "vxd/le"; }
virtual int getCompressionMethod() const;
virtual const int *getFilters() const;
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
protected:
virtual void encodeObjectTable();
virtual void decodeObjectTable();
virtual void encodeFixupPageTable();
virtual void decodeFixupPageTable();
virtual void encodeFixups();
virtual void decodeFixups();
virtual void encodeImage(const Filter *ft);
virtual void decodeImage();
};
#endif /* already included */
/*
vi:ts=4:et
*/

2206
src/p_w32pe.cpp Normal file

File diff suppressed because it is too large Load Diff

229
src/p_w32pe.h Normal file
View File

@ -0,0 +1,229 @@
/* p_w32pe.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_W32PE_H
#define __UPX_P_W32PE_H
class PackW32Pe_Interval;
class PackW32Pe_Reloc;
class PackW32Pe_Resource;
class PackW32Pe_Export;
/*************************************************************************
// w32/pe
**************************************************************************/
class PackW32Pe : public Packer
{
typedef Packer super;
public:
PackW32Pe(InputFile *f);
~PackW32Pe();
virtual int getVersion() const { return 12; }
virtual int getFormat() const { return UPX_F_W32_PE; }
virtual const char *getName() const { return isrtm ? "rtm32/pe" : "win32/pe"; }
virtual int getCompressionMethod() const;
virtual const int *getFilters() const;
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canPack();
virtual bool canUnpack();
// unpacker capabilities
virtual bool canUnpackVersion(int version) const
{
return (version == 12);
}
protected:
unsigned pe_offset;
bool isrtm;
bool readFileHeader();
unsigned processImports();
void processImports(unsigned);
void rebuildImports(upx_byte *&);
upx_byte *oimport;
unsigned soimport;
upx_byte *oimpdlls;
unsigned soimpdlls;
int processRelocs();
void processRelocs(PackW32Pe_Reloc *);
void rebuildRelocs(upx_byte *&);
upx_byte *orelocs;
unsigned sorelocs;
upx_byte *oxrelocs;
unsigned soxrelocs;
void processExports(PackW32Pe_Export *);
void processExports(PackW32Pe_Export *,unsigned);
void rebuildExports();
upx_byte *oexport;
unsigned soexport;
void processResources(PackW32Pe_Resource *);
void processResources(PackW32Pe_Resource *, unsigned);
void rebuildResources(upx_byte *&);
upx_byte *oresources;
unsigned soresources;
void processTls(PackW32Pe_Interval *);
void processTls(PackW32Pe_Reloc *,const PackW32Pe_Interval *,unsigned);
void rebuildTls();
upx_byte *otls;
unsigned sotls;
unsigned stripDebug(unsigned);
unsigned icondir_offset;
int icondir_count;
bool importbyordinal;
bool kernel32ordinal;
unsigned tlsindex;
unsigned rvamin;
struct pe_header_t
{
// 0x0
char _[4]; // pemagic
LE16 cpu;
LE16 objects;
char __[12]; // timestamp + reserved
LE16 opthdrsize;
LE16 flags;
// optional header
char ___[4]; // coffmagic + linkerversion
LE32 codesize;
// 0x20
LE32 datasize;
LE32 bsssize;
LE32 entry;
LE32 codebase;
// 0x30
LE32 database;
// nt specific fields
LE32 imagebase;
LE32 objectalign;
LE32 filealign; // should set to 0x200 ?
// 0x40
char ____[16]; // versions
// 0x50
LE32 imagesize;
LE32 headersize;
LE32 chksum; // should set to 0
LE16 subsystem;
LE16 dllflags;
// 0x60
char _____[20]; // stack + heap sizes
// 0x74
LE32 ddirsentries; // usually 16
struct ddirs_t
{
LE32 vaddr;
LE32 size;
} ddirs[16];
} ih, oh;
struct pe_section_t
{
char name[8];
LE32 vsize;
LE32 vaddr;
LE32 size;
LE32 rawdataptr;
char _[12];
LE32 flags;
} *isection;
static unsigned virta2objnum (unsigned, pe_section_t *, unsigned);
unsigned tryremove (unsigned, unsigned);
enum {
PEDIR_EXPORT = 0,
PEDIR_IMPORT = 1,
PEDIR_RESOURCE = 2,
PEDIR_EXCEPTION = 3, // Exception table
PEDIR_SEC = 4, // Certificate table (file pointer)
PEDIR_RELOC = 5,
PEDIR_DEBUG = 6,
PEDIR_COPYRIGHT = 7, // Architecture-specific data
PEDIR_GLOBALPTR = 8, // Global pointer
PEDIR_TLS = 9,
PEDIR_LOADCONF = 10, // Load Config Table
PEDIR_BOUNDIM = 11,
PEDIR_IAT = 12,
PEDIR_DELAYIMP = 13, // Delay Import Descriptor
PEDIR_COMRT = 14 // Com+ Runtime Header
};
enum {
PEFL_CODE = 0x20,
PEFL_DATA = 0x40,
PEFL_BSS = 0x80,
PEFL_INFO = 0x200,
PEFL_EXTRELS = 0x01000000, // extended relocations
PEFL_DISCARD = 0x02000000,
PEFL_NOCACHE = 0x04000000,
PEFL_NOPAGE = 0x08000000,
PEFL_SHARED = 0x10000000,
PEFL_EXEC = 0x20000000,
PEFL_READ = 0x40000000,
PEFL_WRITE = 0x80000000
};
enum {
RELOCS_STRIPPED = 0x0001,
EXECUTABLE = 0x0002,
LNUM_STRIPPED = 0x0004,
LSYMS_STRIPPED = 0x0008,
AGGRESSIVE_TRIM = 0x0010,
TWO_GIGS_AWARE = 0x0020,
FLITTLE_ENDIAN = 0x0080,
BITS_32_MACHINE = 0x0100,
DEBUG_STRIPPED = 0x0200,
REMOVABLE_SWAP = 0x0400,
SYSTEM_PROGRAM = 0x1000,
DLL_FLAG = 0x2000,
FBIG_ENDIAN = 0x8000
};
};
#endif /* already included */
/*
vi:ts=4:et
*/

827
src/p_wcle.cpp Normal file
View File

@ -0,0 +1,827 @@
/* p_wcle.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "filter.h"
#include "packer.h"
#include "lefile.h"
#include "p_wcle.h"
static const
#include "stub/l_wcle.h"
#define LEOF_READ (1<<0)
#define LEOF_WRITE (1<<1)
#define LEOF_EXEC (1<<2)
#define LEOF_PRELOAD (1<<6)
#define LEOF_HUGE32 (1<<13)
#define IOT(x,y) iobject_table[x].y
#define OOT(x,y) oobject_table[x].y
#define LE_STUB_EDI (1)
#ifdef TESTING
# define dputc(x,y) do { if (opt->debug) putc(x,y); } while (0)
# define Opt_debug opt->debug
#else
# define dputc(x,y) ((void)0)
# define Opt_debug 0
#endif
#define my_base_address reserved
#define objects ih.object_table_entries
#define pages ih.memory_pages
#define mps ih.memory_page_size
#define opages oh.memory_pages
/*************************************************************************
//
**************************************************************************/
int PackWcle::getCompressionMethod() const
{
if (M_IS_NRV2B(opt->method))
return M_NRV2B_LE32;
if (M_IS_NRV2D(opt->method))
return M_NRV2D_LE32;
return opt->level > 1 && file_size >= 512*1024 ? M_NRV2D_LE32 : M_NRV2B_LE32;
}
const int *PackWcle::getFilters() const
{
static const int filters[] = { 0x26, 0x24, 0x14, 0x11, 0x16, 0x13,
0x25, 0x12, 0x15, -1 };
return filters;
}
/*************************************************************************
// util
**************************************************************************/
void PackWcle::handleStub(OutputFile *fo)
{
if (fo && !opt->wcle.le)
Packer::handleStub(fi,fo,le_offset);
}
bool PackWcle::canPack()
{
return LeFile::readFileHeader();
}
/*************************************************************************
//
**************************************************************************/
// IDEA: as all the entries go into object #1, I could create bundles with 255
// elements (of course I still have to handle empty bundles)
void PackWcle::encodeEntryTable()
{
unsigned count,object,n;
upx_byte *p = ientries;
n = 0;
while (*p)
{
count = *p;
n += count;
if (p[1] == 0) // unused bundle
p += 2;
else if (p[1] == 3) // 32-bit bundle
{
object = get_le16(p+2)-1;
set_le16(p+2,1);
p += 4;
for (; count; count--, p += 5)
set_le32(p+1,IOT(object,my_base_address) + get_le32(p+1));
}
else
throwCantPack("unsupported bundle type in entry table");
}
//if (Opt_debug) printf("%d entries encoded.\n",n);
soentries = p - ientries + 1;
oentries = ientries;
ientries = NULL;
}
void PackWcle::readObjectTable()
{
LeFile::readObjectTable();
// temporary copy of the object descriptors
iobject_desc.alloc(objects*sizeof(*iobject_table));
memcpy(iobject_desc,iobject_table,objects*sizeof(*iobject_table));
unsigned ic,jc,virtual_size;
for (ic = jc = virtual_size = 0; ic < objects; ic++)
{
jc += IOT(ic,npages);
IOT(ic,my_base_address) = virtual_size;
virtual_size += (IOT(ic,virtual_size)+mps-1) &~ (mps-1);
}
if (pages != jc)
throwCantPack("bad page number");
}
void PackWcle::encodeObjectTable()
{
unsigned ic,jc;
oobject_table = new le_object_table_entry_t[soobject_table = 2];
memset(oobject_table,0,soobject_table * sizeof(*oobject_table));
// object #1:
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;
if (ic < jc)
ic = jc;
unsigned csection = (ic + overlapoh + mps-1) &~ (mps-1);
OOT(0,virtual_size) = csection + mps;
OOT(0,flags) = LEOF_READ|LEOF_EXEC|LEOF_HUGE32|LEOF_PRELOAD;
OOT(0,pagemap_index) = 1;
OOT(0,npages) = opages;
// object #2: stack
OOT(1,base_address) = (OOT(0,base_address)
+OOT(0,virtual_size)+mps-1) & ~(mps-1);
OOT(1,virtual_size) = mps;
OOT(1,flags) = LEOF_READ|LEOF_HUGE32|LEOF_WRITE;
OOT(1,pagemap_index) = 1;
oh.init_cs_object = 1;
oh.init_eip_offset = neweip;
oh.init_ss_object = 2;
oh.init_esp_offset = OOT(1,virtual_size);
}
void PackWcle::encodePageMap()
{
opm_entries = new le_pagemap_entry_t[sopm_entries = opages];
for (unsigned ic = 0; ic < sopm_entries; ic++)
{
opm_entries[ic].l = (unsigned char) (ic+1);
opm_entries[ic].m = (unsigned char) ((ic+1)>>8);
opm_entries[ic].h = 0;
opm_entries[ic].type = 0;
}
}
void PackWcle::encodeFixupPageTable()
{
unsigned ic;
ofpage_table = new unsigned[sofpage_table = 1 + opages];
for (ofpage_table[0] = ic = 0; ic < opages; ic++)
set_le32(ofpage_table+ic+1,sofixups-FIXUP_EXTRA);
}
void PackWcle::encodeFixups()
{
ofixups = new upx_byte[sofixups = 1*7 + FIXUP_EXTRA];
memset(ofixups,0,sofixups);
ofixups[0] = 7;
set_le16(ofixups+2,(LE_STUB_EDI + neweip) & (mps-1));
ofixups[4] = 1;
}
int PackWcle::preprocessFixups()
{
unsigned ic,jc;
int big;
MemBuffer counts_buf((objects+2)*sizeof(unsigned));
unsigned *counts = (unsigned *) (unsigned char *) counts_buf;
countFixups(counts);
for (ic = jc = 0; ic < objects; ic++)
jc += counts[ic];
MemBuffer rl(jc);
MemBuffer srf(counts[objects+0]+1);
MemBuffer slf(counts[objects+1]+1);
upx_byte *selector_fixups = srf;
upx_byte *selfrel_fixups = slf;
unsigned rc = 0;
upx_byte *fix = ifixups;
for (ic = jc = 0; ic < pages; ic++)
{
while ((unsigned)(fix - ifixups) < get_le32(ifpage_table+ic+1))
{
const short fixp2 = get_le16(fix+2);
unsigned value;
switch (*fix)
{
case 2: // selector fixup
if (fixp2 < 0)
{
// cross page selector fixup
dputc('S',stdout);
fix += 5;
break;
}
dputc('s',stdout);
memcpy(selector_fixups,"\x8C\xCB\x66\x89\x9D",5); // mov bx, cs ; mov [xxx+ebp], bx
if (IOT(fix[4]-1,flags) & LEOF_WRITE)
selector_fixups[1] = 0xDB; // ds
set_le32(selector_fixups+5,jc+fixp2);
selector_fixups += 9;
fix += 5;
break;
case 5: // 16-bit offset
if ((unsigned)fixp2 < 4096 && IOT(fix[4]-1,my_base_address) == jc)
dputc('6',stdout);
else
throwCantPack("unsupported 16-bit offset relocation");
fix += (fix[1] & 0x10) ? 9 : 7;
break;
case 6: // 16:32 pointer
if (fixp2 < 0)
{
// cross page pointer fixup
dputc('P',stdout);
fix += (fix[1] & 0x10) ? 9 : 7;
break;
}
dputc('p',stdout);
memcpy(iimage+jc+fixp2,fix+5,(fix[1] & 0x10) ? 4 : 2);
set_le32(rl+4*rc++,jc+fixp2);
set_le32(iimage+jc+fixp2,get_le32(iimage+jc+fixp2)+IOT(fix[4]-1,my_base_address));
memcpy(selector_fixups,"\x8C\xCA\x66\x89\x95",5);
if (IOT(fix[4]-1,flags) & LEOF_WRITE)
selector_fixups[1] = 0xDA; // ds
set_le32(selector_fixups+5,jc+fixp2+4);
selector_fixups += 9;
fix += (fix[1] & 0x10) ? 9 : 7;
break;
case 7: // 32-bit offset
if (fixp2 < 0)
{
fix += (fix[1] & 0x10) ? 9 : 7;
break;
}
//if (memcmp(iimage+jc+fixp2,fix+5,(fix[1] & 0x10) ? 4 : 2))
// throwCantPack("illegal fixup offset");
// work around an 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);
set_le32(iimage+jc+fixp2,get_le32(iimage+jc+fixp2)+IOT(fix[4]-1,my_base_address));
}
fix += (fix[1] & 0x10) ? 9 : 7;
break;
case 8: // 32-bit self relative fixup
if (fixp2 < 0)
{
// cross page self relative fixup
dputc('R',stdout);
fix += (fix[1] & 0x10) ? 9 : 7;
break;
}
value = get_le32(fix+5);
if (fix[1] == 0)
value &= 0xffff;
set_le32(iimage+jc+fixp2,(value+IOT(fix[4]-1,my_base_address))-jc-fixp2-4);
set_le32(selfrel_fixups,jc+fixp2);
selfrel_fixups += 4;
dputc('r',stdout);
fix += (fix[1] & 0x10) ? 9 : 7;
break;
default:
throwCantPack("unsupported fixup record");
}
}
jc += mps;
}
// resize ifixups if it's too small
if (sofixups < 1000)
{
delete[] ifixups;
ifixups = new upx_byte[1000];
}
fix = optimizeReloc32 (rl,rc,ifixups,iimage,1,&big);
has_extra_code = srf != selector_fixups;
// FIXME: this could be removed if has_extra_code = false
// but then we'll need a flag
*selector_fixups++ = 0xC3; // ret
memcpy(fix,srf,selector_fixups-srf); // copy selector fixup code
fix += selector_fixups-srf;
memcpy(fix,slf,selfrel_fixups-slf); // copy self-relative fixup positions
fix += selfrel_fixups-slf;
set_le32(fix,0xFFFFFFFFUL);
fix += 4;
sofixups = fix-ifixups;
return big;
}
#define RESERVED 0x1000
void PackWcle::encodeImage(const Filter *ft)
{
// concatenate image & preprocessed fixups
unsigned isize = soimage + sofixups;
ibuf.alloc(isize);
memcpy(ibuf,iimage,soimage);
memcpy(ibuf+soimage,ifixups,sofixups);
delete[] ifixups; ifixups = NULL;
// compress
oimage.allocForCompression(isize+RESERVED+512);
ph.filter = ft->id;
ph.filter_cto = ft->cto;
ph.u_len = isize;
// reserve RESERVED bytes for the decompressor
if (!compress(ibuf,oimage+RESERVED))
throwNotCompressible();
overlapoh = findOverlapOverhead(oimage+RESERVED, 512);
ibuf.free();
soimage = (ph.c_len + 3) &~ 3;
}
void PackWcle::pack(OutputFile *fo)
{
handleStub(fo);
if (ih.byte_order || ih.word_order
|| ih.exe_format_level
|| ih.cpu_type < 2 || ih.cpu_type > 5
|| ih.target_os != 1
|| ih.module_type != 0x200
|| ih.object_iterate_data_map_offset
|| ih.resource_entries
|| ih.module_directives_entries
|| ih.imported_modules_count
|| ih.object_table_entries > 255)
throwCantPack("unexpected value in header");
readObjectTable();
readPageMap();
readResidentNames();
readEntryTable();
readFixupPageTable();
readFixups();
readImage();
readNonResidentNames();
if (find_le32(iimage,20,get_le32("UPX ")))
throwAlreadyPacked();
if (ih.init_ss_object != objects)
throwCantPack("the stack is not in the last object");
int big = preprocessFixups();
const unsigned text_size = IOT(ih.init_cs_object-1,npages) * mps;
const unsigned text_vaddr = IOT(ih.init_cs_object-1,my_base_address);
// filter
Filter ft(opt->level);
tryFilters(&ft, iimage+text_vaddr, text_size, text_vaddr);
const unsigned calltrickoffset = ft.cto << 24;
// attach some useful data at the end of preprocessed fixups
unsigned ic = objects*sizeof(*iobject_table);
memcpy(ifixups+sofixups,iobject_desc,ic);
iobject_desc.free();
sofixups += ic;
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
ifixups[sofixups+12] = (unsigned char) objects;
sofixups += 13;
encodeImage(&ft);
// verify filter
ft.verifyUnfilter();
// prepare loader
initLoader(nrv_loader,sizeof(nrv_loader));
addLoader("IDENTSTR""WCLEMAIN""UPX1HEAD""WCLECUTP""+0000000",
getDecompressor(),
"WCLEMAI2",
NULL
);
if (ft.id)
{
assert(ft.calls > 0);
addLoader(text_vaddr ? "WCCTTPOS" : "WCCTTNUL",NULL);
addFilter32(ft.id);
}
#if 1
// FIXME: if (has_relocation)
{
addLoader("WCRELOC1""RELOC320",
big ? "REL32BIG" : "",
"RELOC32J",
NULL
);
}
#endif
addLoader(has_extra_code ? "WCRELSEL" : "",
"WCLEMAI4",
NULL
);
const unsigned lsize = getLoaderSize();
neweip = getLoaderSection("WCLEMAIN");
int e_len = getLoaderSection("WCLECUTP");
const unsigned d_len = lsize - e_len;
assert(e_len > 0);
getLoader();
memcpy(oimage,getLoader(),e_len);
memmove(oimage+e_len,oimage+RESERVED,soimage);
soimage = (soimage + e_len);
memcpy(oimage+soimage,getLoader() + e_len,d_len);
soimage += d_len;
opages = (soimage+mps-1)/mps;
oh.bytes_on_last_page = soimage%mps;
encodeObjectTable();
encodeFixups();
encodeFixupPageTable();
encodePageMap();
encodeEntryTable();
encodeResidentNames();
encodeNonResidentNames();
// patch loader
ic = (OOT(0,virtual_size) - d_len) &~ 15;
assert(ic > ((ph.u_len + overlapoh + 31) &~ 15));
upx_byte *p = oimage+soimage-d_len;
patch_le32(p,d_len,"JMPO",ih.init_eip_offset+text_vaddr-(ic+d_len));
patch_le32(p,d_len,"ESP0",ih.init_esp_offset+IOT(ih.init_ss_object-1,my_base_address));
if (ft.id)
{
assert(ft.calls > 0);
if (ft.id > 0x20)
patch_le16(p,d_len,"??",'?'+(calltrickoffset>>16));
patch_le32(p,d_len,"TEXL",(ft.id & 0xf) % 3 == 0 ? ft.calls :
ft.lastcall - ft.calls * 4);
if (text_vaddr)
patch_le32(p,d_len,"TEXV",text_vaddr);
}
patch_le32(p,d_len,"RELO",mps*pages);
unsigned jpos = find_le32(oimage,e_len,get_le32("JMPD")) - oimage;
patch_le32(oimage,e_len,"JMPD",ic-jpos-4);
jpos = (((ph.c_len+3)&~3) + d_len+3)/4;
patch_le32(oimage,e_len,"ECX0",jpos);
patch_le32(oimage,e_len,"EDI0",((ic+d_len+3)&~3)-4);
patch_le32(oimage,e_len,"ESI0",e_len+jpos*4-4);
putPackHeader(oimage,e_len);
writeFile(fo, opt->wcle.le);
// copy the overlay
const unsigned overlaystart = ih.data_pages_offset + exe_offset
+ mps * (pages - 1) + ih.bytes_on_last_page;
const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length;
checkOverlay(overlay);
copyOverlay(fo, overlay, &oimage);
}
/*************************************************************************
//
**************************************************************************/
void PackWcle::decodeFixups()
{
upx_byte *p = oimage + soimage;
iimage.free();
MemBuffer tmpbuf;
unsigned fixupn = unoptimizeReloc32(&p,oimage,&tmpbuf,1);
MemBuffer wrkmem(8*fixupn+8);
unsigned ic,jc,o,r;
for (ic=0; ic<fixupn; ic++)
{
jc=get_le32(tmpbuf+4*ic);
set_le32(wrkmem+ic*8,jc);
o = soobject_table;
r = get_le32(oimage+jc);
virt2rela(oobject_table,&o,&r);
set_le32(wrkmem+ic*8+4,OOT(o-1,my_base_address));
set_le32(oimage+jc,r);
}
set_le32(wrkmem+ic*8,0xFFFFFFFF); // end of 32-bit offset fixups
tmpbuf.free();
// selector fixups and self-relative fixups
const upx_byte *selector_fixups = p;
const upx_byte *selfrel_fixups = p;
while (*selfrel_fixups != 0xC3)
selfrel_fixups += 9;
selfrel_fixups++;
unsigned selectlen = (selfrel_fixups - selector_fixups)/9;
ofixups = new upx_byte[fixupn*9+1000+selectlen*5];
upx_bytep fp = ofixups;
for (ic = 1, jc = 0; ic <= opages; ic++)
{
// self relative fixups
while ((r = get_le32(selfrel_fixups))/mps == ic-1)
{
fp[0] = 8;
set_le16(fp+2,r & (mps-1));
o = 4+get_le32(oimage+r);
set_le32(oimage+r,0);
r += o;
o = soobject_table;
virt2rela(oobject_table,&o,&r);
fp[4] = (unsigned char) o;
set_le32(fp+5,r);
fp[1] = (unsigned char) (r > 0xFFFF ? 0x10 : 0);
fp += fp[1] ? 9 : 7;
selfrel_fixups += 4;
dputc('r',stdout);
}
// selector fixups
while (selectlen && (r = get_le32(selector_fixups+5))/mps == ic-1)
{
fp[0] = 2;
fp[1] = 0;
set_le16(fp+2,r & (mps-1));
unsigned x = selector_fixups[1] > 0xD0 ? oh.init_ss_object : oh.init_cs_object;
fp[4] = (unsigned char) x;
fp += 5;
selector_fixups += 9;
selectlen--;
dputc('s',stdout);
}
// 32 bit offset fixups
while (get_le32(wrkmem+4*jc) < ic*mps)
{
if (ic > 1 && ((get_le32(wrkmem+4*(jc-2))+3) & (mps-1)) < 3) // cross page fixup?
{
r = get_le32(oimage+get_le32(wrkmem+4*(jc-2)));
fp[0] = 7;
fp[1] = (unsigned char) (r > 0xFFFF ? 0x10 : 0);
set_le16(fp+2,get_le32(wrkmem+4*(jc-2)) | ~3);
set_le32(fp+5,r);
o = soobject_table;
r = get_le32(wrkmem+4*(jc-1));
virt2rela(oobject_table,&o,&r);
fp[4] = (unsigned char) o;
fp += fp[1] ? 9 : 7;
dputc('0',stdout);
}
o = soobject_table;
r = get_le32(wrkmem+4*(jc+1));
virt2rela(oobject_table,&o,&r);
r = get_le32(oimage+get_le32(wrkmem+4*jc));
fp[0] = 7;
fp[1] = (unsigned char) (r > 0xFFFF ? 0x10 : 0);
set_le16(fp+2,get_le32(wrkmem+4*jc) & (mps-1));
fp[4] = (unsigned char) o;
set_le32(fp+5,r);
fp += fp[1] ? 9 : 7;
jc += 2;
}
set_le32(ofpage_table+ic,fp-ofixups);
}
for (ic=0; ic < FIXUP_EXTRA; ic++)
*fp++ = 0;
sofixups = fp-ofixups;
}
void PackWcle::decodeFixupPageTable()
{
ofpage_table = new unsigned[sofpage_table = 1 + opages];
set_le32(ofpage_table,0);
// the rest of ofpage_table is filled by decodeFixups()
}
void PackWcle::decodeObjectTable()
{
soobject_table = oimage[ph.u_len - 1];
oobject_table = new le_object_table_entry_t[soobject_table];
unsigned jc, ic = soobject_table * sizeof(*oobject_table);
const unsigned extradata = ph.version == 10 ? 17 : 13;
memcpy(oobject_table,oimage + ph.u_len - extradata - ic,ic);
for (ic = jc = 0; ic < soobject_table; ic++)
{
OOT(ic,my_base_address) = jc;
jc += (OOT(ic,virtual_size)+mps-1) &~ (mps-1);
}
// restore original cs:eip & ss:esp
ic = soobject_table;
jc = get_le32(oimage + ph.u_len - (ph.version < 11 ? 13 : 9));
virt2rela(oobject_table,&ic,&jc);
oh.init_cs_object = ic;
oh.init_eip_offset = jc;
ic = soobject_table;
if (ph.version < 10)
jc = ih.init_esp_offset;
else
jc = get_le32(oimage + ph.u_len - (ph.version == 10 ? 17 : 13));
virt2rela(oobject_table,&ic,&jc);
oh.init_ss_object = ic;
oh.init_esp_offset = jc;
}
void PackWcle::decodeImage()
{
oimage.allocForUncompression(ph.u_len);
decompress(iimage + ph.buf_offset + ph.getPackHeaderSize(),oimage);
soimage = get_le32(oimage + ph.u_len - 5);
opages = soimage / mps;
oh.memory_page_size = mps;
}
void PackWcle::decodeEntryTable()
{
unsigned count,object,n,r;
upx_byte *p = ientries;
n = 0;
while (*p)
{
count = *p;
n += count;
if (p[1] == 0) // unused bundle
p += 2;
else if (p[1] == 3) // 32-bit offset bundle
{
object = get_le16(p+2);
if (object != 1)
throwCantUnpack("corrupted entry found");
object = soobject_table;
r = get_le32(p+5);
virt2rela(oobject_table,&object,&r);
set_le16(p+2,object--);
p += 4;
for (; count; count--, p += 5)
set_le32(p+1,get_le32(p+1) - OOT(object,my_base_address));
}
else
throwCantUnpack("unsupported bundle type in entry table");
}
//if (Opt_debug) printf("\n%d entries decoded.\n",n);
soentries = p - ientries + 1;
oentries = ientries;
ientries = NULL;
}
bool PackWcle::canUnpack()
{
if (!LeFile::readFileHeader())
return false;
// FIXME: 1024 could be too large for some files
return super::readPackHeader(1024, ih.data_pages_offset+exe_offset);
}
void PackWcle::virt2rela(const le_object_table_entry_t *entr,unsigned *objn,unsigned *addr)
{
for (; *objn > 1; objn[0]--)
{
if (entr[*objn-1].my_base_address > *addr)
continue;
*addr -= entr[*objn-1].my_base_address;
break;
}
}
/*************************************************************************
//
**************************************************************************/
void PackWcle::unpack(OutputFile *fo)
{
handleStub(fo);
readObjectTable();
iobject_desc.free();
readPageMap();
readResidentNames();
readEntryTable();
readFixupPageTable();
readFixups();
readImage();
readNonResidentNames();
decodeImage();
decodeObjectTable();
// unfilter
if (ph.filter)
{
const unsigned text_size = OOT(oh.init_cs_object-1,npages) * mps;
const unsigned text_vaddr = OOT(oh.init_cs_object-1,my_base_address);
Filter ft(ph.level);
ft.init(ph.filter, text_vaddr);
ft.cto = (unsigned char) (ph.version < 11 ? (get_le32(oimage+ph.u_len-9) >> 24) : ph.filter_cto);
ft.unfilter(oimage+text_vaddr, text_size);
}
decodeFixupPageTable();
decodeFixups();
decodeEntryTable();
decodePageMap();
decodeResidentNames();
decodeNonResidentNames();
for (unsigned ic = 0; ic < soobject_table; ic++)
OOT(ic,my_base_address) = 0;
while (oimage[soimage-1] == 0)
soimage--;
oh.bytes_on_last_page = soimage % mps;
// write decompressed file
if (fo)
writeFile(fo, opt->wcle.le);
// copy the overlay
const unsigned overlaystart = ih.data_pages_offset + exe_offset
+ mps * (pages - 1) + ih.bytes_on_last_page;
const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length;
checkOverlay(overlay);
copyOverlay(fo, overlay, &oimage);
}
/*
vi:ts=4:et
*/

92
src/p_wcle.h Normal file
View File

@ -0,0 +1,92 @@
/* p_wcle.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_P_WCLE_H
#define __UPX_P_WCLE_H
/*************************************************************************
// watcom/le
**************************************************************************/
class PackWcle : public Packer, public LeFile
{
typedef Packer super;
public:
PackWcle(InputFile *f) : super(f), LeFile(f){};
virtual int getVersion() const { return 11; }
virtual int getFormat() const { return UPX_F_WC_LE; }
virtual const char *getName() const { return "watcom/le"; }
virtual int getCompressionMethod() const;
virtual const int *getFilters() const;
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canPack();
virtual bool canUnpack();
protected:
virtual void handleStub(OutputFile *fo);
virtual void readObjectTable();
virtual void encodeObjectTable();
virtual void decodeObjectTable();
virtual void encodeFixupPageTable();
virtual void decodeFixupPageTable();
virtual void encodePageMap();
virtual void encodeEntryTable();
virtual void decodeEntryTable();
virtual int preprocessFixups();
virtual void encodeFixups();
virtual void decodeFixups();
virtual void encodeImage(const Filter *ft);
virtual void decodeImage();
static void virt2rela(const le_object_table_entry_t *, unsigned *objn, unsigned *addr);
// temporary copy of the object descriptors
MemBuffer iobject_desc;
bool has_extra_code;
unsigned overlapoh;
unsigned neweip;
};
#endif /* already included */
/*
vi:ts=4:et
*/

1193
src/packer.cpp Normal file

File diff suppressed because it is too large Load Diff

244
src/packer.h Normal file
View File

@ -0,0 +1,244 @@
/* packer.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_PACKER_H
#define __UPX_PACKER_H
#include "mem.h"
class InputFile;
class OutputFile;
class Packer;
class PackMaster;
class UiPacker;
class Linker;
class Filter;
/*************************************************************************
//
**************************************************************************/
// see stub/header.ash
class PackHeader
{
public:
bool fillPackHeader(upx_bytep buf, unsigned len);
bool checkPackHeader(const upx_bytep hbuf, int hlen) const;
void putPackHeader(upx_bytep buf, unsigned len);
int getPackHeaderSize() const;
public:
// fields stored in compressed file
unsigned magic; // UPX_MAGIC_LE32
int version;
int format; // executable format
int method; // compresison method
int level; // compresison level 1..10
unsigned u_len;
unsigned c_len;
unsigned u_adler;
unsigned c_adler;
off_t u_file_size;
int filter;
int filter_cto;
int header_checksum;
// info fields set by fillPackHeader()
long buf_offset;
// info fields set by Packer::compress()
//unsigned min_offset_found;
unsigned max_offset_found;
//unsigned min_match_found;
unsigned max_match_found;
//unsigned min_run_found;
unsigned max_run_found;
unsigned first_offset_found;
//unsigned same_match_offsets_found;
};
/*************************************************************************
// abstract base class for packers
**************************************************************************/
class Packer
{
//friend class PackMaster;
friend class UiPacker;
protected:
Packer(InputFile *f);
public:
virtual ~Packer();
virtual int getVersion() const = 0;
// A unique integer ID for this executable format. See conf.h.
virtual int getFormat() const = 0;
virtual const char *getName() const = 0;
virtual int getCompressionMethod() const = 0;
virtual int getCompressionLevel() const { return opt->level; }
virtual const int *getFilters() const = 0;
// PackMaster entries
void initPackHeader();
void updatePackHeader();
void doPack(OutputFile *fo);
void doUnpack(OutputFile *fo);
void doTest();
void doList();
void doFileInfo();
// unpacker capabilities
virtual bool canUnpackVersion(int version) const
{ return (version >= 8); }
virtual bool canUnpackFormat(int format) const
{ return (format == getFormat()); }
protected:
virtual void pack(OutputFile *fo) = 0;
virtual void unpack(OutputFile *fo) = 0;
virtual void test();
virtual void list();
virtual void fileInfo();
public:
virtual bool canPack() = 0;
virtual bool canUnpack() = 0;
virtual bool canTest() { return canUnpack(); }
virtual bool canList() { return canUnpack(); }
protected:
// main compression drivers
virtual bool compress(upx_bytep in, upx_bytep out,
unsigned max_offset = 0, unsigned max_match = 0);
virtual void decompress(const upx_bytep in,
upx_bytep out, bool verify_checksum=true);
virtual bool checkCompressionRatio(unsigned c_len, unsigned u_len) const;
// high-level compression drivers
void compressWithFilters(Filter *ft, unsigned *overlapoh,
const unsigned overlap_range,
int strategy=-1, const int *filters=NULL,
unsigned max_offset = 0, unsigned max_match = 0);
// util for verifying overlapping decompresion
// non-destructive test
bool testOverlappingDecompression(const upx_bytep buf,
unsigned overlap_overhead) const;
// non-destructive find
unsigned findOverlapOverhead(const upx_bytep buf,
unsigned range = 0,
unsigned upper_limit = ~0u) const;
// destructive decompress + verify
void verifyOverlappingDecompression(MemBuffer *buf,
unsigned overlap_overhead);
// packheader handling
virtual void putPackHeader(upx_byte *buf, unsigned len);
virtual bool readPackHeader(unsigned len, off_t seek_offset,
upx_byte *buf=NULL);
// filter handling
virtual bool isValidFilter(int filter_id) const;
virtual void tryFilters(Filter *ft, upx_byte *buf, unsigned buf_len,
unsigned addvalue=0) const;
virtual void scanFilters(Filter *ft, const upx_byte *buf, unsigned buf_len,
unsigned addvalue=0) const;
virtual void optimizeFilter(Filter *, const upx_byte *, unsigned) const
{ }
// loader util
virtual int buildLoader(const Filter *) { return getLoaderSize(); }
virtual const upx_byte *getLoader() const;
virtual int getLoaderSize() const;
virtual void initLoader(const void *pdata, int plen, int pinfo=-1);
virtual void addLoader(const char *s, ...);
virtual void addSection(const char *sname, const char *sdata, unsigned len);
virtual int getLoaderSection(const char *name, int *slen = NULL);
virtual void addFilter32(int filter_id);
virtual const char *getDecompressor() const;
// stub and overlay util
static void handleStub(InputFile *fi, OutputFile *fo, long size);
virtual void checkOverlay(unsigned overlay);
virtual void copyOverlay(OutputFile *fo, unsigned overlay,
MemBuffer *buf, bool do_seek=true);
// misc util
virtual unsigned getRandomId() const;
// patch util
void patch_be16(void *l, int llen, unsigned old, unsigned new_);
void patch_be16(void *l, int llen, const void * old, unsigned new_);
void patch_be32(void *l, int llen, unsigned old, unsigned new_);
void patch_be32(void *l, int llen, const void * old, unsigned new_);
void patch_le16(void *l, int llen, unsigned old, unsigned new_);
void patch_le16(void *l, int llen, const void * old, unsigned new_);
void patch_le32(void *l, int llen, unsigned old, unsigned new_);
void patch_le32(void *l, int llen, const void * old, unsigned new_);
void patchVersion(void *l, int llen);
void checkPatch(void *l, void *p, int size);
protected:
// relocation util
virtual upx_byte *optimizeReloc32(upx_byte *in,unsigned relocnum,upx_byte *out,upx_byte *image,int bs,int *big);
virtual unsigned unoptimizeReloc32(upx_byte **in,upx_byte *image,MemBuffer *out,int bs);
protected:
InputFile *fi;
off_t file_size; // will get set by constructor
PackHeader ph; // must be filled by canUnpack()
// compression buffers
MemBuffer ibuf; // input
MemBuffer obuf; // output
// UI handler
UiPacker *uip;
int pass;
int total_passes;
// linker
Linker *linker;
private:
// private to checkPatch()
void *last_patch;
long last_patch_offset;
};
#endif /* already included */
/*
vi:ts=4:et
*/

256
src/packhead.cpp Normal file
View File

@ -0,0 +1,256 @@
/* packhead.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "packer.h"
/*************************************************************************
// packheader
//
// We try to be able to unpack UPX 0.7x (versions 8 & 9) and at
// least to detect older versions, so this is a little bit messy.
**************************************************************************/
// simple checksum for the header itself (since version 10)
static unsigned char get_packheader_checksum(const upx_bytep buf, int len)
{
assert(get_le32(buf) == UPX_MAGIC_LE32);
//printf("1 %d\n", len);
buf += 4;
len -= 4;
unsigned c = 0;
while (len-- > 0)
c += *buf++;
c %= 251;
//printf("2 %d\n", c);
return (unsigned char) c;
}
/*************************************************************************
//
**************************************************************************/
static int get_packheader_size(int version, int format)
{
int n = 0;
if (version <= 3)
n = 24;
else if (version <= 9)
{
if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS)
n = 20;
else if (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH)
n = 25;
else
n = 28;
}
else
{
if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS)
n = 22;
else if (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH)
n = 27;
else
n = 32;
}
if (n == 0)
throwCantUnpack("unknown header version");
return n;
}
int PackHeader::getPackHeaderSize() const
{
return get_packheader_size(version, format);
}
/*************************************************************************
//
**************************************************************************/
void PackHeader::putPackHeader(upx_bytep buf, unsigned len)
{
#if defined(UNUPX)
throwBadLoader();
#else
upx_bytep l = find_le32(buf,len,magic);
if (l == 0)
throwBadLoader();
l[4] = (unsigned char) version;
l[5] = (unsigned char) format;
l[6] = (unsigned char) method;
l[7] = (unsigned char) level;
// the new variable length header
if (format < 128)
{
set_le32(l+8,u_adler);
set_le32(l+12,c_adler);
if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS)
{
set_le16(l+16,u_len);
set_le16(l+18,c_len);
l[20] = (unsigned char) filter;
}
else if (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH)
{
set_le24(l+16,u_len);
set_le24(l+19,c_len);
set_le24(l+22,u_file_size);
l[25] = (unsigned char) filter;
}
else
{
set_le32(l+16,u_len);
set_le32(l+20,c_len);
set_le32(l+24,u_file_size);
l[28] = (unsigned char) filter;
l[29] = (unsigned char) filter_cto;
l[30] = 0;
}
}
else
{
set_be32(l+8,u_len);
set_be32(l+12,c_len);
set_be32(l+16,u_adler);
set_be32(l+20,c_adler);
set_be32(l+24,u_file_size);
l[28] = (unsigned char) filter;
l[29] = (unsigned char) filter_cto;
l[30] = 0;
}
// store header_checksum
const int hs = getPackHeaderSize();
l[hs - 1] = get_packheader_checksum(l, hs - 1);
#endif /* UNUPX */
}
/*************************************************************************
//
**************************************************************************/
bool PackHeader::fillPackHeader(upx_bytep buf, unsigned len)
{
upx_bytep l = find_le32(buf,len,magic);
if (l == 0)
return false;
buf_offset = l - buf;
version = l[4];
format = l[5];
method = l[6];
level = l[7];
filter_cto = 0;
// the new variable length header
int off_filter = 0;
if (format < 128)
{
u_adler = get_le32(l+8);
c_adler = get_le32(l+12);
if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS)
{
u_len = get_le16(l+16);
c_len = get_le16(l+18);
u_file_size = u_len;
off_filter = 20;
}
else if (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH)
{
u_len = get_le24(l+16);
c_len = get_le24(l+19);
u_file_size = get_le24(l+22);
off_filter = 25;
}
else
{
u_len = get_le32(l+16);
c_len = get_le32(l+20);
u_file_size = get_le32(l+24);
off_filter = 28;
filter_cto = l[29];
}
}
else
{
u_len = get_be32(l+8);
c_len = get_be32(l+12);
u_adler = get_be32(l+16);
c_adler = get_be32(l+20);
u_file_size = get_be32(l+24);
off_filter = 28;
filter_cto = l[29];
}
if (version >= 10)
filter = l[off_filter];
else if ((level & 128) == 0)
filter = 0;
else
{
// convert old flags to new filter id
level &= 127;
if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS)
filter = 0x06;
else
filter = 0x26;
}
level &= 15;
return true;
}
bool PackHeader::checkPackHeader(const upx_bytep hbuf, int hlen) const
{
if (version == 0xff)
throwCantUnpack("cannot unpack UPX ;-)");
const int hs = getPackHeaderSize();
if (hlen <= 0 || hs > hlen)
throwCantUnpack("header corrupted");
// check header_checksum
if (version > 9)
if (hbuf[hs - 1] != get_packheader_checksum(hbuf, hs - 1))
throwCantUnpack("header corrupted");
return true;
}
/*
vi:ts=4:et:nowrap
*/

258
src/packmast.cpp Normal file
View File

@ -0,0 +1,258 @@
/* packmast.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#include "file.h"
#include "packmast.h"
#include "packer.h"
#include "lefile.h"
#include "p_com.h"
#include "p_djgpp2.h"
#include "p_exe.h"
#include "p_elf.h"
#include "p_unix.h"
#include "p_lx_elf.h"
#include "p_lx_sep.h"
#include "p_lx_sh.h"
#include "p_sys.h"
#include "p_tos.h"
#include "p_wcle.h"
#include "p_tmt.h"
#include "p_vxd.h"
#include "p_w32pe.h"
/*************************************************************************
//
**************************************************************************/
PackMaster::PackMaster(InputFile *f, struct options_t *o) :
fi(f), p(NULL)
{
// replace options with local options
saved_opt = o;
if (o)
{
this->local_options = *o; // struct copy
opt = &this->local_options;
}
}
PackMaster::~PackMaster()
{
fi = NULL;
delete p; p = NULL;
// restore options
if (saved_opt)
opt = saved_opt;
saved_opt = NULL;
}
/*************************************************************************
//
**************************************************************************/
typedef Packer* (*try_function)(Packer *p, InputFile *f);
static Packer* try_pack(Packer *p, InputFile *f)
{
if (p == NULL)
return NULL;
#if !defined(UNUPX)
try {
p->initPackHeader();
f->seek(0,SEEK_SET);
if (p->canPack())
{
p->updatePackHeader();
f->seek(0,SEEK_SET);
return p;
}
} catch (IOException&) {
} catch (...) {
delete p;
throw;
}
#endif /* UNUPX */
delete p;
return NULL;
}
static Packer* try_unpack(Packer *p, InputFile *f)
{
if (p == NULL)
return NULL;
try {
p->initPackHeader();
f->seek(0,SEEK_SET);
if (p->canUnpack())
{
f->seek(0,SEEK_SET);
return p;
}
} catch (IOException&) {
} catch (...) {
delete p;
throw;
}
delete p;
return NULL;
}
/*************************************************************************
//
**************************************************************************/
static Packer* try_packers(InputFile *f, try_function func)
{
Packer *p = NULL;
// note: order of tries is important !
if (!opt->dos.force_stub)
{
if ((p = func(new PackDjgpp2(f),f)) != NULL)
return p;
if ((p = func(new PackTmt(f),f)) != NULL)
return p;
if ((p = func(new PackWcle(f),f)) != NULL)
return p;
#if 0
if ((p = func(new PackVxd(f),f)) != NULL)
return p;
#endif
if ((p = func(new PackW32Pe(f),f)) != NULL)
return p;
}
if ((p = func(new PackExe(f),f)) != NULL)
return p;
if ((p = func(new PackTos(f),f)) != NULL)
return p;
if (opt->script_name) {
if ((p = func(new PackLinuxI386sep(f),f)) != NULL)
return p;
}
if ((p = func(new PackLinuxI386elf(f),f)) != NULL)
return p;
if ((p = func(new PackLinuxI386sh(f),f)) != NULL)
return p;
if ((p = func(new PackBvmlinuxI386(f),f)) != NULL)
return p;
if ((p = func(new PackLinuxI386(f),f)) != NULL)
return p;
if ((p = func(new PackSys(f),f)) != NULL)
return p;
if ((p = func(new PackCom(f),f)) != NULL)
return p;
return NULL;
}
static Packer *getPacker(InputFile *f)
{
Packer *p = try_packers(f, try_pack);
if (!p)
throwUnknownExecutableFormat();
return p;
}
static Packer *getUnpacker(InputFile *f)
{
Packer *p = try_packers(f, try_unpack);
if (!p)
throwNotPacked();
return p;
}
static void assertPacker(const Packer *p)
{
assert(strlen(p->getName()) <= 13);
}
/*************************************************************************
// delegation
**************************************************************************/
void PackMaster::pack(OutputFile *fo)
{
p = getPacker(fi);
assertPacker(p);
fi = NULL;
p->doPack(fo);
}
void PackMaster::unpack(OutputFile *fo)
{
p = getUnpacker(fi);
assertPacker(p);
fi = NULL;
p->doUnpack(fo);
}
void PackMaster::test()
{
p = getUnpacker(fi);
assertPacker(p);
fi = NULL;
p->doTest();
}
void PackMaster::list()
{
p = getUnpacker(fi);
assertPacker(p);
fi = NULL;
p->doList();
}
void PackMaster::fileInfo()
{
p = try_packers(fi, try_unpack);
if (!p)
p = try_packers(fi, try_pack);
if (!p)
throwUnknownExecutableFormat(NULL, 1); // make a warning here
assertPacker(p);
fi = NULL;
p->doFileInfo();
}
/*
vi:ts=4:et:nowrap
*/

68
src/packmast.h Normal file
View File

@ -0,0 +1,68 @@
/* packmast.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_PACKMASTER_H
#define __UPX_PACKMASTER_H
class Packer;
class InputFile;
class OutputFile;
/*************************************************************************
// interface for work.cpp
**************************************************************************/
class PackMaster
{
public:
PackMaster(InputFile *f, struct options_t *o = NULL);
virtual ~PackMaster();
void pack(OutputFile *fo);
void unpack(OutputFile *fo);
void test();
void list();
void fileInfo();
private:
InputFile *fi;
Packer *p;
// setup local options for each file
struct options_t local_options;
struct options_t *saved_opt;
};
#endif /* already included */
/*
vi:ts=4:et
*/

546
src/s_djgpp2.cpp Normal file
View File

@ -0,0 +1,546 @@
/* s_djgpp2.cpp -- djggp2 DOS screen driver
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#if defined(USE_SCREEN) && defined(__DJGPP__)
#include "screen.h"
#define this local_this
#define mask_fg 0x0f
#define mask_bg 0xf0
/* #define USE_SCROLLBACK */
/*************************************************************************
// direct screen access
**************************************************************************/
#include <dos.h>
#if 0
#include <conio.h>
#endif
#include <dpmi.h>
#include <go32.h>
#include <sys/exceptn.h>
#include <sys/farptr.h>
#include <sys/movedata.h>
#define dossel _go32_info_block.selector_for_linear_memory
#define co80 _go32_info_block.linear_address_of_primary_screen
#undef kbhit
struct screen_data_t
{
int mode;
int cols;
int rows;
int cursor_x;
int cursor_y;
unsigned char attr;
unsigned char init_attr;
unsigned char empty_attr;
unsigned short empty_cell;
#ifdef USE_SCROLLBACK
/* scrollback buffer */
unsigned short sb_buf[32][256];
int sb_size;
int sb_base;
int sb_sp;
#endif /* USE_SCROLLBACK */
};
/* atExit information */
static struct
{
int cursor_shape;
} ae = {
-1
};
#ifdef USE_SCROLLBACK
static __inline__ void sb_add(screen_t *this, int *val, int inc)
{
*val = (*val + inc) & (this->data->sb_size - 1);
}
static void sb_push(screen_t *this, const unsigned short *line, int len)
{
memcpy(this->data->sb_buf[this->data->sb_sp],line,len);
sb_add(this,&this->data->sb_sp,1);
if (this->data->sb_sp == this->data->sb_base)
sb_add(this,&this->data->sb_base,1);
}
static const unsigned short *sb_pop(screen_t *this)
{
if (this->data->sb_sp == this->data->sb_base)
return NULL;
sb_add(this,&this->data->sb_sp,-1);
return this->data->sb_buf[this->data->sb_sp];
}
#endif /* USE_SCROLLBACK */
static void refresh(screen_t *this)
{
UNUSED(this);
}
static __inline__
unsigned short make_cell(screen_t *this, int ch, int attr)
{
UNUSED(this);
return ((attr & 0xff) << 8) | (ch & 0xff);
}
static int getMode(const screen_t *this)
{
UNUSED(this);
return ScreenMode();
}
static int getPage(const screen_t *this)
{
UNUSED(this);
return _farpeekb(dossel, 0x462);
}
static int getRows(const screen_t *this)
{
return this->data->rows;
}
static int getCols(const screen_t *this)
{
return this->data->cols;
}
static int isMono(const screen_t *this)
{
if (this->data->mode == 7)
return 1;
if ((_farpeekb(dossel, 0x465) & (4 | 16)) != 0)
return 1;
return 0;
}
static int getFg(const screen_t *this)
{
return this->data->attr & mask_fg;
}
static int getBg(const screen_t *this)
{
return this->data->attr & mask_bg;
}
static void setFg(screen_t *this, int fg)
{
this->data->attr = (this->data->attr & mask_bg) | (fg & mask_fg);
}
static void setBg(screen_t *this, int bg)
{
this->data->attr = (this->data->attr & mask_fg) | (bg & mask_bg);
}
static void setCursor(screen_t *this, int x, int y)
{
if (x >= 0 && y >= 0 && x < this->data->cols && y < this->data->rows)
{
ScreenSetCursor(y,x);
this->data->cursor_x = x;
this->data->cursor_y = y;
}
}
// I added ScreenGetCursor, because when upx prints something longer than
// 1 line (an error message for example), the this->data->cursor_y can
// have a bad value - ml1050
// FIXME:
// Laszlo: when does this happen ? This probably indicates a
// bug in c_screen.cpp(print0) I've introduced with
// the 2 passes implementation.
static void getCursor(const screen_t *this, int *x, int *y)
{
int cx = this->data->cursor_x;
int cy = this->data->cursor_y;
#if 1
ScreenGetCursor(&cy,&cx);
#endif
if (x) *x = cx;
if (y) *y = cy;
}
static void putCharAttr(screen_t *this, int ch, int attr, int x, int y)
{
UNUSED(this);
ScreenPutChar(ch,attr,x,y);
}
static void putChar(screen_t *this, int ch, int x, int y)
{
ScreenPutChar(ch,this->data->attr,x,y);
}
static void putStringAttr(screen_t *this, const char *s, int attr, int x, int y)
{
UNUSED(this);
assert((int)strlen(s) <= 256);
assert(x + (int)strlen(s) <= this->data->cols);
ScreenPutString(s,attr,x,y);
}
static void putString(screen_t *this, const char *s, int x, int y)
{
assert((int)strlen(s) <= 256);
assert(x + (int)strlen(s) <= this->data->cols);
ScreenPutString(s,this->data->attr,x,y);
}
/* private */
static void getChar(screen_t *this, int *ch, int *attr, int x, int y)
{
UNUSED(this);
ScreenGetChar(ch,attr,x,y);
}
static int getCursorShape(const screen_t *this)
{
UNUSED(this);
return _farpeekw(dossel, 0x460);
}
static void setCursorShape(screen_t *this, int shape)
{
__dpmi_regs r;
memset(&r,0,sizeof(r)); /* just in case... */
r.x.ax = 0x0103;
#if 1
if (this)
r.h.al = getMode(this); /* required for buggy BIOSes */
#endif
r.x.cx = shape & 0x7f1f;
__dpmi_int(0x10, &r);
}
static int hideCursor(screen_t *this)
{
int shape = getCursorShape(this);
setCursorShape(this,0x2000);
return shape;
}
static int init(screen_t *this, int fd)
{
int mode;
int cols, rows;
int attr;
#if 0
/* force linkage of conio.o */
(void) _conio_kbhit();
#endif
if (!this || !this->data)
return -1;
this->data->mode = -1;
#ifdef USE_SCROLLBACK
this->data->sb_size = 32;
this->data->sb_base = 0;
this->data->sb_sp = 0;
#endif
if (fd < 0 || !isatty(fd))
return -1;
if (getPage(this) != 0)
return -1;
cols = ScreenCols();
rows = ScreenRows();
mode = getMode(this);
if (mode > 0x13)
{
/* assume this is some SVGA/VESA text mode */
__dpmi_regs r;
memset(&r,0,sizeof(r)); /* just in case... */
r.x.ax = 0x4f03; /* VESA - get current video mode */
__dpmi_int(0x10, &r);
if (r.h.ah == 0)
mode = r.x.bx;
}
else
{
if (mode != 2 && mode != 3 && mode != 7)
return -1;
}
ScreenGetCursor(&this->data->cursor_y,&this->data->cursor_x);
getChar(this,NULL,&attr,this->data->cursor_x,this->data->cursor_y);
this->data->init_attr = attr;
if (mode != 7)
{
/* Does it normally blink when bg has its 3rd bit set? */
int b_mask = (_farpeekb(dossel, 0x465) & 0x20) ? 0x70 : 0xf0;
attr = attr & (mask_fg | b_mask);
}
this->data->mode = mode;
this->data->cols = cols;
this->data->rows = rows;
this->data->attr = attr;
this->data->empty_attr = attr;
this->data->empty_cell = make_cell(this,' ',attr);
ae.cursor_shape = getCursorShape(this);
return 0;
}
static void updateLineN(screen_t *this, const void *line, int y, int len)
{
if (y >= 0 && y < this->data->rows && len > 0 && len <= 2*this->data->cols)
movedata(_my_ds(),(unsigned)line,dossel,co80+y*this->data->cols*2,len);
}
static void clearLine(screen_t *this, int y)
{
if (y >= 0 && y < this->data->rows)
{
unsigned sp = co80 + y * this->data->cols * 2;
unsigned short a = this->data->empty_cell;
int i = this->data->cols;
_farsetsel(dossel);
do {
_farnspokew(sp, a);
sp += 2;
} while (--i);
}
}
static void clear(screen_t *this)
{
unsigned char attr = ScreenAttrib;
ScreenAttrib = this->data->empty_attr;
ScreenClear();
ScreenAttrib = attr;
}
static int scrollUp(screen_t *this, int lines)
{
int sr = this->data->rows;
int sc = this->data->cols;
int y;
if (lines <= 0 || lines > sr)
return 0;
#ifdef USE_SCROLLBACK
/* copy to scrollback buffer */
for (y = 0; y < lines; y++)
{
unsigned short buf[ sc ];
movedata(dossel,co80+y*this->data->cols*2,_my_ds(),(unsigned)buf,sizeof(buf));
sb_push(this,buf,sizeof(buf));
}
#endif
/* move screen up */
if (lines < sr)
movedata(dossel,co80+lines*sc*2,dossel,co80,(sr-lines)*sc*2);
/* fill in blank lines at bottom */
for (y = sr - lines; y < sr; y++)
clearLine(this,y);
return lines;
}
static int scrollDown(screen_t *this, int lines)
{
int sr = this->data->rows;
int sc = this->data->cols;
int y;
if (lines <= 0 || lines > sr)
return 0;
/* move screen down */
if (lines < sr)
{
/* !@#% movedata can't handle overlapping regions... */
/* movedata(dossel,co80,dossel,co80+lines*sc*2,(sr-lines)*sc*2); */
unsigned short buf[ (sr-lines)*sc ];
movedata(dossel,co80,_my_ds(),(unsigned)buf,sizeof(buf));
movedata(_my_ds(),(unsigned)buf,dossel,co80+lines*sc*2,sizeof(buf));
}
/* copy top lines from scrollback buffer */
for (y = lines; --y >= 0; )
{
#ifdef USE_SCROLLBACK
const unsigned short *buf = sb_pop(this);
if (buf == NULL)
clearLine(this,y);
else
updateLineN(this,buf,y,sc*2);
#else
clearLine(this,y);
#endif
}
return lines;
}
static int s_kbhit(screen_t *this)
{
UNUSED(this);
return kbhit();
}
static int intro(screen_t *this, void (*show_frames)(screen_t *) )
{
int shape;
unsigned short old_flags = __djgpp_hwint_flags;
if ((this->data->init_attr & mask_bg) != BG_BLACK)
return 0;
__djgpp_hwint_flags |= 3;
while (kbhit())
(void) getkey();
shape = hideCursor(this);
show_frames(this);
setCursorShape(this,shape);
while (kbhit())
(void) getkey();
__djgpp_hwint_flags = old_flags;
return 1;
}
static void atExit(void)
{
static int done = 0;
if (done) return;
done = 1;
if (ae.cursor_shape >= 0)
setCursorShape(NULL,ae.cursor_shape);
}
static const screen_t driver =
{
sobject_destroy,
0, /* finalize, */
atExit,
init,
refresh,
getMode,
getPage,
getRows,
getCols,
isMono,
getFg,
getBg,
getCursor,
getCursorShape,
setFg,
setBg,
setCursor,
setCursorShape,
hideCursor,
putChar,
putCharAttr,
putString,
putStringAttr,
clear,
clearLine,
updateLineN,
scrollUp,
scrollDown,
s_kbhit,
intro,
(struct screen_data_t *) 0
};
/* public constructor */
screen_t *screen_djgpp2_construct(void)
{
return sobject_construct(&driver,sizeof(*driver.data));
}
#endif /* defined(USE_SCREEN) && defined(__DJGPP__) */
/*
vi:ts=4:et
*/

100
src/s_object.cpp Normal file
View File

@ -0,0 +1,100 @@
/* s_object.cpp -- base of all screen drivers
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#if defined(USE_SCREEN)
#define this local_this
#include "screen.h"
/*************************************************************************
//
**************************************************************************/
// ugly hacks
static screen_t *last_screen = NULL;
screen_t *sobject_get_screen(void)
{
return last_screen;
}
void sobject_destroy(screen_t *this)
{
last_screen = NULL;
if (!this)
return;
if (this->data)
{
if (this->finalize)
this->finalize(this);
free(this->data);
this->data = NULL;
}
free(this);
}
screen_t *sobject_construct(const screen_t *c, size_t data_size)
{
screen_t *this;
last_screen = NULL;
/* allocate object */
this = (screen_t *) malloc(sizeof(*this));
if (!this)
return NULL;
/* copy function table */
*this = *c;
/* initialize instance variables */
this->data = (struct screen_data_t *) malloc(data_size);
if (!this->data)
{
free(this);
return NULL;
}
memset(this->data,0,data_size);
last_screen = this;
return this;
}
#endif /* defined(USE_SCREEN) */
/*
vi:ts=4:et
*/

601
src/s_vcsa.cpp Normal file
View File

@ -0,0 +1,601 @@
/* s_vcsa.cpp -- Linux /dev/vcsa screen driver
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#if defined(USE_SCREEN) && defined(USE_SCREEN_VCSA)
#include "screen.h"
#define this local_this
#define mask_fg 0x0f
#define mask_bg 0xf0
/* #define USE_SCROLLBACK */
/*************************************************************************
// direct screen access ( /dev/vcsaNN )
**************************************************************************/
#include <sys/ioctl.h>
#include <sys/select.h>
#include <termios.h>
#if defined(__linux__)
# include <linux/kd.h>
# include <linux/kdev_t.h>
# include <linux/major.h>
#endif
struct screen_data_t
{
int fd;
int mode;
int page;
int cols;
int rows;
int cursor_x;
int cursor_y;
unsigned char attr;
unsigned char init_attr;
unsigned char map[256];
unsigned short empty_line[256];
#ifdef USE_SCROLLBACK
/* scrollback buffer */
unsigned short sb_buf[32][256];
int sb_size;
int sb_base;
int sb_sp;
#endif /* USE_SCROLLBACK */
};
#ifdef USE_SCROLLBACK
static __inline__ void sb_add(screen_t *this, int *val, int inc)
{
*val = (*val + inc) & (this->data->sb_size - 1);
}
static void sb_push(screen_t *this, const unsigned short *line, int len)
{
memcpy(this->data->sb_buf[this->data->sb_sp],line,len);
sb_add(this,&this->data->sb_sp,1);
if (this->data->sb_sp == this->data->sb_base)
sb_add(this,&this->data->sb_base,1);
}
static const unsigned short *sb_pop(screen_t *this)
{
if (this->data->sb_sp == this->data->sb_base)
return NULL;
sb_add(this,&this->data->sb_sp,-1);
return this->data->sb_buf[this->data->sb_sp];
}
#endif /* USE_SCROLLBACK */
static void refresh(screen_t *this)
{
UNUSED(this);
}
static __inline__
unsigned short make_cell(screen_t *this, int ch, int attr)
{
return ((attr & 0xff) << 8) | (this->data->map[ch & 0xff] & 0xff);
}
static int getMode(const screen_t *this)
{
return this->data->mode;
}
static int getPage(const screen_t *this)
{
return this->data->page;
}
static int getRows(const screen_t *this)
{
return this->data->rows;
}
static int getCols(const screen_t *this)
{
return this->data->cols;
}
static int isMono(const screen_t *this)
{
/* FIXME */
UNUSED(this);
return 0;
}
static int getFg(const screen_t *this)
{
return this->data->attr & mask_fg;
}
static int getBg(const screen_t *this)
{
return this->data->attr & mask_bg;
}
static void setFg(screen_t *this, int fg)
{
this->data->attr = (this->data->attr & mask_bg) | (fg & mask_fg);
}
static void setBg(screen_t *this, int bg)
{
this->data->attr = (this->data->attr & mask_fg) | (bg & mask_bg);
}
/* private */
static int gotoxy(screen_t *this, int x, int y)
{
if (x >= 0 && y >= 0 && x < this->data->cols && y < this->data->rows)
{
if (lseek(this->data->fd, 4 + (x + y * this->data->cols) * 2, SEEK_SET) != -1)
{
return 0;
}
}
return -1;
}
static void setCursor(screen_t *this, int x, int y)
{
if (gotoxy(this,x,y) == 0)
{
unsigned char b[2] = { x, y };
if (lseek(this->data->fd, 2, SEEK_SET) != -1)
write(this->data->fd, b, 2);
this->data->cursor_x = x;
this->data->cursor_y = y;
}
}
static void getCursor(const screen_t *this, int *x, int *y)
{
int cx = this->data->cursor_x;
int cy = this->data->cursor_y;
#if 1
if (lseek(this->data->fd, 2, SEEK_SET) != -1)
{
unsigned char b[2];
if (read(this->data->fd, b, 2) == 2)
{
if (b[0] < this->data->cols && b[1] < this->data->rows)
{
cx = b[0];
cy = b[1];
}
}
}
#endif
if (x) *x = cx;
if (y) *y = cy;
}
static void putCharAttr(screen_t *this, int ch, int attr, int x, int y)
{
unsigned short a = make_cell(this,ch,attr);
if (gotoxy(this,x,y) == 0)
write(this->data->fd, &a, 2);
}
static void putChar(screen_t *this, int ch, int x, int y)
{
putCharAttr(this,ch,this->data->attr,x,y);
}
static void putStringAttr(screen_t *this, const char *s, int attr, int x, int y)
{
assert((int)strlen(s) <= 256);
assert(x + (int)strlen(s) <= this->data->cols);
while (*s)
putCharAttr(this,*s++,attr,x++,y);
}
static void putString(screen_t *this, const char *s, int x, int y)
{
putStringAttr(this,s,this->data->attr,x,y);
}
/* private */
static void getChar(screen_t *this, int *ch, int *attr, int x, int y)
{
unsigned short a;
if (gotoxy(this,x,y) == 0 && read(this->data->fd, &a, 2) == 2)
{
if (ch)
*ch = a & 0xff;
if (attr)
*attr = (a >> 8) & 0xff;
}
}
/* private */
static int init_scrnmap(screen_t *this, int fd)
{
int scrnmap_done = 0;
int i;
#if 1 && defined(GIO_UNISCRNMAP) && defined(E_TABSZ)
if (!scrnmap_done)
{
unsigned short scrnmap[E_TABSZ];
if (ioctl(fd, GIO_UNISCRNMAP, scrnmap) == 0)
{
for (i = 0; i < E_TABSZ; i++)
this->data->map[scrnmap[i] & 0xff] = i;
scrnmap_done = 1;
}
}
#endif
#if 1 && defined(GIO_SCRNMAP) && defined(E_TABSZ)
if (!scrnmap_done)
{
unsigned char scrnmap[E_TABSZ];
if (ioctl(fd, GIO_SCRNMAP, scrnmap) == 0)
{
for (i = 0; i < E_TABSZ; i++)
this->data->map[scrnmap[i] & 0xff] = i;
scrnmap_done = 1;
}
}
#endif
return scrnmap_done;
}
static int init(screen_t *this, int fd)
{
struct stat st;
if (!this || !this->data)
return -1;
this->data->fd = -1;
this->data->mode = -1;
this->data->page = 0;
#ifdef USE_SCROLLBACK
this->data->sb_size = 32;
this->data->sb_base = 0;
this->data->sb_sp = 0;
#endif
if (fd < 0 || !isatty(fd))
return -1;
if (fstat(fd,&st) != 0)
return -1;
/* check if we are running in a virtual console */
#if defined(MINOR) && defined(MAJOR) && defined(TTY_MAJOR)
if (MAJOR(st.st_rdev) == TTY_MAJOR)
{
char vc_name[32];
unsigned char vc_data[4];
int i;
int attr;
unsigned short a;
sprintf(vc_name, "/dev/vcsa%d", (int) MINOR(st.st_rdev));
this->data->fd = open(vc_name, O_RDWR);
if (this->data->fd != -1)
{
if (read(this->data->fd, vc_data, 4) == 4)
{
this->data->mode = 3;
this->data->rows = vc_data[0];
this->data->cols = vc_data[1];
this->data->cursor_x = vc_data[2];
this->data->cursor_y = vc_data[3];
for (i = 0; i < 256; i++)
this->data->map[i] = i;
i = init_scrnmap(this,this->data->fd) ||
init_scrnmap(this,STDIN_FILENO);
getChar(this,NULL,&attr,this->data->cursor_x,this->data->cursor_y);
this->data->init_attr = attr;
this->data->attr = attr;
a = make_cell(this,' ',attr);
for (i = 0; i < 256; i++)
this->data->empty_line[i] = a;
}
else
{
close(this->data->fd);
this->data->fd = -1;
}
}
}
#endif
if (this->data->mode < 0)
return -1;
return 0;
}
static void finalize(screen_t *this)
{
if (this->data->fd != -1)
(void) close(this->data->fd);
}
static void updateLineN(screen_t *this, const void *line, int y, int len)
{
if (len > 0 && len <= 2*this->data->cols && gotoxy(this,0,y) == 0)
{
int i;
unsigned char new_line[len];
unsigned char *l1 = new_line;
const unsigned char *l2 = (const unsigned char *) line;
for (i = 0; i < len; i += 2)
{
*l1++ = *l2++;
*l1++ = this->data->map[*l2++];
}
write(this->data->fd, new_line, len);
}
}
static void clearLine(screen_t *this, int y)
{
if (gotoxy(this,0,y) == 0)
write(this->data->fd, this->data->empty_line, 2*this->data->cols);
}
static void clear(screen_t *this)
{
int y;
for (y = 0; y < this->data->rows; y++)
clearLine(this,y);
}
static int scrollUp(screen_t *this, int lines)
{
int sr = this->data->rows;
int sc = this->data->cols;
int y;
if (lines <= 0 || lines > sr)
return 0;
#ifdef USE_SCROLLBACK
/* copy to scrollback buffer */
for (y = 0; y < lines; y++)
{
unsigned short buf[ sc ];
gotoxy(this,0,y);
read(this->data->fd, buf, sizeof(buf));
sb_push(this,buf,sizeof(buf));
}
#endif
/* move screen up */
if (lines < sr)
{
unsigned short buf[ (sr-lines)*sc ];
gotoxy(this,0,lines);
read(this->data->fd, buf, sizeof(buf));
gotoxy(this,0,0);
write(this->data->fd, buf, sizeof(buf));
}
/* fill in blank lines at bottom */
for (y = sr - lines; y < sr; y++)
clearLine(this,y);
return lines;
}
static int scrollDown(screen_t *this, int lines)
{
int sr = this->data->rows;
int sc = this->data->cols;
int y;
if (lines <= 0 || lines > sr)
return 0;
/* move screen down */
if (lines < sr)
{
unsigned short buf[ (sr-lines)*sc ];
gotoxy(this,0,0);
read(this->data->fd, buf, sizeof(buf));
gotoxy(this,0,lines);
write(this->data->fd, buf, sizeof(buf));
}
/* copy top lines from scrollback buffer */
for (y = lines; --y >= 0; )
{
#ifdef USE_SCROLLBACK
const unsigned short *buf = sb_pop(this);
if (buf == NULL)
clearLine(this,y);
else
updateLineN(this,buf,y,sc*2);
#else
clearLine(this,y);
#endif
}
return lines;
}
static int getCursorShape(const screen_t *this)
{
UNUSED(this);
return 0;
}
static void setCursorShape(screen_t *this, int shape)
{
UNUSED(this);
UNUSED(shape);
}
static int kbhit(screen_t *this)
{
const int fd = STDIN_FILENO;
const unsigned long usec = 0;
struct timeval tv;
fd_set fds;
UNUSED(this);
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = usec / 1000000;
tv.tv_usec = usec % 1000000;
return (select(fd + 1, &fds, NULL, NULL, &tv) > 0);
}
static int intro(screen_t *this, void (*show_frames)(screen_t *) )
{
int shape;
struct termios term_old, term_new;
int term_r;
if ((this->data->init_attr & mask_bg) != BG_BLACK)
return 0;
term_r = tcgetattr(STDIN_FILENO, &term_old);
if (term_r == 0)
{
term_new = term_old;
term_new.c_lflag &= ~(ISIG | ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &term_new);
}
shape = getCursorShape(this);
setCursorShape(this,0x2000);
show_frames(this);
if (this->data->rows > 24)
setCursor(this,this->data->cursor_x,this->data->cursor_y+1);
setCursorShape(this,shape);
while (kbhit(this))
(void) fgetc(stdin);
if (term_r == 0)
tcsetattr(STDIN_FILENO, TCSANOW, &term_old);
return 1;
}
static const screen_t driver =
{
sobject_destroy,
finalize,
0, /* atExit */
init,
refresh,
getMode,
getPage,
getRows,
getCols,
isMono,
getFg,
getBg,
getCursor,
getCursorShape,
setFg,
setBg,
setCursor,
setCursorShape,
0, /* hideCursor */
putChar,
putCharAttr,
putString,
putStringAttr,
clear,
clearLine,
updateLineN,
scrollUp,
scrollDown,
kbhit,
intro,
(struct screen_data_t *) 0
};
/* public constructor */
screen_t *screen_vcsa_construct(void)
{
return sobject_construct(&driver,sizeof(*driver.data));
}
#endif /* defined(USE_SCREEN) && defined(USE_SCREEN_VCSA) */
/*
vi:ts=4:et
*/

489
src/s_win32.cpp Normal file
View File

@ -0,0 +1,489 @@
/* s_win32.cpp -- Win32 console screen driver
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#include "conf.h"
#if defined(USE_SCREEN) && defined(__MFX_WIN32)
#include "screen.h"
#define this local_this
#define mask_fg 0x0f
#define mask_bg 0xf0
/*************************************************************************
// direct screen access
**************************************************************************/
#include <windows.h>
#if defined(HAVE_CONIO_H)
# include <conio.h>
#endif
struct screen_data_t
{
HANDLE hi;
HANDLE ho;
CONSOLE_SCREEN_BUFFER_INFO csbi;
char title[512];
int mode;
int cols;
int rows;
int cursor_x;
int cursor_y;
WORD attr;
WORD init_attr;
CHAR_INFO empty_cell;
CHAR_INFO empty_line[256];
};
#define P(x) ((SHORT) (x))
static const COORD pos00 = { 0, 0 };
static const COORD size11 = { 1, 1 };
/* atExit information */
static struct
{
int is_valid;
HANDLE ho;
CONSOLE_CURSOR_INFO cci;
} ae;
static void refresh(screen_t *this)
{
UNUSED(this);
}
static int getMode(const screen_t *this)
{
return this->data->mode;
}
static int getPage(const screen_t *this)
{
UNUSED(this);
return 0;
}
static int getRows(const screen_t *this)
{
return this->data->rows;
}
static int getCols(const screen_t *this)
{
return this->data->cols;
}
static int isMono(const screen_t *this)
{
UNUSED(this);
return 0;
}
static int getFg(const screen_t *this)
{
return this->data->attr & mask_fg;
}
static int getBg(const screen_t *this)
{
return this->data->attr & mask_bg;
}
static void setFg(screen_t *this, int fg)
{
this->data->attr = (WORD) ((this->data->attr & mask_bg) | (fg & mask_fg));
SetConsoleTextAttribute(this->data->ho, this->data->attr);
}
static void setBg(screen_t *this, int bg)
{
this->data->attr = (WORD) ((this->data->attr & mask_fg) | (bg & mask_bg));
SetConsoleTextAttribute(this->data->ho, this->data->attr);
}
static void setCursor(screen_t *this, int x, int y)
{
if (x >= 0 && y >= 0 && x < this->data->cols && y < this->data->rows)
{
COORD coord = { P(x), P(y) };
SetConsoleCursorPosition(this->data->ho, coord);
this->data->cursor_x = x;
this->data->cursor_y = y;
}
}
static void getCursor(const screen_t *this, int *x, int *y)
{
int cx = this->data->cursor_x;
int cy = this->data->cursor_y;
#if 1
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(this->data->ho, &csbi))
{
cx = csbi.dwCursorPosition.X;
cy = csbi.dwCursorPosition.Y;
}
#endif
if (x) *x = cx;
if (y) *y = cy;
}
static void putCharAttr(screen_t *this, int ch, int attr, int x, int y)
{
CHAR_INFO ci;
SMALL_RECT region = { P(x), P(y), P(x), P(y) };
ci.Char.UnicodeChar = 0;
ci.Char.AsciiChar = (CHAR) ch;
ci.Attributes = (WORD) attr;
WriteConsoleOutput(this->data->ho, &ci, size11, pos00, &region);
}
static void putChar(screen_t *this, int ch, int x, int y)
{
this->putCharAttr(this, ch, this->data->attr, x, y);
}
static void putStringAttr(screen_t *this, const char *s, int attr, int x, int y)
{
int i;
int l = (int) strlen(s);
if (l <= 0)
return;
assert(l <= 256);
assert(x + l <= this->data->cols);
CHAR_INFO ci[256];
COORD size = { P(l), 1 };
SMALL_RECT region = { P(x), P(y), P(x + l - 1), P(y) };
for (i = 0; i < l; i++)
{
ci[i].Char.UnicodeChar = 0;
ci[i].Char.AsciiChar = *s++;
ci[i].Attributes = (WORD) attr;
}
WriteConsoleOutput(this->data->ho, &ci[0], size, pos00, &region);
}
static void putString(screen_t *this, const char *s, int x, int y)
{
this->putStringAttr(this, s, this->data->attr, x, y);
}
/* private */
static int cci2shape(CONSOLE_CURSOR_INFO *cci)
{
int shape = cci->dwSize & 255;
if (!cci->bVisible)
shape |= 0x2000;
return shape;
}
static int getCursorShape(const screen_t *this)
{
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(this->data->ho, &cci);
return cci2shape(&cci);
}
static void setCursorShape(screen_t *this, int shape)
{
CONSOLE_CURSOR_INFO cci;
cci.dwSize = shape & 255;
cci.bVisible = (shape & 0x2000) ? 0 : 1;
SetConsoleCursorInfo(this->data->ho, &cci);
}
static int hideCursor(screen_t *this)
{
CONSOLE_CURSOR_INFO cci;
int shape;
GetConsoleCursorInfo(this->data->ho, &cci);
shape = cci2shape(&cci);
if (cci.bVisible)
{
cci.bVisible = 0;
SetConsoleCursorInfo(this->data->ho, &cci);
}
return shape;
}
static int init(screen_t *this, int fd)
{
HANDLE hi, ho;
CONSOLE_SCREEN_BUFFER_INFO *csbi;
DWORD mode;
WORD attr;
int i;
if (!this || !this->data)
return -1;
this->data->hi = INVALID_HANDLE_VALUE;
this->data->ho = INVALID_HANDLE_VALUE;
this->data->mode = -1;
if (fd < 0 || !isatty(fd))
return -1;
hi = GetStdHandle(STD_INPUT_HANDLE);
ho = GetStdHandle(STD_OUTPUT_HANDLE);
if (hi == INVALID_HANDLE_VALUE || ho == INVALID_HANDLE_VALUE)
return -1;
if (!GetConsoleMode(ho, &mode))
return -1;
csbi = &this->data->csbi;
if (!GetConsoleScreenBufferInfo(ho, csbi))
return -1;
if (csbi->srWindow.Left != 0 || csbi->srWindow.Top != 0)
return -1;
if (!GetConsoleCursorInfo(ho, &ae.cci))
return -1;
if (!GetConsoleTitle(this->data->title, sizeof(this->data->title)))
return -1;
this->data->cols = csbi->srWindow.Right - csbi->srWindow.Left + 1;
this->data->rows = csbi->srWindow.Bottom - csbi->srWindow.Top + 1;
this->data->cursor_x = csbi->dwCursorPosition.X;
this->data->cursor_y = csbi->dwCursorPosition.Y;
ae.ho = ho;
ae.is_valid = 1;
attr = csbi->wAttributes;
this->data->hi = hi;
this->data->ho = ho;
this->data->mode = 3; // ???
this->data->attr = attr;
this->data->init_attr = attr;
this->data->empty_cell.Char.UnicodeChar = 0;
this->data->empty_cell.Char.AsciiChar = ' ';
this->data->empty_cell.Attributes = attr;
for (i = 0; i < 256; i++)
this->data->empty_line[i] = this->data->empty_cell;
return 0;
}
static void updateLineN(screen_t *this, const void *line, int y, int len)
{
if (y >= 0 && y < this->data->rows && len > 0 && len <= 2*this->data->cols)
{
#if 0
const char *s = (const char *) line;
int l = len / 2;
int i;
assert(l <= 256);
CHAR_INFO ci[256];
COORD size = { P(l), 1 };
SMALL_RECT region = { 0, P(y), P(0 + l - 1), P(y) };
for (i = 0; i < l; i++)
{
ci[i].Char.UnicodeChar = 0;
ci[i].Char.AsciiChar = *s++;
ci[i].Attributes = *s++;
}
WriteConsoleOutput(this->data->ho, &ci[0], size, pos00, &region);
#endif
UNUSED(line);
}
}
static void clearLine(screen_t *this, int y)
{
if (y >= 0 && y < this->data->rows)
{
COORD size = { P(this->data->cols), 1 };
SMALL_RECT region = { 0, P(y), P(this->data->cols-1), P(y) };
WriteConsoleOutput(this->data->ho, this->data->empty_line, size, pos00, &region);
}
}
static void clear(screen_t *this)
{
int y;
for (y = 0; y < this->data->rows; y++)
this->clearLine(this, y);
}
/* private */
static int do_scroll(screen_t *this, int lines, int way)
{
if (lines <= 0 || lines > this->data->rows)
return 0;
if (lines == this->data->rows)
{
this->clear(this);
return lines;
}
SMALL_RECT rect = { 0, 0, P(this->data->cols-1), P(this->data->rows-1) };
//SMALL_RECT clip = rect;
COORD dest = { 0, 0 };
switch (way)
{
case 0:
rect.Top = P(rect.Top + lines);
break;
case 1:
rect.Bottom = P(rect.Bottom - lines);
dest.Y = P(dest.Y + lines);
break;
}
//ScrollConsoleScreenBuffer(this->data->ho, &rect, &clip, dest, &this->data->empty_cell);
ScrollConsoleScreenBuffer(this->data->ho, &rect, NULL, dest, &this->data->empty_cell);
return lines;
}
static int scrollUp(screen_t *this, int lines)
{
return do_scroll(this, lines, 0);
}
static int scrollDown(screen_t *this, int lines)
{
return do_scroll(this, lines, 1);
}
static int s_kbhit(screen_t *this)
{
#if defined(HAVE_CONIO_H)
UNUSED(this);
return _kbhit();
#else
UNUSED(this);
return 0;
#endif
}
static int intro(screen_t *this, void (*show_frames)(screen_t *) )
{
UNUSED(this);
UNUSED(show_frames);
return 0;
}
static void atExit(void)
{
static int done = 0;
if (done) return;
done = 1;
if (ae.is_valid)
{
}
}
static const screen_t driver =
{
sobject_destroy,
0, /* finalize, */
atExit,
init,
refresh,
getMode,
getPage,
getRows,
getCols,
isMono,
getFg,
getBg,
getCursor,
getCursorShape,
setFg,
setBg,
setCursor,
setCursorShape,
hideCursor,
putChar,
putCharAttr,
putString,
putStringAttr,
clear,
clearLine,
updateLineN,
scrollUp,
scrollDown,
s_kbhit,
intro,
(struct screen_data_t *) 0
};
/* public constructor */
screen_t *screen_win32_construct(void)
{
return sobject_construct(&driver,sizeof(*driver.data));
}
#endif /* defined(USE_SCREEN) && defined(__MFX_WIN32) */
/*
vi:ts=4:et
*/

111
src/screen.h Normal file
View File

@ -0,0 +1,111 @@
/* screen.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_SCREEN_H
#define __UPX_SCREEN_H
#if defined(USE_SCREEN)
/*************************************************************************
//
**************************************************************************/
struct screen_data_t;
struct screen_t;
typedef struct screen_t screen_t;
struct screen_t
{
/* public: */
void (*destroy)(screen_t *s);
void (*finalize)(screen_t *s);
void (*atExit)(void); /* atexit/signal handler */
int (*init)(screen_t *s, int fd);
void (*refresh)(screen_t *s);
int (*getMode)(const screen_t *s);
int (*getPage)(const screen_t *s);
int (*getRows)(const screen_t *s);
int (*getCols)(const screen_t *s);
int (*isMono)(const screen_t *s);
int (*getFg)(const screen_t *s);
int (*getBg)(const screen_t *s);
void (*getCursor)(const screen_t *s, int *x, int *y);
int (*getCursorShape)(const screen_t *s);
void (*setFg)(screen_t *s, int);
void (*setBg)(screen_t *s, int);
void (*setCursor)(screen_t *s, int x, int y);
void (*setCursorShape)(screen_t *s, int shape);
int (*hideCursor)(screen_t *s);
void (*putChar)(screen_t *s, int c, int x, int y);
void (*putCharAttr)(screen_t *s, int c, int attr, int x, int y);
void (*putString)(screen_t *s, const char *, int x, int y);
void (*putStringAttr)(screen_t *s, const char *, int attr, int x, int y);
void (*clear)(screen_t *s);
void (*clearLine)(screen_t *s, int);
void (*updateLineN)(screen_t *s, const void *, int y, int len);
int (*scrollUp)(screen_t *s, int);
int (*scrollDown)(screen_t *s, int);
int (*kbhit)(screen_t *s);
int (*intro)(screen_t *s, void (*)(screen_t*) );
/* private: */
struct screen_data_t *data;
};
screen_t *sobject_construct(const screen_t *c, size_t data_size);
void sobject_destroy(screen_t *);
screen_t *sobject_get_screen(void);
screen_t *screen_curses_construct(void);
screen_t *screen_djgpp2_construct(void);
screen_t *screen_vcsa_construct(void);
screen_t *screen_win32_construct(void);
void screen_show_frames(screen_t *);
#endif
#endif /* already included */
/*
vi:ts=4:et
*/

49
src/stdcxx.cpp Normal file
View File

@ -0,0 +1,49 @@
/* stdcxx.cpp --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
//#define WANT_STL
#include "conf.h"
#include "stdcxx.h"
#ifdef WANT_STL
#if defined(__DJGPP__) || defined(__MINGW32__) || defined(__sparc__)
void (*__malloc_alloc_template<0>::__malloc_alloc_oom_handler)() = 0;
# if !defined(__USE_MALLOC)
template class __default_alloc_template<false, 0>;
# endif
#endif
#endif
/*
vi:ts=4:et:nowrap
*/

83
src/stdcxx.h Normal file
View File

@ -0,0 +1,83 @@
/* stdcxx.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#ifndef __UPX_STDCXX_H
#define __UPX_STDCXX_H
#ifdef __cplusplus
/*************************************************************************
// exceptions, RTTI
**************************************************************************/
#include <exception>
//#include <stdexcept>
#include <new>
#include <typeinfo>
/*************************************************************************
// STL
**************************************************************************/
#ifdef WANT_STL
#if defined(__linux__)
# define _NOTHREADS
#endif
#if defined(__DJGPP__) || defined(__MINGW32__) || defined(__sparc__)
# define __THROW_BAD_ALLOC throw bad_alloc()
# define __USE_MALLOC
# define enable upx_stl_enable
#endif
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4018 4100 4663)
#endif
#include <vector>
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#endif /* WANT_STL */
using namespace std;
#endif /* __cplusplus */
#endif /* already included */
/*
vi:ts=4:et:nowrap
*/

322
src/stub/Makefile Normal file
View File

@ -0,0 +1,322 @@
#
# UPX stub Makefile (GNU make)
#
ifeq ($(strip $(UCLDIR)),)
# change this to reflect where the UCL library is
UCLDIR = $(HOME)/local/src/ucl-0.91
endif
# -------------------------------------------------------
# You should not have to change anything below this line.
# -------------------------------------------------------
SHELL = /bin/sh
top_srcdir = ../..
# These are the files we want to create.
STUBS = \
l_com.h \
l_djgpp2.h stubify.h \
l_exe.h \
l_sys.h \
l_t_n2b.h l_t_n2bs.h l_t_n2d.h l_t_n2ds.h \
l_tmt.h \
l_wcle.h \
l_w32pe.h \
l_lx_n2b.h l_lx_n2d.h \
l_le_n2b.h l_le_n2d.h \
l_sh_n2b.h l_sh_n2d.h
# util var for use in the rules - basename of the current target
override T = $(basename $@)
# /***********************************************************************
# // source directories
# ************************************************************************/
UCL_UPX = $(UCLDIR)/upx
UCL_I386 = $(UCLDIR)/upx/i386
UCL_M68K = $(UCLDIR)/upx/m68k
.SUFFIXES:
.SUFFIXES: .asm .ash .asx .asy .bin .c .h .s
vpath %.ash $(UCL_I386)
vpath %.ash $(UCL_M68K)
# /***********************************************************************
# // tools
# ************************************************************************/
NASM = nasm -w+macro-params -w+orphan-labels
APP = perl -w scripts/app.pl
BIN2H = perl -w scripts/bin2h.pl
BRANDELF = perl -w scripts/brandelf.pl
O2BIN = perl -w scripts/o2bin.pl
SETFOLD = perl -w scripts/setfold.pl
##STRIPELF = perl -w scripts/stripelf.pl
STRIPELF = ./util/sstrip/sstrip
# Preprocessor for a68k assembler.
CPP_M68K = gcc -I$(UCL_UPX) -E -x assembler-with-cpp -Wall -Wp,-P,-C,-traditional
# Use gcc 2.95.2 for smallest code.
CC_LINUX_CFLAGS = -Wall -W -Wcast-align -Wcast-qual -Wwrite-strings
CC_LINUX_CFLAGS += -funsigned-char
###CC_LINUX_CFLAGS += -fwritable-strings -save-temps
CC_LINUX = gcc272 -O2 -m386 -malign-functions=0 -malign-jumps=0 -malign-loops=0 $(CC_LINUX_CFLAGS)
CC_LINUX = gcc -Os -march=i386 -mcpu=i386 -malign-functions=0 -malign-jumps=0 -malign-loops=0 $(CC_LINUX_CFLAGS)
# Specifying -mcpu=i586 inhibits use of 'leave', which costs 2 bytes per subr
#CC_LINUX =gcc -Os -march=i386 -mcpu=i586 -malign-functions=0 -malign-jumps=0 -malign-loops=0 $(CC_LINUX_CFLAGS)
# /***********************************************************************
# // main targets
# ************************************************************************/
.PHONY: default all stubs mostlyclean clean distclean maintainer-clean ident strings
default:
@echo "UPX info: type 'make all' if you have all the needed build tools."
all: stubs upxb upxd
stubs: $(STUBS)
mostlyclean:
-rm -f *~ *.bin *.bkp *.i *.lst *.map
clean: mostlyclean
-rm -f *.o *.asx *.asy upxb upxd
distclean: clean
# This command is intended for maintainers to use; it deletes files
# that may require special tools to rebuild.
maintainer-clean: distclean
-rm -f $(STUBS)
ident: all
ident *.bin
strings: all
strings *.bin
# /***********************************************************************
# // rules
# ************************************************************************/
.asm.asx:
$(APP) $< $@
.ash.asy:
$(APP) $< $@
stubify.h: stub.asm
djasm $< $@
l_com.h: l_com.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv2b_loader $@
l_djgpp2.h: l_djgpp2.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_exe.h: l_exe.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_sys.h: l_sys.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv2b_loader $@
l_tmt.h: l_tmt.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_t_n2b.h: l_tos.s
$(CPP_M68K) -D__A68K__ -DNRV2B -o $T.i $<
a68k -q -x $T.i
$(O2BIN) $T.o $T.bin 'UPX1' 'UPX9'
$(BIN2H) $T.bin nrv2b_loader $@
l_t_n2bs.h: l_tos.s
$(CPP_M68K) -D__A68K__ -DNRV2B -DSMALL -o $T.i $<
a68k -q -x $T.i
$(O2BIN) $T.o $T.bin 'UPX1' 'UPX9'
$(BIN2H) $T.bin nrv2b_loader_small $@
l_t_n2d.h: l_tos.s
$(CPP_M68K) -D__A68K__ -DNRV2D -o $T.i $<
a68k -q -x $T.i
$(O2BIN) $T.o $T.bin 'UPX1' 'UPX9'
$(BIN2H) $T.bin nrv2d_loader $@
l_t_n2ds.h: l_tos.s
$(CPP_M68K) -D__A68K__ -DNRV2D -DSMALL -o $T.i $<
a68k -q -x $T.i
$(O2BIN) $T.o $T.bin 'UPX1' 'UPX9'
$(BIN2H) $T.bin nrv2d_loader_small $@
l_vxd.h: l_vxd.asm
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_wcle.h: l_wcle.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_w32pe.h: l_w32pe.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
# /***********************************************************************
# // linux rules (exec, elf, sh, sep)
# ************************************************************************/
l_lx_n2b.h: l_lx_exec.c l_xe_n2b.o
$(CC_LINUX) -DNRV2B -s -o $T.o -c $<
ld -s -Map l_lx_n2b.map -o $T.bin \
l_xe_n2b.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386exec_nrv2b_loader $@
l_le_n2b.h: l_lx_elf.c l_6e_n2b.o l_lx_elf86.lds
$(CC_LINUX) -DNRV2B -s -o $T.o -c $<
ld -T l_lx_elf86.lds -s -Map $T.map -o $T.bin \
l_6e_n2b.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(SETFOLD) $T.bin 0x`nm l_6e_n2b.o | grep fold_begin`
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386elf_nrv2b_loader $@
l_sh_n2b.h: l_lx_sh.c l_6h_n2b.o l_lx_sh86.lds
$(CC_LINUX) -DNRV2B -s -o $T.o -c $<
ld -T l_lx_sh86.lds -s -Map $T.map -o $T.bin \
l_6h_n2b.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(SETFOLD) $T.bin 0x`nm l_6h_n2b.o | grep fold_begin`
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386sh_nrv2b_loader $@
l_xe_n2b.o: l_lx_exec86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o $@ $<
l_6e_n2b.o: l_lx_elf86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o $@ $<
l_6h_n2b.o: l_lx_sh86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o $@ $<
l_lx_n2d.h: l_lx_exec.c l_xe_n2d.o
$(CC_LINUX) -DNRV2D -s -o $T.o -c $<
ld -s -Map $T.map -o $T.bin \
l_xe_n2d.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386exec_nrv2d_loader $@
l_le_n2d.h: l_lx_elf.c l_6e_n2d.o l_lx_elf86.lds
$(CC_LINUX) -DNRV2D -s -o $T.o -c $<
ld -T l_lx_elf86.lds -s -Map $T.map -o $T.bin \
l_6e_n2d.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(SETFOLD) $T.bin 0x`nm l_6e_n2d.o | grep fold_begin`
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386elf_nrv2d_loader $@
l_sh_n2d.h: l_lx_sh.c l_6h_n2d.o l_lx_sh86.lds
$(CC_LINUX) -DNRV2D -s -o $T.o -c $<
ld -T l_lx_sh86.lds -s -Map $T.map -o $T.bin \
l_6h_n2d.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(SETFOLD) $T.bin 0x`nm l_6h_n2d.o | grep fold_begin`
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386sh_nrv2d_loader $@
l_xe_n2d.o: l_lx_exec86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o $@ $<
l_6e_n2d.o: l_lx_elf86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o $@ $<
l_6h_n2d.o: l_lx_sh86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o $@ $<
l_lx_sep.o: l_lx_sep.c
$(CC_LINUX) -c $<
upxb: l_lx_sep.o l_lx_sep86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o upxb.o l_lx_sep86.asm
ld -T l_lx_sep86.lds -Map upxb.map -o upxb upxb.o l_lx_sep.o
objcopy -S -R .comment -R .note upxb
$(STRIPELF) upxb
$(BRANDELF) upxb
upxd: l_lx_sep.o l_lx_sep86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o upxd.o l_lx_sep86.asm
ld -T l_lx_sep86.lds -Map upxd.map -o upxd upxd.o l_lx_sep.o
objcopy -S -R .comment -R .note upxd
$(STRIPELF) upxd
$(BRANDELF) upxd
# /***********************************************************************
# // dependencies
# ************************************************************************/
DEPS1 = header.ash macros.ash ident.ash ident_n.ash ident_s.ash
DEPS2 = header.asy macros.asy
l_com.h: n2b_d16.asy $(DEPS2)
l_djgpp2.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_exe.h: n2b_d8e.asy n2d_d8e.asy $(DEPS2)
l_sys.h: n2b_d16.asy $(DEPS2)
l_t_n2b.h: n2b_d.ash bits.ash $(DEPS1)
l_t_n2bs.h: n2b_d.ash bits.ash $(DEPS1)
l_t_n2d.h: n2d_d.ash bits.ash $(DEPS1)
l_t_n2ds.h: n2d_d.ash bits.ash $(DEPS1)
l_tmt.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_vxd.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_wcle.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_w32pe.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_xe_n2b.o: n2b_d32.ash $(DEPS1)
l_6e_n2b.o: n2b_d32.ash $(DEPS1)
l_6h_n2b.o: n2b_d32.ash $(DEPS1)
l_xe_n2d.o: n2d_d32.ash $(DEPS1)
l_6e_n2d.o: n2d_d32.ash $(DEPS1)
l_6h_n2d.o: n2d_d32.ash $(DEPS1)
l_lx_n2b.h: linux.hh
l_lx_n2d.h: linux.hh
l_le_n2b.h: linux.hh
l_le_n2d.h: linux.hh
l_sh_n2b.h: linux.hh
l_sh_n2d.h: linux.hh
upxb: linux.hh
upxd: linux.hh
.NOEXPORT:
# vi:nowrap

60
src/stub/header.ash Normal file
View File

@ -0,0 +1,60 @@
; header.ash --
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; ------------- HEADER ------------- ; __UPX1HEAD__
db 'UPX!' ; 0 magic
db 0 ; 4 version
db 0 ; 5 type (com,sys,...)
db 0 ; 6 compression method
db 0 ; 7 compression level
dd 0 ; 8 uncompressed adler32
dd 0 ; 12 compressed adler32
%ifdef COM
dw 0 ; 16 uncompressed len
dw 0 ; 18 compressed len
db 0 ; 20 filter
db 0 ; 21 header checksum
%elifdef EXE
db 0,0,0 ; 16 uncompressed len
db 0,0,0 ; 19 compressed len
db 0,0,0 ; 22 original file size
db 0 ; 25 filter
db 0 ; 26 header checksum
%else
dd 0 ; 16 uncompressed len
dd 0 ; 20 compressed len
dd 0 ; 24 original file size
db 0 ; 28 filter id
db 0 ; 29 cto (for filters 0x21..0x29)
db 0 ; unsused
db 0 ; 31 header checksum
%endif
; vi:ts=8:et:nowrap

37
src/stub/ident.ash Normal file
View File

@ -0,0 +1,37 @@
; ident.ash --
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; ------------- COPYRIGHT -------------
%ifdef __IDENTSMA__
%include "ident_s.ash"
%else; __IDENTBIG__
%include "ident_n.ash"
%endif; __IDENTEND__
; vi:ts=8:et:nowrap

39
src/stub/ident_n.ash Normal file
View File

@ -0,0 +1,39 @@
; ident_n.ash --
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; ------------- COPYRIGHT -------------
db 10,0
db '$Info: This file is packed with the UPX executable packer http://upx.tsx.org $'
db 10,0
db '$Id: UPX '
db 'UPXV'
db ' Copyright (C) 1996-2000 the UPX Team. All Rights Reserved. $'
db 10,0
; vi:ts=8:et:nowrap

35
src/stub/ident_s.ash Normal file
View File

@ -0,0 +1,35 @@
; ident_s.ash --
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; ------------- COPYRIGHT -------------
db 10
db '$Id: ident_s.ash,v 1.1 2000/05/10 04:57:58 jreiser Exp jreiser $'
db 10,0
; vi:ts=8:et:nowrap

95
src/stub/l_com.asm Normal file
View File

@ -0,0 +1,95 @@
; l_com.asm -- loader & decompressor for the dos/com format
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
%define COM 1
%define CJT16 1
%define jmps jmp short
%include "macros.ash"
BITS 16
ORG 0
SECTION .text
; =============
; ============= ENTRY POINT
; =============
; __COMMAIN1__
start:
cmp sp, 'SP'
ja mem_ok
int 0x20
mem_ok:
mov cx, 'CX' ; size of decomp + sizeof (data) + 1
mov si, 'SI' ; cx + 0x100
mov di, 'DI'
mov bx, 0x8000
std
rep
movsb
cld
xchg si, di
sub si, byte start - cutpoint
; __COMSUBSI__
sbb bp, bp
push di
%ifdef __COMCALLT__
push di
%endif; __COMMAIN2__
jmp .1+'JM'
.1:
%include "header.ash"
cutpoint:
; __COMCUTPO__
; =============
; ============= DECOMPRESSION
; =============
%include "n2b_d16.ash"
; =============
; ============= CALLTRICK
; =============
; =============
; __CORETURN__
ret
eof:
; __COMTHEND__
section .data
dd -1
dw eof
; vi:ts=8:et:nowrap

93
src/stub/l_djgpp2.asm Normal file
View File

@ -0,0 +1,93 @@
; l_djgpp2.asm -- loader & decompressor for the djgpp2/coff format
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
%define jmps jmp short
%include "macros.ash"
BITS 32
SECTION .text
ORG 0
; =============
; ============= ENTRY POINT
; =============
; __DJ2MAIN1__
start:
push ds
pop es
mov esi, 'INPP' ; input pointer
mov edi, 'OUTP' ; output pointer
%ifdef __DJCALLT1__
push edi
%endif; __DJ2MAIN2__
; cld ; the stub sets this
or ebp, byte -1
; =============
; ============= DECOMPRESSION
; =============
%include "n2b_d32.ash"
%include "n2d_d32.ash"
; =============
; __DJ2BSS00__
mov ecx, 'BSSL'
rep
stosd
%ifdef __DJCALLT2__
; =============
; ============= CALLTRICK
; =============
pop edi
cjt32 0
%endif; __DJRETURN__
; =============
push dword 'ENTR' ; entry point
ret
; because of a feature of the djgpp loader, the size of this stub must be
; a multiple of 4 and as the upx decompressor depends on the fact that
; the compressed data stream begins just after the header, i must
; use an alignment here - ML
align 4
%include "header.ash"
eof:
; __DJTHEEND__
section .data
dd -1
dw eof
; vi:ts=8:et:nowrap

177
src/stub/l_exe.asm Normal file
View File

@ -0,0 +1,177 @@
; l_exe.asm -- loader & decompressor for the dos/exe format
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
%define EXE
%define jmps jmp short
BITS 16
ORG 0
SECTION .text
; =============
; ============= ENTRY POINT
; =============
; __EXEENTRY__
mov cx, 'CX' ; first_copy_len/2
mov si, 'SI' ; cx*2-2
mov di, si
push ds
db 0xa9
do_copy:
mov ch, 0x80 ; 64 kbyte
mov ax, cs
add ax, 'DS'
mov ds, ax
add ax, 'ES'
mov es, ax
std
rep
movsw
cld
sub [byte cs:si+do_copy+6+2], byte 0x10
jnc do_copy
xchg ax, dx
scasw
lodsw
%ifdef __EXERELPU__
push cs
%endif; __EXEMAIN4__
push cs
push cs
push es
pop ds
pop es
push ss
mov bp, 'BP' ; entry point [0x1,0x10]
mov bx, 'BX' ; 0x800F + 0x10*bp - 0x10
push bp
retf
%include "header.ash"
; __EXECUTPO__
; =============
; ============= DECOMPRESSION
; =============
%include "n2b_d8e.ash"
%include "n2d_d8e.ash"
; =============
; ============= RELOCATION
; =============
; __EXEMAIN5__
pop bp
%ifdef __EXERELOC__
%ifdef __EXEADJUS__
mov ax, es
sub ah, 0x6 ; MAXRELOCS >> 12
mov ds, ax
%else; __EXENOADJ__
push es
pop ds
%endif; __EXERELO1__
lea si, [di+'RS']
lodsw
pop bx
xchg ax, cx ; number of 0x01 bytes (not exactly)
lodsw
xchg ax, dx ; seg_hi
reloc_0:
lodsw
xchg ax, di
lodsw
add bx, ax
mov es, bx
xor ax, ax
reloc_1:
add di, ax
add [es:di], bp
reloc_2:
lodsb
dec ax
jz reloc_5
inc ax
jnz reloc_1
%ifdef __EXEREL9A__
inc di
reloc_4:
inc di
cmp byte [es:di], 0x9a
jne reloc_4
cmp [es:di+3], dx
ja reloc_4
mov al, 3
jmps reloc_1
%endif; __EXERELO2__
reloc_5:
add di, 0xfe
%ifdef __EXEREBIG__
jc reloc_0
%endif; __EXERELO3__
loop reloc_2
%endif; __EXEMAIN8__
; =============
pop es
push es
pop ds
%ifdef __EXESTACK__
lea ax, ['SS'+bp]
mov ss, ax
%endif; __EXEDUMMS__
%ifdef __EXESTASP__
mov sp, 'SP'
%endif; __EXEDUMMP__
; =============
%ifdef __EXEJUMPF__
jmp 'CS':'IP'
%else; __EXERETUR__
%ifdef __EXERCSPO__
add bp, 'CS'
%endif; __EXERETIP__
push bp
mov ax, 'IP'
push ax
retf
%endif; __EXEDUMMZ__
eof:
; __EXETHEND__
section .data
dd -1
dw eof
; vi:ts=8:et:nowrap

385
src/stub/l_lx_elf.c Normal file
View File

@ -0,0 +1,385 @@
/* l_lx_elf.c -- stub loader for Linux x86 ELF executable
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Integration of virtual exec() with decompression is
Copyright (C) 2000 John F. Reiser. 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
John F. Reiser
jreiser@BitWagon.com
*/
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include "linux.hh"
/*************************************************************************
// configuration section
**************************************************************************/
// In order to make it much easier to move this code at runtime and execute
// it at an address different from it load address: there must be no
// static data, and no string constants.
#define PAGEMASK (~0u<<12) // discards the offset, keeps the page
#define PAGESIZE ( 1u<<12)
#define MAX_ELF_HDR 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this
/*************************************************************************
// "file" util
**************************************************************************/
struct Extent {
size_t size; // must be first to match size[0] uncompressed size
char *buf;
};
static void
xread(struct Extent *x, char *buf, size_t count)
{
char *p=x->buf, *q=buf;
size_t j;
if (x->size < count) {
exit(127);
}
for (j = count; 0!=j--; ++p, ++q) {
*q = *p;
}
x->buf += count;
x->size -= count;
}
/*************************************************************************
// util
**************************************************************************/
#if 0 //{ save space
#define ERR_LAB error: exit(127);
#define err_exit(a) goto error
#else //}{ save debugging time
#define ERR_LAB
static void
err_exit(int a)
{
(void)a; // debugging convenience
exit(127);
}
#endif //}
static void *
do_brk(void *addr)
{
return brk(addr);
}
static char *
do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
(void)len; (void)prot; (void)flags; (void)fd; (void)offset;
return mmap((int *)&addr);
}
/*************************************************************************
// UPX & NRV stuff
**************************************************************************/
typedef int f_expand(
const nrv_byte *, nrv_uint,
nrv_byte *, nrv_uint * );
static void
unpackExtent(
struct Extent *const xi, // input
struct Extent *const xo, // output
f_expand *const f_decompress
)
{
while (xo->size) {
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
// Read and check block sizes.
xread(xi, (char *)&h, sizeof(h));
if (h.sz_unc == 0) { // uncompressed size 0 -> EOF
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
err_exit(2);
if (xi->size != 0) // all bytes must be written
err_exit(3);
break;
}
if (h.sz_cpr <= 0) {
err_exit(4);
ERR_LAB
}
if (h.sz_cpr > h.sz_unc
|| h.sz_unc > (int32_t)xo->size ) {
err_exit(5);
}
// Now we have:
// assert(h.sz_cpr <= h.sz_unc);
// assert(h.sz_unc > 0 && h.sz_unc <= blocksize);
// assert(h.sz_cpr > 0 && h.sz_cpr <= blocksize);
if (h.sz_cpr < h.sz_unc) { // Decompress block
nrv_uint out_len;
int const j = (*f_decompress)(xi->buf, h.sz_cpr, xo->buf, &out_len);
if (j != 0 || out_len != (nrv_uint)h.sz_unc)
err_exit(7);
xi->buf += h.sz_cpr;
xi->size -= h.sz_cpr;
}
else { // copy literal block
xread(xi, xo->buf, h.sz_cpr);
}
xo->buf += h.sz_unc;
xo->size -= h.sz_unc;
}
}
// Create (or find) an escape hatch to use when munmapping ourselves the stub.
// Called by do_xmap to create it, and by assembler code to find it.
void *
make_hatch(Elf32_Phdr const *const phdr)
{
if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
unsigned *hatch;
// The format of the 'if' is
// if ( ( (hatch = loc1), test_loc1 )
// || ( (hatch = loc2), test_loc2 ) ) {
// action
// }
// which uses the comma to save bytes when test_locj involves locj
// and the action is the same when either test succeeds.
// Try page fragmentation just beyond .text .
if ( ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr)),
( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss
&& 4<=(~PAGEMASK & -(int)hatch) ) ) // space left on page
// Try Elf32_Ehdr.e_ident[12..15] . warning: 'const' cast away
|| ( (hatch = (void *)(&((Elf32_Ehdr *)phdr->p_vaddr)->e_ident[12])),
(phdr->p_offset==0) ) ) {
// Omitting 'const' saves repeated literal in gcc.
unsigned /*const*/ escape = 0xc36180cd; // "int $0x80; popa; ret"
// Don't store into read-only page if value is already there.
if (*hatch != escape) {
*hatch = escape;
}
return hatch;
}
}
return 0;
}
static void
bzero(char *p, size_t len)
{
if (len) do {
*p++= 0;
} while (--len);
}
static Elf32_Addr // entry address
do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, struct Extent *const xi,
Elf32_auxv_t *const a)
{
Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff +
(char const *)ehdr);
unsigned long base = (ET_DYN==ehdr->e_type) ? 0x40000000 : 0;
int j;
for (j=0; j < ehdr->e_phnum; ++phdr, ++j)
if (PT_PHDR==phdr->p_type) {
a->a_un.a_val = phdr->p_vaddr;
}
else if (PT_LOAD==phdr->p_type) {
struct Extent xo;
size_t mlen = xo.size = phdr->p_filesz;
char *addr = xo.buf = (char *)phdr->p_vaddr;
char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr;
size_t frag = (int)addr &~ PAGEMASK;
mlen += frag;
addr -= frag;
if (ET_DYN==ehdr->e_type) {
addr += base;
haddr += base;
}
else { // There is only one brk, the one for the ET_EXEC
// Not needed if compressed a.elf is invoked directly.
// Needed only if compressed shell script invokes compressed shell.
do_brk(haddr+OVERHEAD); // Also takes care of whole pages of .bss
}
// Decompressor can overrun the destination by 3 bytes.
if (addr != do_mmap(addr, mlen + (xi ? 3 : 0), PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | (xi ? MAP_ANONYMOUS : 0),
fdi, phdr->p_offset - frag) ) {
err_exit(8);
}
if (0==base) {
base = (unsigned long)addr;
}
if (xi) {
unpackExtent(xi, &xo, (f_expand *)fdi);
}
bzero(addr, frag); // fragment at lo end
frag = (-mlen) &~ PAGEMASK; // distance to next page boundary
bzero(mlen+addr, frag); // fragment at hi end
if (xi) {
make_hatch(phdr);
}
if (phdr->p_memsz != phdr->p_filesz) { // .bss
if (ET_DYN==ehdr->e_type) { // PT_INTERP whole pages of .bss?
addr += frag + mlen;
mlen = haddr - addr;
if (0 < (int)mlen) { // need more pages, too
if (addr != do_mmap(addr, mlen, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 ) ) {
err_exit(9);
ERR_LAB
}
}
}
}
else { // no .bss
int prot = 0;
if (phdr->p_flags & PF_X) { prot |= PROT_EXEC; }
if (phdr->p_flags & PF_W) { prot |= PROT_WRITE; }
if (phdr->p_flags & PF_R) { prot |= PROT_READ; }
if (0!=mprotect(addr, mlen, prot)) {
err_exit(10);
}
if (xi) { // cleanup if decompressor overrun crosses page boundary
mlen += 3;
addr += mlen;
mlen &= ~PAGEMASK;
if (mlen<=3) { // page fragment was overrun buffer only
munmap(addr - mlen, mlen);
}
}
}
if (ET_DYN!=ehdr->e_type) {
// Needed only if compressed shell script invokes compressed shell.
do_brk(haddr);
}
}
if (!xi) {
if (0!=close(fdi)) {
err_exit(11);
}
}
if (ET_DYN==ehdr->e_type) {
return ehdr->e_entry + base;
}
else {
return ehdr->e_entry;
}
}
/*************************************************************************
// upx_main - called by our entry code
//
// This function is optimized for size.
**************************************************************************/
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr,
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr
) __asm__("upx_main");
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr, // to get compressed size and data
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR+OVERHEAD]
)
{
size_t const lsize = *(unsigned short const *)(0x7c + (char const *)my_ehdr);
Elf32_Phdr const *phdr = (Elf32_Phdr const *)(1+ehdr);
Elf32_Addr entry;
struct Extent xo;
struct Extent xi = { 0, (sizeof(struct p_info) + lsize + (char *)my_ehdr) };
// warning: 'const' cast away
size_t const sz_elfhdrs = ((size_t *)xi.buf)[0]; // sizeof(Ehdr+Phdrs), uncompressed
size_t const sz_pckhdrs = ((size_t *)xi.buf)[1]; // sizeof(Ehdr+Phdrs), compressed
(void)uncbuf; // used by l_lx_sh.c
// Uncompress Ehdr and Phdrs.
xo.size = sz_elfhdrs; xo.buf = (char *)ehdr;
xi.size = 2*sizeof(size_t) + sz_pckhdrs;
unpackExtent(&xi, &xo, f_decompress);
// Prepare to decompress the Elf headers again, into the first PT_LOAD.
xi.buf -= 2*sizeof(size_t) + sz_pckhdrs;
xi.size = ((Elf32_Phdr const *)(1 + my_ehdr))->p_filesz - lsize;
av[0].a_type = AT_PHDR; // av[0].a_un.a_val is set by do_xmap
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;
av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGESIZE;
av[4].a_type = AT_ENTRY; av[4].a_un.a_val = ehdr->e_entry;
av[5].a_type = AT_NULL;
entry = do_xmap((int)f_decompress, ehdr, &xi, av);
{ // Map PT_INTERP program interpreter
int j;
for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_INTERP==phdr->p_type) {
char const *const iname = (char const *)phdr->p_vaddr;
int const fdi = open(iname, O_RDONLY, 0);
if (0 > fdi) {
err_exit(18);
}
if (MAX_ELF_HDR!=read(fdi, (void *)ehdr, MAX_ELF_HDR)) {
err_exit(19);
}
entry = do_xmap(fdi, ehdr, 0, 0);
break;
}
}
return (void *)entry;
}
/*
vi:ts=4:et:nowrap
*/

281
src/stub/l_lx_elf86.asm Normal file
View File

@ -0,0 +1,281 @@
; l_lx_elf86.asm -- Linux program entry point & decompressor (Elf binary)
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; Integration of virtual exec() with decompression is
; Copyright (C) 2000 John F. Reiser. 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; John F. Reiser
; jreiser@BitWagon.com
BITS 32
SECTION .text
%define jmps jmp short
; defines for ident.ash and n2b_d32.ash
%ifdef SMALL
%define __IDENTSMA__
%define __N2BSMA10__
%define __N2BSMA20__
%define __N2BSMA30__
%define __N2BSMA40__
%define __N2BSMA50__
%define __N2BSMA60__
%define __N2DSMA10__
%define __N2DSMA20__
%define __N2DSMA30__
%define __N2DSMA40__
%define __N2DSMA50__
%define __N2DSMA60__
%endif
%include "ident.ash"
; /*************************************************************************
; // program entry point
; // see glibc/sysdeps/i386/elf/start.S
; **************************************************************************/
GLOBAL _start
_start:
;;;; int3
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
;; Build the stubs and upx. Compress a testcase, such as a copy of /bin/date.
;; Invoke gdb, and give a 'run' command. Define a single-step macro such as
;; define g
;; stepi
;; x/i $pc
;; end
;; and a step-over macro such as
;; define h
;; x/2i $pc
;; tbreak *$_
;; continue
;; x/i $pc
;; end
;; Step through the code; remember that <Enter> repeats the previous command.
;;
call main ; push address of decompress subroutine
; /*************************************************************************
; // C callable decompressor
; **************************************************************************/
%define INP dword [esp+8*4+4]
%define INS dword [esp+8*4+8]
%define OUTP dword [esp+8*4+12]
%define OUTS dword [esp+8*4+16]
decompress:
pusha
; cld
mov esi, INP
mov edi, OUTP
or ebp, byte -1
;;; align 8
%ifdef NRV2B
%include "n2b_d32.ash"
%elifdef NRV2D
%include "n2d_d32.ash"
%else
%error
%endif
; eax is 0 from decompressor code
;xor eax, eax ; return code
; check compressed size
mov edx, INP
add edx, INS
cmp esi, edx
jz .ok
dec eax
.ok:
; write back the uncompressed size
sub edi, OUTP
mov edx, OUTS
mov [edx], edi
mov [7*4 + esp], eax
popa
ret
%define PAGE_MASK (~0<<12)
%define PAGE_SIZE ( 1<<12)
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define p_filesz 4*4
%define p_memsz 5*4
%define a_val 4
%define MAP_FIXED 0x10
%define MAP_PRIVATE 0x02
%define MAP_ANONYMOUS 0x20
%define PROT_READ 1
%define PROT_WRITE 2
%define PROT_EXEC 4
%define __NR_mmap 90
%define __NR_munmap 91
; Decompress the rest of this loader, and jump to it
unfold:
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
cld
lodsd
push eax ; sz_uncompressed (junk, actually)
push esp ; &sz_uncompressed
mov eax, ebp ; &decompress
and eax, dword PAGE_MASK ; &my_elfhdr
mov edx, eax ; need my_elfhdr later
mov ah,0 ; round down to 64KB boundary
push eax ; &destination
; mmap a page to hold the decompressed program
xor ecx,ecx
push ecx
push ecx
mov ch, PAGE_SIZE >> 8
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
push byte PROT_READ | PROT_WRITE | PROT_EXEC
push ecx
push eax ; destination
push byte __NR_mmap
pop eax
mov ebx, esp
int 0x80
add esp, byte 6*4 ; discard args to mmap
lodsd
push eax ; sz_compressed
push esi ; &compressed_data
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop eax ; discard &compressed_data
pop eax ; discard sz_compressed
ret ; &destination
main:
pop ebp ; &decompress
call unfold
fold_begin:
; patchLoader will modify to be
; dword sz_uncompressed, sz_compressed
; byte compressed_data...
pop eax ; discard &sz_uncompressed
pop eax ; discard sz_uncompressed
; Move argc,argv,envp down so that we can insert more Elf_auxv entries.
; ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance
%define OVERHEAD 2048
%define MAX_ELF_HDR 512
mov esi, esp
sub esp, byte 6*8 ; AT_PHENT, AT_PHNUM, AT_PAGESZ, AT_ENTRY, AT_PHDR, AT_NULL
mov edi, esp
call do_auxv
sub esp, dword MAX_ELF_HDR + OVERHEAD
push esp ; argument: temp space
push edi ; argument: AT_next
push ebp ; argument: &decompress
push edx ; argument: my_elfhdr
add edx, [p_memsz + szElf32_Ehdr + edx]
push edx ; argument: uncbuf
EXTERN upx_main
call upx_main ; entry = upx_main(uncbuf, my_elfhdr, &decompress, AT_next, tmp_ehdr)
pop esi ; decompression buffer == (p_vaddr + p_memsz) of stub
pop ebx ; my_elfhdr
add esp, dword 3*4 + MAX_ELF_HDR + OVERHEAD ; remove 3 params, temp space
push eax ; save entry address
mov edi, [a_val + edi] ; AT_PHDR
find_hatch:
push edi
EXTERN make_hatch
call make_hatch ; find hatch = make_hatch(phdr)
pop ecx ; junk the parameter
add edi, byte szElf32_Phdr ; prepare to try next Elf32_Phdr
test eax,eax
jz find_hatch
xchg eax,edx ; edx= &hatch
; _dl_start and company (ld-linux.so.2) assumes that it has virgin stack,
; and does not initialize all its stack local variables to zero.
; Ulrich Drepper (drepper@cyngus.com) has refused to fix the bugs.
; See GNU wwwgnats libc/1165 .
%define N_STKCLR (0x100 + MAX_ELF_HDR + OVERHEAD)/4
lea edi, [esp - 4*N_STKCLR]
pusha ; values will be zeroed
mov ecx, N_STKCLR
xor eax,eax
rep stosd
mov ecx,esi ; my p_vaddr + p_memsz
mov bh,0 ; round down to 64KB boundary
sub ecx,ebx ; length to unmap
push byte __NR_munmap
pop eax
jmp edx ; unmap ourselves via escape hatch, then goto entry
do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL
; cld
L10: ; move argc+argv
lodsd
stosd
test eax,eax
jne L10
L20: ; move envp
lodsd
stosd
test eax,eax
jne L20
L30: ; move existing Elf32_auxv
lodsd
stosd
test eax,eax ; AT_NULL ?
lodsd
stosd
jne L30
sub edi, byte 8 ; point to AT_NULL
ret
; vi:ts=8:et:nowrap

17
src/stub/l_lx_elf86.lds Normal file
View File

@ -0,0 +1,17 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS
{
/* 0x00401000: l_lx_elf86.asm assumes 1 page up from 64KB boundary */
. = 0x00401000 + SIZEOF_HEADERS;
. = ALIGN(0x80);
.text : {
*(.text)
*(.data)
}
/* 0x08048000: customary Linux/x86 Elf .text start */
. = 0x08048000 + (0xfff & .);
.data : {
}
}

495
src/stub/l_lx_exec.c Normal file
View File

@ -0,0 +1,495 @@
/* l_lx_exec.c -- generic stub loader for Linux using execve()
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include "linux.hh"
/*************************************************************************
// configuration section
**************************************************************************/
// use malloc instead of the bss segement
#define USE_MALLOC
/*************************************************************************
// file util
**************************************************************************/
#undef xread
#undef xwrite
#if 1
//static int xread(int fd, void *buf, int count) __attribute__((__stdcall__));
static int xread(int fd, void *buf, int count)
{
// note: we can assert(count > 0);
do {
int n = read(fd, buf, count);
if (n == -EINTR)
continue;
if (n <= 0)
break;
buf += n; // gcc extension: add to void *
count -= n;
} while (count > 0);
return count;
}
#else
#define xread(fd,buf,count) ((count) - read(fd,buf,count))
#endif
#if 1
static __inline__ int xwrite(int fd, const void *buf, int count)
{
// note: we can assert(count > 0);
do {
int n = write(fd, buf, count);
if (n == -EINTR)
continue;
if (n <= 0)
break;
buf += n; // gcc extension: add to void *
count -= n;
} while (count > 0);
return count;
}
#else
#define xwrite(fd,buf,count) ((count) - write(fd,buf,count))
#endif
/*************************************************************************
// util
**************************************************************************/
static char *upx_itoa(char *buf, unsigned long v)
{
char *p = buf;
{
unsigned long k = v;
do {
p++;
k /= 10;
} while (k > 0);
}
buf = p;
*p = 0;
{
unsigned long k = v;
do {
*--p = '0' + k % 10;
k /= 10;
} while (k > 0);
}
return buf;
}
#if defined(__i386__)
# define SET2(p, c0, c1) \
* (unsigned short *) (p) = ((c1)<<8 | (c0))
# define SET4(p, c0, c1, c2, c3) \
* (uint32_t *) (p) = ((c3)<<24 | (c2)<<16 | (c1)<<8 | (c0))
# define SET3(p, c0, c1, c2) \
SET4(p, c0, c1, c2, 0)
#else
# define SET2(p, c0, c1) \
(p)[0] = c0, (p)[1] = c1
# define SET3(p, c0, c1, c2) \
(p)[0] = c0, (p)[1] = c1, (p)[2] = c2
# define SET4(p, c0, c1, c2, c3) \
(p)[0] = c0, (p)[1] = c1, (p)[2] = c2, (p)[3] = c3
#endif
/*************************************************************************
// UPX & NRV stuff
**************************************************************************/
// must be the same as in p_unix.cpp !
#if !defined(USE_MALLOC)
# define BLOCKSIZE (512*1024)
#endif
// patch constants for our loader (le32 format)
#define UPX1 0x31585055 // "UPX1"
#define UPX2 0x32585055 // "UPX2"
#define UPX3 0x33585055 // "UPX4"
#define UPX4 0x34585055 // "UPX4"
#define UPX5 0x35585055 // "UPX5"
#if defined(__i386__)
extern int
nrv2b_decompress_asm_fast ( const nrv_byte *src, nrv_uint src_len,
nrv_byte *dst, nrv_uint *dst_len );
#define nrv2b_decompress nrv2b_decompress_asm_fast
extern int
nrv2d_decompress_asm_fast ( const nrv_byte *src, nrv_uint src_len,
nrv_byte *dst, nrv_uint *dst_len );
#define nrv2d_decompress nrv2d_decompress_asm_fast
#endif /* __i386__ */
/*************************************************************************
// upx_main - called by our entry code
//
// This function is optimized for size.
**************************************************************************/
void upx_main(char *argv[], char *envp[]) __asm__("upx_main");
void upx_main(char *argv[], char *envp[])
{
// file descriptors
int fdi, fdo;
struct p_info header;
// for getpid()
pid_t pid;
// temporary file name (max 14 chars)
static char tmpname_buf[] = "/tmp/upxAAAAAAAAAAA";
char *tmpname = tmpname_buf;
char procself_buf[64];
char *procself;
// decompression buffer
#if defined(USE_MALLOC)
unsigned char *buf;
static int malloc_args[6] = {
0, UPX5, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0
};
#else
static unsigned char buf[BLOCKSIZE + OVERHEAD];
#endif
//
// ----- Step 0: set /proc/self using /proc/<pid> -----
//
//personality(PER_LINUX);
pid = getpid();
SET4(procself_buf + 0, '/', 'p', 'r', 'o');
SET2(procself_buf + 4, 'c', '/');
procself = upx_itoa(procself_buf + 6, pid);
*procself++ = '/';
//
// ----- Step 1: prepare input file -----
//
// Open the exe.
SET3(procself, 'e', 'x', 'e');
fdi = open(procself_buf, O_RDONLY, 0);
#if 1
// try /proc/<pid>/file for the sake of FreeBSD
if (fdi < 0)
{
SET4(procself, 'f', 'i', 'l', 'e');
fdi = open(procself_buf, O_RDONLY, 0);
}
#endif
#if 0
// Save some bytes of code - the lseek() below will fail anyway.
if (fdi < 0)
goto error1;
#endif
// Seek to start of compressed data. The offset is patched
// by the compressor.
if (lseek(fdi, UPX1, 0) < 0)
goto error1;
// Read header.
if (xread(fdi, (void *)&header, sizeof(header)) != 0)
goto error1;
// Paranoia. Make sure this is actually our expected executable
// by checking the random program id. (The id is both stored
// in the header and patched into this stub.)
if (header.p_progid != UPX2)
goto error1;
//
// ----- Step 2: prepare temporary output file -----
//
// Compute name of temporary output file in tmpname[].
// Protect against Denial-of-Service attacks.
{
char *p = tmpname_buf + sizeof(tmpname_buf) - 1;
uint32_t r;
// Compute the last 4 characters (20 bits) from getpid().
{
unsigned k = 4;
r = (uint32_t) pid;
do {
unsigned char d = r % 32;
if (d >= 26) d += '0' - 'Z' - 1;
*--p += d;
r /= 32;
} while (--k > 0);
}
// Provide 4 random bytes from our program id.
r ^= header.p_progid;
// Mix in 4 runtime random bytes.
// Don't consume precious bytes from /dev/urandom.
{
#if 1
struct timeval tv;
gettimeofday(&tv, 0);
r ^= (uint32_t) tv.tv_sec;
r ^= ((uint32_t) tv.tv_usec) << 12; // shift into high-bits
#else
// using adjtimex() may cause portability problems
static struct timex tx;
adjtimex(&tx);
r ^= (uint32_t) tx.time.tv_sec;
r ^= ((uint32_t) tx.time.tv_usec) << 12; // shift into high-bits
r ^= (uint32_t) tx.errcnt;
#endif
}
// Compute 7 more characters from the 32 random bits.
{
unsigned k = 7;
do {
unsigned char d = r % 32;
if (d >= 26) d += '0' - 'Z' - 1;
*--p += d;
r /= 32;
} while (--k > 0);
}
}
// Just in case, remove the file.
{
int err = unlink(tmpname);
if (err != -ENOENT && err != 0)
goto error1;
}
// Create the temporary output file.
fdo = open(tmpname, O_WRONLY | O_CREAT | O_EXCL, 0700);
#if 0
// Save some bytes of code - the ftruncate() below will fail anyway.
if (fdo < 0)
goto error;
#endif
// Set expected file size.
if (ftruncate(fdo, header.p_filesize) != 0)
goto error;
//
// ----- Step 3: setup memory -----
//
#if defined(USE_MALLOC)
buf = mmap(malloc_args);
if ((unsigned long) buf >= (unsigned long) -4095)
goto error;
#else
if (header.p_blocksize > BLOCKSIZE)
goto error;
#endif
//
// ----- Step 4: decompress blocks -----
//
for (;;)
{
int32_t size[2];
// size[0]: uncompressed block size
// size[1]: compressed block size
// Note: if size[0] == size[1] then the block was not
// compressible and is stored in its uncompressed form.
int i;
// Read and check block sizes.
if (xread(fdi, (void *)size, 8) != 0)
goto error;
if (size[0] == 0) // uncompressed size 0 -> EOF
{
if (size[1] != UPX_MAGIC_LE32) // size[1] must be h->magic
goto error;
if (header.p_filesize != 0) // all bytes must be written
goto error;
break;
}
if (size[1] <= 0)
goto error;
if (size[1] > size[0] || size[0] > (int32_t)header.p_blocksize)
goto error;
// Now we have:
// assert(size[1] <= size[0]);
// assert(size[0] > 0 && size[0] <= blocksize);
// assert(size[1] > 0 && size[1] <= blocksize);
// Read compressed block.
i = header.p_blocksize + OVERHEAD - size[1];
if (xread(fdi, buf+i, size[1]) != 0)
goto error;
// Decompress block.
if (size[1] < size[0])
{
// in-place decompression
nrv_uint out_len;
#if defined(NRV2B)
i = nrv2b_decompress(buf+i, size[1], buf, &out_len);
#elif defined(NRV2D)
i = nrv2d_decompress(buf+i, size[1], buf, &out_len);
#else
# error
#endif
if (i != 0 || out_len != (nrv_uint)size[0])
goto error;
// i == 0 now
}
// Write uncompressed block.
if (xwrite(fdo, buf+i, size[0]) != 0)
{
// error exit is here in the middle to keep the jumps short.
error:
(void) unlink(tmpname);
error1:
// Note: the kernel will close all open files and
// unmap any allocated memory.
for (;;)
(void) exit(127);
}
header.p_filesize -= size[0];
}
//
// ----- Step 5: release resources -----
//
#if defined(USE_MALLOC)
munmap(buf, malloc_args[1]);
#endif
if (close(fdo) != 0)
goto error;
if (close(fdi) != 0)
goto error;
//
// ----- Step 6: try to start program via /proc/self/fd/X -----
//
// Many thanks to Andi Kleen <ak@muc.de> and
// Jamie Lokier <nospam@cern.ch> for this nice idea.
// Open the temp file.
fdi = open(tmpname, O_RDONLY, 0);
if (fdi < 0)
goto error;
// Compute name of temp fdi.
SET3(procself, 'f', 'd', '/');
upx_itoa(procself + 3, fdi);
// Check for working /proc/self/fd/X by accessing the
// temp file again, now via temp fdi.
#define err fdo
err = access(procself_buf, R_OK | X_OK);
if (err == UPX3)
{
// Now it's safe to unlink the temp file (as it is still open).
unlink(tmpname);
// Set the file close-on-exec.
fcntl(fdi, F_SETFD, FD_CLOEXEC);
// Execute the original program via /proc/self/fd/X.
execve(procself_buf, argv, envp);
// If we get here we've lost.
}
#undef err
// The proc filesystem isn't working. No problem.
close(fdi);
//
// ----- Step 7: start program in /tmp -----
//
// Fork off a subprocess to clean up.
// We have to do this double-fork trick to keep a zombie from
// hanging around if the spawned original program doesn't check for
// subprocesses (as well as to prevent the real program from getting
// confused about this subprocess it shouldn't have).
// Thanks to Adam Ierymenko <api@one.net> for this solution.
if (fork() == 0)
{
if (fork() == 0)
{
// Sleep 3 seconds, then remove the temp file.
static const struct timespec ts = { UPX4, 0 };
nanosleep(&ts, 0);
unlink(tmpname);
}
exit(0);
}
// Wait for the first fork()'d process to die.
waitpid(-1, (int *)0, 0);
// Execute the original program.
execve(tmpname, argv, envp);
//
// ----- Step 8: error exit -----
//
// If we return from execve() there was an error. Give up.
goto error;
}
/*
vi:ts=4:et:nowrap
*/

148
src/stub/l_lx_exec86.asm Normal file
View File

@ -0,0 +1,148 @@
; l_lx_exec86.asm -- Linux program entry point & decompressor (execve)
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
BITS 32
SECTION .text
%define jmps jmp short
; defines for ident.ash and n2b_d32.ash
%ifdef SMALL
%define __IDENTSMA__
%define __N2BSMA10__
%define __N2BSMA20__
%define __N2BSMA30__
%define __N2BSMA40__
%define __N2BSMA50__
%define __N2BSMA60__
%define __N2DSMA10__
%define __N2DSMA20__
%define __N2DSMA30__
%define __N2DSMA40__
%define __N2DSMA50__
%define __N2DSMA60__
%endif
; /*************************************************************************
; // program entry point
; // see glibc/sysdeps/i386/elf/start.S
; **************************************************************************/
GLOBAL _start
EXTERN upx_main
_start:
xor ebp, ebp ; Clear the frame pointer
%if 0
; personality(PER_LINUX)
mov eax, 136 ; syscall_personality
xor ebx, ebx ; PER_LINUX
int 0x80
%endif
pop eax ; Pop the argument count
mov ecx, esp ; argv starts just at the current stack top
lea edx, [ecx+eax*4+4] ; envp = &argv[argc + 1]
push eax ; Restore the stack
and esp, byte -8 ; Align the stack
push edx ; Push third argument: envp
push ecx ; Push second argument: argv
;;; push eax ; Push first argument: argc
call upx_main ; Call the UPX main function
hlt ; Crash if somehow upx_main does return
%include "ident.ash"
; /*************************************************************************
; // C callable decompressor
; **************************************************************************/
%ifdef NRV2B
%define decompress nrv2b_decompress_asm_fast
%elifdef NRV2D
%define decompress nrv2d_decompress_asm_fast
%else
%error
%endif
GLOBAL decompress
%define INP dword [esp+24+4]
%define INS dword [esp+24+8]
%define OUTP dword [esp+24+12]
%define OUTS dword [esp+24+16]
decompress:
push ebp
push edi
push esi
push ebx
push ecx
push edx
cld
mov esi, INP
mov edi, OUTP
or ebp, byte -1
;;; align 8
%ifdef NRV2B
%include "n2b_d32.ash"
%elifdef NRV2D
%include "n2d_d32.ash"
%else
%error
%endif
; eax is 0 from decompressor code
;xor eax, eax ; return code
; check compressed size
mov edx, INP
add edx, INS
cmp esi, edx
jz .ok
dec eax
.ok:
; write back the uncompressed size
sub edi, OUTP
mov edx, OUTS
mov [edx], edi
pop edx
pop ecx
pop ebx
pop esi
pop edi
pop ebp
ret
; vi:ts=8:et:nowrap

449
src/stub/l_lx_sep.c Normal file
View File

@ -0,0 +1,449 @@
/* l_lxsep.c -- separate loader for Linux Elf executable
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Integration of virtual exec() with decompression is
Copyright (C) 2000 John F. Reiser. All rights reserved.
<jreiser@BitWagon.com>
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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include <sys/types.h>
#include <fcntl.h>
#include <linux/errno.h>
#include <linux/mman.h>
#include <linux/unistd.h>
#include "linux.hh"
/*************************************************************************
// configuration section
**************************************************************************/
// must be the same as in p_linux.cpp !
#define OVERHEAD 2048
#define PAGEMASK (~0u<<12) // discards the offset, keeps the page
#define PAGESIZE ( 1u<<12)
#define MAX_ELF 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this
#undef int32_t
#undef uint32_t
#define int32_t int
#define uint32_t unsigned int
#define SEEK_SET 0
#define SEEK_CUR 1
/*************************************************************************
// file util
**************************************************************************/
#undef xread
#undef xwrite
#if 1
//static int xread(int fd, void *buf, int count) __attribute__((__stdcall__));
static int xread(int fd, void *buf, int count)
{
// note: we can assert(count > 0);
do {
int n = read(fd, buf, count);
if (n == -EINTR)
continue;
if (n <= 0)
break;
buf += n; // gcc extension: add to void *
count -= n;
} while (count > 0);
return count;
}
#else
#define xread(fd,buf,count) ((count) - read(fd,buf,count))
#endif
#if 1
static __inline__ int xwrite(int fd, const void *buf, int count)
{
// note: we can assert(count > 0);
do {
int n = write(fd, buf, count);
if (n == -EINTR)
continue;
if (n <= 0)
break;
buf += n; // gcc extension: add to void *
count -= n;
} while (count > 0);
return count;
}
#else
#define xwrite(fd,buf,count) ((count) - write(fd,buf,count))
#endif
/*************************************************************************
// util
**************************************************************************/
#if 1 //{ save space
#define ERR_LAB error: exit(127);
#define err_exit(a) goto error
#else //}{ save debugging time
#define ERR_LAB
static void
err_exit(int a)
{
(void)a; // debugging convenience
exit(127);
}
#endif //}
static void *
do_brk(void *addr)
{
return brk(addr);
}
static char *
do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
(void)len; (void)prot; (void)flags; (void)fd; (void)offset;
return mmap((int *)&addr);
}
/*************************************************************************
// UPX & NRV stuff
**************************************************************************/
// patch & magic constants for our loader (le32 format)
#define UPX_MAGIC_LE32 0x21585055 // "UPX!"
typedef int f_expand(
const nrv_byte *, nrv_uint,
nrv_byte *, nrv_uint * );
struct Extent {
size_t size; // must be first to match size[0] uncompressed size
char *buf;
};
static void
unpackExtent(
struct Extent *const xo,
int fdi,
f_expand *const f_decompress
)
{
while (xo->size) {
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
int j = 0;
// Read and check block sizes.
if (xread(fdi, (void *)&h, sizeof(h)) != 0)
err_exit(1);
if (h.sz_unc == 0) // uncompressed size 0 -> EOF
{
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
err_exit(2);
if (xo->size != 0) // all bytes must be written
err_exit(3);
break;
}
if (h.sz_cpr <= 0) {
err_exit(4);
ERR_LAB
}
if (h.sz_cpr > h.sz_unc || h.sz_unc > (int32_t)xo->size) {
err_exit(5);
}
// Now we have:
// assert(h.sz_cpr <= h.sz_unc);
// assert(h.sz_unc > 0 && h.sz_unc <= blocksize);
// assert(h.sz_cpr > 0 && h.sz_cpr <= blocksize);
j = h.sz_unc - h.sz_cpr;
if (0 < j) { // Compressed block.
j += OVERHEAD;
}
if (0!=xread(fdi, xo->buf+j, h.sz_cpr)) {
err_exit(6);
}
// Decompress block.
if (h.sz_cpr < h.sz_unc) {
// in-place decompression
nrv_uint out_len;
j = (*f_decompress)(xo->buf+j, h.sz_cpr, xo->buf, &out_len);
if (j != 0 || out_len != (nrv_uint)h.sz_unc)
err_exit(7);
// j == 0 now
}
xo->buf += h.sz_unc;
xo->size -= h.sz_unc;
}
}
#include <elf.h>
// Create (or find) an escape hatch to use when munmapping ourselves the stub.
// Called by do_xmap to create it, and by assembler code to find it.
void *
make_hatch(Elf32_Phdr const *const phdr)
{
if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
unsigned *hatch;
// The format of the 'if' is
// if ( ( (hatch = loc1), test_loc1 )
// || ( (hatch = loc2), test_loc2 ) ) {
// action
// }
// which uses the comma to save bytes when test_locj involves locj
// and the action is the same when either test succeeds.
// Try page fragmentation just beyond .text .
if ( ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr)),
( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss
&& 4<=(~PAGEMASK & -(int)hatch) ) ) // space left on page
// Try Elf32_Ehdr.e_ident[12..15] . warning: 'const' cast away
|| ( (hatch = (void *)(&((Elf32_Ehdr *)phdr->p_vaddr)->e_ident[12])),
(phdr->p_offset==0) ) ) {
// Omitting 'const' saves repeated literal in gcc.
unsigned /*const*/ escape = 0xc36180cd; // "int $0x80; popa; ret"
// Don't store into read-only page if value is already there.
if (*hatch != escape) {
*hatch = escape;
}
return hatch;
}
}
return 0;
}
static void
bzero(char *p, size_t len)
{
if (len) do {
*p++= 0;
} while (--len);
}
static Elf32_Addr // entry address
do_xmap(int fdi, Elf32_Ehdr const *const ehdr, f_expand *const f_decompress,
Elf32_auxv_t *const a)
{
struct Extent x;
Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff +
(char const *)ehdr);
unsigned long base = (ET_DYN==ehdr->e_type) ? 0x40000000 : 0;
int j;
for (j=0; j < ehdr->e_phnum; ++phdr, ++j)
if (PT_PHDR==phdr->p_type) {
a->a_un.a_val = phdr->p_vaddr;
}
else if (PT_LOAD==phdr->p_type) {
size_t mlen = x.size = phdr->p_filesz;
char *addr = x.buf = (char *)phdr->p_vaddr;
char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr;
size_t frag = (int)addr &~ PAGEMASK;
mlen += frag;
addr -= frag;
if (ET_DYN==ehdr->e_type) {
addr += base;
haddr += base;
}
else { // There is only one brk, the one for the ET_EXEC
do_brk(haddr+OVERHEAD); // Also takes care of whole pages of .bss
}
// Decompressor can overrun the destination by 3 bytes.
if (addr != do_mmap(addr, mlen + (f_decompress ? 3 : 0), PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | (f_decompress ? MAP_ANONYMOUS : 0),
fdi, phdr->p_offset - frag) ) {
err_exit(8);
}
if (0==base) {
base = (unsigned long)addr;
}
if (f_decompress) {
unpackExtent(&x, fdi, f_decompress);
}
bzero(addr, frag); // fragment at lo end
frag = (-mlen) &~ PAGEMASK; // distance to next page boundary
bzero(mlen+addr, frag); // fragment at hi end
if (f_decompress) {
make_hatch(phdr);
}
if (phdr->p_memsz != phdr->p_filesz) { // .bss
if (ET_DYN==ehdr->e_type) { // PT_INTERP whole pages of .bss?
addr += frag + mlen;
mlen = haddr - addr;
if (0 < (int)mlen) { // need more pages, too
if (addr != do_mmap(addr, mlen, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 ) ) {
err_exit(9);
ERR_LAB
}
}
}
}
else { // no .bss
int prot = 0;
if (phdr->p_flags & PF_X) { prot |= PROT_EXEC; }
if (phdr->p_flags & PF_W) { prot |= PROT_WRITE; }
if (phdr->p_flags & PF_R) { prot |= PROT_READ; }
if (0!=mprotect(addr, mlen, prot)) {
err_exit(10);
}
if (f_decompress) { // cleanup if decompressor overrun crosses page boundary
mlen += 3;
addr += mlen;
mlen &= ~PAGEMASK;
if (mlen<=3) { // page fragment was overrun buffer only
munmap(addr - mlen, mlen);
}
}
}
if (ET_DYN!=ehdr->e_type) {
do_brk(haddr);
}
}
if (close(fdi) != 0)
err_exit(11);
if (ET_DYN==ehdr->e_type) {
return ehdr->e_entry + base;
}
else {
return ehdr->e_entry;
}
}
/*************************************************************************
// upx_main - called by our entry code
//
// This function is optimized for size.
**************************************************************************/
void *upx_main(
char const *argv[],
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr
) __asm__("upx_main");
void *upx_main(
char const *argv[],
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR+OVERHEAD]
)
{
Elf32_Phdr const *phdr = (Elf32_Phdr const *)(1+ehdr);
int fdi; // file descriptor
size_t sz_elfhdrs; // sizeof(Ehdr and Phdrs), uncompressed
size_t sz_pckhdrs; // sizeof(Ehdr and Phdrs), compressed
Elf32_Addr entry;
struct Extent xo;
int j;
struct p_info header;
fdi = open(argv[1], O_RDONLY, 0);
#if 0
// Save some bytes of code - the lseek() below will fail anyway.
if (fdi < 0)
err_exit(12);
#endif
#define SCRIPT_MAX 32
// Seek to start of compressed data.
if (lseek(fdi, SCRIPT_MAX+sizeof(struct l_info), SEEK_SET) < 0)
err_exit(13);
// Read header.
if (xread(fdi, (void *)&header, sizeof(header)) != 0) {
err_exit(14);
}
//
// ----- Step 4: decompress blocks -----
//
// Get Elf32_Ehdr. First set xo.size = size[0] = uncompressed size
if (0!=xread(fdi, (void *)&xo, sizeof(xo))) {
err_exit(15);
}
if (lseek(fdi, -sizeof(xo), SEEK_CUR) < 0) {
err_exit(16);
ERR_LAB
}
sz_elfhdrs = xo.size;
sz_pckhdrs = (size_t)xo.buf;
xo.buf = (char *)ehdr;
unpackExtent(&xo, fdi, f_decompress);
// Prepare to decompress the Elf headers again, into the first PT_LOAD.
if (lseek(fdi, -(sizeof(xo) + sz_pckhdrs), SEEK_CUR) < 0) {
err_exit(17);
}
av[0].a_type = AT_PHDR; av[0].a_un.a_val = 0; // updated by do_xmap
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;
av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGESIZE;
av[4].a_type = AT_ENTRY; av[4].a_un.a_val = ehdr->e_entry;
av[5].a_type = AT_NULL;
entry = do_xmap(fdi, ehdr, f_decompress, av);
// Map PT_INTERP program interpreter
for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_INTERP==phdr->p_type) {
char const *const iname = (char const *)phdr->p_vaddr;
if (0 > (fdi = open(iname, O_RDONLY, 0))) {
err_exit(18);
}
if (0!=xread(fdi, (void *)ehdr, MAX_ELF)) {
err_exit(19);
}
entry = do_xmap(fdi, ehdr, 0, 0);
break;
}
return (void *)entry;
}
/*
vi:ts=4:et:nowrap
*/

232
src/stub/l_lx_sep86.asm Normal file
View File

@ -0,0 +1,232 @@
; l_lxsep86.asm -- Linux program entry point & decompressor (separate script)
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; Integration of virtual exec() with decompression is
; Copyright (C) 2000 John F. Reiser. 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; John F. Reiser
; jreiser@BitWagon.com
BITS 32
SECTION .text
%define jmps jmp short
; defines for ident.ash and n2b_d32.ash
%ifdef SMALL
%define __IDENTSMA__
%define __N2BSMA10__
%define __N2BSMA20__
%define __N2BSMA30__
%define __N2BSMA40__
%define __N2BSMA50__
%define __N2BSMA60__
%define __N2DSMA10__
%define __N2DSMA20__
%define __N2DSMA30__
%define __N2DSMA40__
%define __N2DSMA50__
%define __N2DSMA60__
%endif
%include "ident.ash"
; /*************************************************************************
; // program entry point
; // see glibc/sysdeps/i386/elf/start.S
; **************************************************************************/
GLOBAL _start
_start:
;;;; int3
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
;; Build the stubs and upx. Compress a testcase, such as a copy of /bin/date.
;; Invoke gdb on the separate stub (such as "gdb upxb"), and give the command
;; "run date". Define a single-step macro such as
;; define g
;; stepi
;; x/i $pc
;; end
;; and a step-over macro such as
;; define h
;; x/2i $pc
;; tbreak *$_
;; continue
;; x/i $pc
;; end
;; Step through the code; remember that <Enter> repeats the previous command.
;;
call main ; push address of decompress subroutine
; /*************************************************************************
; // C callable decompressor
; **************************************************************************/
%define INP dword [esp+8*4+4]
%define INS dword [esp+8*4+8]
%define OUTP dword [esp+8*4+12]
%define OUTS dword [esp+8*4+16]
decompress:
pusha
; cld
mov esi, INP
mov edi, OUTP
or ebp, byte -1
;;; align 8
%ifdef NRV2B
%include "n2b_d32.ash"
%elifdef NRV2D
%include "n2d_d32.ash"
%else
%error
%endif
; eax is 0 from decompressor code
;xor eax, eax ; return code
; check compressed size
mov edx, INP
add edx, INS
cmp esi, edx
jz .ok
dec eax
.ok:
; write back the uncompressed size
sub edi, OUTP
mov edx, OUTS
mov [edx], edi
mov [7*4 + esp], eax
popa
ret
%define PAGE_MASK (~0<<12)
%define PAGE_SIZE ( 1<<12)
%define szElf32_Phdr 8*4
%define a_val 4
%define __NR_munmap 91
main:
pop ebp ; &decompress
cld
; Move argc,argv,envp down so that we can insert more Elf_auxv entries.
; ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance
%define OVERHEAD 2048
%define MAX_ELF_HDR 512
mov esi, esp
sub esp, byte 6*8 ; AT_PHENT, AT_PHNUM, AT_PAGESZ, AT_ENTRY, AT_PHDR, AT_NULL
mov edi, esp
call do_auxv ; edi= &AT_next
lea ecx, [4+esp] ; argv
sub esp, dword MAX_ELF_HDR + OVERHEAD
push esp ; argument: temp space
push edi ; argument: AT_next
push ebp ; argument: &decompress
push ecx ; argument: argv
EXTERN upx_main
call upx_main ; entry = upx_main(argv, &decompress, AT_next, tmp_ehdr)
add esp, dword 4*4 + MAX_ELF_HDR + OVERHEAD ; remove temp space, args
pop ecx ; argc
pop edx ; ++argv discard argv[0] == pathname of stub
dec ecx ; --argc
push ecx
push eax ; save entry address
mov edi, [a_val + edi] ; AT_PHDR
find_hatch:
push edi
EXTERN make_hatch
call make_hatch ; find hatch = make_hatch(phdr)
pop ecx ; junk the parameter
add edi, byte szElf32_Phdr ; prepare to try next Elf32_Phdr
test eax,eax
jz find_hatch
xchg eax,edx ; edx= &hatch
; _dl_start and company (ld-linux.so.2) assumes that it has virgin stack,
; and does not initialize all its stack local variables to zero.
; Ulrich Drepper (drepper@cyngus.com) has refused to fix the bugs.
; See GNU wwwgnats libc/1165 .
%define N_STKCLR (0x100 + MAX_ELF_HDR + OVERHEAD)/4
lea edi, [esp - 4*N_STKCLR]
pusha ; values will be zeroed
mov ecx, N_STKCLR
xor eax,eax
rep stosd
mov ecx, dword -PAGE_SIZE
mov ebx, ebp
and ebx, ecx ; round down to page boundary
neg ecx ; PAGE_SIZE (this stub fits in it)
push byte __NR_munmap
pop eax
jmp edx ; unmap ourselves, then goto entry
do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL
; cld
L10: ; move argc+argv
lodsd
stosd
test eax,eax
jne L10
L20: ; move envp
lodsd
stosd
test eax,eax
jne L20
L30: ; move existing Elf32_auxv
lodsd
stosd
test eax,eax ; AT_NULL ?
lodsd
stosd
jne L30
sub edi, byte 8 ; point to AT_NULL
ret
; vi:ts=8:et:nowrap

15
src/stub/l_lx_sep86.lds Normal file
View File

@ -0,0 +1,15 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS
{
. = 0x00400000 + SIZEOF_HEADERS;
.text : {
*(.text)
*(.data)
}
/* 0x08048000: customary Linux/x86 Elf .text start */
. = 0x08048000 + (0xfff & .);
.data : {
}
}

357
src/stub/l_lx_sh.c Normal file
View File

@ -0,0 +1,357 @@
/* l_lx_sh.c -- stub loader for Linux x86 shell script executable
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Integration of virtual exec() with decompression is
Copyright (C) 2000 John F. Reiser. 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
John F. Reiser
jreiser@BitWagon.com
*/
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include "linux.hh"
/*************************************************************************
// configuration section
**************************************************************************/
// In order to make it much easier to move this code at runtime and execute
// it at an address different from it load address: there must be no
// static data, and no string constants.
#define PAGEMASK (~0u<<12) // discards the offset, keeps the page
#define PAGESIZE ( 1u<<12)
#define MAX_ELF_HDR 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this
/*************************************************************************
// "file" util
**************************************************************************/
struct Extent {
size_t size; // must be first to match size[0] uncompressed size
char *buf;
};
static void
xread(struct Extent *x, char *buf, size_t count)
{
char *p=x->buf, *q=buf;
size_t j;
if (x->size < count) {
exit(127);
}
for (j = count; 0!=j--; ++p, ++q) {
*q = *p;
}
x->buf += count;
x->size -= count;
}
/*************************************************************************
// util
**************************************************************************/
#if 0 //{ save space
#define ERR_LAB error: exit(127);
#define err_exit(a) goto error
#else //}{ save debugging time
#define ERR_LAB
static void
err_exit(int a)
{
(void)a; // debugging convenience
exit(127);
}
#endif //}
static void *
do_brk(void *addr)
{
return brk(addr);
}
static char *
do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
(void)len; (void)prot; (void)flags; (void)fd; (void)offset;
return mmap((int *)&addr);
}
/*************************************************************************
// UPX & NRV stuff
**************************************************************************/
typedef int f_expand(
const nrv_byte *, nrv_uint,
nrv_byte *, nrv_uint * );
static void
unpackExtent(
struct Extent *const xi, // input
struct Extent *const xo, // output
f_expand *const f_decompress
)
{
while (xo->size) {
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
// Read and check block sizes.
xread(xi, (char *)&h, sizeof(h));
if (h.sz_unc == 0) { // uncompressed size 0 -> EOF
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
err_exit(2);
if (xi->size != 0) // all bytes must be written
err_exit(3);
break;
}
if (h.sz_cpr <= 0) {
err_exit(4);
ERR_LAB
}
if (h.sz_cpr > h.sz_unc
|| h.sz_unc > (int32_t)xo->size ) {
err_exit(5);
}
// Now we have:
// assert(h.sz_cpr <= h.sz_unc);
// assert(h.sz_unc > 0 && h.sz_unc <= blocksize);
// assert(h.sz_cpr > 0 && h.sz_cpr <= blocksize);
if (h.sz_cpr < h.sz_unc) { // Decompress block
nrv_uint out_len;
int const j = (*f_decompress)(xi->buf, h.sz_cpr, xo->buf, &out_len);
if (j != 0 || out_len != (nrv_uint)h.sz_unc)
err_exit(7);
xi->buf += h.sz_cpr;
xi->size -= h.sz_cpr;
}
else { // copy literal block
xread(xi, xo->buf, h.sz_cpr);
}
xo->buf += h.sz_unc;
xo->size -= h.sz_unc;
}
}
static void
bzero(char *p, size_t len)
{
if (len) do {
*p++= 0;
} while (--len);
}
// This do_xmap() has no Extent *xi input because it doesn't decompress anything;
// it only maps the shell and its PT_INTERP. So, it was specialized by hand
// to reduce compiled instruction size. gdb 2.91.66 does not notice that
// there is only one call to this static function (from getexec(), which
// would specify 0 for xi), so gdb does not propagate the constant parameter.
// Notice there is no make_hatch(), either.
static Elf32_Addr // entry address
do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, Elf32_auxv_t *const a)
{
Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff +
(char const *)ehdr);
unsigned long base = (ET_DYN==ehdr->e_type) ? 0x40000000 : 0;
int j;
for (j=0; j < ehdr->e_phnum; ++phdr, ++j)
if (PT_PHDR==phdr->p_type) {
a->a_un.a_val = phdr->p_vaddr;
}
else if (PT_LOAD==phdr->p_type) {
struct Extent xo;
size_t mlen = xo.size = phdr->p_filesz;
char *addr = xo.buf = (char *)phdr->p_vaddr;
char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr;
size_t frag = (int)addr &~ PAGEMASK;
mlen += frag;
addr -= frag;
if (ET_DYN==ehdr->e_type) {
addr += base;
haddr += base;
}
else { // There is only one brk, the one for the ET_EXEC
do_brk(haddr+OVERHEAD); // Also takes care of whole pages of .bss
}
// Decompressor can overrun the destination by 3 bytes.
if (addr != do_mmap(addr, mlen, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE,
fdi, phdr->p_offset - frag) ) {
err_exit(8);
}
if (0==base) {
base = (unsigned long)addr;
}
bzero(addr, frag); // fragment at lo end
frag = (-mlen) &~ PAGEMASK; // distance to next page boundary
bzero(mlen+addr, frag); // fragment at hi end
if (phdr->p_memsz != phdr->p_filesz) { // .bss
if (ET_DYN==ehdr->e_type) { // PT_INTERP whole pages of .bss?
addr += frag + mlen;
mlen = haddr - addr;
if (0 < (int)mlen) { // need more pages, too
if (addr != do_mmap(addr, mlen, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 ) ) {
err_exit(9);
ERR_LAB
}
}
}
}
else { // no .bss
int prot = 0;
if (phdr->p_flags & PF_X) { prot |= PROT_EXEC; }
if (phdr->p_flags & PF_W) { prot |= PROT_WRITE; }
if (phdr->p_flags & PF_R) { prot |= PROT_READ; }
if (0!=mprotect(addr, mlen, prot)) {
err_exit(10);
}
}
if (ET_DYN!=ehdr->e_type) {
do_brk(haddr);
}
}
if (0!=close(fdi)) {
err_exit(11);
}
if (ET_DYN==ehdr->e_type) {
return ehdr->e_entry + base;
}
else {
return ehdr->e_entry;
}
}
Elf32_Addr // entry address
getexec(char const *const fname, Elf32_Ehdr *const ehdr, Elf32_auxv_t *const av)
{
int const fdi = open(fname, O_RDONLY, 0);
if (0 > fdi) {
err_exit(18);
}
if (MAX_ELF_HDR!=read(fdi, (void *)ehdr, MAX_ELF_HDR)) {
err_exit(19);
}
return do_xmap(fdi, ehdr, av);
}
/*************************************************************************
// upx_main - called by our entry code
//
// This function is optimized for size.
**************************************************************************/
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr,
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr
) __asm__("upx_main");
void *upx_main(
char *const uncbuf, // place to put decompressed shell script
Elf32_Ehdr const *const my_ehdr, // to get compressed size and data
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR]
)
{
Elf32_Addr entry;
size_t const lsize = sizeof(struct p_info) +
*(unsigned short const *)(0x7c + (char const *)my_ehdr);
struct Extent xi = { // describe compressed shell script
((Elf32_Phdr const *)(1 + my_ehdr))->p_filesz - lsize,
(lsize + (char *)my_ehdr) // warning: 'const' cast away
};
struct Extent xo = { ((struct p_info *)xi.buf)[-1].p_filesize, uncbuf };
// Allocate space for decompressed shell script.
// "1+": guarantee '\0' terminator at end of decompressed script
if (xo.buf != do_mmap(xo.buf, 1+3+xo.size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0)) {
err_exit(20);
}
// Uncompress shell script
xo.buf += 3; // leave room for "-c" argument
unpackExtent(&xi, &xo, f_decompress);
{ // Map shell program
// 'fn' and 'efn' must not suffer constant-propagation by gcc
// UPX2 = 3 + offset to name_of_shell
// UPX3 = strlen(name_of_shell)
// patch & magic constants for our loader (le32 format)
#define UPX2 0x32585055 // "UPX2"
#define UPX3 0x33585055 // "UPX3"
char * /*const*/ volatile fn = UPX2 + uncbuf; // past "-c" and "#!"
char * /*const*/ volatile efn = UPX3 + fn; // &terminator
char const c = *efn; *efn = 0; // terminator
entry = getexec(fn, ehdr, av);
*efn = c; // replace terminator character
av[0].a_type = AT_PHDR; // av[0].a_un.a_val is set by do_xmap
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;
av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGESIZE;
av[4].a_type = AT_ENTRY; av[4].a_un.a_val = entry;
av[5].a_type = AT_NULL;
}
{ // Map PT_INTERP program interpreter
Elf32_Phdr const *phdr = (Elf32_Phdr *)(1+ehdr);
int j;
for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_INTERP==phdr->p_type) {
entry = getexec((char const *)phdr->p_vaddr, ehdr, 0);
break;
}
}
return (void *)entry;
}
/*
vi:ts=4:et:nowrap
*/

Some files were not shown because too many files have changed in this diff Show More