Initial commit (from git)
This commit is contained in:
+476
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+115
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+229
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+244
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 : {
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 : {
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
; l_lx_sh86.asm -- Linux program entry point & decompressor (shell 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, 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
|
||||
add eax, [p_memsz + szElf32_Ehdr + eax]
|
||||
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 ecx ; discard &compressed_data
|
||||
pop ecx ; discard sz_compressed
|
||||
pop ecx ; &destination
|
||||
jmp ecx ; goto fold_begin at p_vaddr + p_memsz
|
||||
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 ecx, PAGE_SIZE ; uncompressed stub fits in this
|
||||
push ecx ; argument: uncbuf
|
||||
EXTERN upx_main
|
||||
call upx_main ; entry = upx_main(uncbuf, my_elfhdr, &decompress, AT_next, tmp_ehdr)
|
||||
pop esi ; decompression buffer
|
||||
pop ebx ; my_elfhdr
|
||||
add esp, dword 3*4 + MAX_ELF_HDR + OVERHEAD ; remove 3 params, temp space
|
||||
|
||||
pop ecx ; argc
|
||||
pop edx ; $0 filename, to become argv[0]
|
||||
push edx ; restore $0 filename
|
||||
|
||||
add esi, byte 3
|
||||
inc ecx
|
||||
push esi ; &uncompressed shell script
|
||||
sub esi, byte 3
|
||||
|
||||
mov [esi], word 0x632d ; "-c"
|
||||
inc ecx
|
||||
push esi ; "-c"
|
||||
|
||||
inc ecx
|
||||
push edx ; argv[0] is duplicate of $0
|
||||
|
||||
push ecx ; new argc
|
||||
push eax ; save entry address
|
||||
|
||||
; _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
|
||||
|
||||
; Because the decompressed shell script occupies low memory anyway,
|
||||
; there isn't much payback to unmapping the compressed script and
|
||||
; ourselves the stub. We would need a place to put the escape hatch
|
||||
; "int $0x80; popa; ret", and some kernels do not allow execution
|
||||
; on the stack. So, we would have to dirty a page of the shell
|
||||
; or of /lib/ld-linux.so. It's simpler just to omit the unapping.
|
||||
popa
|
||||
ret
|
||||
|
||||
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
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
/* 0x00800000: avoid 0x00400000 for shell itself being compressed */
|
||||
. = 0x00800000 + SIZEOF_HEADERS;
|
||||
. = ALIGN(0x80);
|
||||
.text : {
|
||||
*(.text)
|
||||
*(.data)
|
||||
}
|
||||
/* 0x08048000: customary Linux/x86 Elf .text start */
|
||||
. = 0x08048000 + (0xfff & .);
|
||||
.data : {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
; l_sys.asm -- loader & decompressor for the dos/sys 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 SYS 1
|
||||
%define COM 0
|
||||
%define CJT16 1
|
||||
%define jmps jmp short
|
||||
%include "macros.ash"
|
||||
|
||||
BITS 16
|
||||
ORG 0
|
||||
SECTION .text
|
||||
|
||||
; =============
|
||||
; ============= ENTRY POINT
|
||||
; =============
|
||||
|
||||
; __SYSMAIN1__
|
||||
start:
|
||||
dd -1
|
||||
dw 0
|
||||
dw strategy ; .sys header
|
||||
dw 0 ; opendos wants this field untouched
|
||||
strategy:
|
||||
%ifdef __SYSI2861__
|
||||
pusha
|
||||
%else; __SYSI0861__
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push si
|
||||
push di
|
||||
push bp
|
||||
%endif; __SYSMAIN2__
|
||||
mov si, 'SI'
|
||||
mov di, 'DI'
|
||||
|
||||
mov cx, si ; at the end of the copy si will be 0
|
||||
|
||||
push es
|
||||
push ds
|
||||
pop es
|
||||
|
||||
std
|
||||
rep
|
||||
movsb
|
||||
cld
|
||||
|
||||
mov bx, 0x8000
|
||||
|
||||
xchg si, di
|
||||
sub si, byte start - cutpoint
|
||||
; __SYSSUBSI__
|
||||
sbb bp, bp
|
||||
%ifdef __SYSCALLT__
|
||||
push di
|
||||
%endif; __SYSMAIN3__
|
||||
jmp .1+'JM' ; jump to the decompressor
|
||||
.1:
|
||||
%include "header.ash"
|
||||
|
||||
cutpoint:
|
||||
; __SYSCUTPO__
|
||||
|
||||
; =============
|
||||
; ============= DECOMPRESSION
|
||||
; =============
|
||||
|
||||
%include "n2b_d16.ash"
|
||||
|
||||
; =============
|
||||
; ============= CALLTRICK
|
||||
; =============
|
||||
|
||||
|
||||
; =============
|
||||
|
||||
; __SYSMAIN5__
|
||||
pop es
|
||||
%ifdef __SYSI2862__
|
||||
popa
|
||||
%else; __SYSI0862__
|
||||
pop bp
|
||||
pop di
|
||||
pop si
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
%endif; __SYSJUMP1__
|
||||
jmp eof+'JO'
|
||||
eof:
|
||||
; __SYSTHEND__
|
||||
section .data
|
||||
dd -1
|
||||
dw eof
|
||||
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
@@ -0,0 +1,105 @@
|
||||
; l_tmt.asm -- loader & decompressor for the tmt/adam 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
|
||||
; =============
|
||||
|
||||
start:
|
||||
; __TMTMAIN1__
|
||||
mov edi, 0 ; relocation offset
|
||||
push edi
|
||||
lea esi, [edi + 'ESI0']
|
||||
lea edi, [edi + 'EDI0']
|
||||
mov ecx, 'ECX0'
|
||||
|
||||
std
|
||||
rep
|
||||
movsb
|
||||
cld
|
||||
|
||||
lea esi, [edi + 1]
|
||||
pop edi
|
||||
or ebp, byte -1
|
||||
push edi
|
||||
%ifdef __TMTCALT1__
|
||||
push edi
|
||||
%endif; __TMTMAIN2__
|
||||
jmp .1 + 'JMPD'
|
||||
.1:
|
||||
%include "header.ash"
|
||||
|
||||
cutpoint:
|
||||
; __TMTCUTPO__
|
||||
|
||||
; =============
|
||||
; ============= DECOMPRESSION
|
||||
; =============
|
||||
|
||||
%include "n2b_d32.ash"
|
||||
%include "n2d_d32.ash"
|
||||
|
||||
; __TMTMAIN5__
|
||||
pop ebp
|
||||
mov esi, edi
|
||||
sub esi, [edi - 4]
|
||||
|
||||
; =============
|
||||
; ============= CALLTRICK
|
||||
; =============
|
||||
|
||||
%ifdef __TMTCALT2__
|
||||
pop edi
|
||||
cjt32 ebp
|
||||
%endif; __TMTRELOC__
|
||||
|
||||
; =============
|
||||
; ============= RELOCATION
|
||||
; =============
|
||||
|
||||
lea edi, [ebp - 4]
|
||||
reloc32 esi, edi, ebp
|
||||
|
||||
; =============
|
||||
; __TMTJUMP1__
|
||||
jmp .1+'JMPO'
|
||||
.1:
|
||||
eof:
|
||||
; __TMTHEEND__
|
||||
section .data
|
||||
dd -1
|
||||
dw eof
|
||||
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
@@ -0,0 +1,349 @@
|
||||
; l_tos.s -- loader & decompressor for the atari/tos 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 NRV_BB 8
|
||||
|
||||
|
||||
;
|
||||
; see also:
|
||||
; mint/src/basepage.h
|
||||
; mint/src/mem.h (FILEHEAD)
|
||||
; mint/src/mem.c (load_region, load_and_reloc)
|
||||
;
|
||||
|
||||
;
|
||||
; This file is first preprocessed by cpp, then the a68k assembler
|
||||
; is run and finally the generated object file is translated to a .h file
|
||||
; by a simple perl script. We also maintain compatiblity with the pasm
|
||||
; assembler (which must be started in the emulator window).
|
||||
;
|
||||
|
||||
|
||||
#ifdef __A68K__
|
||||
# define align4 align 0,4
|
||||
# define L(label) \/**/label
|
||||
# define macro(name) name macro
|
||||
# define text section code
|
||||
#else
|
||||
# define align4 align 4
|
||||
# define L(label) ./**/label
|
||||
# define macro(name) macro name
|
||||
#endif
|
||||
|
||||
; defines needed for including ident_[ns].ash
|
||||
#define db dc.b
|
||||
#define dw dc.w
|
||||
#define dd dc.l
|
||||
|
||||
|
||||
; basepage offsets
|
||||
p_lowtpa equ $0 ; .l
|
||||
p_hitpa equ $4 ; .l
|
||||
p_tbase equ $8 ; .l
|
||||
p_tlen equ $c ; .l
|
||||
p_dbase equ $10 ; .l
|
||||
p_dlen equ $14 ; .l
|
||||
p_bbase equ $18 ; .l
|
||||
p_blen equ $1c ; .l
|
||||
|
||||
#if 0
|
||||
; file header offsets (NOT USED)
|
||||
fh_branch equ $0 ; .w $601a
|
||||
fh_tlen equ $2 ; .l
|
||||
fh_dlen equ $6 ; .l
|
||||
fh_blen equ $a ; .l
|
||||
fh_slen equ $e ; .l
|
||||
fh_res1 equ $12 ; .l
|
||||
fh_res2 equ $16 ; .l
|
||||
fh_flag equ $1a ; .w
|
||||
|
||||
fh_size equ $1c ; 28 bytes
|
||||
#endif
|
||||
|
||||
;
|
||||
; long living registers:
|
||||
; d4 p_tbase - start of text segment
|
||||
; a6 p_bbase - start of uncompressed bss segment, this also is the
|
||||
; - end of decompressed text+data
|
||||
; - beginning of decompressed relocations
|
||||
; - beginning of dirty bss
|
||||
; a5 final startup code copied below stack
|
||||
;
|
||||
|
||||
|
||||
; /*************************************************************************
|
||||
; // entry - the text segment of a compressed executable
|
||||
; //
|
||||
; // note: compressed programs never have the F_SHTEXT flag set,
|
||||
; // so we can assume that the text, data & bss segments
|
||||
; // are contiguous in memory
|
||||
; **************************************************************************/
|
||||
|
||||
text
|
||||
dc.b 'UPX1' ; marker for o2bin.pl
|
||||
start:
|
||||
move.l a0,d0 ; a0 is basepage if accessory
|
||||
beq L(l_app)
|
||||
move.l 4(a0),sp ; accessory - get stack
|
||||
bra L(start)
|
||||
L(l_app): move.l 4(sp),d0 ; application - get basepage
|
||||
L(start): movem.l d1-d7/a0-a6,-(sp)
|
||||
|
||||
|
||||
; ------------- restore original basepage
|
||||
|
||||
; we also setup d4, a6 and a1 here
|
||||
|
||||
move.l d0,a2 ; a2 = basepage
|
||||
addq.l #p_tbase,a2
|
||||
move.l (a2)+,a6
|
||||
move.l a6,d4 ; d4 = p_tbase
|
||||
move.l #'up11',(a2) ; p_tlen
|
||||
add.l (a2)+,a6
|
||||
move.l a6,(a2)+ ; p_dbase
|
||||
move.l #'up12',(a2) ; p_dlen
|
||||
add.l (a2)+,a6 ; a6 = uncompressed p_bbase
|
||||
move.l (a2),a1 ; a1 = compressed p_bbase
|
||||
move.l a6,(a2)+ ; p_bbase
|
||||
move.l #'up13',(a2) ; p_blen
|
||||
|
||||
|
||||
; ------------- copy data segment (from a1 to a0, downwards)
|
||||
|
||||
; a1 (top of compressed data) already initialized above
|
||||
|
||||
move.l d4,a0
|
||||
add.l #'up21',a0 ; top of data segment + offset
|
||||
|
||||
#if defined(SMALL)
|
||||
|
||||
move.l #'up22',d0 ; (len / 4)
|
||||
|
||||
; copy 4 bytes per loop
|
||||
L(loop): move.l -(a1),-(a0)
|
||||
;;subq.l #1,d0
|
||||
dc.b 'u1' ; subq.l #1,d0 / subq.w #1,d0
|
||||
bne L(loop)
|
||||
|
||||
#else
|
||||
|
||||
move.l #'up22',d0 ; (len / 160)
|
||||
|
||||
; loop1 - use 10 registers to copy 4*10*4 = 160 bytes per loop
|
||||
L(loop1):
|
||||
lea.l -160(a1),a1
|
||||
movem.l 120(a1),d1-d3/d5-d7/a2-a5
|
||||
movem.l d1-d3/d5-d7/a2-a5,-(a0)
|
||||
movem.l 80(a1),d1-d3/d5-d7/a2-a5
|
||||
movem.l d1-d3/d5-d7/a2-a5,-(a0)
|
||||
movem.l 40(a1),d1-d3/d5-d7/a2-a5
|
||||
movem.l d1-d3/d5-d7/a2-a5,-(a0)
|
||||
movem.l (a1),d1-d3/d5-d7/a2-a5
|
||||
movem.l d1-d3/d5-d7/a2-a5,-(a0)
|
||||
;;subq.l #1,d0
|
||||
dc.b 'u1' ; subq.l #1,d0 / subq.w #1,d0
|
||||
bne L(loop1)
|
||||
|
||||
; loop2 - copy the remaining 4..160 bytes
|
||||
;;moveq.l #xx,d0 ; ((len % 160) / 4) - 1
|
||||
dc.b 'u2' ; moveq.l #xx,d0
|
||||
|
||||
L(loop2): move.l -(a1),-(a0)
|
||||
dbra d0,L(loop2)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
; ------------- copy code to stack
|
||||
|
||||
; Copy the final startup code below the stack. This will get
|
||||
; called via "jmp (a5)" after decompression and relocation.
|
||||
|
||||
copy_to_stack:
|
||||
lea.l clear_bss_end(pc),a2
|
||||
move.l sp,a5
|
||||
moveq.l #((clear_bss_end-clear_bss)/2),d0
|
||||
|
||||
move.l d4,-(a5) ; entry point for final jmp
|
||||
L(loop): move.w -(a2),-(a5)
|
||||
subq.w #1,d0
|
||||
bne L(loop)
|
||||
|
||||
; note: now d0 is 0
|
||||
|
||||
|
||||
; ------------- prepare decompressor
|
||||
|
||||
; a0 now points to the start of the compressed block
|
||||
; note: the next statement can be moved below cutpoint
|
||||
; if it helps for the align4
|
||||
;;move.l d4,a1 ; dest. for uncompressing
|
||||
move.l d4,a1 ; dest. for uncompressing
|
||||
|
||||
|
||||
; ------------- jump to copied decompressor
|
||||
|
||||
move.l d4,a2
|
||||
add.l #'up31',a2
|
||||
jmp (a2) ; jmp cutpoint
|
||||
|
||||
|
||||
; /*************************************************************************
|
||||
; // this is the final part of the startup code which runs in the stack
|
||||
; **************************************************************************/
|
||||
|
||||
; on entry d1 and d2 are 0
|
||||
|
||||
; ------------- clear dirty bss
|
||||
|
||||
clear_bss:
|
||||
|
||||
#if defined(SMALL)
|
||||
L(loop): move.l d1,(a6)+
|
||||
;;subq.l #1,d0
|
||||
dc.b 'u4' ; subq.l #1,d0 / subq.w #1,d0
|
||||
bne L(loop)
|
||||
#else
|
||||
; the dirty bss is usually not too large, so we don't
|
||||
; bother making movem optimizations here
|
||||
L(loop): move.l d1,(a6)+
|
||||
move.l d1,(a6)+
|
||||
move.l d1,(a6)+
|
||||
move.l d1,(a6)+
|
||||
;;subq.l #1,d0
|
||||
dc.b 'u4' ; subq.l #1,d0 / subq.w #1,d0
|
||||
bne L(loop)
|
||||
#endif
|
||||
|
||||
|
||||
; ------------- start program
|
||||
|
||||
; note: d0.l is now 0
|
||||
|
||||
movem.l (sp)+,d1-d7/a0-a6
|
||||
cmp.l d0,a0
|
||||
beq L(l_app)
|
||||
;;suba.l sp,sp ; accessory: no stack
|
||||
move.l d0,sp ; accessory: no stack
|
||||
L(l_app): dc.w $4ef9 ; jmp $xxxxxxxx - jmp to text segment
|
||||
|
||||
clear_bss_end:
|
||||
|
||||
|
||||
; /*************************************************************************
|
||||
; // UPX ident & packheader
|
||||
; **************************************************************************/
|
||||
|
||||
#if defined(SMALL)
|
||||
# include "ident_s.ash"
|
||||
#else
|
||||
# include "ident_n.ash"
|
||||
#endif
|
||||
even
|
||||
|
||||
align4
|
||||
|
||||
dc.b 'UPX!' ; magic
|
||||
ds.b 28 ; #include "header.ash"
|
||||
|
||||
|
||||
; end of text segment - size is a multiple of 4
|
||||
|
||||
|
||||
; /*************************************************************************
|
||||
; // This part is appended after the compressed data.
|
||||
; // It runs in the last part of the dirty bss (after the relocations).
|
||||
; **************************************************************************/
|
||||
|
||||
cutpoint:
|
||||
|
||||
; ------------- decompress (from a0 to a1)
|
||||
|
||||
#if defined(NRV2B)
|
||||
# include "m68k/n2b_d.ash"
|
||||
#elif defined(NRV2D)
|
||||
# include "m68k/n2d_d.ash"
|
||||
#else
|
||||
# error
|
||||
#endif
|
||||
|
||||
|
||||
; ------------- reloc
|
||||
|
||||
; The decompressed relocations now are just after the decompressed
|
||||
; data segment, i.e. at the beginning of the (dirty) bss.
|
||||
|
||||
; note: d1 and d2 are 0 from decompressor above
|
||||
|
||||
reloc:
|
||||
;;move.w #'u3',d3 ; #0 or #1
|
||||
dc.b 'u3' ; moveq.l #0,d3 / moveq.l #1,d3
|
||||
beq reloc_end ; don't reloc
|
||||
|
||||
move.l a6,a0 ; a0 = start of relocations
|
||||
|
||||
move.l d4,a1
|
||||
add.l (a0)+,a1 ; get initial fixup
|
||||
|
||||
L(loop1): add.l d1,a1 ; increase fixup
|
||||
add.l d4,(a1) ; reloc one address
|
||||
L(loop2): move.b (a0)+,d1
|
||||
beq reloc_end
|
||||
cmp.b d3,d1 ; note: d3.b is #1
|
||||
bne L(loop1)
|
||||
lea 254(a1),a1 ; d1 == 1 -> add 254, don't reloc
|
||||
bra L(loop2)
|
||||
|
||||
reloc_end:
|
||||
|
||||
; note: d1 and d2 are still 0
|
||||
|
||||
|
||||
; ------------- clear dirty bss & start program
|
||||
|
||||
; We are currently running in the dirty bss.
|
||||
; Jump to the code we copied below the stack.
|
||||
|
||||
#if defined(SMALL)
|
||||
move.l #'up41',d0 ; dirty_bss / 4
|
||||
#else
|
||||
move.l #'up41',d0 ; dirty_bss / 16
|
||||
#endif
|
||||
|
||||
jmp (a5) ; jmp clear_bss (on stack)
|
||||
|
||||
|
||||
eof:
|
||||
dc.w cutpoint-start ; size of entry
|
||||
dc.w eof-cutpoint ; size of decompressor
|
||||
dc.b 'UPX9' ; marker for o2bin.pl
|
||||
|
||||
end
|
||||
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
; l_w32pe.asm -- loader & decompressor for the w32/pe 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
|
||||
%define jnzn jnz near
|
||||
%define jbn jb near
|
||||
%include "macros.ash"
|
||||
|
||||
BITS 32
|
||||
SECTION .text
|
||||
ORG 0
|
||||
|
||||
; =============
|
||||
; ============= ENTRY POINT
|
||||
; =============
|
||||
|
||||
%ifdef __PEISDLL1__
|
||||
cmp byte [esp + 8], 1
|
||||
jnzn reloc_end_jmp
|
||||
%endif; __PEMAIN01__
|
||||
pushad
|
||||
mov esi, 'ESI0' ; relocated
|
||||
lea edi, [esi + 'EDI0']
|
||||
%ifdef __PEICONS1__
|
||||
inc word [edi + 'ICON']
|
||||
%else; __PEICONS2__
|
||||
add word [edi + 'ICON'],'DR'
|
||||
%endif; __PEICONSZ__
|
||||
%ifdef __PETLSHAK__
|
||||
mov dword [edi + 'TLSA'],'TLSV'
|
||||
%endif; __PEMAIN02__
|
||||
push edi
|
||||
mpass:
|
||||
or ebp, byte -1
|
||||
|
||||
; =============
|
||||
; ============= DECOMPRESSION
|
||||
; =============
|
||||
|
||||
%include "n2b_d32.ash"
|
||||
%include "n2d_d32.ash"
|
||||
|
||||
; =============
|
||||
|
||||
%ifdef __PEMULTIP__
|
||||
lodsd
|
||||
add edi, eax
|
||||
jbn mpass
|
||||
%endif; __PEMAIN10__
|
||||
|
||||
; =============
|
||||
pop esi ; load vaddr
|
||||
|
||||
; =============
|
||||
; ============= CALLTRICK
|
||||
; =============
|
||||
|
||||
%ifdef __PECALLTR__
|
||||
%ifdef __PECTTPOS__
|
||||
lea edi, [esi + 'TEXV']
|
||||
%else; __PECTTNUL__
|
||||
mov edi, esi
|
||||
%endif; __PEDUMMY0__
|
||||
cjt32 esi
|
||||
%endif; __PEDUMMY1__
|
||||
|
||||
; =============
|
||||
; ============= IMPORTS
|
||||
; =============
|
||||
|
||||
%ifdef __PEIMPORT__
|
||||
lea edi, [esi + 'BIMP']
|
||||
next_dll:
|
||||
mov eax, [edi]
|
||||
or eax, eax
|
||||
jz imports_done
|
||||
mov ebx, [edi+4] ; iat
|
||||
lea eax, [eax + esi + 'IMPS']
|
||||
add ebx, esi
|
||||
push eax
|
||||
add edi, byte 8
|
||||
call [esi + 'LOAD'] ; LoadLibraryA
|
||||
xchg eax, ebp
|
||||
next_func:
|
||||
mov al, [edi]
|
||||
inc edi
|
||||
or al, al
|
||||
jz next_dll
|
||||
mov ecx, edi ; something > 0
|
||||
%ifdef __PEIBYORD__
|
||||
jns byname
|
||||
%ifdef __PEK32ORD__
|
||||
jpe not_kernel32
|
||||
mov eax, [edi]
|
||||
add edi, byte 4
|
||||
mov eax, [eax + esi + 'K32O']
|
||||
jmps next_imp
|
||||
not_kernel32:
|
||||
%endif; __PEIMORD1__
|
||||
movzx eax, word [edi]
|
||||
inc edi
|
||||
push eax
|
||||
inc edi
|
||||
db 0xb9 ; mov ecx,xxxx
|
||||
byname:
|
||||
%endif; __PEIMPOR2__
|
||||
push edi
|
||||
dec eax
|
||||
repne
|
||||
scasb
|
||||
|
||||
push ebp
|
||||
call [esi + 'GETP'] ; GetProcAddr
|
||||
or eax, eax
|
||||
jz imp_failed
|
||||
next_imp:
|
||||
mov [ebx], eax
|
||||
add ebx, byte 4
|
||||
jmps next_func
|
||||
imp_failed:
|
||||
%ifdef __PEIERDLL__
|
||||
popad
|
||||
xor eax, eax
|
||||
retn 0x0c
|
||||
%else; __PEIEREXE__
|
||||
call [esi + 'EXIT'] ; ExitProcess
|
||||
%endif; __PEIMDONE__
|
||||
imports_done:
|
||||
%endif; __PEIMPOR9__
|
||||
|
||||
; =============
|
||||
; ============= RELOCATION
|
||||
; =============
|
||||
|
||||
%ifdef __PERELOC1__
|
||||
lea edi, [esi + 'BREL']
|
||||
; __PERELOC2__
|
||||
add edi, byte 4
|
||||
; __PERELOC3__
|
||||
lea ebx, [esi - 4]
|
||||
reloc32 edi, ebx, esi
|
||||
%endif; __PERELOC9__
|
||||
|
||||
; =============
|
||||
|
||||
; FIXME: depends on that in PERELOC1 edi is set!!
|
||||
%ifdef __PERLOHI0__
|
||||
xchg edi, esi
|
||||
lea ecx, [edi + 'DELT']
|
||||
%endif; __PERLOHIZ__
|
||||
|
||||
%ifdef __PERELLO0__
|
||||
db 0xA9
|
||||
rello0:
|
||||
add [edi + eax], cx
|
||||
lodsd
|
||||
or eax, eax
|
||||
jnz rello0
|
||||
%endif; __PERELLOZ__
|
||||
|
||||
; =============
|
||||
|
||||
%ifdef __PERELHI0__
|
||||
shr ecx, 16
|
||||
db 0xA9
|
||||
relhi0:
|
||||
add [edi + eax], cx
|
||||
lodsd
|
||||
or eax, eax
|
||||
jnz relhi0
|
||||
%endif; __PERELHIZ__
|
||||
|
||||
; =============
|
||||
|
||||
; __PEMAIN20__
|
||||
popad
|
||||
reloc_end_jmp:
|
||||
%ifdef __PERETURN__
|
||||
xor eax, eax
|
||||
inc eax
|
||||
retn 0x0C
|
||||
%else; __PEDOJUMP__
|
||||
jmp .1+'JMPO'
|
||||
.1:
|
||||
%endif; __PEDUMMY3__
|
||||
|
||||
; =============
|
||||
; ============= CUT HERE
|
||||
; =============
|
||||
|
||||
%include "header.ash"
|
||||
|
||||
eof:
|
||||
; __PETHEEND__
|
||||
section .data
|
||||
dd -1
|
||||
dw eof
|
||||
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
@@ -0,0 +1,139 @@
|
||||
; l_wcle.asm -- loader & decompressor for the watcom/le 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
|
||||
; =============
|
||||
|
||||
start:
|
||||
; __WCLEMAIN__
|
||||
mov edi, 'alib' ; address of obj#1:0 (filled by a fixup record)
|
||||
|
||||
; The following hack fools the lame protection of dos4g/w, which expects the
|
||||
; 'WATCOM' string somewhere in the first 18 bytes after the entry point
|
||||
; I use this imul thingy, because it's 1 byte shorter than a jump ;-)
|
||||
; ... and "alibiWATCOM" looks cool
|
||||
db 'iWATCOM' ; imul edx,[edi+0x41],'TCOM'
|
||||
|
||||
push es
|
||||
push ds
|
||||
pop es
|
||||
push edi
|
||||
|
||||
lea esi, [edi + 'ESI0']
|
||||
lea edi, [edi + 'EDI0']
|
||||
mov ecx, 'ECX0'
|
||||
|
||||
std
|
||||
rep
|
||||
movsd
|
||||
cld
|
||||
|
||||
lea esi, [edi + 4]
|
||||
pop edi
|
||||
or ebp, byte -1
|
||||
push edi
|
||||
jmp .1 + 'JMPD'
|
||||
.1:
|
||||
%include "header.ash"
|
||||
|
||||
cutpoint:
|
||||
; __WCLECUTP__
|
||||
|
||||
; =============
|
||||
; ============= DECOMPRESSION
|
||||
; =============
|
||||
|
||||
%include "n2b_d32.ash"
|
||||
%include "n2d_d32.ash"
|
||||
|
||||
; =============
|
||||
|
||||
; __WCLEMAI2__
|
||||
pop ebp
|
||||
push esi
|
||||
lea esi, [ebp + 'RELO']
|
||||
push esi
|
||||
|
||||
; =============
|
||||
; ============= CALLTRICK
|
||||
; =============
|
||||
|
||||
%ifdef __WCALLTRI__
|
||||
%ifdef __WCCTTPOS__
|
||||
lea edi, [ebp + 'TEXV']
|
||||
%else; __WCCTTNUL__
|
||||
mov edi, ebp
|
||||
%endif; __WCALLTR1__
|
||||
cjt32 ebp
|
||||
%endif; __WCDUMMY1__
|
||||
|
||||
; =============
|
||||
; ============= RELOCATION
|
||||
; =============
|
||||
|
||||
%ifdef __WCRELOC1__
|
||||
lea edi, [ebp - 4]
|
||||
reloc32 esi, edi, ebp
|
||||
; eax = 0
|
||||
%endif; __WCDUMMY2__
|
||||
|
||||
%ifdef __WCRELSEL__
|
||||
call esi ; selector fixup code (modifies bx)
|
||||
%endif; __WCLEMAI4__
|
||||
|
||||
; =============
|
||||
|
||||
pop edi
|
||||
pop ecx
|
||||
sub ecx, edi
|
||||
shr ecx, 2
|
||||
rep
|
||||
stosd ; clear dirty memory
|
||||
pop es
|
||||
lea esp, [ebp + 'ESP0']
|
||||
|
||||
jmp .1+'JMPO'
|
||||
.1:
|
||||
|
||||
; =============
|
||||
|
||||
eof:
|
||||
; __WCTHEEND__
|
||||
section .data
|
||||
dd -1
|
||||
dw eof
|
||||
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
@@ -0,0 +1,276 @@
|
||||
/* linux.hh -- common stuff the the Linux stub loaders
|
||||
|
||||
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
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
// includes
|
||||
**************************************************************************/
|
||||
|
||||
#define __need_timeval
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <elf.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <time.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/unistd.h>
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
// constants and types
|
||||
**************************************************************************/
|
||||
|
||||
// !!! must be the same as in p_unix.h !!!
|
||||
#define OVERHEAD 2048
|
||||
|
||||
|
||||
#define UPX_MAGIC_LE32 0x21585055 // "UPX!"
|
||||
|
||||
|
||||
#undef int32_t
|
||||
#undef uint32_t
|
||||
#define int32_t int
|
||||
#define uint32_t unsigned int
|
||||
|
||||
|
||||
typedef int nrv_int;
|
||||
typedef int nrv_int32;
|
||||
typedef unsigned int nrv_uint;
|
||||
typedef unsigned int nrv_uint32;
|
||||
#define nrv_byte unsigned char
|
||||
#define nrv_voidp void *
|
||||
|
||||
|
||||
// From ../p_unix.h
|
||||
struct l_info { // 12-byte trailer in header for loader
|
||||
uint32_t l_checksum;
|
||||
uint32_t l_magic;
|
||||
uint16_t l_lsize;
|
||||
uint8_t l_version;
|
||||
uint8_t l_format;
|
||||
};
|
||||
struct p_info // 12-byte packed program header follows stub loader
|
||||
{
|
||||
uint32_t p_progid;
|
||||
uint32_t p_filesize;
|
||||
uint32_t p_blocksize;
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
// syscalls
|
||||
//
|
||||
// Because of different <asm/unistd.h> versions and subtle bugs
|
||||
// in both gcc and egcs we define all syscalls manually.
|
||||
//
|
||||
// Also, errno conversion is not necessary in our case, and we
|
||||
// use optimized assembly statements to further decrease the size.
|
||||
**************************************************************************/
|
||||
|
||||
#undef _syscall0
|
||||
#undef _syscall1
|
||||
#undef _syscall2
|
||||
#undef _syscall3
|
||||
#ifndef __NR__exit
|
||||
# define __NR__exit __NR_exit
|
||||
#endif
|
||||
|
||||
#define Z0(x) (__builtin_constant_p(x) && (long)(x) == 0)
|
||||
#define Z1(x) (__builtin_constant_p(x) && (long)(x) >= -128 && (long)(x) <= 127)
|
||||
|
||||
#define _syscall0(type,name) \
|
||||
type name(void) \
|
||||
{ \
|
||||
long __res; \
|
||||
if (Z1(__NR_##name)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name)); \
|
||||
} else { \
|
||||
__asm__ __volatile__ ("int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "a" (__NR_##name)); \
|
||||
} \
|
||||
return (type) __res; \
|
||||
}
|
||||
|
||||
#define _syscall1(type,name,type1,arg1) \
|
||||
type name(type1 arg1) \
|
||||
{ \
|
||||
long __res; \
|
||||
if (Z1(__NR_##name)) { \
|
||||
if (Z0(arg1)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; xorl %%ebx,%%ebx; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name) \
|
||||
: "ebx"); \
|
||||
} else if (Z1(arg1)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; push %2; popl %%ebx; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"g" ((long)(arg1)) \
|
||||
: "ebx"); \
|
||||
} else { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"b" ((long)(arg1))); \
|
||||
} \
|
||||
} else { \
|
||||
__asm__ __volatile__ ("int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "a" (__NR_##name),"b" ((long)(arg1))); \
|
||||
} \
|
||||
return (type) __res; \
|
||||
}
|
||||
|
||||
#define _syscall2(type,name,type1,arg1,type2,arg2) \
|
||||
type name(type1 arg1,type2 arg2) \
|
||||
{ \
|
||||
long __res; \
|
||||
if (Z1(__NR_##name)) { \
|
||||
if (Z0(arg1) && Z0(arg2)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; xorl %%ebx,%%ebx; xorl %%ecx,%%ecx; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name) \
|
||||
: "ebx", "ecx"); \
|
||||
} else if (Z0(arg1) && Z1(arg2)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; xorl %%ebx,%%ebx; push %2; popl %%ecx; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"g" ((long)(arg2)) \
|
||||
: "ebx", "ecx"); \
|
||||
} else if (Z1(arg1) && Z0(arg2)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; push %2; popl %%ebx; xorl %%ecx,%%ecx; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"g" ((long)(arg1)) \
|
||||
: "ebx", "ecx"); \
|
||||
} else if (Z1(arg1) && Z1(arg2)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; push %2; popl %%ebx; push %3; popl %%ecx; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"g" ((long)(arg1)),"g" ((long)(arg2)) \
|
||||
: "ebx", "ecx"); \
|
||||
} else if (Z0(arg1)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; xorl %%ebx,%%ebx; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"c" ((long)(arg2)) \
|
||||
: "ebx"); \
|
||||
} else if (Z0(arg2)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; xorl %%ecx,%%ecx; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"b" ((long)(arg1)) \
|
||||
: "ecx"); \
|
||||
} else if (Z1(arg1)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; push %2; popl %%ebx; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"g" ((long)(arg1)),"c" ((long)(arg2)) \
|
||||
: "ebx"); \
|
||||
} else if (Z1(arg2)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; push %3; popl %%ecx; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"b" ((long)(arg1)),"g" ((long)(arg2)) \
|
||||
: "ecx"); \
|
||||
} else { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
|
||||
} \
|
||||
} else { \
|
||||
__asm__ __volatile__ ("int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "a" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
|
||||
} \
|
||||
return (type) __res; \
|
||||
}
|
||||
|
||||
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
|
||||
type name(type1 arg1,type2 arg2,type3 arg3) \
|
||||
{ \
|
||||
long __res; \
|
||||
if (Z1(__NR_##name)) { \
|
||||
__asm__ __volatile__ ("push %1; popl %0; int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "g" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
|
||||
"d" ((long)(arg3))); \
|
||||
} else { \
|
||||
__asm__ __volatile__ ("int $0x80" \
|
||||
: "=a" (__res) \
|
||||
: "a" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
|
||||
"d" ((long)(arg3))); \
|
||||
} \
|
||||
return (type) __res; \
|
||||
}
|
||||
|
||||
#define access syscall_access
|
||||
#define fcntl syscall_fcntl
|
||||
#define getcwd syscall_getcwd
|
||||
#define getrusage syscall_getrusage
|
||||
#define gettimeofday syscall_gettimeofday
|
||||
#define nanosleep syscall_nanosleep
|
||||
#define open syscall_open
|
||||
#define personality syscall_personality
|
||||
|
||||
static inline _syscall2(int,access,const char *,file,int,mode)
|
||||
static inline _syscall1(int,adjtimex,struct timex *,ntx)
|
||||
static inline _syscall1(void *,brk,void *,high)
|
||||
static inline _syscall1(int,close,int,fd)
|
||||
static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
|
||||
static inline _syscall1(int,_exit,int,exitcode)
|
||||
static inline _syscall3(int,fcntl,int,fd,int,cmd,long,arg)
|
||||
static inline _syscall2(int,ftruncate,int,fd,size_t,len)
|
||||
static inline _syscall0(pid_t,fork)
|
||||
static inline _syscall2(int,getcwd,char *,buf,unsigned long,size);
|
||||
static inline _syscall0(pid_t,getpid)
|
||||
static inline _syscall2(int,getrusage,int,who,struct rusage *,usage);
|
||||
static inline _syscall2(int,gettimeofday,struct timeval *,tv,void *,tz)
|
||||
static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,whence)
|
||||
static inline _syscall1(caddr_t,mmap,const int *,args)
|
||||
static inline _syscall3(int,mprotect,void *,addr,size_t,len,int,prot)
|
||||
static inline _syscall3(int,msync,const void *,start,size_t,length,int,flags)
|
||||
static inline _syscall2(int,munmap,void *,start,size_t,length)
|
||||
static inline _syscall2(int,nanosleep,const struct timespec *,rqtp,struct timespec *,rmtp)
|
||||
static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
|
||||
static inline _syscall1(int,personality,unsigned long,persona)
|
||||
static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
|
||||
static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
|
||||
static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
|
||||
static inline _syscall1(int,unlink,const char *,file)
|
||||
#define exit _exit
|
||||
|
||||
#undef Z0
|
||||
#undef Z1
|
||||
|
||||
|
||||
/*
|
||||
vi:ts=4:et:nowrap
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
; macros.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
|
||||
;
|
||||
|
||||
|
||||
; =============
|
||||
; ============= 16-BIT CALLTRICK & JUMPTRICK
|
||||
; =============
|
||||
|
||||
|
||||
%macro cjt16 1
|
||||
%ifdef __CALLTR16__
|
||||
pop si
|
||||
mov cx, 'CT'
|
||||
cjt16_L1:
|
||||
lodsb
|
||||
sub al, 0xe8
|
||||
cmp al, 1
|
||||
ja cjt16_L1
|
||||
|
||||
%ifdef __CT16I286__
|
||||
rol word [si], 8
|
||||
; __CT16SUB0__
|
||||
sub [si], si
|
||||
%else; __CT16I086__
|
||||
mov bx, [si]
|
||||
xchg bl, bh
|
||||
sub bx, si
|
||||
mov [si], bx
|
||||
%endif; __CALLTRI2__
|
||||
lodsw
|
||||
loop cjt16_L1
|
||||
%endif; __CT16DUM1__
|
||||
|
||||
; =============
|
||||
|
||||
%ifdef __CT16E800__
|
||||
mov al, 0xe8
|
||||
%else; __CT16E900__
|
||||
mov al, 0xe9
|
||||
%endif; __CALLTRI5__
|
||||
pop di
|
||||
mov cx, 'CT'
|
||||
cjt16_L11:
|
||||
repne
|
||||
scasb
|
||||
%ifdef __CT16JEND__
|
||||
jnz %1 ; FIXME: this doesn't get relocated
|
||||
%else; __CT16JUL2__
|
||||
jnz cjt16_L2
|
||||
%endif; __CT16DUM2__
|
||||
|
||||
%ifdef __CT16I287__
|
||||
rol word [di], 8
|
||||
; __CT16SUB1__
|
||||
sub [di], di
|
||||
%else; __CT16I087__
|
||||
mov bx, [di]
|
||||
xchg bl, bh
|
||||
sub bx, di
|
||||
mov [di], bx
|
||||
%endif; __CALLTRI6__
|
||||
scasw
|
||||
jmps cjt16_L11
|
||||
cjt16_L2:
|
||||
; __CT16DUMM3__
|
||||
%endmacro
|
||||
|
||||
|
||||
|
||||
;; =============
|
||||
;; ============= 32-BIT CALLTRICK & JUMPTRICK
|
||||
;; =============
|
||||
|
||||
;; call & jump trick : 2 in 1
|
||||
%macro cjt32 1
|
||||
%ifdef __CALLTR00__
|
||||
mov ecx, 'TEXL'
|
||||
calltrickloop:
|
||||
mov al, [edi]
|
||||
inc edi
|
||||
sub al, 0xE8
|
||||
ct1:
|
||||
cmp al, 1
|
||||
ja calltrickloop
|
||||
%ifdef __CTCLEVE1__
|
||||
cmp byte [edi], '?'
|
||||
jnz calltrickloop
|
||||
%endif; __CALLTR01__
|
||||
mov eax, [edi]
|
||||
mov bl, [edi + 4]
|
||||
%ifdef __CTDUMMY1__
|
||||
%ifdef __CTBSHR01__
|
||||
shr ax, 8
|
||||
%else; __CTBROR01__
|
||||
xchg al, ah
|
||||
%endif; __CTBSWA01__
|
||||
rol eax, 16
|
||||
xchg al, ah
|
||||
%endif; __CALLTR02__
|
||||
sub eax, edi
|
||||
sub bl, 0xE8
|
||||
%ifnidn %1,0
|
||||
add eax, %1
|
||||
%endif
|
||||
mov [edi], eax
|
||||
add edi, byte 5
|
||||
mov eax, ebx
|
||||
loop ct1
|
||||
%else; __CALLTR10__
|
||||
;; 32-bit call XOR jump trick
|
||||
mov ecx, 'TEXL'
|
||||
ctloop1:
|
||||
%ifdef __CALLTRE8__
|
||||
mov al,0xE8
|
||||
%else; __CALLTRE9__
|
||||
mov al,0xE9
|
||||
%endif; __CALLTR11__
|
||||
ctloop2:
|
||||
repnz
|
||||
scasb
|
||||
jnz ctend
|
||||
%ifdef __CTCLEVE2__
|
||||
cmp byte [edi], '?'
|
||||
jnz ctloop2
|
||||
%endif; __CALLTR12__
|
||||
mov eax, [edi]
|
||||
%ifdef __CTDUMMY2__
|
||||
%ifdef __CTBSHR11__
|
||||
shr ax, 8
|
||||
%else; __CTBROR11__
|
||||
xchg al, ah
|
||||
%endif; __CTBSWA11__
|
||||
rol eax, 16
|
||||
xchg al, ah
|
||||
%endif; __CALLTR13__
|
||||
sub eax, edi
|
||||
%ifnidn %1,0
|
||||
add eax, %1
|
||||
%endif
|
||||
stosd
|
||||
jmps ctloop1
|
||||
ctend:
|
||||
%endif; __CTTHEEND__
|
||||
%endmacro
|
||||
|
||||
|
||||
|
||||
;; =============
|
||||
;; ============= 32-BIT RELOCATIONS
|
||||
;; =============
|
||||
|
||||
%macro reloc32 3
|
||||
; __RELOC320__
|
||||
reloc_main:
|
||||
xor eax, eax
|
||||
mov al, [%1]
|
||||
inc %1
|
||||
or eax, eax
|
||||
jz reloc_endx
|
||||
cmp al, 0xEF
|
||||
ja reloc_fx
|
||||
reloc_add:
|
||||
add %2, eax
|
||||
%if 1
|
||||
mov eax, [%2]
|
||||
xchg al, ah
|
||||
rol eax, 16
|
||||
xchg al, ah
|
||||
add eax, %3
|
||||
mov [%2], eax
|
||||
%else
|
||||
add [%2], %3
|
||||
%endif
|
||||
jmps reloc_main
|
||||
reloc_fx:
|
||||
and al, 0x0F
|
||||
shl eax, 16
|
||||
mov ax, [%1]
|
||||
add %1, byte 2
|
||||
%ifdef __REL32BIG__
|
||||
or eax, eax
|
||||
jnz reloc_add
|
||||
mov eax, [%1]
|
||||
add %1, byte 4
|
||||
%endif; __RELOC32J__
|
||||
jmps reloc_add
|
||||
reloc_endx:
|
||||
; __REL32END__
|
||||
%endmacro
|
||||
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
|
||||
for i in Makefile *.h *.c *.ash *.asm *.lds
|
||||
do
|
||||
diff3 -m ./$i ../../../upx-ancestor/src/stub/$i ../../../upx-1.10/src/stub/$i > tmp.$$
|
||||
mv tmp.$$ ./$i
|
||||
read junk
|
||||
done
|
||||
@@ -0,0 +1,120 @@
|
||||
#! /usr/bin/perl -w
|
||||
#
|
||||
# app.pl -- assembly preprocessor for upx
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
#
|
||||
# usage: app.pl infile outfile
|
||||
#
|
||||
|
||||
$in = shift || die;
|
||||
$ou = shift || die;
|
||||
|
||||
open (IN,"<$in") or die;
|
||||
open (OU,">$ou") or die;
|
||||
binmode IN;
|
||||
binmode OU;
|
||||
|
||||
@lines = <IN>;
|
||||
|
||||
%labels = ();
|
||||
$i = 0;
|
||||
$cs = "";
|
||||
|
||||
($ilabel = $in) =~ s,^.*[\/\\],,; # get basename
|
||||
$ilabel =~ s/\W//g;
|
||||
|
||||
# 1st pass
|
||||
for $line (@lines)
|
||||
{
|
||||
$labels{$1} = "$cs" if ($line =~ /^(\w+):/ && $cs);
|
||||
if ($line =~ /__([A-Z0-9]{8})__/) {
|
||||
$cs = $1;
|
||||
# verify the line
|
||||
if ($line =~ /^\%ifdef/) {
|
||||
# ok
|
||||
} elsif ($line =~ /^(\%\w+)?\s*;/) {
|
||||
# ok
|
||||
} else {
|
||||
print STDERR "$in:$i:warning:$line"
|
||||
}
|
||||
}
|
||||
|
||||
if ($line =~ /^\%(if|el|endi)/)
|
||||
{
|
||||
if ($line =~ /__([A-Z0-9]{8})__/)
|
||||
{
|
||||
$line=";$line";
|
||||
}
|
||||
else
|
||||
{
|
||||
print STDERR "$in:$i:warning:$line";
|
||||
}
|
||||
}
|
||||
$line =~ s/\.ash/\.asy/ if ($line =~ /^\s*\%include/);
|
||||
$i++;
|
||||
}
|
||||
|
||||
$cs = "";
|
||||
$i = 0;
|
||||
|
||||
# 2nd pass
|
||||
for $line (@lines)
|
||||
{
|
||||
if ($line =~ /^\s+(j\w+|loop|call)\s+(\w*)/)
|
||||
{
|
||||
$label = $2;
|
||||
die "$line" if ($label =~ /(\bnear\b|\bshort\b)/);
|
||||
if (defined $labels{$label})
|
||||
{
|
||||
$ts = $labels{$label};
|
||||
if ($ts ne $cs)
|
||||
{
|
||||
$line =~ s/$label/J$i$ilabel/;
|
||||
print OU $line;
|
||||
print OU "J$i$ilabel:\n";
|
||||
print OU "\t\tsection\t.data\n\t\tdd\t";
|
||||
print OU "0,J$i$ilabel,\'$ts\',$label - S$ts$ilabel\n";
|
||||
print OU "\t\tsection\t.text\n\n";
|
||||
$line = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$line = ";$line" if ($line =~ /^\s+align\s/);
|
||||
|
||||
print OU $line;
|
||||
if ($line =~ /__([A-Z0-9]{8})__/)
|
||||
{
|
||||
print OU "S$1$ilabel:\n";
|
||||
print OU "\t\tsection\t.data\n\t\tdd\t\'$1\',S$1$ilabel\n";
|
||||
print OU "\t\tsection\t.text\n\n";
|
||||
$cs = $1;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
# vi:ts=4:et
|
||||
@@ -0,0 +1,100 @@
|
||||
#! /usr/bin/perl -w
|
||||
#
|
||||
# bin2h.pl --
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
|
||||
$delim = $/;
|
||||
undef $/; # undef input record separator - read file as a whole
|
||||
|
||||
$ifile = shift || die;
|
||||
$ident = shift || die;
|
||||
$ofile = shift || die;
|
||||
|
||||
open(INFILE,$ifile) || die "$ifile\n";
|
||||
binmode(INFILE);
|
||||
open(OUTFILE,">$ofile") || die "$ofile\n";
|
||||
binmode(OUTFILE);
|
||||
|
||||
# read whole file
|
||||
$data = <INFILE>;
|
||||
close(INFILE);
|
||||
$n = length($data);
|
||||
|
||||
# print
|
||||
select(OUTFILE);
|
||||
|
||||
$o = $ofile;
|
||||
$o =~ s/.*[\/\\]//;
|
||||
|
||||
print <<"EOF";
|
||||
/* $o -- created from $ifile, $n bytes
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
EOF
|
||||
|
||||
printf("unsigned char %s[%d] = {", $ident, $n);
|
||||
for ($i = 0; $i < $n; $i++) {
|
||||
if ($i % 16 == 0) {
|
||||
printf(" /* 0x%4x */", $i - 16) if $i > 0;
|
||||
print "\n";
|
||||
}
|
||||
printf("%3d", ord(substr($data, $i, 1)));
|
||||
print "," if ($i != $n - 1);
|
||||
}
|
||||
print "\n};\n";
|
||||
|
||||
close(OUTFILE) || die;
|
||||
select(STDOUT);
|
||||
|
||||
undef $delim;
|
||||
exit(0);
|
||||
|
||||
# vi:ts=4:et
|
||||
@@ -0,0 +1,47 @@
|
||||
#! /usr/bin/perl -w
|
||||
#
|
||||
# brandelf.pl -- brand an ELF binary as Linux or FreeBSD
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
|
||||
$fname = shift || die;
|
||||
|
||||
$sig = shift || "Linux";
|
||||
die if length($sig) > 7;
|
||||
|
||||
sysopen (FH,$fname,2) || die;
|
||||
binmode FH;
|
||||
|
||||
sysread (FH,$header,8) || die;
|
||||
die if (substr($header, 0, 7) ne "\x7f\x45\x4c\x46\x01\x01\x01");
|
||||
|
||||
syswrite (FH,$sig,length($sig)) || die;
|
||||
syswrite (FH,"\0\0\0\0\0\0\0\0",8-length($sig)) || die;
|
||||
close (FH) || die;
|
||||
|
||||
exit (0);
|
||||
|
||||
# vi:ts=4:et
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user