mirror of
https://github.com/upx/upx.git
synced 2024-11-23 04:39:59 +00:00
Initial commit (from git)
This commit is contained in:
commit
1a9128a473
51
BUGS
Normal file
51
BUGS
Normal 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
340
COPYING
Normal 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
138
LICENSE
Normal 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
89
LOADER.TXT
Normal 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
21
Makefile
Normal 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
197
NEWS
Normal 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
92
PROJECTS
Normal 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
143
README
Normal 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
153
README.SRC
Normal 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
55
THANKS
Normal 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
186
TODO
Normal 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
63
doc/Makefile
Normal 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
612
doc/upx.pod
Normal 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
476
src/Makefile
Normal 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
261
src/bele.h
Normal 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
95
src/c_file.cpp
Normal 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
165
src/c_init.cpp
Normal 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
81
src/c_none.cpp
Normal 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
286
src/c_screen.cpp
Normal 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
269
src/compress.cpp
Normal 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
613
src/conf.h
Normal 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
240
src/config_h/linux.h
Normal 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
186
src/console.h
Normal 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
138
src/except.cpp
Normal 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
226
src/except.h
Normal 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
105
src/fcto_ml.ch
Normal 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
191
src/fcto_ml2.ch
Normal 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
379
src/file.cpp
Normal 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
174
src/file.h
Normal 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
206
src/filter.cpp
Normal 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
129
src/filter.h
Normal 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
453
src/filteri.cpp
Normal 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
278
src/help.cpp
Normal 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
349
src/lefile.cpp
Normal 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
223
src/lefile.h
Normal 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
204
src/linker.cpp
Normal 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
65
src/linker.h
Normal 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
1134
src/main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
115
src/mem.cpp
Normal file
115
src/mem.cpp
Normal 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
82
src/mem.h
Normal 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
10
src/merge.sh
Normal 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
232
src/msg.cpp
Normal 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
696
src/mygetopt.cpp
Normal 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
102
src/mygetopt.h
Normal 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
268
src/p_com.cpp
Normal 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
69
src/p_com.h
Normal 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
433
src/p_djgpp2.cpp
Normal 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
107
src/p_djgpp2.h
Normal 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
83
src/p_elf.h
Normal 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
658
src/p_exe.cpp
Normal 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
109
src/p_exe.h
Normal 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
504
src/p_lx_elf.cpp
Normal 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
84
src/p_lx_elf.h
Normal 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
85
src/p_lx_sep.cpp
Normal 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
55
src/p_lx_sep.h
Normal 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
223
src/p_lx_sh.cpp
Normal 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
73
src/p_lx_sh.h
Normal 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
132
src/p_sys.cpp
Normal 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
62
src/p_sys.h
Normal 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
333
src/p_tmt.cpp
Normal 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
76
src/p_tmt.h
Normal 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
544
src/p_tos.cpp
Normal 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
85
src/p_tos.h
Normal 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
460
src/p_unix.cpp
Normal 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
217
src/p_unix.h
Normal 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
154
src/p_vmlinux.cpp
Normal 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
72
src/p_vxd.h
Normal 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
2206
src/p_w32pe.cpp
Normal file
File diff suppressed because it is too large
Load Diff
229
src/p_w32pe.h
Normal file
229
src/p_w32pe.h
Normal 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
827
src/p_wcle.cpp
Normal 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
92
src/p_wcle.h
Normal 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
1193
src/packer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
244
src/packer.h
Normal file
244
src/packer.h
Normal 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
256
src/packhead.cpp
Normal 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
258
src/packmast.cpp
Normal 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
68
src/packmast.h
Normal 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
546
src/s_djgpp2.cpp
Normal 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
100
src/s_object.cpp
Normal 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
601
src/s_vcsa.cpp
Normal 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
489
src/s_win32.cpp
Normal 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, ®ion);
|
||||
}
|
||||
|
||||
|
||||
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, ®ion);
|
||||
}
|
||||
|
||||
|
||||
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, ®ion);
|
||||
#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, ®ion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
111
src/screen.h
Normal 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
49
src/stdcxx.cpp
Normal 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
83
src/stdcxx.h
Normal 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
322
src/stub/Makefile
Normal 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
60
src/stub/header.ash
Normal 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
37
src/stub/ident.ash
Normal 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
39
src/stub/ident_n.ash
Normal 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
35
src/stub/ident_s.ash
Normal 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
95
src/stub/l_com.asm
Normal 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
93
src/stub/l_djgpp2.asm
Normal 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
177
src/stub/l_exe.asm
Normal 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
385
src/stub/l_lx_elf.c
Normal 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
281
src/stub/l_lx_elf86.asm
Normal 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
17
src/stub/l_lx_elf86.lds
Normal 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
495
src/stub/l_lx_exec.c
Normal 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
148
src/stub/l_lx_exec86.asm
Normal 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
449
src/stub/l_lx_sep.c
Normal 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
232
src/stub/l_lx_sep86.asm
Normal 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
15
src/stub/l_lx_sep86.lds
Normal 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
357
src/stub/l_lx_sh.c
Normal 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
Loading…
Reference in New Issue
Block a user