Initial commit (from git)
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,75 @@
|
||||
#! /usr/bin/perl -w
|
||||
#
|
||||
# o2bin.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;
|
||||
$ofile = shift || die;
|
||||
$x_start = shift || die;
|
||||
$x_end = shift || die;
|
||||
|
||||
# read whole file
|
||||
open(INFILE,$ifile) || die "$ifile\n";
|
||||
binmode(INFILE);
|
||||
$data = <INFILE>;
|
||||
close(INFILE) || die;
|
||||
|
||||
# delete everything up to 'UPX1'
|
||||
die if ($data =~ s/^.*${x_start}//s) != 1;
|
||||
|
||||
# delete everything from 'UPX9'
|
||||
die if ($data =~ s/${x_end}.*$//s) != 1;
|
||||
|
||||
# write file
|
||||
open(OUTFILE,">$ofile") || die "$ofile\n";
|
||||
binmode(OUTFILE);
|
||||
if ($ofile =~ /\.(db)$/i) {
|
||||
# asm "db xx" output
|
||||
$n = length($data);
|
||||
$l = 16;
|
||||
for ($i = 0; $i < $n; ) {
|
||||
print OUTFILE "db " if ($i % $l == 0);
|
||||
printf OUTFILE ("%d", ord(substr($data, $i, 1)));
|
||||
++$i;
|
||||
if ($i == $n || $i % $l == 0) {
|
||||
print OUTFILE "\n";
|
||||
} else {
|
||||
print OUTFILE ",";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print OUTFILE $data;
|
||||
}
|
||||
close(OUTFILE) || die;
|
||||
|
||||
undef $delim;
|
||||
exit(0);
|
||||
|
||||
# vi:ts=4:et
|
||||
@@ -0,0 +1,45 @@
|
||||
#! /usr/bin/perl -w
|
||||
#
|
||||
# setfold.pl -- set Elf32_Phdr[1].p_offset
|
||||
#
|
||||
# This file is part of the UPX executable compressor.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# John Reiser
|
||||
# jreiser@BitWagon.com
|
||||
#
|
||||
|
||||
$fname = shift || die;
|
||||
sysopen (FH,$fname,2) || die;
|
||||
binmode FH;
|
||||
|
||||
$val = oct shift || die;
|
||||
$num = pack("V", $val);
|
||||
|
||||
# 0x34 = sizeof(Elf32_Ehdr)
|
||||
# 0x20 = sizeof(Elf32_Phdr)
|
||||
# 4 = offset(p_offset)
|
||||
sysseek (FH,0x34+0x20+4,0) || die;
|
||||
|
||||
syswrite (FH,$num,4) || die;
|
||||
|
||||
close(FH) || die;
|
||||
exit 0;
|
||||
|
||||
# vi:ts=4:et
|
||||
@@ -0,0 +1,77 @@
|
||||
#! /usr/bin/perl -w
|
||||
#
|
||||
# stripelf.pl -- strip section headers from an 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
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
#
|
||||
# Strip section headers from the Linux stub. Section headers are
|
||||
# optional for executables, but nevertheless binutils (2.9.1.0.25)
|
||||
# complain with a "File format not recognized" error.
|
||||
# Looks like a bug in binutils to me.
|
||||
#
|
||||
# A positive side effect of this is that `strip' cannot ruin an UPX
|
||||
# compressed file any longer.
|
||||
#
|
||||
|
||||
$fname = shift || die;
|
||||
sysopen (FH,$fname,2) || die;
|
||||
binmode FH;
|
||||
|
||||
sysseek (FH,0x20,0) || die;
|
||||
sysread (FH,$num,4) || die;
|
||||
$shpos = unpack ("V",$num); # e_shoff
|
||||
|
||||
sysseek (FH,0x2e,0) || die;
|
||||
sysread (FH,$num,2) || die;
|
||||
$ssize = unpack ("v",$num); # e_shentsize
|
||||
|
||||
sysseek (FH,0x32,0) || die;
|
||||
sysread (FH,$num,2) || die;
|
||||
$idx = unpack ("v",$num); # e_shstrndx
|
||||
|
||||
sysseek (FH,$shpos + $idx * $ssize + 16,0) || die;
|
||||
sysread (FH,$num,4) || die;
|
||||
$neweof = unpack ("V",$num); # sh_offset of the e_shstrndx section
|
||||
|
||||
$num = pack ("x6");
|
||||
sysseek (FH,0x20,0) || die;
|
||||
syswrite (FH,$num,4) || die; # clear e_shoff
|
||||
|
||||
if (1) {
|
||||
sysseek (FH,0x2e,0) || die;
|
||||
syswrite (FH,$num,6) || die; # clear e_shentsize, e_shnum & e_shstrndx
|
||||
} else {
|
||||
sysseek (FH,0x30,0) || die;
|
||||
syswrite (FH,$num,4) || die; # clear e_shnum & e_shstrndx
|
||||
}
|
||||
|
||||
truncate (FH,$neweof) || die;
|
||||
close(FH) || die;
|
||||
|
||||
print STDOUT "$0: truncated $fname to $neweof bytes.\n";
|
||||
exit 0;
|
||||
|
||||
# vi:ts=4:et
|
||||
@@ -0,0 +1,40 @@
|
||||
#! /usr/bin/perl -w
|
||||
#
|
||||
# version.pl -- convert version.h into version.asy
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
$mode = shift || "--nasm";
|
||||
while (<>) {
|
||||
chop;
|
||||
s/\s+$//;
|
||||
if (/^\s*\#\s*define\s+(.*)/) {
|
||||
print "%define $1\n" if ($mode eq "--nasm");
|
||||
}
|
||||
}
|
||||
|
||||
exit (0);
|
||||
|
||||
# vi:ts=4:et
|
||||
@@ -0,0 +1,984 @@
|
||||
; Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details
|
||||
; Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details
|
||||
; Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details
|
||||
; Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
|
||||
; -*- asm -*-
|
||||
;
|
||||
; KLUDGE-WARNING!
|
||||
;
|
||||
; So you say you want to change this file, right? Are you really sure
|
||||
; that's a good idea? Let me tell you a bit about the pitfalls here:
|
||||
;
|
||||
; * Some code runs in protected mode, some in real-mode, some in both.
|
||||
; * Some code must run on a 8088 without crashing it.
|
||||
; * Registers and flags may be expected to survive for a long time.
|
||||
; * The code is optimized for size, not for speed or readability.
|
||||
; * Some comments are parsed by other programs.
|
||||
;
|
||||
; You still want to change it? Oh well, go ahead, but don't come
|
||||
; crying back saying you weren't warned.
|
||||
;
|
||||
;-----------------------------------------------------------------------------
|
||||
; djgpp extender-less stub loader
|
||||
;
|
||||
; (C) Copyright 1993-1995 DJ Delorie
|
||||
;
|
||||
; Redistribution and use in source and binary forms are permitted
|
||||
; provided that: (1) source distributions retain this entire copyright
|
||||
; notice and comment, (2) distributions including binaries display
|
||||
; the following acknowledgement: ``This product includes software
|
||||
; developed by DJ Delorie and contributors to the djgpp project''
|
||||
; in the documentation or other materials provided with the distribution
|
||||
; and in all advertising materials mentioning features or use of this
|
||||
; software, and (3) binary distributions include information sufficient
|
||||
; for the binary user to obtain the sources for the binary and utilities
|
||||
; required to built and use it. Neither the name of DJ Delorie nor the
|
||||
; names of djgpp's contributors may be used to endorse or promote
|
||||
; products derived from this software without specific prior written
|
||||
; permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
; IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
;
|
||||
; Revision history:
|
||||
;
|
||||
; 93/12/05 DJ Delorie Initial version v2.00, requires DPMI 0.9
|
||||
; 94/10/13 CW Sandmann v2.01, accumlated changes: 60K load bug, limits, cwsdpmi, optimization
|
||||
; 94/10/29 CW Sandmann v2.03, M Welinder changes; cwsdpmi load anywhere, size decrease
|
||||
;
|
||||
.copyright "The STUB.EXE stub loader is Copyright (C) 1993-1995 DJ Delorie. "
|
||||
.copyright "Permission granted to use for any purpose provided this copyright "
|
||||
.copyright "remains present and unmodified. "
|
||||
.copyright "This only applies to the stub, and not necessarily the whole program.\n"
|
||||
.id
|
||||
;
|
||||
;-----------------------------------------------------------------------------
|
||||
; Interface to 32-bit executable:
|
||||
;
|
||||
; cs:eip according to COFF header
|
||||
; ds 32-bit data segment for COFF program
|
||||
; fs selector for our data segment (fs:0 is stubinfo)
|
||||
; ss:sp our stack (ss to be freed)
|
||||
; <others> All unspecified registers have unspecified values in them.
|
||||
;-----------------------------------------------------------------------------
|
||||
; This is the stubinfo structure. The presence of this structure
|
||||
; indicates that the executable is a djgpp v2.00 executable.
|
||||
; Fields will never be deleted from this structure, only obsoleted.
|
||||
;
|
||||
.org 0 ; just in case
|
||||
stubinfo:
|
||||
stubinfo_magic: ; char [16]
|
||||
.db "go32stub, v 2.02" ; version may change, [0..7] won't
|
||||
stubinfo_size: ; unsigned long
|
||||
.dd stubinfo_end ; bytes in structure
|
||||
stubinfo_minstack: ; unsigned long
|
||||
.dd 0x80000 ; minimum amount of DPMI stack space (512K)
|
||||
stubinfo_memory_handle: ; unsigned long
|
||||
.dd 0 ; DPMI memory handle
|
||||
stubinfo_initial_size: ; unsigned long
|
||||
.dd 0 ; size of initial segment
|
||||
stubinfo_minkeep: ; unsigned short
|
||||
.dw 16384 ; amount of automatic real-mode buffer
|
||||
stubinfo_ds_selector: ; unsigned short
|
||||
.dw 0 ; our DS selector (used for transfer buffer)
|
||||
stubinfo_ds_segment: ; unsigned short
|
||||
.dw 0 ; our DS segment (used for simulated calls)
|
||||
stubinfo_psp_selector: ; unsigned short
|
||||
.dw 0 ; PSP selector
|
||||
stubinfo_cs_selector: ; unsigned short
|
||||
.dw 0 ; to be freed
|
||||
stubinfo_env_size: ; unsigned short
|
||||
.dw 0 ; number of bytes of environment
|
||||
stubinfo_basename: ; char [8]
|
||||
.db 8 .dup 0 ; base name of executable to load (asciiz if < 8)
|
||||
stubinfo_argv0: ; char [16]
|
||||
.db 16 .dup 0 ; used ONLY by the application (asciiz if < 16)
|
||||
stubinfo_dpmi_server: ; char [16]
|
||||
.db "CWSDPMI.EXE\0\0\0\0\0" ; used by stub to load DPMI server if no DPMI already present
|
||||
|
||||
.align 4
|
||||
stubinfo_end:
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; First, set up our memory and stack environment
|
||||
|
||||
.start ; execution begins here
|
||||
push cs
|
||||
pop ds
|
||||
mov [stubinfo_ds_segment], ds
|
||||
|
||||
mov [psp_segment], es ; save the PSP segment
|
||||
cld
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Check that we have DOS 3.00 or later. (We need this because earlier
|
||||
; versions don't supply argv[0] to us and will scrog registers on dpmi exec).
|
||||
mov ah, 0x30
|
||||
int 0x21
|
||||
cmp al, 3
|
||||
jae dos3ok
|
||||
mov al, 109
|
||||
mov dx, msg_bad_dos
|
||||
jmpl error
|
||||
dos3ok:
|
||||
mov [dos_major], al
|
||||
mov si, stubinfo_minkeep
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Resize memory in case we need to exec a DPMI server
|
||||
|
||||
resize_again:
|
||||
mov ax, [si] ; si=&stubinfo_minkeep
|
||||
or ax, ax
|
||||
jnz @f1
|
||||
; mov ax,0xfe00 ; 0 was probably 64k, so max it! (mod 512)
|
||||
mov ah,0xfe ; al already 0
|
||||
@f1:
|
||||
mov bx, end_of_memory ; does not include PSP
|
||||
cmp bx, ax ; is our program big enough to hold it?
|
||||
jae @f1
|
||||
mov bx, ax
|
||||
@f1:
|
||||
mov [si], bx ; si=&stubinfo_minkeep store for reference
|
||||
inc bh ; add 256 bytes for PSP
|
||||
mov cx, 0xff04 ; 0xff is for below
|
||||
shr bx, cl ; bytes to paragraphs
|
||||
|
||||
mov ah, 0x4a ; ES = PSP segment from above
|
||||
int 0x21 ; resize our memory block
|
||||
jnc @f1 ; did it work?
|
||||
shl bx,cl ; calculate smaller [keep] value
|
||||
dec bh
|
||||
mov [si], bx ; si=&stubinfo_minkeep
|
||||
jmp resize_again ; and try again
|
||||
@f1:
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Scan environment for "PATH=" and the stub's full name after environment
|
||||
|
||||
mov es, es:[0x2c] ; get environment segment
|
||||
xor di, di ; begin search for NUL/NUL (di = 0)
|
||||
; mov cx, 0xff04 ; effectively `infinite' loop
|
||||
xor al, al
|
||||
.db 0xa9 ; "test ax,...." -- skip 2 bytes
|
||||
scan_environment:
|
||||
repne
|
||||
scasb ; search for NUL
|
||||
cmpw es:[di], 0x4150 ; "PA"
|
||||
jne not_path
|
||||
scasw
|
||||
cmpw es:[di], 0x4854 ; "TH"
|
||||
jne not_path
|
||||
scasw
|
||||
cmpb es:[di], '='
|
||||
jne not_path
|
||||
inc di ; Point to PATH contents
|
||||
mov [path_off], di ; save for later
|
||||
dec di ; in case the PATH is empty
|
||||
not_path:
|
||||
scasb
|
||||
jne scan_environment ; no, still environment
|
||||
scasw ; adjust pointer to point to prog name
|
||||
|
||||
;; When we are spawned from a program which has more than 20 handles in use,
|
||||
;; all the handles passed to us by DOS are taken (since only the first 20
|
||||
;; handles are inherited), and opening the .exe file will fail.
|
||||
;; Therefore, we forcefully close handles 18 and 19, to make sure at least two
|
||||
;; handles are available.
|
||||
|
||||
mov ah, 0x3e
|
||||
mov bx, 19
|
||||
int 0x21 ; don't care about errors
|
||||
mov ah, 0x3e
|
||||
mov bx, 18
|
||||
int 0x21 ; don't care about errors
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Get DPMI information before doing anything 386-specific
|
||||
|
||||
push es
|
||||
push di
|
||||
xor cx, cx ; flag for load attempt set cx = 0
|
||||
jz @f2 ; We always jump, shorter than jmp
|
||||
@b1:
|
||||
mov al, 110
|
||||
mov dx, msg_no_dpmi
|
||||
jmpl error
|
||||
@b2:
|
||||
or cx, cx
|
||||
jnz @b1 ; we already tried load once before
|
||||
inc cx
|
||||
call load_dpmi
|
||||
jc @b1
|
||||
@f2:
|
||||
mov ax, 0x1687 ; get DPMI entry point
|
||||
int 0x2f
|
||||
or ax, ax
|
||||
jnz @b2 ; if 0 then it's there
|
||||
and bl, 1 ; 32 bit capable?
|
||||
jz @b2
|
||||
@f3:
|
||||
mov [modesw], di ; store the DPMI entry point
|
||||
mov [modesw+2], es
|
||||
mov [modesw_mem], si
|
||||
pop di
|
||||
pop es
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Now, find the name of the program file we are supposed to load.
|
||||
|
||||
; xor ah, ah ; termination character (set above!)
|
||||
call store_env_string ; copy it to loadname, set bx
|
||||
|
||||
mov [stubinfo_env_size], di
|
||||
mov [loadname_nul], si ; remember nul so we can change it to $
|
||||
cmpb stubinfo_basename[0], 0
|
||||
je no_symlink
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Replace the stub's file name with the link's name after the directory
|
||||
|
||||
mov cx, 8 ; max length of basename
|
||||
mov di, stubinfo_basename ; pointer to new basename
|
||||
@b1:
|
||||
mov al, [di] ; get next character
|
||||
inc di
|
||||
or al, al ; end of basename?
|
||||
je @f1
|
||||
mov [bx], al ; store character
|
||||
inc bx
|
||||
loop @b1 ; eight characters?
|
||||
@f1:
|
||||
movd [bx], 0x4558452e ; append ".EXE"
|
||||
add bx, 4
|
||||
movb [bx], 0 ; null terminate
|
||||
mov [loadname_nul], bx ; remember nul so we can change it to $
|
||||
|
||||
no_symlink:
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Load the COFF information from the file
|
||||
|
||||
mov ax, 0x3d00 ; open file for reading
|
||||
mov dx, loadname
|
||||
int 0x21
|
||||
jcl error_no_progfile ; do rest of error message
|
||||
|
||||
@f1:
|
||||
mov [program_file], ax ; store for future reference
|
||||
|
||||
mov bx, ax
|
||||
mov cx, exe_header_length
|
||||
mov dx, exe_header
|
||||
mov ah, 0x3f ; read EXE header
|
||||
int 0x21
|
||||
|
||||
xor dx, dx ; dx = 0
|
||||
xor cx, cx ; offset of COFF header
|
||||
|
||||
mov ax, [exe_magic]
|
||||
cmp ax, 0x014c ; COFF?
|
||||
je file_is_just_coff
|
||||
cmp ax, 0x5a4d ; EXE magic value
|
||||
jnel error_not_exe
|
||||
|
||||
mov dx, [exe_sectors]
|
||||
shl dx, 9 ; 512 bytes per sector
|
||||
mov bx, [exe_bytes_last_page]
|
||||
or bx, bx ; is bx = 0 ?
|
||||
je @f1
|
||||
sub dh, 2 ; dx -= 512
|
||||
add dx, bx
|
||||
@f1:
|
||||
|
||||
file_is_just_coff: ; cx:dx is offset
|
||||
mov coff_offset[0], dx
|
||||
mov coff_offset[2], cx
|
||||
mov ax, 0x4200 ; seek from beginning
|
||||
mov bx, [program_file]
|
||||
int 0x21
|
||||
|
||||
mov cx, coff_header_length
|
||||
mov dx, coff_header
|
||||
mov ah, 0x3f ; read file (bx = handle)
|
||||
int 0x21
|
||||
|
||||
cmp ax, coff_header_length
|
||||
jne @f2
|
||||
cmpw coff_header[coff_magic], 0x014c
|
||||
@f2:
|
||||
jnel error_not_coff
|
||||
|
||||
mov eax, aout_header[aout_entry]
|
||||
mov [start_eip], eax
|
||||
|
||||
mov ecx, [coff_offset]
|
||||
|
||||
mov eax, text_section[s_scnptr]
|
||||
add eax, ecx
|
||||
mov [text_foffset], eax
|
||||
|
||||
mov eax, data_section[s_scnptr]
|
||||
add eax, ecx
|
||||
mov [data_foffset], eax
|
||||
|
||||
mov ebx, bss_section[s_vaddr]
|
||||
mov eax, bss_section[s_size]
|
||||
add ebx, eax
|
||||
mov eax, 0x00010001
|
||||
cmp ebx, eax
|
||||
jae @f1
|
||||
mov ebx, eax ; ensure 32-bit segment
|
||||
@f1:
|
||||
add ebx, 0x0000ffff ; ensure 64K rounded
|
||||
xor bx, bx ; clear rounded bits
|
||||
mov [stubinfo_initial_size], ebx
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Set up for the DPMI environment
|
||||
|
||||
call include_umb
|
||||
mov bx, [modesw_mem]
|
||||
or bx, bx
|
||||
jz no_dos_alloc
|
||||
|
||||
mov ah, 0x48 ; allocate memory for the DPMI host
|
||||
int 0x21
|
||||
jcl error_no_dos_memory_umb
|
||||
mov es, ax
|
||||
|
||||
no_dos_alloc:
|
||||
call restore_umb
|
||||
mov ax, 1 ; indicates a 32-bit client
|
||||
callf [modesw] ; enter protected mode
|
||||
|
||||
jcl error_in_modesw
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; We're in protected mode at this point.
|
||||
|
||||
mov [stubinfo_psp_selector], es
|
||||
mov [stubinfo_cs_selector], cs
|
||||
mov ax, ds
|
||||
mov [stubinfo_ds_selector], ax
|
||||
mov es, ax
|
||||
|
||||
xor ax, ax ; AX = 0x0000
|
||||
mov cx, 1
|
||||
int 0x31 ; allocate LDT descriptor
|
||||
jc @f2
|
||||
mov [client_cs], ax
|
||||
|
||||
xor ax, ax ; AX = 0x0000
|
||||
; mov cx, 1 ; already set above
|
||||
int 0x31 ; allocate LDT descriptor
|
||||
@f2:
|
||||
jcl perror_no_selectors
|
||||
mov [client_ds], ax
|
||||
|
||||
; Try getting a DPMI 1.0 memory block first, then try DPMI 0.9
|
||||
; Note: This causes the Borland Windows VxD to puke, commented for now with ;*
|
||||
;* mov ax, 0x0504
|
||||
;* xor ebx, ebx ; don't specify linear address
|
||||
mov ecx, stubinfo_initial_size[0]
|
||||
;* mov edx, 1 ; allocate committed pages
|
||||
;* int 0x31 ; allocate memory block
|
||||
;* jc try_old_dpmi_alloc
|
||||
;* mov client_memory[0], ebx
|
||||
;* mov stubinfo_memory_handle[0], esi
|
||||
;* jmp got_dpmi_memory
|
||||
try_old_dpmi_alloc:
|
||||
mov ax, 0x0501
|
||||
mov bx, stubinfo_initial_size[2]
|
||||
; mov cx, stubinfo_initial_size[0] ;Set above
|
||||
int 0x31 ; allocate memory block
|
||||
jcl perror_no_dpmi_memory
|
||||
mov client_memory[2], bx
|
||||
mov client_memory[0], cx
|
||||
mov stubinfo_memory_handle[2], si
|
||||
mov stubinfo_memory_handle[0], di
|
||||
got_dpmi_memory:
|
||||
|
||||
mov ax, 0x0007
|
||||
mov bx, [client_cs] ; initialize client CS
|
||||
mov cx, client_memory[2]
|
||||
mov dx, client_memory[0]
|
||||
int 0x31 ; set segment base address
|
||||
|
||||
mov ax, 0x0009
|
||||
; mov bx, [client_cs] ; already set above
|
||||
mov cx, cs ; get CPL
|
||||
and cx, 0x0003
|
||||
shl cx, 5
|
||||
push cx ; save shifted CPL for below
|
||||
or cx, 0xc09b ; 32-bit, big, code, non-conforming, readable
|
||||
int 0x31 ; set descriptor access rights
|
||||
|
||||
mov ax, 0x0008
|
||||
; mov bx, [client_cs] ; already set above
|
||||
mov cx, stubinfo_initial_size[2]
|
||||
dec cx
|
||||
mov dx, 0xffff
|
||||
int 0x31 ; set segment limit
|
||||
|
||||
mov ax, 0x0007
|
||||
mov bx, [client_ds] ; initialize client DS
|
||||
mov cx, client_memory[2]
|
||||
mov dx, client_memory[0]
|
||||
int 0x31 ; set segment base address
|
||||
|
||||
mov ax, 0x0009
|
||||
; mov bx, [client_ds] ; already set above
|
||||
pop cx ; shifted CPL from above
|
||||
or cx, 0xc093 ; 32-bit, big, data, r/w, expand-up
|
||||
int 0x31 ; set descriptor access rights
|
||||
|
||||
mov ax, 0x0008
|
||||
; mov bx, [client_ds] ; already set above
|
||||
mov cx, stubinfo_initial_size[2]
|
||||
dec cx
|
||||
mov dx, 0xffff
|
||||
int 0x31 ; set segment limit
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Load the program data
|
||||
|
||||
mov ax, 0x0100
|
||||
mov bx, 0x0f00 ; 60K DOS block size
|
||||
int 0x31 ; allocate DOS memory
|
||||
jnc @f1
|
||||
cmp ax, 0x0008
|
||||
jnel perror_no_dos_memory
|
||||
mov ax, 0x0100 ; try again with new value in bx
|
||||
int 0x31 ; allocate DOS memory
|
||||
jcl perror_no_dos_memory
|
||||
@f1:
|
||||
mov [dos_block_seg], ax
|
||||
mov [dos_block_sel], dx
|
||||
shl bx, 4 ; paragraphs to bytes
|
||||
mov [dos_block_size], bx
|
||||
|
||||
mov esi, [text_foffset] ; load text section
|
||||
mov edi, text_section[s_vaddr]
|
||||
mov ecx, text_section[s_size]
|
||||
call read_section
|
||||
|
||||
mov esi, [data_foffset] ; load data section
|
||||
mov edi, data_section[s_vaddr]
|
||||
mov ecx, data_section[s_size]
|
||||
call read_section
|
||||
|
||||
mov es, [client_ds] ; clear the BSS section
|
||||
mov edi, bss_section[s_vaddr]
|
||||
mov ecx, bss_section[s_size]
|
||||
xor eax,eax
|
||||
shr ecx,2
|
||||
.addrsize
|
||||
rep
|
||||
stosd
|
||||
|
||||
mov ah,0x3e
|
||||
mov bx, [program_file]
|
||||
int 0x21 ; close the file
|
||||
|
||||
mov ax, 0x0101
|
||||
mov dx, [dos_block_sel]
|
||||
int 0x31 ; free up the DOS memory
|
||||
|
||||
push ds
|
||||
pop fs
|
||||
mov ds, [client_ds]
|
||||
.opsize
|
||||
jmpf fs:[start_eip] ; start program
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Read a section from the program file
|
||||
|
||||
read_section:
|
||||
mov eax, esi ; sector alignment by default
|
||||
and eax, 0x1ff
|
||||
add ecx, eax
|
||||
sub si, ax ; sector align disk offset (can't carry)
|
||||
sub edi, eax ; memory maybe not aligned!
|
||||
|
||||
mov [read_size], ecx ; store for later reference
|
||||
mov [read_soffset], edi
|
||||
|
||||
call zero_regs
|
||||
mov dpmi_regs[dr_dx], si ; store file offset
|
||||
shr esi, 16
|
||||
mov dpmi_regs[dr_cx], si
|
||||
mov bx, [program_file]
|
||||
mov dpmi_regs[dr_bx], bx
|
||||
movw dpmi_regs[dr_ax], 0x4200
|
||||
call pm_dos ; seek to start of data
|
||||
|
||||
; Note, handle set above
|
||||
mov ax, [dos_block_seg]
|
||||
mov dpmi_regs[dr_ds], ax
|
||||
movw dpmi_regs[dr_dx], 0 ; store file offset
|
||||
read_loop:
|
||||
movb dpmi_regs[dr_ah], 0x3f
|
||||
mov ax, read_size[2] ; see how many bytes to read
|
||||
or ax, ax
|
||||
jnz read_too_big
|
||||
mov ax, read_size[0]
|
||||
cmp ax, [dos_block_size]
|
||||
jna read_size_in_ax ; jna shorter than jmp
|
||||
read_too_big:
|
||||
mov ax, [dos_block_size]
|
||||
read_size_in_ax:
|
||||
mov dpmi_regs[dr_cx], ax
|
||||
call pm_dos ; read the next chunk of file data
|
||||
|
||||
xor ecx, ecx
|
||||
mov cx, dpmi_regs[dr_ax] ; get byte count
|
||||
mov edi, [read_soffset] ; adjust pointers
|
||||
add [read_soffset], ecx
|
||||
sub [read_size], ecx
|
||||
|
||||
xor esi, esi ; esi=0 offset for copy data
|
||||
shr cx, 2 ; ecx < 64K
|
||||
push ds
|
||||
push es
|
||||
mov es, [client_ds]
|
||||
mov ds, [dos_block_sel]
|
||||
.addrsize
|
||||
rep
|
||||
movsd
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
add ecx, [read_size] ; ecx zero from the rep movsd
|
||||
jnz read_loop
|
||||
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Routine to check al for delimiter
|
||||
|
||||
test_delim:
|
||||
cmp al, ':' ; watch for file name part
|
||||
je @f3
|
||||
cmp al, '/'
|
||||
je @f3
|
||||
cmp al, '\\'
|
||||
@f3:
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Copy string from environment to loadname.
|
||||
; On entry: di = environment offset
|
||||
; ah = termination character (null also does)
|
||||
; On exit: bx = pointer to one character after last observed file delimiter
|
||||
; di = pointer to one character after last copied
|
||||
; si = pointer to the copied termination character
|
||||
; al = terminating character
|
||||
|
||||
store_env_string:
|
||||
mov si, loadname ; pointer to buffer
|
||||
mov bx, si ; in case no delimiters
|
||||
@b1:
|
||||
mov al, es:[di] ; copy a character to buffer
|
||||
inc di
|
||||
mov [si], al
|
||||
cmp al, ah ; end of file name?
|
||||
je @f1
|
||||
or al, al ; end of file name?
|
||||
je @f1
|
||||
inc si
|
||||
call test_delim
|
||||
jne @b1
|
||||
mov bx, si ; remember pointer to first char of
|
||||
je @b1 ; next name component (shorter than jmp)
|
||||
@f1:
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Most errors come here, early ones jump direct (8088 instructions)
|
||||
|
||||
error_no_progfile:
|
||||
mov al, 102
|
||||
mov dx, msg_no_progfile
|
||||
jmp error_fn
|
||||
|
||||
error_not_exe:
|
||||
mov al, 103
|
||||
mov dx, msg_not_exe
|
||||
jmp error_fn
|
||||
|
||||
error_not_coff:
|
||||
mov al, 104
|
||||
mov dx, msg_not_coff
|
||||
; jmp error_fn
|
||||
|
||||
error_fn:
|
||||
push dx
|
||||
mov bx, [loadname_nul] ; error, print file name
|
||||
movb [bx], '$'
|
||||
mov bx, loadname
|
||||
jmp @f1
|
||||
|
||||
error_no_dos_memory_umb:
|
||||
call restore_umb
|
||||
error_no_dos_memory:
|
||||
mov al, 105
|
||||
mov dx, msg_no_dos_memory
|
||||
jmp error
|
||||
|
||||
error_in_modesw:
|
||||
mov al, 106
|
||||
mov dx, msg_error_in_modesw
|
||||
jmp error
|
||||
|
||||
perror_no_selectors:
|
||||
mov al, 107
|
||||
mov dx, msg_no_selectors
|
||||
jmp error
|
||||
|
||||
perror_no_dpmi_memory:
|
||||
mov al, 108
|
||||
mov dx, msg_no_dpmi_memory
|
||||
jmp error
|
||||
|
||||
perror_no_dos_memory:
|
||||
mov al, 105
|
||||
mov dx, msg_no_dos_memory
|
||||
; jmp error
|
||||
|
||||
error:
|
||||
push dx
|
||||
mov bx, err_string
|
||||
@f1:
|
||||
call printstr
|
||||
pop bx
|
||||
call printstr
|
||||
exit:
|
||||
mov bx, crlfdollar
|
||||
call printstr
|
||||
mov ah, 0x4c ; error exit - exit code is in al
|
||||
int 0x21
|
||||
|
||||
printstr1:
|
||||
inc bx
|
||||
push ax ; have to preserve al set by error call
|
||||
mov ah, 2
|
||||
int 0x21
|
||||
pop ax ; restore ax (John A.)
|
||||
printstr:
|
||||
mov dl, [bx]
|
||||
cmp dl, '$'
|
||||
jne printstr1
|
||||
ret
|
||||
|
||||
crlfdollar:
|
||||
.db 13,10,'$'
|
||||
;-----------------------------------------------------------------------------
|
||||
; DPMI utility functions
|
||||
|
||||
zero_regs:
|
||||
push ax
|
||||
push cx
|
||||
push di
|
||||
xor ax, ax
|
||||
mov di, dpmi_regs
|
||||
mov cx, 0x19
|
||||
rep
|
||||
stosw
|
||||
pop di
|
||||
pop cx
|
||||
pop ax
|
||||
ret
|
||||
|
||||
pm_dos:
|
||||
mov ax, 0x0300 ; simulate interrupt
|
||||
mov bx, 0x0021 ; int 21, no flags
|
||||
xor cx, cx ; cx = 0x0000 (copy no args)
|
||||
mov edi, dpmi_regs
|
||||
int 0x31
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; load DPMI server if not present
|
||||
; First check directory from which stub is loaded, then path, then default
|
||||
; On entry di points to image name
|
||||
|
||||
path_off:
|
||||
.dw 0 ; If stays zero, no path
|
||||
|
||||
load_dpmi:
|
||||
xor ah, ah ; Copy until this character (=0)
|
||||
call store_env_string ; copy stub image to "loadname"
|
||||
mov si, bx ; remove name so we can add DPMI name
|
||||
mov di, [path_off] ; Pointer to path contents (next try)
|
||||
jmp @f2
|
||||
loadloop:
|
||||
mov ah, ';' ; Copy until this character
|
||||
call store_env_string ; to "loadname"
|
||||
cmp si, loadname ; anything there?
|
||||
je do_exec ; final try (no path) let it return
|
||||
mov al, [si-1]
|
||||
call test_delim ; is final character a path delimiter
|
||||
je @f2
|
||||
movb [si], '\\' ; no, add separator between path & name
|
||||
inc si
|
||||
@f2:
|
||||
call do_exec ; copy our name to string and try load
|
||||
jc loadloop
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; add the string CWSDPMI to path ending
|
||||
|
||||
do_exec:
|
||||
call include_umb
|
||||
mov bx, stubinfo_dpmi_server
|
||||
@b1:
|
||||
mov al, [bx]
|
||||
mov [si], al
|
||||
inc bx
|
||||
inc si
|
||||
or al, al
|
||||
jne @b1
|
||||
; movw [si], 0x0a0d ;debug
|
||||
; movb [si+2], '$' ;debug
|
||||
|
||||
push es ; Save in case of failure
|
||||
push di
|
||||
|
||||
;memory saving - use dpmi_regs as a temporary parameter block
|
||||
push ds
|
||||
pop es ;zero_regs needs es set
|
||||
call zero_regs
|
||||
mov bx, dpmi_regs
|
||||
mov [bx+4], ds ;segment of command tail
|
||||
mov [bx+2], bx ;offset (point to zero)
|
||||
|
||||
mov dx, loadname
|
||||
; mov ah, 9 ;debug
|
||||
; int 0x21 ;debug
|
||||
mov ax, 0x4b00 ;Do program exec
|
||||
int 0x21
|
||||
pop di
|
||||
pop es
|
||||
jc @f1 ;carry set if exec failed
|
||||
|
||||
mov ah, 0x4d ;get return code
|
||||
int 0x21
|
||||
sub ax, 0x300 ;ah=3 TSR, al=code (success)
|
||||
neg ax ;CY, if not originally 0x300
|
||||
@f1:
|
||||
jmp restore_umb ;called func. return for us.
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Make upper memory allocatable. Clobbers Ax and Bx.
|
||||
|
||||
include_umb:
|
||||
cmpb [dos_major], 5 ; Won't work before dos 5
|
||||
jb @f1
|
||||
mov ax, 0x5800 ; get allocation strategy
|
||||
int 0x21
|
||||
mov [old_strategy],al
|
||||
mov ax, 0x5802 ; Get UMB status.
|
||||
int 0x21
|
||||
mov [old_umb],al
|
||||
mov ax, 0x5801
|
||||
mov bx, 0x0080 ; first fit, first high then low
|
||||
int 0x21
|
||||
mov ax, 0x5803
|
||||
mov bx, 0x0001 ; include UMB in memory chain
|
||||
int 0x21
|
||||
@f1:
|
||||
ret
|
||||
|
||||
; Restore upper memory status. All registers and flags preserved.
|
||||
|
||||
restore_umb:
|
||||
pushf
|
||||
cmpb [dos_major], 5 ; Won't work before dos 5
|
||||
jb @f1
|
||||
push ax
|
||||
push bx
|
||||
mov ax, 0x5803 ; restore UMB status.
|
||||
mov bl,[old_umb]
|
||||
xor bh, bh
|
||||
int 0x21
|
||||
mov ax, 0x5801 ; restore allocation strategy
|
||||
mov bl,[old_strategy]
|
||||
xor bh, bh
|
||||
int 0x21
|
||||
pop bx
|
||||
pop ax
|
||||
@f1:
|
||||
popf
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Stored Data
|
||||
err_string:
|
||||
.db "Load error: $"
|
||||
msg_no_progfile:
|
||||
.db ": can't open$"
|
||||
msg_not_exe:
|
||||
.db ": not EXE$"
|
||||
msg_not_coff:
|
||||
.db ": not COFF (Check for viruses)$"
|
||||
msg_no_dpmi:
|
||||
.db "no DPMI - Get csdpmi*b.zip$"
|
||||
msg_no_dos_memory:
|
||||
.db "no DOS memory$"
|
||||
msg_bad_dos:
|
||||
.db "need DOS 3$"
|
||||
msg_error_in_modesw:
|
||||
.db "can't switch mode$"
|
||||
msg_no_selectors:
|
||||
.db "no DPMI selectors$"
|
||||
msg_no_dpmi_memory:
|
||||
.db "no DPMI memory$"
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Unstored Data, available during and after mode switch
|
||||
|
||||
last_generated_byte:
|
||||
|
||||
.align 512 ; Align ourselves to a sector
|
||||
; boundary for startup speed.
|
||||
.bss ; data after this isn't in file.
|
||||
|
||||
modesw: ; address of DPMI mode switch
|
||||
.dd 0
|
||||
modesw_mem: ; amount of memory DPMI needs
|
||||
.dw 0
|
||||
|
||||
program_file: ; file ID of program data
|
||||
.dw 0
|
||||
|
||||
text_foffset: ; offset in file
|
||||
.dd 0
|
||||
|
||||
data_foffset: ; offset in file
|
||||
.dd 0
|
||||
|
||||
start_eip: ; EIP value to start at
|
||||
.dd 0
|
||||
client_cs: ; must follow start_eip
|
||||
.dw 0
|
||||
client_ds:
|
||||
.dw 0
|
||||
|
||||
client_memory:
|
||||
.dd 0
|
||||
|
||||
dos_block_seg:
|
||||
.dw 0
|
||||
dos_block_sel:
|
||||
.dw 0
|
||||
dos_block_size:
|
||||
.dw 0
|
||||
|
||||
read_soffset:
|
||||
.dd 0
|
||||
read_size:
|
||||
.dd 0
|
||||
|
||||
dpmi_regs:
|
||||
.db 0x32 .dup 0
|
||||
dr_edi = 0x00
|
||||
dr_di = 0x00
|
||||
dr_esi = 0x04
|
||||
dr_si = 0x04
|
||||
dr_ebp = 0x08
|
||||
dr_bp = 0x08
|
||||
dr_ebx = 0x10
|
||||
dr_bx = 0x10
|
||||
dr_bl = 0x10
|
||||
dr_bh = 0x11
|
||||
dr_edx = 0x14
|
||||
dr_dx = 0x14
|
||||
dr_dl = 0x14
|
||||
dr_dh = 0x15
|
||||
dr_ecx = 0x18
|
||||
dr_cx = 0x18
|
||||
dr_cl = 0x18
|
||||
dr_ch = 0x19
|
||||
dr_eax = 0x1c
|
||||
dr_ax = 0x1c
|
||||
dr_al = 0x1c
|
||||
dr_ah = 0x1d
|
||||
dr_efl = 0x20
|
||||
dr_es = 0x22
|
||||
dr_ds = 0x24
|
||||
dr_fs = 0x26
|
||||
dr_gs = 0x28
|
||||
dr_ip = 0x2a
|
||||
dr_cs = 0x2c
|
||||
dr_sp = 0x2e
|
||||
dr_ss = 0x30
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
.align 16 ; so that stack ends on para boundary
|
||||
.dw 128 .dup 0
|
||||
.stack
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; At one time real mode only data. Header stuff now used during image load.
|
||||
|
||||
psp_segment:
|
||||
.dw 0
|
||||
|
||||
loadname_nul: ; offset of NUL so it can become '$'
|
||||
.dw 0
|
||||
loadname: ; name of program file to load, if it
|
||||
.db 81 .dup 0 ; gets really long ok to overwrite next
|
||||
|
||||
exe_header: ; loaded from front of loadfile
|
||||
exe_magic:
|
||||
.dw 0
|
||||
exe_bytes_last_page:
|
||||
.dw 0
|
||||
exe_sectors:
|
||||
.dw 0
|
||||
exe_header_length = . - exe_header
|
||||
|
||||
coff_offset:
|
||||
.dd 0 ; from start of file
|
||||
|
||||
coff_header: ; loaded from after stub
|
||||
.db 20 .dup 0
|
||||
aout_header:
|
||||
.db 28 .dup 0
|
||||
text_section:
|
||||
.db 40 .dup 0
|
||||
data_section:
|
||||
.db 40 .dup 0
|
||||
bss_section:
|
||||
.db 40 .dup 0
|
||||
coff_header_length = . - coff_header
|
||||
|
||||
old_strategy:
|
||||
.db 0
|
||||
old_umb:
|
||||
.db 0
|
||||
|
||||
dos_major:
|
||||
.db 0
|
||||
|
||||
.align 16 ; Align ourselves to a paragraph
|
||||
end_of_memory: ; resize is done early so must keep all
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; structure definitions
|
||||
;
|
||||
|
||||
coff_magic = 0 ; from coff header
|
||||
|
||||
aout_entry = 16 ; from aout header
|
||||
|
||||
s_paddr = 8 ; from section headers
|
||||
s_vaddr = 12
|
||||
s_size = 16
|
||||
s_scnptr = 20
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# Makefile for sstrip
|
||||
|
||||
sstrip: sstrip.c
|
||||
gcc -ggdb -Wall -W -o sstrip sstrip.c
|
||||
|
||||
clean:
|
||||
rm -f sstrip
|
||||
@@ -0,0 +1,40 @@
|
||||
sstrip is a small utility that removes the contents at the end of an
|
||||
ELF file that are not part of the program's memory image.
|
||||
|
||||
Most ELF executables are built with both a program header table and a
|
||||
section header table. However, only the former is required in order
|
||||
for the OS to load, link and execute a program. sstrip attempts to
|
||||
extract the ELF header, the program header table, and its contents,
|
||||
leaving everything else in the bit bucket. It can only remove parts of
|
||||
the file that occur at the end, after the parts to be saved. However,
|
||||
this almost always includes the section header table, and occasionally
|
||||
a few random sections that are not used when running a program.
|
||||
|
||||
It should be noted that the GNU bfd library is (understandably)
|
||||
dependent on the section header table as an index to the file's
|
||||
contents. Thus, an executable file that has no section header table
|
||||
cannot be used with gdb, objdump, or any other program based upon the
|
||||
bfd library, at all. In fact, the program will not even recognize the
|
||||
file as a valid executable. (This limitation is noted in the source
|
||||
code comments for bfd, and is marked "FIXME", so this may change at
|
||||
some future date. However, I would imagine that it is a pretty
|
||||
low-priority item, as executables without a section header table are
|
||||
rare in the extreme.) This probably also explains why strip doesn't
|
||||
offer the option to do this.
|
||||
|
||||
Shared library files may also have their section header table removed.
|
||||
Such a library will still function; however, it will no longer be
|
||||
possible for a compiler to link a new program against it.
|
||||
|
||||
As an added bonus, sstrip also tries to removes trailing zero bytes
|
||||
from the end of the file. (This normally cannot be done with an
|
||||
executable that has a section header table.)
|
||||
|
||||
sstrip is a very simplistic program. It depends upon the common
|
||||
practice of putting the parts of the file that contribute to the
|
||||
memory image at the front, and the remaining material at the end. This
|
||||
permits it to discard the latter material without affecting file
|
||||
offsets and memory addresses in what remains. However, the ELF
|
||||
standard permits files to be organized in almost any order. So
|
||||
although this procedure usually works in practice, it is not meant to
|
||||
be taken too seriously.
|
||||
@@ -0,0 +1,70 @@
|
||||
This distribution is a collection of programs that are generally
|
||||
unrelated, except in that they all deal with the ELF file format.
|
||||
|
||||
The main purpose of these programs is to be illustrative and
|
||||
educational -- to help fellow programmers understand the ELF file
|
||||
format and something of how it works under the Linux platform. For the
|
||||
most part, these programs have limited real-world utility. (Although I
|
||||
myself have found these programs quite useful while writing the
|
||||
others.)
|
||||
|
||||
Each program is independent. There is no shared code between them, and
|
||||
in fact they all take slightly different approaches to handling ELF
|
||||
files.
|
||||
|
||||
The table of contents:
|
||||
|
||||
sstrip/
|
||||
sstrip is a small utility that removes everything from an ELF file
|
||||
that is not part of the file's memory image.
|
||||
|
||||
elfls/
|
||||
elfls is a utility that displays an ELF file's program and/or
|
||||
section header tables, which serve as a kind of global roadmap to
|
||||
the file's contents.
|
||||
|
||||
elftoc/
|
||||
elftoc takes an ELF file and generates C code that defines a
|
||||
structure with the same memory image, using the structures and
|
||||
preprocessor symbols defined in <linux/elf.h>.
|
||||
|
||||
ebfc/
|
||||
ebfc is a compiler for a tiny programming language. The compiler can
|
||||
generate ELF executables, object files, and shared libraries.
|
||||
|
||||
tiny/
|
||||
This directory contains a collection of very small ELF executables.
|
||||
|
||||
See the README in each directory for more details.
|
||||
|
||||
The ELF standard is necessary reading if you wish to fully understand
|
||||
how these programs work. You can download a copy as a Postscript
|
||||
document from ftp://tsx.mit.edu/pub/linux/packages/GCC/ELF.doc.tar.gz.
|
||||
Alternately, you can obtain a flat-text transcription of this document
|
||||
from http://www.muppetlabs.com/~breadbox/software/ELF.txt.
|
||||
|
||||
All these programs are Copyright (C) 1999 by Brian Raiter.
|
||||
|
||||
These programs are all free software; you can redistribute 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.
|
||||
|
||||
These programs are distributed in the hope that they will be
|
||||
interesting, 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, in the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA.
|
||||
|
||||
Bug reports and general feedback should be directed to the author at
|
||||
breadbox@muppetlabs.com.
|
||||
|
||||
Share and enjoy.
|
||||
|
||||
Brian Raiter
|
||||
breadbox@muppetlabs.com
|
||||
July, 1999
|
||||
@@ -0,0 +1,218 @@
|
||||
/* sstrip, version 1.0: Copyright (C) 1999 by Brian Raiter, under the
|
||||
* GNU General Public License. No warranty. See COPYING for details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/elf.h>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* The memory-allocation macro.
|
||||
*/
|
||||
#define alloc(p, n) (((p) = realloc(p, n)) \
|
||||
|| (fputs("Out of memory.\n", stderr), \
|
||||
exit(EXIT_FAILURE), 0))
|
||||
|
||||
static char const *thefilename; /* the current file name */
|
||||
static FILE *thefile; /* the current file handle */
|
||||
|
||||
static Elf32_Ehdr elfhdr; /* original ELF header */
|
||||
static Elf32_Phdr *phdrs = NULL; /* original program header tbl */
|
||||
static unsigned long phdrsize; /* size of program header tbl */
|
||||
static unsigned long newsize; /* size of the new file */
|
||||
|
||||
/* An error-handling function. The given error message is used only
|
||||
* when errno is not set.
|
||||
*/
|
||||
static int err(char const *errmsg)
|
||||
{
|
||||
if (errno)
|
||||
perror(thefilename);
|
||||
else
|
||||
fprintf(stderr, "%s: %s\n", thefilename, errmsg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* readheaders() reads the ELF header and the program header table,
|
||||
* and checks to make sure that this is in fact a file that we should
|
||||
* be munging.
|
||||
*/
|
||||
static int readheaders(void)
|
||||
{
|
||||
int bigend;
|
||||
|
||||
errno = 0;
|
||||
if (fread(&elfhdr, sizeof elfhdr, 1, thefile) != 1)
|
||||
return err("not an ELF file.");
|
||||
if (elfhdr.e_ident[EI_MAG0] != ELFMAG0
|
||||
|| elfhdr.e_ident[EI_MAG1] != ELFMAG1
|
||||
|| elfhdr.e_ident[EI_MAG2] != ELFMAG2
|
||||
|| elfhdr.e_ident[EI_MAG3] != ELFMAG3)
|
||||
return err("not an ELF file.");
|
||||
|
||||
bigend = TRUE;
|
||||
*(char*)&bigend = 0;
|
||||
if (elfhdr.e_ident[EI_DATA] != (bigend ? ELFDATA2MSB : ELFDATA2LSB)) {
|
||||
fprintf(stderr, "%s: not %s-endian.\n",
|
||||
thefilename, bigend ? "big" : "little");
|
||||
return FALSE;
|
||||
}
|
||||
if (elfhdr.e_ehsize != sizeof(Elf32_Ehdr)) {
|
||||
fprintf(stderr, "%s: unrecognized ELF header size "
|
||||
"(size = %u instead of %u).\n",
|
||||
thefilename, elfhdr.e_ehsize, sizeof(Elf32_Ehdr));
|
||||
return FALSE;
|
||||
}
|
||||
if (!elfhdr.e_phoff)
|
||||
return err("no program header table.");
|
||||
if (elfhdr.e_phentsize != sizeof(Elf32_Phdr)) {
|
||||
fprintf(stderr, "%s: unrecognized program header size "
|
||||
"(size = %u instead of %u).\n",
|
||||
thefilename, elfhdr.e_phentsize, sizeof(Elf32_Ehdr));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
phdrsize = elfhdr.e_phnum * elfhdr.e_phentsize;
|
||||
alloc(phdrs, phdrsize);
|
||||
errno = 0;
|
||||
if (fread(phdrs, phdrsize, 1, thefile) != 1)
|
||||
return err("invalid program header table.");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* getloadsize() determines the offset of the last byte of the file
|
||||
* that is actually loaded into memory. Anything after this point can
|
||||
* be safely discarded.
|
||||
*/
|
||||
static int getloadsize(void)
|
||||
{
|
||||
Elf32_Phdr *phdr;
|
||||
unsigned long n;
|
||||
int i;
|
||||
|
||||
newsize = elfhdr.e_phoff + phdrsize;
|
||||
phdr = phdrs;
|
||||
for (i = 0 ; i < elfhdr.e_phnum ; ++i) {
|
||||
if (phdr->p_type == PT_NULL || phdr->p_type == PT_NOTE)
|
||||
continue;
|
||||
n = phdr->p_offset + phdr->p_filesz;
|
||||
if (n > newsize)
|
||||
newsize = n;
|
||||
phdr = (Elf32_Phdr*)((char*)phdr + elfhdr.e_phentsize);
|
||||
}
|
||||
|
||||
for (i = 0 ; i < elfhdr.e_phnum ; ++i)
|
||||
if (phdr->p_filesz > 0 && phdr->p_offset >= newsize)
|
||||
memset(phdr, 0, elfhdr.e_phentsize);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* truncatezeros() examines the bytes at the end of the file's
|
||||
* size-to-be, and reduces the size to exclude trailing zero bytes.
|
||||
*/
|
||||
static int truncatezeros(void)
|
||||
{
|
||||
char contents[1024];
|
||||
unsigned long n;
|
||||
|
||||
do {
|
||||
n = sizeof contents;
|
||||
if (n > newsize)
|
||||
n = newsize;
|
||||
if (fseek(thefile, newsize - n, SEEK_SET)
|
||||
|| fread(contents, n, 1, thefile) != 1)
|
||||
return err("cannot read file contents");
|
||||
while (n && !contents[--n])
|
||||
--newsize;
|
||||
} while (newsize && !n);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* modifyheaders() removes references to the section header table if
|
||||
* it was removed, and reduces program header table entries that
|
||||
* included truncated bytes at the end of the file.
|
||||
*/
|
||||
static int modifyheaders(void)
|
||||
{
|
||||
Elf32_Phdr *phdr;
|
||||
int i;
|
||||
|
||||
if (elfhdr.e_shoff >= newsize) {
|
||||
elfhdr.e_shoff = 0;
|
||||
elfhdr.e_shnum = 0;
|
||||
elfhdr.e_shentsize = 0;
|
||||
elfhdr.e_shstrndx = 0;
|
||||
}
|
||||
|
||||
phdr = phdrs;
|
||||
for (i = 0 ; i < elfhdr.e_phnum ; ++i) {
|
||||
if (phdr->p_offset + phdr->p_filesz > newsize) {
|
||||
if (phdr->p_offset >= newsize)
|
||||
phdr->p_filesz = 0;
|
||||
else
|
||||
phdr->p_filesz = newsize - phdr->p_offset;
|
||||
}
|
||||
phdr = (Elf32_Phdr*)((char*)phdr + elfhdr.e_phentsize);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* savestripped() writes the new headers back to the original file
|
||||
* and sets the new file size.
|
||||
*/
|
||||
static int savestripped(void)
|
||||
{
|
||||
rewind(thefile);
|
||||
|
||||
errno = 0;
|
||||
if (fwrite(&elfhdr, sizeof elfhdr, 1, thefile) != 1
|
||||
|| fwrite(phdrs, phdrsize, 1, thefile) != 1
|
||||
|| ftruncate(fileno(thefile), newsize)) {
|
||||
err("could not write contents");
|
||||
fprintf(stderr, "WARNING: %s may be corrupted!\n", thefilename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* main() loops over the cmdline arguments, leaving all the real work
|
||||
* to the other functions.
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char **arg;
|
||||
int ret = 0;
|
||||
|
||||
if (argc < 2 || !strcmp(argv[1], "-h")) {
|
||||
printf("sstrip, version 2.0: Copyright (C) 1999 Brian Raiter\n"
|
||||
"Usage: sstrip FILE...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (arg = argv + 1 ; (thefilename = *arg) != NULL ; ++arg) {
|
||||
if (!(thefile = fopen(thefilename, "rb+"))) {
|
||||
err("unable to open.");
|
||||
++ret;
|
||||
continue;
|
||||
}
|
||||
if (!readheaders() || !getloadsize() || !truncatezeros()
|
||||
|| !modifyheaders() || !savestripped())
|
||||
++ret;
|
||||
fclose(thefile);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user