Initial commit (from git)

This commit is contained in:
convert-repo
2000-05-19 16:04:55 +00:00
commit 1a9128a473
130 changed files with 31392 additions and 0 deletions
+322
View File
@@ -0,0 +1,322 @@
#
# UPX stub Makefile (GNU make)
#
ifeq ($(strip $(UCLDIR)),)
# change this to reflect where the UCL library is
UCLDIR = $(HOME)/local/src/ucl-0.91
endif
# -------------------------------------------------------
# You should not have to change anything below this line.
# -------------------------------------------------------
SHELL = /bin/sh
top_srcdir = ../..
# These are the files we want to create.
STUBS = \
l_com.h \
l_djgpp2.h stubify.h \
l_exe.h \
l_sys.h \
l_t_n2b.h l_t_n2bs.h l_t_n2d.h l_t_n2ds.h \
l_tmt.h \
l_wcle.h \
l_w32pe.h \
l_lx_n2b.h l_lx_n2d.h \
l_le_n2b.h l_le_n2d.h \
l_sh_n2b.h l_sh_n2d.h
# util var for use in the rules - basename of the current target
override T = $(basename $@)
# /***********************************************************************
# // source directories
# ************************************************************************/
UCL_UPX = $(UCLDIR)/upx
UCL_I386 = $(UCLDIR)/upx/i386
UCL_M68K = $(UCLDIR)/upx/m68k
.SUFFIXES:
.SUFFIXES: .asm .ash .asx .asy .bin .c .h .s
vpath %.ash $(UCL_I386)
vpath %.ash $(UCL_M68K)
# /***********************************************************************
# // tools
# ************************************************************************/
NASM = nasm -w+macro-params -w+orphan-labels
APP = perl -w scripts/app.pl
BIN2H = perl -w scripts/bin2h.pl
BRANDELF = perl -w scripts/brandelf.pl
O2BIN = perl -w scripts/o2bin.pl
SETFOLD = perl -w scripts/setfold.pl
##STRIPELF = perl -w scripts/stripelf.pl
STRIPELF = ./util/sstrip/sstrip
# Preprocessor for a68k assembler.
CPP_M68K = gcc -I$(UCL_UPX) -E -x assembler-with-cpp -Wall -Wp,-P,-C,-traditional
# Use gcc 2.95.2 for smallest code.
CC_LINUX_CFLAGS = -Wall -W -Wcast-align -Wcast-qual -Wwrite-strings
CC_LINUX_CFLAGS += -funsigned-char
###CC_LINUX_CFLAGS += -fwritable-strings -save-temps
CC_LINUX = gcc272 -O2 -m386 -malign-functions=0 -malign-jumps=0 -malign-loops=0 $(CC_LINUX_CFLAGS)
CC_LINUX = gcc -Os -march=i386 -mcpu=i386 -malign-functions=0 -malign-jumps=0 -malign-loops=0 $(CC_LINUX_CFLAGS)
# Specifying -mcpu=i586 inhibits use of 'leave', which costs 2 bytes per subr
#CC_LINUX =gcc -Os -march=i386 -mcpu=i586 -malign-functions=0 -malign-jumps=0 -malign-loops=0 $(CC_LINUX_CFLAGS)
# /***********************************************************************
# // main targets
# ************************************************************************/
.PHONY: default all stubs mostlyclean clean distclean maintainer-clean ident strings
default:
@echo "UPX info: type 'make all' if you have all the needed build tools."
all: stubs upxb upxd
stubs: $(STUBS)
mostlyclean:
-rm -f *~ *.bin *.bkp *.i *.lst *.map
clean: mostlyclean
-rm -f *.o *.asx *.asy upxb upxd
distclean: clean
# This command is intended for maintainers to use; it deletes files
# that may require special tools to rebuild.
maintainer-clean: distclean
-rm -f $(STUBS)
ident: all
ident *.bin
strings: all
strings *.bin
# /***********************************************************************
# // rules
# ************************************************************************/
.asm.asx:
$(APP) $< $@
.ash.asy:
$(APP) $< $@
stubify.h: stub.asm
djasm $< $@
l_com.h: l_com.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv2b_loader $@
l_djgpp2.h: l_djgpp2.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_exe.h: l_exe.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_sys.h: l_sys.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv2b_loader $@
l_tmt.h: l_tmt.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_t_n2b.h: l_tos.s
$(CPP_M68K) -D__A68K__ -DNRV2B -o $T.i $<
a68k -q -x $T.i
$(O2BIN) $T.o $T.bin 'UPX1' 'UPX9'
$(BIN2H) $T.bin nrv2b_loader $@
l_t_n2bs.h: l_tos.s
$(CPP_M68K) -D__A68K__ -DNRV2B -DSMALL -o $T.i $<
a68k -q -x $T.i
$(O2BIN) $T.o $T.bin 'UPX1' 'UPX9'
$(BIN2H) $T.bin nrv2b_loader_small $@
l_t_n2d.h: l_tos.s
$(CPP_M68K) -D__A68K__ -DNRV2D -o $T.i $<
a68k -q -x $T.i
$(O2BIN) $T.o $T.bin 'UPX1' 'UPX9'
$(BIN2H) $T.bin nrv2d_loader $@
l_t_n2ds.h: l_tos.s
$(CPP_M68K) -D__A68K__ -DNRV2D -DSMALL -o $T.i $<
a68k -q -x $T.i
$(O2BIN) $T.o $T.bin 'UPX1' 'UPX9'
$(BIN2H) $T.bin nrv2d_loader_small $@
l_vxd.h: l_vxd.asm
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_wcle.h: l_wcle.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_w32pe.h: l_w32pe.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
# /***********************************************************************
# // linux rules (exec, elf, sh, sep)
# ************************************************************************/
l_lx_n2b.h: l_lx_exec.c l_xe_n2b.o
$(CC_LINUX) -DNRV2B -s -o $T.o -c $<
ld -s -Map l_lx_n2b.map -o $T.bin \
l_xe_n2b.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386exec_nrv2b_loader $@
l_le_n2b.h: l_lx_elf.c l_6e_n2b.o l_lx_elf86.lds
$(CC_LINUX) -DNRV2B -s -o $T.o -c $<
ld -T l_lx_elf86.lds -s -Map $T.map -o $T.bin \
l_6e_n2b.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(SETFOLD) $T.bin 0x`nm l_6e_n2b.o | grep fold_begin`
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386elf_nrv2b_loader $@
l_sh_n2b.h: l_lx_sh.c l_6h_n2b.o l_lx_sh86.lds
$(CC_LINUX) -DNRV2B -s -o $T.o -c $<
ld -T l_lx_sh86.lds -s -Map $T.map -o $T.bin \
l_6h_n2b.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(SETFOLD) $T.bin 0x`nm l_6h_n2b.o | grep fold_begin`
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386sh_nrv2b_loader $@
l_xe_n2b.o: l_lx_exec86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o $@ $<
l_6e_n2b.o: l_lx_elf86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o $@ $<
l_6h_n2b.o: l_lx_sh86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o $@ $<
l_lx_n2d.h: l_lx_exec.c l_xe_n2d.o
$(CC_LINUX) -DNRV2D -s -o $T.o -c $<
ld -s -Map $T.map -o $T.bin \
l_xe_n2d.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386exec_nrv2d_loader $@
l_le_n2d.h: l_lx_elf.c l_6e_n2d.o l_lx_elf86.lds
$(CC_LINUX) -DNRV2D -s -o $T.o -c $<
ld -T l_lx_elf86.lds -s -Map $T.map -o $T.bin \
l_6e_n2d.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(SETFOLD) $T.bin 0x`nm l_6e_n2d.o | grep fold_begin`
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386elf_nrv2d_loader $@
l_sh_n2d.h: l_lx_sh.c l_6h_n2d.o l_lx_sh86.lds
$(CC_LINUX) -DNRV2D -s -o $T.o -c $<
ld -T l_lx_sh86.lds -s -Map $T.map -o $T.bin \
l_6h_n2d.o $T.o
objcopy -S -R .comment -R .note $T.bin
$(SETFOLD) $T.bin 0x`nm l_6h_n2d.o | grep fold_begin`
$(STRIPELF) $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386sh_nrv2d_loader $@
l_xe_n2d.o: l_lx_exec86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o $@ $<
l_6e_n2d.o: l_lx_elf86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o $@ $<
l_6h_n2d.o: l_lx_sh86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o $@ $<
l_lx_sep.o: l_lx_sep.c
$(CC_LINUX) -c $<
upxb: l_lx_sep.o l_lx_sep86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o upxb.o l_lx_sep86.asm
ld -T l_lx_sep86.lds -Map upxb.map -o upxb upxb.o l_lx_sep.o
objcopy -S -R .comment -R .note upxb
$(STRIPELF) upxb
$(BRANDELF) upxb
upxd: l_lx_sep.o l_lx_sep86.asm
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o upxd.o l_lx_sep86.asm
ld -T l_lx_sep86.lds -Map upxd.map -o upxd upxd.o l_lx_sep.o
objcopy -S -R .comment -R .note upxd
$(STRIPELF) upxd
$(BRANDELF) upxd
# /***********************************************************************
# // dependencies
# ************************************************************************/
DEPS1 = header.ash macros.ash ident.ash ident_n.ash ident_s.ash
DEPS2 = header.asy macros.asy
l_com.h: n2b_d16.asy $(DEPS2)
l_djgpp2.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_exe.h: n2b_d8e.asy n2d_d8e.asy $(DEPS2)
l_sys.h: n2b_d16.asy $(DEPS2)
l_t_n2b.h: n2b_d.ash bits.ash $(DEPS1)
l_t_n2bs.h: n2b_d.ash bits.ash $(DEPS1)
l_t_n2d.h: n2d_d.ash bits.ash $(DEPS1)
l_t_n2ds.h: n2d_d.ash bits.ash $(DEPS1)
l_tmt.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_vxd.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_wcle.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_w32pe.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_xe_n2b.o: n2b_d32.ash $(DEPS1)
l_6e_n2b.o: n2b_d32.ash $(DEPS1)
l_6h_n2b.o: n2b_d32.ash $(DEPS1)
l_xe_n2d.o: n2d_d32.ash $(DEPS1)
l_6e_n2d.o: n2d_d32.ash $(DEPS1)
l_6h_n2d.o: n2d_d32.ash $(DEPS1)
l_lx_n2b.h: linux.hh
l_lx_n2d.h: linux.hh
l_le_n2b.h: linux.hh
l_le_n2d.h: linux.hh
l_sh_n2b.h: linux.hh
l_sh_n2d.h: linux.hh
upxb: linux.hh
upxd: linux.hh
.NOEXPORT:
# vi:nowrap
+60
View File
@@ -0,0 +1,60 @@
; header.ash --
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; UPX and the UCL library are free software; you can redistribute them
; and/or modify them under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; see the file COPYING.
; If not, write to the Free Software Foundation, Inc.,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
; Markus F.X.J. Oberhumer Laszlo Molnar
; markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; ------------- HEADER ------------- ; __UPX1HEAD__
db 'UPX!' ; 0 magic
db 0 ; 4 version
db 0 ; 5 type (com,sys,...)
db 0 ; 6 compression method
db 0 ; 7 compression level
dd 0 ; 8 uncompressed adler32
dd 0 ; 12 compressed adler32
%ifdef COM
dw 0 ; 16 uncompressed len
dw 0 ; 18 compressed len
db 0 ; 20 filter
db 0 ; 21 header checksum
%elifdef EXE
db 0,0,0 ; 16 uncompressed len
db 0,0,0 ; 19 compressed len
db 0,0,0 ; 22 original file size
db 0 ; 25 filter
db 0 ; 26 header checksum
%else
dd 0 ; 16 uncompressed len
dd 0 ; 20 compressed len
dd 0 ; 24 original file size
db 0 ; 28 filter id
db 0 ; 29 cto (for filters 0x21..0x29)
db 0 ; unsused
db 0 ; 31 header checksum
%endif
; vi:ts=8:et:nowrap
+37
View File
@@ -0,0 +1,37 @@
; ident.ash --
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; UPX and the UCL library are free software; you can redistribute them
; and/or modify them under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; see the file COPYING.
; If not, write to the Free Software Foundation, Inc.,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
; Markus F.X.J. Oberhumer Laszlo Molnar
; markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; ------------- COPYRIGHT -------------
%ifdef __IDENTSMA__
%include "ident_s.ash"
%else; __IDENTBIG__
%include "ident_n.ash"
%endif; __IDENTEND__
; vi:ts=8:et:nowrap
+39
View File
@@ -0,0 +1,39 @@
; ident_n.ash --
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; UPX and the UCL library are free software; you can redistribute them
; and/or modify them under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; see the file COPYING.
; If not, write to the Free Software Foundation, Inc.,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
; Markus F.X.J. Oberhumer Laszlo Molnar
; markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; ------------- COPYRIGHT -------------
db 10,0
db '$Info: This file is packed with the UPX executable packer http://upx.tsx.org $'
db 10,0
db '$Id: UPX '
db 'UPXV'
db ' Copyright (C) 1996-2000 the UPX Team. All Rights Reserved. $'
db 10,0
; vi:ts=8:et:nowrap
+35
View File
@@ -0,0 +1,35 @@
; ident_s.ash --
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; UPX and the UCL library are free software; you can redistribute them
; and/or modify them under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; see the file COPYING.
; If not, write to the Free Software Foundation, Inc.,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
; Markus F.X.J. Oberhumer Laszlo Molnar
; markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; ------------- COPYRIGHT -------------
db 10
db '$Id: ident_s.ash,v 1.1 2000/05/10 04:57:58 jreiser Exp jreiser $'
db 10,0
; vi:ts=8:et:nowrap
+95
View File
@@ -0,0 +1,95 @@
; l_com.asm -- loader & decompressor for the dos/com format
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; UPX and the UCL library are free software; you can redistribute them
; and/or modify them under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; see the file COPYING.
; If not, write to the Free Software Foundation, Inc.,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
; Markus F.X.J. Oberhumer Laszlo Molnar
; markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
%define COM 1
%define CJT16 1
%define jmps jmp short
%include "macros.ash"
BITS 16
ORG 0
SECTION .text
; =============
; ============= ENTRY POINT
; =============
; __COMMAIN1__
start:
cmp sp, 'SP'
ja mem_ok
int 0x20
mem_ok:
mov cx, 'CX' ; size of decomp + sizeof (data) + 1
mov si, 'SI' ; cx + 0x100
mov di, 'DI'
mov bx, 0x8000
std
rep
movsb
cld
xchg si, di
sub si, byte start - cutpoint
; __COMSUBSI__
sbb bp, bp
push di
%ifdef __COMCALLT__
push di
%endif; __COMMAIN2__
jmp .1+'JM'
.1:
%include "header.ash"
cutpoint:
; __COMCUTPO__
; =============
; ============= DECOMPRESSION
; =============
%include "n2b_d16.ash"
; =============
; ============= CALLTRICK
; =============
; =============
; __CORETURN__
ret
eof:
; __COMTHEND__
section .data
dd -1
dw eof
; vi:ts=8:et:nowrap
+93
View File
@@ -0,0 +1,93 @@
; l_djgpp2.asm -- loader & decompressor for the djgpp2/coff format
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; UPX and the UCL library are free software; you can redistribute them
; and/or modify them under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; see the file COPYING.
; If not, write to the Free Software Foundation, Inc.,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
; Markus F.X.J. Oberhumer Laszlo Molnar
; markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
%define jmps jmp short
%include "macros.ash"
BITS 32
SECTION .text
ORG 0
; =============
; ============= ENTRY POINT
; =============
; __DJ2MAIN1__
start:
push ds
pop es
mov esi, 'INPP' ; input pointer
mov edi, 'OUTP' ; output pointer
%ifdef __DJCALLT1__
push edi
%endif; __DJ2MAIN2__
; cld ; the stub sets this
or ebp, byte -1
; =============
; ============= DECOMPRESSION
; =============
%include "n2b_d32.ash"
%include "n2d_d32.ash"
; =============
; __DJ2BSS00__
mov ecx, 'BSSL'
rep
stosd
%ifdef __DJCALLT2__
; =============
; ============= CALLTRICK
; =============
pop edi
cjt32 0
%endif; __DJRETURN__
; =============
push dword 'ENTR' ; entry point
ret
; because of a feature of the djgpp loader, the size of this stub must be
; a multiple of 4 and as the upx decompressor depends on the fact that
; the compressed data stream begins just after the header, i must
; use an alignment here - ML
align 4
%include "header.ash"
eof:
; __DJTHEEND__
section .data
dd -1
dw eof
; vi:ts=8:et:nowrap
+177
View File
@@ -0,0 +1,177 @@
; l_exe.asm -- loader & decompressor for the dos/exe format
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; UPX and the UCL library are free software; you can redistribute them
; and/or modify them under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; see the file COPYING.
; If not, write to the Free Software Foundation, Inc.,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
; Markus F.X.J. Oberhumer Laszlo Molnar
; markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
%define EXE
%define jmps jmp short
BITS 16
ORG 0
SECTION .text
; =============
; ============= ENTRY POINT
; =============
; __EXEENTRY__
mov cx, 'CX' ; first_copy_len/2
mov si, 'SI' ; cx*2-2
mov di, si
push ds
db 0xa9
do_copy:
mov ch, 0x80 ; 64 kbyte
mov ax, cs
add ax, 'DS'
mov ds, ax
add ax, 'ES'
mov es, ax
std
rep
movsw
cld
sub [byte cs:si+do_copy+6+2], byte 0x10
jnc do_copy
xchg ax, dx
scasw
lodsw
%ifdef __EXERELPU__
push cs
%endif; __EXEMAIN4__
push cs
push cs
push es
pop ds
pop es
push ss
mov bp, 'BP' ; entry point [0x1,0x10]
mov bx, 'BX' ; 0x800F + 0x10*bp - 0x10
push bp
retf
%include "header.ash"
; __EXECUTPO__
; =============
; ============= DECOMPRESSION
; =============
%include "n2b_d8e.ash"
%include "n2d_d8e.ash"
; =============
; ============= RELOCATION
; =============
; __EXEMAIN5__
pop bp
%ifdef __EXERELOC__
%ifdef __EXEADJUS__
mov ax, es
sub ah, 0x6 ; MAXRELOCS >> 12
mov ds, ax
%else; __EXENOADJ__
push es
pop ds
%endif; __EXERELO1__
lea si, [di+'RS']
lodsw
pop bx
xchg ax, cx ; number of 0x01 bytes (not exactly)
lodsw
xchg ax, dx ; seg_hi
reloc_0:
lodsw
xchg ax, di
lodsw
add bx, ax
mov es, bx
xor ax, ax
reloc_1:
add di, ax
add [es:di], bp
reloc_2:
lodsb
dec ax
jz reloc_5
inc ax
jnz reloc_1
%ifdef __EXEREL9A__
inc di
reloc_4:
inc di
cmp byte [es:di], 0x9a
jne reloc_4
cmp [es:di+3], dx
ja reloc_4
mov al, 3
jmps reloc_1
%endif; __EXERELO2__
reloc_5:
add di, 0xfe
%ifdef __EXEREBIG__
jc reloc_0
%endif; __EXERELO3__
loop reloc_2
%endif; __EXEMAIN8__
; =============
pop es
push es
pop ds
%ifdef __EXESTACK__
lea ax, ['SS'+bp]
mov ss, ax
%endif; __EXEDUMMS__
%ifdef __EXESTASP__
mov sp, 'SP'
%endif; __EXEDUMMP__
; =============
%ifdef __EXEJUMPF__
jmp 'CS':'IP'
%else; __EXERETUR__
%ifdef __EXERCSPO__
add bp, 'CS'
%endif; __EXERETIP__
push bp
mov ax, 'IP'
push ax
retf
%endif; __EXEDUMMZ__
eof:
; __EXETHEND__
section .data
dd -1
dw eof
; vi:ts=8:et:nowrap
+385
View File
@@ -0,0 +1,385 @@
/* l_lx_elf.c -- stub loader for Linux x86 ELF executable
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Integration of virtual exec() with decompression is
Copyright (C) 2000 John F. Reiser. All rights reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar
markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
John F. Reiser
jreiser@BitWagon.com
*/
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include "linux.hh"
/*************************************************************************
// configuration section
**************************************************************************/
// In order to make it much easier to move this code at runtime and execute
// it at an address different from it load address: there must be no
// static data, and no string constants.
#define PAGEMASK (~0u<<12) // discards the offset, keeps the page
#define PAGESIZE ( 1u<<12)
#define MAX_ELF_HDR 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this
/*************************************************************************
// "file" util
**************************************************************************/
struct Extent {
size_t size; // must be first to match size[0] uncompressed size
char *buf;
};
static void
xread(struct Extent *x, char *buf, size_t count)
{
char *p=x->buf, *q=buf;
size_t j;
if (x->size < count) {
exit(127);
}
for (j = count; 0!=j--; ++p, ++q) {
*q = *p;
}
x->buf += count;
x->size -= count;
}
/*************************************************************************
// util
**************************************************************************/
#if 0 //{ save space
#define ERR_LAB error: exit(127);
#define err_exit(a) goto error
#else //}{ save debugging time
#define ERR_LAB
static void
err_exit(int a)
{
(void)a; // debugging convenience
exit(127);
}
#endif //}
static void *
do_brk(void *addr)
{
return brk(addr);
}
static char *
do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
(void)len; (void)prot; (void)flags; (void)fd; (void)offset;
return mmap((int *)&addr);
}
/*************************************************************************
// UPX & NRV stuff
**************************************************************************/
typedef int f_expand(
const nrv_byte *, nrv_uint,
nrv_byte *, nrv_uint * );
static void
unpackExtent(
struct Extent *const xi, // input
struct Extent *const xo, // output
f_expand *const f_decompress
)
{
while (xo->size) {
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
// Read and check block sizes.
xread(xi, (char *)&h, sizeof(h));
if (h.sz_unc == 0) { // uncompressed size 0 -> EOF
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
err_exit(2);
if (xi->size != 0) // all bytes must be written
err_exit(3);
break;
}
if (h.sz_cpr <= 0) {
err_exit(4);
ERR_LAB
}
if (h.sz_cpr > h.sz_unc
|| h.sz_unc > (int32_t)xo->size ) {
err_exit(5);
}
// Now we have:
// assert(h.sz_cpr <= h.sz_unc);
// assert(h.sz_unc > 0 && h.sz_unc <= blocksize);
// assert(h.sz_cpr > 0 && h.sz_cpr <= blocksize);
if (h.sz_cpr < h.sz_unc) { // Decompress block
nrv_uint out_len;
int const j = (*f_decompress)(xi->buf, h.sz_cpr, xo->buf, &out_len);
if (j != 0 || out_len != (nrv_uint)h.sz_unc)
err_exit(7);
xi->buf += h.sz_cpr;
xi->size -= h.sz_cpr;
}
else { // copy literal block
xread(xi, xo->buf, h.sz_cpr);
}
xo->buf += h.sz_unc;
xo->size -= h.sz_unc;
}
}
// Create (or find) an escape hatch to use when munmapping ourselves the stub.
// Called by do_xmap to create it, and by assembler code to find it.
void *
make_hatch(Elf32_Phdr const *const phdr)
{
if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
unsigned *hatch;
// The format of the 'if' is
// if ( ( (hatch = loc1), test_loc1 )
// || ( (hatch = loc2), test_loc2 ) ) {
// action
// }
// which uses the comma to save bytes when test_locj involves locj
// and the action is the same when either test succeeds.
// Try page fragmentation just beyond .text .
if ( ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr)),
( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss
&& 4<=(~PAGEMASK & -(int)hatch) ) ) // space left on page
// Try Elf32_Ehdr.e_ident[12..15] . warning: 'const' cast away
|| ( (hatch = (void *)(&((Elf32_Ehdr *)phdr->p_vaddr)->e_ident[12])),
(phdr->p_offset==0) ) ) {
// Omitting 'const' saves repeated literal in gcc.
unsigned /*const*/ escape = 0xc36180cd; // "int $0x80; popa; ret"
// Don't store into read-only page if value is already there.
if (*hatch != escape) {
*hatch = escape;
}
return hatch;
}
}
return 0;
}
static void
bzero(char *p, size_t len)
{
if (len) do {
*p++= 0;
} while (--len);
}
static Elf32_Addr // entry address
do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, struct Extent *const xi,
Elf32_auxv_t *const a)
{
Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff +
(char const *)ehdr);
unsigned long base = (ET_DYN==ehdr->e_type) ? 0x40000000 : 0;
int j;
for (j=0; j < ehdr->e_phnum; ++phdr, ++j)
if (PT_PHDR==phdr->p_type) {
a->a_un.a_val = phdr->p_vaddr;
}
else if (PT_LOAD==phdr->p_type) {
struct Extent xo;
size_t mlen = xo.size = phdr->p_filesz;
char *addr = xo.buf = (char *)phdr->p_vaddr;
char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr;
size_t frag = (int)addr &~ PAGEMASK;
mlen += frag;
addr -= frag;
if (ET_DYN==ehdr->e_type) {
addr += base;
haddr += base;
}
else { // There is only one brk, the one for the ET_EXEC
// Not needed if compressed a.elf is invoked directly.
// Needed only if compressed shell script invokes compressed shell.
do_brk(haddr+OVERHEAD); // Also takes care of whole pages of .bss
}
// Decompressor can overrun the destination by 3 bytes.
if (addr != do_mmap(addr, mlen + (xi ? 3 : 0), PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | (xi ? MAP_ANONYMOUS : 0),
fdi, phdr->p_offset - frag) ) {
err_exit(8);
}
if (0==base) {
base = (unsigned long)addr;
}
if (xi) {
unpackExtent(xi, &xo, (f_expand *)fdi);
}
bzero(addr, frag); // fragment at lo end
frag = (-mlen) &~ PAGEMASK; // distance to next page boundary
bzero(mlen+addr, frag); // fragment at hi end
if (xi) {
make_hatch(phdr);
}
if (phdr->p_memsz != phdr->p_filesz) { // .bss
if (ET_DYN==ehdr->e_type) { // PT_INTERP whole pages of .bss?
addr += frag + mlen;
mlen = haddr - addr;
if (0 < (int)mlen) { // need more pages, too
if (addr != do_mmap(addr, mlen, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 ) ) {
err_exit(9);
ERR_LAB
}
}
}
}
else { // no .bss
int prot = 0;
if (phdr->p_flags & PF_X) { prot |= PROT_EXEC; }
if (phdr->p_flags & PF_W) { prot |= PROT_WRITE; }
if (phdr->p_flags & PF_R) { prot |= PROT_READ; }
if (0!=mprotect(addr, mlen, prot)) {
err_exit(10);
}
if (xi) { // cleanup if decompressor overrun crosses page boundary
mlen += 3;
addr += mlen;
mlen &= ~PAGEMASK;
if (mlen<=3) { // page fragment was overrun buffer only
munmap(addr - mlen, mlen);
}
}
}
if (ET_DYN!=ehdr->e_type) {
// Needed only if compressed shell script invokes compressed shell.
do_brk(haddr);
}
}
if (!xi) {
if (0!=close(fdi)) {
err_exit(11);
}
}
if (ET_DYN==ehdr->e_type) {
return ehdr->e_entry + base;
}
else {
return ehdr->e_entry;
}
}
/*************************************************************************
// upx_main - called by our entry code
//
// This function is optimized for size.
**************************************************************************/
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr,
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr
) __asm__("upx_main");
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr, // to get compressed size and data
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR+OVERHEAD]
)
{
size_t const lsize = *(unsigned short const *)(0x7c + (char const *)my_ehdr);
Elf32_Phdr const *phdr = (Elf32_Phdr const *)(1+ehdr);
Elf32_Addr entry;
struct Extent xo;
struct Extent xi = { 0, (sizeof(struct p_info) + lsize + (char *)my_ehdr) };
// warning: 'const' cast away
size_t const sz_elfhdrs = ((size_t *)xi.buf)[0]; // sizeof(Ehdr+Phdrs), uncompressed
size_t const sz_pckhdrs = ((size_t *)xi.buf)[1]; // sizeof(Ehdr+Phdrs), compressed
(void)uncbuf; // used by l_lx_sh.c
// Uncompress Ehdr and Phdrs.
xo.size = sz_elfhdrs; xo.buf = (char *)ehdr;
xi.size = 2*sizeof(size_t) + sz_pckhdrs;
unpackExtent(&xi, &xo, f_decompress);
// Prepare to decompress the Elf headers again, into the first PT_LOAD.
xi.buf -= 2*sizeof(size_t) + sz_pckhdrs;
xi.size = ((Elf32_Phdr const *)(1 + my_ehdr))->p_filesz - lsize;
av[0].a_type = AT_PHDR; // av[0].a_un.a_val is set by do_xmap
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;
av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGESIZE;
av[4].a_type = AT_ENTRY; av[4].a_un.a_val = ehdr->e_entry;
av[5].a_type = AT_NULL;
entry = do_xmap((int)f_decompress, ehdr, &xi, av);
{ // Map PT_INTERP program interpreter
int j;
for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_INTERP==phdr->p_type) {
char const *const iname = (char const *)phdr->p_vaddr;
int const fdi = open(iname, O_RDONLY, 0);
if (0 > fdi) {
err_exit(18);
}
if (MAX_ELF_HDR!=read(fdi, (void *)ehdr, MAX_ELF_HDR)) {
err_exit(19);
}
entry = do_xmap(fdi, ehdr, 0, 0);
break;
}
}
return (void *)entry;
}
/*
vi:ts=4:et:nowrap
*/
+281
View File
@@ -0,0 +1,281 @@
; l_lx_elf86.asm -- Linux program entry point & decompressor (Elf binary)
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; Integration of virtual exec() with decompression is
; Copyright (C) 2000 John F. Reiser. All rights reserved.
;
; UPX and the UCL library are free software; you can redistribute them
; and/or modify them under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; see the file COPYING.
; If not, write to the Free Software Foundation, Inc.,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
; Markus F.X.J. Oberhumer Laszlo Molnar
; markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; John F. Reiser
; jreiser@BitWagon.com
BITS 32
SECTION .text
%define jmps jmp short
; defines for ident.ash and n2b_d32.ash
%ifdef SMALL
%define __IDENTSMA__
%define __N2BSMA10__
%define __N2BSMA20__
%define __N2BSMA30__
%define __N2BSMA40__
%define __N2BSMA50__
%define __N2BSMA60__
%define __N2DSMA10__
%define __N2DSMA20__
%define __N2DSMA30__
%define __N2DSMA40__
%define __N2DSMA50__
%define __N2DSMA60__
%endif
%include "ident.ash"
; /*************************************************************************
; // program entry point
; // see glibc/sysdeps/i386/elf/start.S
; **************************************************************************/
GLOBAL _start
_start:
;;;; int3
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
;; Build the stubs and upx. Compress a testcase, such as a copy of /bin/date.
;; Invoke gdb, and give a 'run' command. Define a single-step macro such as
;; define g
;; stepi
;; x/i $pc
;; end
;; and a step-over macro such as
;; define h
;; x/2i $pc
;; tbreak *$_
;; continue
;; x/i $pc
;; end
;; Step through the code; remember that <Enter> repeats the previous command.
;;
call main ; push address of decompress subroutine
; /*************************************************************************
; // C callable decompressor
; **************************************************************************/
%define INP dword [esp+8*4+4]
%define INS dword [esp+8*4+8]
%define OUTP dword [esp+8*4+12]
%define OUTS dword [esp+8*4+16]
decompress:
pusha
; cld
mov esi, INP
mov edi, OUTP
or ebp, byte -1
;;; align 8
%ifdef NRV2B
%include "n2b_d32.ash"
%elifdef NRV2D
%include "n2d_d32.ash"
%else
%error
%endif
; eax is 0 from decompressor code
;xor eax, eax ; return code
; check compressed size
mov edx, INP
add edx, INS
cmp esi, edx
jz .ok
dec eax
.ok:
; write back the uncompressed size
sub edi, OUTP
mov edx, OUTS
mov [edx], edi
mov [7*4 + esp], eax
popa
ret
%define PAGE_MASK (~0<<12)
%define PAGE_SIZE ( 1<<12)
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define p_filesz 4*4
%define p_memsz 5*4
%define a_val 4
%define MAP_FIXED 0x10
%define MAP_PRIVATE 0x02
%define MAP_ANONYMOUS 0x20
%define PROT_READ 1
%define PROT_WRITE 2
%define PROT_EXEC 4
%define __NR_mmap 90
%define __NR_munmap 91
; Decompress the rest of this loader, and jump to it
unfold:
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
cld
lodsd
push eax ; sz_uncompressed (junk, actually)
push esp ; &sz_uncompressed
mov eax, ebp ; &decompress
and eax, dword PAGE_MASK ; &my_elfhdr
mov edx, eax ; need my_elfhdr later
mov ah,0 ; round down to 64KB boundary
push eax ; &destination
; mmap a page to hold the decompressed program
xor ecx,ecx
push ecx
push ecx
mov ch, PAGE_SIZE >> 8
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
push byte PROT_READ | PROT_WRITE | PROT_EXEC
push ecx
push eax ; destination
push byte __NR_mmap
pop eax
mov ebx, esp
int 0x80
add esp, byte 6*4 ; discard args to mmap
lodsd
push eax ; sz_compressed
push esi ; &compressed_data
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop eax ; discard &compressed_data
pop eax ; discard sz_compressed
ret ; &destination
main:
pop ebp ; &decompress
call unfold
fold_begin:
; patchLoader will modify to be
; dword sz_uncompressed, sz_compressed
; byte compressed_data...
pop eax ; discard &sz_uncompressed
pop eax ; discard sz_uncompressed
; Move argc,argv,envp down so that we can insert more Elf_auxv entries.
; ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance
%define OVERHEAD 2048
%define MAX_ELF_HDR 512
mov esi, esp
sub esp, byte 6*8 ; AT_PHENT, AT_PHNUM, AT_PAGESZ, AT_ENTRY, AT_PHDR, AT_NULL
mov edi, esp
call do_auxv
sub esp, dword MAX_ELF_HDR + OVERHEAD
push esp ; argument: temp space
push edi ; argument: AT_next
push ebp ; argument: &decompress
push edx ; argument: my_elfhdr
add edx, [p_memsz + szElf32_Ehdr + edx]
push edx ; argument: uncbuf
EXTERN upx_main
call upx_main ; entry = upx_main(uncbuf, my_elfhdr, &decompress, AT_next, tmp_ehdr)
pop esi ; decompression buffer == (p_vaddr + p_memsz) of stub
pop ebx ; my_elfhdr
add esp, dword 3*4 + MAX_ELF_HDR + OVERHEAD ; remove 3 params, temp space
push eax ; save entry address
mov edi, [a_val + edi] ; AT_PHDR
find_hatch:
push edi
EXTERN make_hatch
call make_hatch ; find hatch = make_hatch(phdr)
pop ecx ; junk the parameter
add edi, byte szElf32_Phdr ; prepare to try next Elf32_Phdr
test eax,eax
jz find_hatch
xchg eax,edx ; edx= &hatch
; _dl_start and company (ld-linux.so.2) assumes that it has virgin stack,
; and does not initialize all its stack local variables to zero.
; Ulrich Drepper (drepper@cyngus.com) has refused to fix the bugs.
; See GNU wwwgnats libc/1165 .
%define N_STKCLR (0x100 + MAX_ELF_HDR + OVERHEAD)/4
lea edi, [esp - 4*N_STKCLR]
pusha ; values will be zeroed
mov ecx, N_STKCLR
xor eax,eax
rep stosd
mov ecx,esi ; my p_vaddr + p_memsz
mov bh,0 ; round down to 64KB boundary
sub ecx,ebx ; length to unmap
push byte __NR_munmap
pop eax
jmp edx ; unmap ourselves via escape hatch, then goto entry
do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL
; cld
L10: ; move argc+argv
lodsd
stosd
test eax,eax
jne L10
L20: ; move envp
lodsd
stosd
test eax,eax
jne L20
L30: ; move existing Elf32_auxv
lodsd
stosd
test eax,eax ; AT_NULL ?
lodsd
stosd
jne L30
sub edi, byte 8 ; point to AT_NULL
ret
; vi:ts=8:et:nowrap
+17
View File
@@ -0,0 +1,17 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS
{
/* 0x00401000: l_lx_elf86.asm assumes 1 page up from 64KB boundary */
. = 0x00401000 + SIZEOF_HEADERS;
. = ALIGN(0x80);
.text : {
*(.text)
*(.data)
}
/* 0x08048000: customary Linux/x86 Elf .text start */
. = 0x08048000 + (0xfff & .);
.data : {
}
}
+495
View File
@@ -0,0 +1,495 @@
/* l_lx_exec.c -- generic stub loader for Linux using execve()
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar
markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include "linux.hh"
/*************************************************************************
// configuration section
**************************************************************************/
// use malloc instead of the bss segement
#define USE_MALLOC
/*************************************************************************
// file util
**************************************************************************/
#undef xread
#undef xwrite
#if 1
//static int xread(int fd, void *buf, int count) __attribute__((__stdcall__));
static int xread(int fd, void *buf, int count)
{
// note: we can assert(count > 0);
do {
int n = read(fd, buf, count);
if (n == -EINTR)
continue;
if (n <= 0)
break;
buf += n; // gcc extension: add to void *
count -= n;
} while (count > 0);
return count;
}
#else
#define xread(fd,buf,count) ((count) - read(fd,buf,count))
#endif
#if 1
static __inline__ int xwrite(int fd, const void *buf, int count)
{
// note: we can assert(count > 0);
do {
int n = write(fd, buf, count);
if (n == -EINTR)
continue;
if (n <= 0)
break;
buf += n; // gcc extension: add to void *
count -= n;
} while (count > 0);
return count;
}
#else
#define xwrite(fd,buf,count) ((count) - write(fd,buf,count))
#endif
/*************************************************************************
// util
**************************************************************************/
static char *upx_itoa(char *buf, unsigned long v)
{
char *p = buf;
{
unsigned long k = v;
do {
p++;
k /= 10;
} while (k > 0);
}
buf = p;
*p = 0;
{
unsigned long k = v;
do {
*--p = '0' + k % 10;
k /= 10;
} while (k > 0);
}
return buf;
}
#if defined(__i386__)
# define SET2(p, c0, c1) \
* (unsigned short *) (p) = ((c1)<<8 | (c0))
# define SET4(p, c0, c1, c2, c3) \
* (uint32_t *) (p) = ((c3)<<24 | (c2)<<16 | (c1)<<8 | (c0))
# define SET3(p, c0, c1, c2) \
SET4(p, c0, c1, c2, 0)
#else
# define SET2(p, c0, c1) \
(p)[0] = c0, (p)[1] = c1
# define SET3(p, c0, c1, c2) \
(p)[0] = c0, (p)[1] = c1, (p)[2] = c2
# define SET4(p, c0, c1, c2, c3) \
(p)[0] = c0, (p)[1] = c1, (p)[2] = c2, (p)[3] = c3
#endif
/*************************************************************************
// UPX & NRV stuff
**************************************************************************/
// must be the same as in p_unix.cpp !
#if !defined(USE_MALLOC)
# define BLOCKSIZE (512*1024)
#endif
// patch constants for our loader (le32 format)
#define UPX1 0x31585055 // "UPX1"
#define UPX2 0x32585055 // "UPX2"
#define UPX3 0x33585055 // "UPX4"
#define UPX4 0x34585055 // "UPX4"
#define UPX5 0x35585055 // "UPX5"
#if defined(__i386__)
extern int
nrv2b_decompress_asm_fast ( const nrv_byte *src, nrv_uint src_len,
nrv_byte *dst, nrv_uint *dst_len );
#define nrv2b_decompress nrv2b_decompress_asm_fast
extern int
nrv2d_decompress_asm_fast ( const nrv_byte *src, nrv_uint src_len,
nrv_byte *dst, nrv_uint *dst_len );
#define nrv2d_decompress nrv2d_decompress_asm_fast
#endif /* __i386__ */
/*************************************************************************
// upx_main - called by our entry code
//
// This function is optimized for size.
**************************************************************************/
void upx_main(char *argv[], char *envp[]) __asm__("upx_main");
void upx_main(char *argv[], char *envp[])
{
// file descriptors
int fdi, fdo;
struct p_info header;
// for getpid()
pid_t pid;
// temporary file name (max 14 chars)
static char tmpname_buf[] = "/tmp/upxAAAAAAAAAAA";
char *tmpname = tmpname_buf;
char procself_buf[64];
char *procself;
// decompression buffer
#if defined(USE_MALLOC)
unsigned char *buf;
static int malloc_args[6] = {
0, UPX5, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0
};
#else
static unsigned char buf[BLOCKSIZE + OVERHEAD];
#endif
//
// ----- Step 0: set /proc/self using /proc/<pid> -----
//
//personality(PER_LINUX);
pid = getpid();
SET4(procself_buf + 0, '/', 'p', 'r', 'o');
SET2(procself_buf + 4, 'c', '/');
procself = upx_itoa(procself_buf + 6, pid);
*procself++ = '/';
//
// ----- Step 1: prepare input file -----
//
// Open the exe.
SET3(procself, 'e', 'x', 'e');
fdi = open(procself_buf, O_RDONLY, 0);
#if 1
// try /proc/<pid>/file for the sake of FreeBSD
if (fdi < 0)
{
SET4(procself, 'f', 'i', 'l', 'e');
fdi = open(procself_buf, O_RDONLY, 0);
}
#endif
#if 0
// Save some bytes of code - the lseek() below will fail anyway.
if (fdi < 0)
goto error1;
#endif
// Seek to start of compressed data. The offset is patched
// by the compressor.
if (lseek(fdi, UPX1, 0) < 0)
goto error1;
// Read header.
if (xread(fdi, (void *)&header, sizeof(header)) != 0)
goto error1;
// Paranoia. Make sure this is actually our expected executable
// by checking the random program id. (The id is both stored
// in the header and patched into this stub.)
if (header.p_progid != UPX2)
goto error1;
//
// ----- Step 2: prepare temporary output file -----
//
// Compute name of temporary output file in tmpname[].
// Protect against Denial-of-Service attacks.
{
char *p = tmpname_buf + sizeof(tmpname_buf) - 1;
uint32_t r;
// Compute the last 4 characters (20 bits) from getpid().
{
unsigned k = 4;
r = (uint32_t) pid;
do {
unsigned char d = r % 32;
if (d >= 26) d += '0' - 'Z' - 1;
*--p += d;
r /= 32;
} while (--k > 0);
}
// Provide 4 random bytes from our program id.
r ^= header.p_progid;
// Mix in 4 runtime random bytes.
// Don't consume precious bytes from /dev/urandom.
{
#if 1
struct timeval tv;
gettimeofday(&tv, 0);
r ^= (uint32_t) tv.tv_sec;
r ^= ((uint32_t) tv.tv_usec) << 12; // shift into high-bits
#else
// using adjtimex() may cause portability problems
static struct timex tx;
adjtimex(&tx);
r ^= (uint32_t) tx.time.tv_sec;
r ^= ((uint32_t) tx.time.tv_usec) << 12; // shift into high-bits
r ^= (uint32_t) tx.errcnt;
#endif
}
// Compute 7 more characters from the 32 random bits.
{
unsigned k = 7;
do {
unsigned char d = r % 32;
if (d >= 26) d += '0' - 'Z' - 1;
*--p += d;
r /= 32;
} while (--k > 0);
}
}
// Just in case, remove the file.
{
int err = unlink(tmpname);
if (err != -ENOENT && err != 0)
goto error1;
}
// Create the temporary output file.
fdo = open(tmpname, O_WRONLY | O_CREAT | O_EXCL, 0700);
#if 0
// Save some bytes of code - the ftruncate() below will fail anyway.
if (fdo < 0)
goto error;
#endif
// Set expected file size.
if (ftruncate(fdo, header.p_filesize) != 0)
goto error;
//
// ----- Step 3: setup memory -----
//
#if defined(USE_MALLOC)
buf = mmap(malloc_args);
if ((unsigned long) buf >= (unsigned long) -4095)
goto error;
#else
if (header.p_blocksize > BLOCKSIZE)
goto error;
#endif
//
// ----- Step 4: decompress blocks -----
//
for (;;)
{
int32_t size[2];
// size[0]: uncompressed block size
// size[1]: compressed block size
// Note: if size[0] == size[1] then the block was not
// compressible and is stored in its uncompressed form.
int i;
// Read and check block sizes.
if (xread(fdi, (void *)size, 8) != 0)
goto error;
if (size[0] == 0) // uncompressed size 0 -> EOF
{
if (size[1] != UPX_MAGIC_LE32) // size[1] must be h->magic
goto error;
if (header.p_filesize != 0) // all bytes must be written
goto error;
break;
}
if (size[1] <= 0)
goto error;
if (size[1] > size[0] || size[0] > (int32_t)header.p_blocksize)
goto error;
// Now we have:
// assert(size[1] <= size[0]);
// assert(size[0] > 0 && size[0] <= blocksize);
// assert(size[1] > 0 && size[1] <= blocksize);
// Read compressed block.
i = header.p_blocksize + OVERHEAD - size[1];
if (xread(fdi, buf+i, size[1]) != 0)
goto error;
// Decompress block.
if (size[1] < size[0])
{
// in-place decompression
nrv_uint out_len;
#if defined(NRV2B)
i = nrv2b_decompress(buf+i, size[1], buf, &out_len);
#elif defined(NRV2D)
i = nrv2d_decompress(buf+i, size[1], buf, &out_len);
#else
# error
#endif
if (i != 0 || out_len != (nrv_uint)size[0])
goto error;
// i == 0 now
}
// Write uncompressed block.
if (xwrite(fdo, buf+i, size[0]) != 0)
{
// error exit is here in the middle to keep the jumps short.
error:
(void) unlink(tmpname);
error1:
// Note: the kernel will close all open files and
// unmap any allocated memory.
for (;;)
(void) exit(127);
}
header.p_filesize -= size[0];
}
//
// ----- Step 5: release resources -----
//
#if defined(USE_MALLOC)
munmap(buf, malloc_args[1]);
#endif
if (close(fdo) != 0)
goto error;
if (close(fdi) != 0)
goto error;
//
// ----- Step 6: try to start program via /proc/self/fd/X -----
//
// Many thanks to Andi Kleen <ak@muc.de> and
// Jamie Lokier <nospam@cern.ch> for this nice idea.
// Open the temp file.
fdi = open(tmpname, O_RDONLY, 0);
if (fdi < 0)
goto error;
// Compute name of temp fdi.
SET3(procself, 'f', 'd', '/');
upx_itoa(procself + 3, fdi);
// Check for working /proc/self/fd/X by accessing the
// temp file again, now via temp fdi.
#define err fdo
err = access(procself_buf, R_OK | X_OK);
if (err == UPX3)
{
// Now it's safe to unlink the temp file (as it is still open).
unlink(tmpname);
// Set the file close-on-exec.
fcntl(fdi, F_SETFD, FD_CLOEXEC);
// Execute the original program via /proc/self/fd/X.
execve(procself_buf, argv, envp);
// If we get here we've lost.
}
#undef err
// The proc filesystem isn't working. No problem.
close(fdi);
//
// ----- Step 7: start program in /tmp -----
//
// Fork off a subprocess to clean up.
// We have to do this double-fork trick to keep a zombie from
// hanging around if the spawned original program doesn't check for
// subprocesses (as well as to prevent the real program from getting
// confused about this subprocess it shouldn't have).
// Thanks to Adam Ierymenko <api@one.net> for this solution.
if (fork() == 0)
{
if (fork() == 0)
{
// Sleep 3 seconds, then remove the temp file.
static const struct timespec ts = { UPX4, 0 };
nanosleep(&ts, 0);
unlink(tmpname);
}
exit(0);
}
// Wait for the first fork()'d process to die.
waitpid(-1, (int *)0, 0);
// Execute the original program.
execve(tmpname, argv, envp);
//
// ----- Step 8: error exit -----
//
// If we return from execve() there was an error. Give up.
goto error;
}
/*
vi:ts=4:et:nowrap
*/
+148
View File
@@ -0,0 +1,148 @@
; l_lx_exec86.asm -- Linux program entry point & decompressor (execve)
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; UPX and the UCL library are free software; you can redistribute them
; and/or modify them under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; see the file COPYING.
; If not, write to the Free Software Foundation, Inc.,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
; Markus F.X.J. Oberhumer Laszlo Molnar
; markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
BITS 32
SECTION .text
%define jmps jmp short
; defines for ident.ash and n2b_d32.ash
%ifdef SMALL
%define __IDENTSMA__
%define __N2BSMA10__
%define __N2BSMA20__
%define __N2BSMA30__
%define __N2BSMA40__
%define __N2BSMA50__
%define __N2BSMA60__
%define __N2DSMA10__
%define __N2DSMA20__
%define __N2DSMA30__
%define __N2DSMA40__
%define __N2DSMA50__
%define __N2DSMA60__
%endif
; /*************************************************************************
; // program entry point
; // see glibc/sysdeps/i386/elf/start.S
; **************************************************************************/
GLOBAL _start
EXTERN upx_main
_start:
xor ebp, ebp ; Clear the frame pointer
%if 0
; personality(PER_LINUX)
mov eax, 136 ; syscall_personality
xor ebx, ebx ; PER_LINUX
int 0x80
%endif
pop eax ; Pop the argument count
mov ecx, esp ; argv starts just at the current stack top
lea edx, [ecx+eax*4+4] ; envp = &argv[argc + 1]
push eax ; Restore the stack
and esp, byte -8 ; Align the stack
push edx ; Push third argument: envp
push ecx ; Push second argument: argv
;;; push eax ; Push first argument: argc
call upx_main ; Call the UPX main function
hlt ; Crash if somehow upx_main does return
%include "ident.ash"
; /*************************************************************************
; // C callable decompressor
; **************************************************************************/
%ifdef NRV2B
%define decompress nrv2b_decompress_asm_fast
%elifdef NRV2D
%define decompress nrv2d_decompress_asm_fast
%else
%error
%endif
GLOBAL decompress
%define INP dword [esp+24+4]
%define INS dword [esp+24+8]
%define OUTP dword [esp+24+12]
%define OUTS dword [esp+24+16]
decompress:
push ebp
push edi
push esi
push ebx
push ecx
push edx
cld
mov esi, INP
mov edi, OUTP
or ebp, byte -1
;;; align 8
%ifdef NRV2B
%include "n2b_d32.ash"
%elifdef NRV2D
%include "n2d_d32.ash"
%else
%error
%endif
; eax is 0 from decompressor code
;xor eax, eax ; return code
; check compressed size
mov edx, INP
add edx, INS
cmp esi, edx
jz .ok
dec eax
.ok:
; write back the uncompressed size
sub edi, OUTP
mov edx, OUTS
mov [edx], edi
pop edx
pop ecx
pop ebx
pop esi
pop edi
pop ebp
ret
; vi:ts=8:et:nowrap
+449
View File
@@ -0,0 +1,449 @@
/* l_lxsep.c -- separate loader for Linux Elf executable
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Integration of virtual exec() with decompression is
Copyright (C) 2000 John F. Reiser. All rights reserved.
<jreiser@BitWagon.com>
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar
markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
*/
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include <sys/types.h>
#include <fcntl.h>
#include <linux/errno.h>
#include <linux/mman.h>
#include <linux/unistd.h>
#include "linux.hh"
/*************************************************************************
// configuration section
**************************************************************************/
// must be the same as in p_linux.cpp !
#define OVERHEAD 2048
#define PAGEMASK (~0u<<12) // discards the offset, keeps the page
#define PAGESIZE ( 1u<<12)
#define MAX_ELF 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this
#undef int32_t
#undef uint32_t
#define int32_t int
#define uint32_t unsigned int
#define SEEK_SET 0
#define SEEK_CUR 1
/*************************************************************************
// file util
**************************************************************************/
#undef xread
#undef xwrite
#if 1
//static int xread(int fd, void *buf, int count) __attribute__((__stdcall__));
static int xread(int fd, void *buf, int count)
{
// note: we can assert(count > 0);
do {
int n = read(fd, buf, count);
if (n == -EINTR)
continue;
if (n <= 0)
break;
buf += n; // gcc extension: add to void *
count -= n;
} while (count > 0);
return count;
}
#else
#define xread(fd,buf,count) ((count) - read(fd,buf,count))
#endif
#if 1
static __inline__ int xwrite(int fd, const void *buf, int count)
{
// note: we can assert(count > 0);
do {
int n = write(fd, buf, count);
if (n == -EINTR)
continue;
if (n <= 0)
break;
buf += n; // gcc extension: add to void *
count -= n;
} while (count > 0);
return count;
}
#else
#define xwrite(fd,buf,count) ((count) - write(fd,buf,count))
#endif
/*************************************************************************
// util
**************************************************************************/
#if 1 //{ save space
#define ERR_LAB error: exit(127);
#define err_exit(a) goto error
#else //}{ save debugging time
#define ERR_LAB
static void
err_exit(int a)
{
(void)a; // debugging convenience
exit(127);
}
#endif //}
static void *
do_brk(void *addr)
{
return brk(addr);
}
static char *
do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
(void)len; (void)prot; (void)flags; (void)fd; (void)offset;
return mmap((int *)&addr);
}
/*************************************************************************
// UPX & NRV stuff
**************************************************************************/
// patch & magic constants for our loader (le32 format)
#define UPX_MAGIC_LE32 0x21585055 // "UPX!"
typedef int f_expand(
const nrv_byte *, nrv_uint,
nrv_byte *, nrv_uint * );
struct Extent {
size_t size; // must be first to match size[0] uncompressed size
char *buf;
};
static void
unpackExtent(
struct Extent *const xo,
int fdi,
f_expand *const f_decompress
)
{
while (xo->size) {
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
int j = 0;
// Read and check block sizes.
if (xread(fdi, (void *)&h, sizeof(h)) != 0)
err_exit(1);
if (h.sz_unc == 0) // uncompressed size 0 -> EOF
{
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
err_exit(2);
if (xo->size != 0) // all bytes must be written
err_exit(3);
break;
}
if (h.sz_cpr <= 0) {
err_exit(4);
ERR_LAB
}
if (h.sz_cpr > h.sz_unc || h.sz_unc > (int32_t)xo->size) {
err_exit(5);
}
// Now we have:
// assert(h.sz_cpr <= h.sz_unc);
// assert(h.sz_unc > 0 && h.sz_unc <= blocksize);
// assert(h.sz_cpr > 0 && h.sz_cpr <= blocksize);
j = h.sz_unc - h.sz_cpr;
if (0 < j) { // Compressed block.
j += OVERHEAD;
}
if (0!=xread(fdi, xo->buf+j, h.sz_cpr)) {
err_exit(6);
}
// Decompress block.
if (h.sz_cpr < h.sz_unc) {
// in-place decompression
nrv_uint out_len;
j = (*f_decompress)(xo->buf+j, h.sz_cpr, xo->buf, &out_len);
if (j != 0 || out_len != (nrv_uint)h.sz_unc)
err_exit(7);
// j == 0 now
}
xo->buf += h.sz_unc;
xo->size -= h.sz_unc;
}
}
#include <elf.h>
// Create (or find) an escape hatch to use when munmapping ourselves the stub.
// Called by do_xmap to create it, and by assembler code to find it.
void *
make_hatch(Elf32_Phdr const *const phdr)
{
if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
unsigned *hatch;
// The format of the 'if' is
// if ( ( (hatch = loc1), test_loc1 )
// || ( (hatch = loc2), test_loc2 ) ) {
// action
// }
// which uses the comma to save bytes when test_locj involves locj
// and the action is the same when either test succeeds.
// Try page fragmentation just beyond .text .
if ( ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr)),
( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss
&& 4<=(~PAGEMASK & -(int)hatch) ) ) // space left on page
// Try Elf32_Ehdr.e_ident[12..15] . warning: 'const' cast away
|| ( (hatch = (void *)(&((Elf32_Ehdr *)phdr->p_vaddr)->e_ident[12])),
(phdr->p_offset==0) ) ) {
// Omitting 'const' saves repeated literal in gcc.
unsigned /*const*/ escape = 0xc36180cd; // "int $0x80; popa; ret"
// Don't store into read-only page if value is already there.
if (*hatch != escape) {
*hatch = escape;
}
return hatch;
}
}
return 0;
}
static void
bzero(char *p, size_t len)
{
if (len) do {
*p++= 0;
} while (--len);
}
static Elf32_Addr // entry address
do_xmap(int fdi, Elf32_Ehdr const *const ehdr, f_expand *const f_decompress,
Elf32_auxv_t *const a)
{
struct Extent x;
Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff +
(char const *)ehdr);
unsigned long base = (ET_DYN==ehdr->e_type) ? 0x40000000 : 0;
int j;
for (j=0; j < ehdr->e_phnum; ++phdr, ++j)
if (PT_PHDR==phdr->p_type) {
a->a_un.a_val = phdr->p_vaddr;
}
else if (PT_LOAD==phdr->p_type) {
size_t mlen = x.size = phdr->p_filesz;
char *addr = x.buf = (char *)phdr->p_vaddr;
char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr;
size_t frag = (int)addr &~ PAGEMASK;
mlen += frag;
addr -= frag;
if (ET_DYN==ehdr->e_type) {
addr += base;
haddr += base;
}
else { // There is only one brk, the one for the ET_EXEC
do_brk(haddr+OVERHEAD); // Also takes care of whole pages of .bss
}
// Decompressor can overrun the destination by 3 bytes.
if (addr != do_mmap(addr, mlen + (f_decompress ? 3 : 0), PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | (f_decompress ? MAP_ANONYMOUS : 0),
fdi, phdr->p_offset - frag) ) {
err_exit(8);
}
if (0==base) {
base = (unsigned long)addr;
}
if (f_decompress) {
unpackExtent(&x, fdi, f_decompress);
}
bzero(addr, frag); // fragment at lo end
frag = (-mlen) &~ PAGEMASK; // distance to next page boundary
bzero(mlen+addr, frag); // fragment at hi end
if (f_decompress) {
make_hatch(phdr);
}
if (phdr->p_memsz != phdr->p_filesz) { // .bss
if (ET_DYN==ehdr->e_type) { // PT_INTERP whole pages of .bss?
addr += frag + mlen;
mlen = haddr - addr;
if (0 < (int)mlen) { // need more pages, too
if (addr != do_mmap(addr, mlen, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 ) ) {
err_exit(9);
ERR_LAB
}
}
}
}
else { // no .bss
int prot = 0;
if (phdr->p_flags & PF_X) { prot |= PROT_EXEC; }
if (phdr->p_flags & PF_W) { prot |= PROT_WRITE; }
if (phdr->p_flags & PF_R) { prot |= PROT_READ; }
if (0!=mprotect(addr, mlen, prot)) {
err_exit(10);
}
if (f_decompress) { // cleanup if decompressor overrun crosses page boundary
mlen += 3;
addr += mlen;
mlen &= ~PAGEMASK;
if (mlen<=3) { // page fragment was overrun buffer only
munmap(addr - mlen, mlen);
}
}
}
if (ET_DYN!=ehdr->e_type) {
do_brk(haddr);
}
}
if (close(fdi) != 0)
err_exit(11);
if (ET_DYN==ehdr->e_type) {
return ehdr->e_entry + base;
}
else {
return ehdr->e_entry;
}
}
/*************************************************************************
// upx_main - called by our entry code
//
// This function is optimized for size.
**************************************************************************/
void *upx_main(
char const *argv[],
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr
) __asm__("upx_main");
void *upx_main(
char const *argv[],
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR+OVERHEAD]
)
{
Elf32_Phdr const *phdr = (Elf32_Phdr const *)(1+ehdr);
int fdi; // file descriptor
size_t sz_elfhdrs; // sizeof(Ehdr and Phdrs), uncompressed
size_t sz_pckhdrs; // sizeof(Ehdr and Phdrs), compressed
Elf32_Addr entry;
struct Extent xo;
int j;
struct p_info header;
fdi = open(argv[1], O_RDONLY, 0);
#if 0
// Save some bytes of code - the lseek() below will fail anyway.
if (fdi < 0)
err_exit(12);
#endif
#define SCRIPT_MAX 32
// Seek to start of compressed data.
if (lseek(fdi, SCRIPT_MAX+sizeof(struct l_info), SEEK_SET) < 0)
err_exit(13);
// Read header.
if (xread(fdi, (void *)&header, sizeof(header)) != 0) {
err_exit(14);
}
//
// ----- Step 4: decompress blocks -----
//
// Get Elf32_Ehdr. First set xo.size = size[0] = uncompressed size
if (0!=xread(fdi, (void *)&xo, sizeof(xo))) {
err_exit(15);
}
if (lseek(fdi, -sizeof(xo), SEEK_CUR) < 0) {
err_exit(16);
ERR_LAB
}
sz_elfhdrs = xo.size;
sz_pckhdrs = (size_t)xo.buf;
xo.buf = (char *)ehdr;
unpackExtent(&xo, fdi, f_decompress);
// Prepare to decompress the Elf headers again, into the first PT_LOAD.
if (lseek(fdi, -(sizeof(xo) + sz_pckhdrs), SEEK_CUR) < 0) {
err_exit(17);
}
av[0].a_type = AT_PHDR; av[0].a_un.a_val = 0; // updated by do_xmap
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;
av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGESIZE;
av[4].a_type = AT_ENTRY; av[4].a_un.a_val = ehdr->e_entry;
av[5].a_type = AT_NULL;
entry = do_xmap(fdi, ehdr, f_decompress, av);
// Map PT_INTERP program interpreter
for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_INTERP==phdr->p_type) {
char const *const iname = (char const *)phdr->p_vaddr;
if (0 > (fdi = open(iname, O_RDONLY, 0))) {
err_exit(18);
}
if (0!=xread(fdi, (void *)ehdr, MAX_ELF)) {
err_exit(19);
}
entry = do_xmap(fdi, ehdr, 0, 0);
break;
}
return (void *)entry;
}
/*
vi:ts=4:et:nowrap
*/
+232
View File
@@ -0,0 +1,232 @@
; l_lxsep86.asm -- Linux program entry point & decompressor (separate script)
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2000 Laszlo Molnar
;
; Integration of virtual exec() with decompression is
; Copyright (C) 2000 John F. Reiser. All rights reserved.
;
; UPX and the UCL library are free software; you can redistribute them
; and/or modify them under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; see the file COPYING.
; If not, write to the Free Software Foundation, Inc.,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;
; Markus F.X.J. Oberhumer Laszlo Molnar
; markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
;
; John F. Reiser
; jreiser@BitWagon.com
BITS 32
SECTION .text
%define jmps jmp short
; defines for ident.ash and n2b_d32.ash
%ifdef SMALL
%define __IDENTSMA__
%define __N2BSMA10__
%define __N2BSMA20__
%define __N2BSMA30__
%define __N2BSMA40__
%define __N2BSMA50__
%define __N2BSMA60__
%define __N2DSMA10__
%define __N2DSMA20__
%define __N2DSMA30__
%define __N2DSMA40__
%define __N2DSMA50__
%define __N2DSMA60__
%endif
%include "ident.ash"
; /*************************************************************************
; // program entry point
; // see glibc/sysdeps/i386/elf/start.S
; **************************************************************************/
GLOBAL _start
_start:
;;;; int3
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
;; Build the stubs and upx. Compress a testcase, such as a copy of /bin/date.
;; Invoke gdb on the separate stub (such as "gdb upxb"), and give the command
;; "run date". Define a single-step macro such as
;; define g
;; stepi
;; x/i $pc
;; end
;; and a step-over macro such as
;; define h
;; x/2i $pc
;; tbreak *$_
;; continue
;; x/i $pc
;; end
;; Step through the code; remember that <Enter> repeats the previous command.
;;
call main ; push address of decompress subroutine
; /*************************************************************************
; // C callable decompressor
; **************************************************************************/
%define INP dword [esp+8*4+4]
%define INS dword [esp+8*4+8]
%define OUTP dword [esp+8*4+12]
%define OUTS dword [esp+8*4+16]
decompress:
pusha
; cld
mov esi, INP
mov edi, OUTP
or ebp, byte -1
;;; align 8
%ifdef NRV2B
%include "n2b_d32.ash"
%elifdef NRV2D
%include "n2d_d32.ash"
%else
%error
%endif
; eax is 0 from decompressor code
;xor eax, eax ; return code
; check compressed size
mov edx, INP
add edx, INS
cmp esi, edx
jz .ok
dec eax
.ok:
; write back the uncompressed size
sub edi, OUTP
mov edx, OUTS
mov [edx], edi
mov [7*4 + esp], eax
popa
ret
%define PAGE_MASK (~0<<12)
%define PAGE_SIZE ( 1<<12)
%define szElf32_Phdr 8*4
%define a_val 4
%define __NR_munmap 91
main:
pop ebp ; &decompress
cld
; Move argc,argv,envp down so that we can insert more Elf_auxv entries.
; ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance
%define OVERHEAD 2048
%define MAX_ELF_HDR 512
mov esi, esp
sub esp, byte 6*8 ; AT_PHENT, AT_PHNUM, AT_PAGESZ, AT_ENTRY, AT_PHDR, AT_NULL
mov edi, esp
call do_auxv ; edi= &AT_next
lea ecx, [4+esp] ; argv
sub esp, dword MAX_ELF_HDR + OVERHEAD
push esp ; argument: temp space
push edi ; argument: AT_next
push ebp ; argument: &decompress
push ecx ; argument: argv
EXTERN upx_main
call upx_main ; entry = upx_main(argv, &decompress, AT_next, tmp_ehdr)
add esp, dword 4*4 + MAX_ELF_HDR + OVERHEAD ; remove temp space, args
pop ecx ; argc
pop edx ; ++argv discard argv[0] == pathname of stub
dec ecx ; --argc
push ecx
push eax ; save entry address
mov edi, [a_val + edi] ; AT_PHDR
find_hatch:
push edi
EXTERN make_hatch
call make_hatch ; find hatch = make_hatch(phdr)
pop ecx ; junk the parameter
add edi, byte szElf32_Phdr ; prepare to try next Elf32_Phdr
test eax,eax
jz find_hatch
xchg eax,edx ; edx= &hatch
; _dl_start and company (ld-linux.so.2) assumes that it has virgin stack,
; and does not initialize all its stack local variables to zero.
; Ulrich Drepper (drepper@cyngus.com) has refused to fix the bugs.
; See GNU wwwgnats libc/1165 .
%define N_STKCLR (0x100 + MAX_ELF_HDR + OVERHEAD)/4
lea edi, [esp - 4*N_STKCLR]
pusha ; values will be zeroed
mov ecx, N_STKCLR
xor eax,eax
rep stosd
mov ecx, dword -PAGE_SIZE
mov ebx, ebp
and ebx, ecx ; round down to page boundary
neg ecx ; PAGE_SIZE (this stub fits in it)
push byte __NR_munmap
pop eax
jmp edx ; unmap ourselves, then goto entry
do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL
; cld
L10: ; move argc+argv
lodsd
stosd
test eax,eax
jne L10
L20: ; move envp
lodsd
stosd
test eax,eax
jne L20
L30: ; move existing Elf32_auxv
lodsd
stosd
test eax,eax ; AT_NULL ?
lodsd
stosd
jne L30
sub edi, byte 8 ; point to AT_NULL
ret
; vi:ts=8:et:nowrap
+15
View File
@@ -0,0 +1,15 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS
{
. = 0x00400000 + SIZEOF_HEADERS;
.text : {
*(.text)
*(.data)
}
/* 0x08048000: customary Linux/x86 Elf .text start */
. = 0x08048000 + (0xfff & .);
.data : {
}
}
+357
View File
@@ -0,0 +1,357 @@
/* l_lx_sh.c -- stub loader for Linux x86 shell script executable
This file is part of the UPX executable compressor.
Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2000 Laszlo Molnar
Integration of virtual exec() with decompression is
Copyright (C) 2000 John F. Reiser. All rights reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar
markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
John F. Reiser
jreiser@BitWagon.com
*/
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include "linux.hh"
/*************************************************************************
// configuration section
**************************************************************************/
// In order to make it much easier to move this code at runtime and execute
// it at an address different from it load address: there must be no
// static data, and no string constants.
#define PAGEMASK (~0u<<12) // discards the offset, keeps the page
#define PAGESIZE ( 1u<<12)
#define MAX_ELF_HDR 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this
/*************************************************************************
// "file" util
**************************************************************************/
struct Extent {
size_t size; // must be first to match size[0] uncompressed size
char *buf;
};
static void
xread(struct Extent *x, char *buf, size_t count)
{
char *p=x->buf, *q=buf;
size_t j;
if (x->size < count) {
exit(127);
}
for (j = count; 0!=j--; ++p, ++q) {
*q = *p;
}
x->buf += count;
x->size -= count;
}
/*************************************************************************
// util
**************************************************************************/
#if 0 //{ save space
#define ERR_LAB error: exit(127);
#define err_exit(a) goto error
#else //}{ save debugging time
#define ERR_LAB
static void
err_exit(int a)
{
(void)a; // debugging convenience
exit(127);
}
#endif //}
static void *
do_brk(void *addr)
{
return brk(addr);
}
static char *
do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
(void)len; (void)prot; (void)flags; (void)fd; (void)offset;
return mmap((int *)&addr);
}
/*************************************************************************
// UPX & NRV stuff
**************************************************************************/
typedef int f_expand(
const nrv_byte *, nrv_uint,
nrv_byte *, nrv_uint * );
static void
unpackExtent(
struct Extent *const xi, // input
struct Extent *const xo, // output
f_expand *const f_decompress
)
{
while (xo->size) {
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
// Read and check block sizes.
xread(xi, (char *)&h, sizeof(h));
if (h.sz_unc == 0) { // uncompressed size 0 -> EOF
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
err_exit(2);
if (xi->size != 0) // all bytes must be written
err_exit(3);
break;
}
if (h.sz_cpr <= 0) {
err_exit(4);
ERR_LAB
}
if (h.sz_cpr > h.sz_unc
|| h.sz_unc > (int32_t)xo->size ) {
err_exit(5);
}
// Now we have:
// assert(h.sz_cpr <= h.sz_unc);
// assert(h.sz_unc > 0 && h.sz_unc <= blocksize);
// assert(h.sz_cpr > 0 && h.sz_cpr <= blocksize);
if (h.sz_cpr < h.sz_unc) { // Decompress block
nrv_uint out_len;
int const j = (*f_decompress)(xi->buf, h.sz_cpr, xo->buf, &out_len);
if (j != 0 || out_len != (nrv_uint)h.sz_unc)
err_exit(7);
xi->buf += h.sz_cpr;
xi->size -= h.sz_cpr;
}
else { // copy literal block
xread(xi, xo->buf, h.sz_cpr);
}
xo->buf += h.sz_unc;
xo->size -= h.sz_unc;
}
}
static void
bzero(char *p, size_t len)
{
if (len) do {
*p++= 0;
} while (--len);
}
// This do_xmap() has no Extent *xi input because it doesn't decompress anything;
// it only maps the shell and its PT_INTERP. So, it was specialized by hand
// to reduce compiled instruction size. gdb 2.91.66 does not notice that
// there is only one call to this static function (from getexec(), which
// would specify 0 for xi), so gdb does not propagate the constant parameter.
// Notice there is no make_hatch(), either.
static Elf32_Addr // entry address
do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, Elf32_auxv_t *const a)
{
Elf32_Phdr const *phdr = (Elf32_Phdr const *) (ehdr->e_phoff +
(char const *)ehdr);
unsigned long base = (ET_DYN==ehdr->e_type) ? 0x40000000 : 0;
int j;
for (j=0; j < ehdr->e_phnum; ++phdr, ++j)
if (PT_PHDR==phdr->p_type) {
a->a_un.a_val = phdr->p_vaddr;
}
else if (PT_LOAD==phdr->p_type) {
struct Extent xo;
size_t mlen = xo.size = phdr->p_filesz;
char *addr = xo.buf = (char *)phdr->p_vaddr;
char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr;
size_t frag = (int)addr &~ PAGEMASK;
mlen += frag;
addr -= frag;
if (ET_DYN==ehdr->e_type) {
addr += base;
haddr += base;
}
else { // There is only one brk, the one for the ET_EXEC
do_brk(haddr+OVERHEAD); // Also takes care of whole pages of .bss
}
// Decompressor can overrun the destination by 3 bytes.
if (addr != do_mmap(addr, mlen, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE,
fdi, phdr->p_offset - frag) ) {
err_exit(8);
}
if (0==base) {
base = (unsigned long)addr;
}
bzero(addr, frag); // fragment at lo end
frag = (-mlen) &~ PAGEMASK; // distance to next page boundary
bzero(mlen+addr, frag); // fragment at hi end
if (phdr->p_memsz != phdr->p_filesz) { // .bss
if (ET_DYN==ehdr->e_type) { // PT_INTERP whole pages of .bss?
addr += frag + mlen;
mlen = haddr - addr;
if (0 < (int)mlen) { // need more pages, too
if (addr != do_mmap(addr, mlen, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 ) ) {
err_exit(9);
ERR_LAB
}
}
}
}
else { // no .bss
int prot = 0;
if (phdr->p_flags & PF_X) { prot |= PROT_EXEC; }
if (phdr->p_flags & PF_W) { prot |= PROT_WRITE; }
if (phdr->p_flags & PF_R) { prot |= PROT_READ; }
if (0!=mprotect(addr, mlen, prot)) {
err_exit(10);
}
}
if (ET_DYN!=ehdr->e_type) {
do_brk(haddr);
}
}
if (0!=close(fdi)) {
err_exit(11);
}
if (ET_DYN==ehdr->e_type) {
return ehdr->e_entry + base;
}
else {
return ehdr->e_entry;
}
}
Elf32_Addr // entry address
getexec(char const *const fname, Elf32_Ehdr *const ehdr, Elf32_auxv_t *const av)
{
int const fdi = open(fname, O_RDONLY, 0);
if (0 > fdi) {
err_exit(18);
}
if (MAX_ELF_HDR!=read(fdi, (void *)ehdr, MAX_ELF_HDR)) {
err_exit(19);
}
return do_xmap(fdi, ehdr, av);
}
/*************************************************************************
// upx_main - called by our entry code
//
// This function is optimized for size.
**************************************************************************/
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr,
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr
) __asm__("upx_main");
void *upx_main(
char *const uncbuf, // place to put decompressed shell script
Elf32_Ehdr const *const my_ehdr, // to get compressed size and data
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR]
)
{
Elf32_Addr entry;
size_t const lsize = sizeof(struct p_info) +
*(unsigned short const *)(0x7c + (char const *)my_ehdr);
struct Extent xi = { // describe compressed shell script
((Elf32_Phdr const *)(1 + my_ehdr))->p_filesz - lsize,
(lsize + (char *)my_ehdr) // warning: 'const' cast away
};
struct Extent xo = { ((struct p_info *)xi.buf)[-1].p_filesize, uncbuf };
// Allocate space for decompressed shell script.
// "1+": guarantee '\0' terminator at end of decompressed script
if (xo.buf != do_mmap(xo.buf, 1+3+xo.size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0)) {
err_exit(20);
}
// Uncompress shell script
xo.buf += 3; // leave room for "-c" argument
unpackExtent(&xi, &xo, f_decompress);
{ // Map shell program
// 'fn' and 'efn' must not suffer constant-propagation by gcc
// UPX2 = 3 + offset to name_of_shell
// UPX3 = strlen(name_of_shell)
// patch & magic constants for our loader (le32 format)
#define UPX2 0x32585055 // "UPX2"
#define UPX3 0x33585055 // "UPX3"
char * /*const*/ volatile fn = UPX2 + uncbuf; // past "-c" and "#!"
char * /*const*/ volatile efn = UPX3 + fn; // &terminator
char const c = *efn; *efn = 0; // terminator
entry = getexec(fn, ehdr, av);
*efn = c; // replace terminator character
av[0].a_type = AT_PHDR; // av[0].a_un.a_val is set by do_xmap
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;
av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGESIZE;
av[4].a_type = AT_ENTRY; av[4].a_un.a_val = entry;
av[5].a_type = AT_NULL;
}
{ // Map PT_INTERP program interpreter
Elf32_Phdr const *phdr = (Elf32_Phdr *)(1+ehdr);
int j;
for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_INTERP==phdr->p_type) {
entry = getexec((char const *)phdr->p_vaddr, ehdr, 0);
break;
}
}
return (void *)entry;
}
/*
vi:ts=4:et:nowrap
*/
+291
View File
@@ -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
+17
View File
@@ -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 : {
}
}
+124
View File
@@ -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
+105
View File
@@ -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
+349
View File
@@ -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
+224
View File
@@ -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
+139
View File
@@ -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
+276
View File
@@ -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
*/
+215
View File
@@ -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
+10
View File
@@ -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
+120
View File
@@ -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
+100
View File
@@ -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
+47
View File
@@ -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
+75
View File
@@ -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
+45
View File
@@ -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
+77
View File
@@ -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
+40
View File
@@ -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
+984
View File
@@ -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
+7
View File
@@ -0,0 +1,7 @@
# Makefile for sstrip
sstrip: sstrip.c
gcc -ggdb -Wall -W -o sstrip sstrip.c
clean:
rm -f sstrip
+40
View File
@@ -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.
+70
View File
@@ -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
+218
View File
@@ -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;
}