filters for unix(linux)

Modified Files:
	filteri.cpp filter/ctojr.h linker.cpp linker.h mem.cpp mem.h
	p_lx_elf.cpp p_lx_elf.h
	p_lx_exc.cpp p_lx_exc.h
	p_lx_sh.cpp  p_lx_sh.h
	p_unix.cpp packer.cpp packer.h packhead.cpp
	stub/Makefile    stub/macros.ash
	stub/l_lx_elf.c  stub/l_lx_elf86.asm  stub/l_lx_elf86.lds
	stub/l_lx_exec.c stub/l_lx_exec86.asm stub/l_lx_exec86.lds
	                 stub/l_lx_sh86.asm   stub/l_lx_sh86.lds
Added Files:
	filter/ctok.h
	stub/fold_elf86.asm stub/fold_exec86.asm stub/fold_sh86.asm

committer: jreiser <jreiser> 979796725 +0000
This commit is contained in:
John Reiser
2001-01-18 05:45:25 +00:00
parent 4d45677160
commit df9db96bd1
30 changed files with 2014 additions and 1105 deletions
+58 -72
View File
@@ -31,9 +31,10 @@ STUBS = \
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 \
l_lx_exec86.h fold_exec86.h \
l_lx_elf86.h fold_elf86.h \
l_lx_sh86.h fold_sh86.h \
l_ext2.h \
l_vmlinz.h
# experimental:
@@ -80,7 +81,7 @@ STRIPELF = ./util/sstrip/sstrip
# Use gcc 2.95.2 for smallest code.
CC_LINUX_CFLAGS = -Wall -W -Wcast-align -Wcast-qual -Wwrite-strings
CC_LINUX_CFLAGS += -Werror
###CC_LINUX_CFLAGS += -Werror
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)
@@ -170,6 +171,10 @@ l_tmt.h: l_tmt.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_ext2.h: l_ext2.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
l_vmlinz.h: l_vmlinz.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin nrv_loader $@
@@ -249,66 +254,56 @@ l_t_x2ds.h: l_tos2.s
# // linux rules (exec, elf, sh, sep)
# ************************************************************************/
l_lx_n2b.h: l_lx_exec.c l_xe_n2b.o l_lx_exec86.lds Makefile
$(CC_LINUX) -DNRV2B -o $T.o -c $<
ld -T $(srcdir)/l_lx_exec86.lds -Map $T.map -o $T.bin l_xe_n2b.o $T.o
$(SETFOLD) $T.bin
l_lx_elf86.h: l_lx_elf86.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin linux_i386elf_loader $@
l_lx_exec86.h: l_lx_exec86.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin linux_i386exec_loader $@
l_lx_sh86.h: l_lx_sh86.asx
$(NASM) -f bin -o $T.bin $<
$(BIN2H) $T.bin linux_i386sh_loader $@
l_lx_elf.o: l_lx_elf.c
$(CC_LINUX) -c $<
fold_elf86.o: fold_elf86.asm
$(NASM) -f elf -o $@ $<
fold_elf86.h: l_lx_elf.o fold_elf86.o l_lx_elf86.lds
ld -T l_lx_elf86.lds -Map $T.map -o $T.bin $T.o l_lx_elf.o
objcopy -S -R .comment -R .note $T.bin
./util/sstrip/sstrip $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386exec_nrv2b_loader $@
$(BIN2H) $T.bin linux_i386elf_fold $@
l_le_n2b.h: l_lx_elf.c l_6e_n2b.o l_lx_elf86.lds
$(CC_LINUX) -DNRV2B -o $T.o -c $<
ld -T $(srcdir)/l_lx_elf86.lds -Map $T.map -o $T.bin l_6e_n2b.o $T.o
$(SETFOLD) $T.bin
l_lx_exec.o: l_lx_exec.c
$(CC_LINUX) -c $<
fold_exec86.o: fold_exec86.asm
$(NASM) -f elf -o $@ $<
fold_exec86.h: l_lx_exec.o fold_exec86.o l_lx_exec86.lds
ld -T l_lx_exec86.lds -Map $T.map -o $T.bin $T.o l_lx_exec.o
objcopy -S -R .comment -R .note $T.bin
./util/sstrip/sstrip $T.bin
$(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386elf_nrv2b_loader $@
$(BIN2H) $T.bin linux_i386exec_fold $@
l_sh_n2b.h: l_lx_sh.c l_6h_n2b.o l_lx_sh86.lds
$(CC_LINUX) -DNRV2B -o $T.o -c $<
ld -T $(srcdir)/l_lx_sh86.lds -Map $T.map -o $T.bin l_6h_n2b.o $T.o
$(SETFOLD) $T.bin
l_lx_sh.o: l_lx_sh.c
$(CC_LINUX) -c $<
fold_sh86.o: fold_sh86.asm
$(NASM) -f elf -o $@ $<
fold_sh86.h: l_lx_sh.o fold_sh86.o l_lx_sh86.lds
ld -T l_lx_sh86.lds -Map $T.map -o $T.bin $T.o l_lx_sh.o
objcopy -S -R .comment -R .note $T.bin
./util/sstrip/sstrip $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 l_lx_exec86.lds
$(CC_LINUX) -DNRV2D -o $T.o -c $<
ld -T $(srcdir)/l_lx_exec86.lds -Map $T.map -o $T.bin l_xe_n2d.o $T.o
$(SETFOLD) $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 -o $T.o -c $<
ld -T $(srcdir)/l_lx_elf86.lds -Map $T.map -o $T.bin l_6e_n2d.o $T.o
$(SETFOLD) $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 -o $T.o -c $<
ld -T $(srcdir)/l_lx_sh86.lds -Map $T.map -o $T.bin l_6h_n2d.o $T.o
$(SETFOLD) $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 $@ $<
$(BIN2H) $T.bin linux_i386sh_fold $@
l_lx_sep.o: l_lx_sep.c
$(CC_LINUX) -c $<
@@ -344,25 +339,16 @@ 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_ext2.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
l_vmlinz.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_lx_elf86.asx: l_lx_elf86.asm macros.ash macros.asy
l_lx_exec86.asx: l_lx_exec86.asm macros.ash macros.asy
l_lx_sh86.asx: l_lx_sh86.asm macros.ash macros.asy
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
+127
View File
@@ -0,0 +1,127 @@
; fold_elf86.asm -- linkage to C code to process Elf binary
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 2000-2001 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 John F. Reiser
; markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com
;
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define p_memsz 5*4
%define a_val 4
%define __NR_munmap 91
;; control just falls through, after this part and compiled C code
;; are uncompressed.
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
+46
View File
@@ -0,0 +1,46 @@
; fold_exec86.asm -- linkage to C code to process Elf binary
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 2000-2001 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 John F. Reiser
; markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com
;
;; control just falls through, after this part and compiled C code
;; are uncompressed.
fold_begin: ;; this label is known to the Makefile
pop eax ; discard &dstlen
pop eax ; discard dstlen
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
push ebp ; argument: &decompress
push ebx ; argument: &my_elfhdr
push edx ; argument: envp
push ecx ; argument: argv
EXTERN upx_main
call upx_main ; Call the UPX main function
hlt ; Crash if somehow upx_main does return
; vi:ts=8:et:nowrap
+134
View File
@@ -0,0 +1,134 @@
; fold_sh86.asm -- Linux program entry point & decompressor (shell script)
;
; This file is part of the UPX executable compressor.
;
; Copyright (C) 1996-2001 Markus Franz Xaver Johannes Oberhumer
; Copyright (C) 1996-2001 Laszlo Molnar
; Copyright (C) 2000-2001 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 John F. Reiser
; markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com
;
BITS 32
SECTION .text
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
%define PAGE_SIZE ( 1<<12)
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 -5
View File
@@ -102,7 +102,11 @@ do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
// UPX & NRV stuff
**************************************************************************/
typedef void f_unfilter(nrv_byte *, nrv_uint); // 1st param is also addvalue
typedef void f_unfilter(
nrv_byte *, // also addvalue
nrv_uint,
unsigned cto8 // junk in high 24 bits
);
typedef int f_expand(
const nrv_byte *, nrv_uint,
nrv_byte *, nrv_uint * );
@@ -116,6 +120,7 @@ unpackExtent(
)
{
while (xo->size) {
unsigned cto8;
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
@@ -125,6 +130,8 @@ unpackExtent(
// Read and check block sizes.
xread(xi, (char *)&h, sizeof(h));
cto8 = h.sz_cpr;
h.sz_cpr >>= 8;
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);
@@ -155,7 +162,7 @@ ERR_LAB
&& ((512 < out_len) // this block is longer than Ehdr+Phdrs
|| (xo->size==(unsigned)h.sz_unc) ) // block is last in Extent
) {
(*f_unf)(xo->buf, out_len);
(*f_unf)(xo->buf, out_len, cto8);
}
xi->buf += h.sz_cpr;
xi->size -= h.sz_cpr;
@@ -330,14 +337,19 @@ void *upx_main(
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR+OVERHEAD]
)
{
size_t const lsize = *(unsigned short const *)(0x7c + (char const *)my_ehdr);
struct cprElfhdr {
Elf32_Ehdr ehdr;
Elf32_Phdr phdr[2];
struct l_info linfo;
};
size_t const lsize = ((struct cprElfhdr const *)my_ehdr)->linfo.l_lsize;
Elf32_Phdr const *phdr = (Elf32_Phdr const *)(1+ehdr);
Elf32_Addr entry;
struct Extent xo;
struct Extent xi = { 0, sizeof(struct p_info) + lsize + CONST_CAST(char *, my_ehdr) };
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
size_t const sz_elfhdrs = ((size_t *)xi.buf)[0]; // sizeof(Ehdr+Phdrs), uncompressed
size_t const sz_pckhdrs = ((size_t *)xi.buf)[1]>>8; // sizeof(Ehdr+Phdrs), compressed
(void)uncbuf; // used by l_lx_sh.c
// Uncompress Ehdr and Phdrs.
+21 -327
View File
@@ -33,42 +33,13 @@
%define jmps jmp short
%define jmpn jmp near
; 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"
;;;; names of pseudo-sections for addLoader:
;; LXUNFnnn Linux unfilter
;; LXNJMPnn omit filtering of 6-byte Jxx (0x0f 0x80..0x8f)
;; LXMRUnnn MostRecentlyUsed recoding of destinations
;; MRUARBnn arbitrary number of entries in wheel
;; MRUBITSn power of 2 entries in wheel (smaller code)
;; MRUBYTEn 256 entries in wheel (smallest code)
; /*************************************************************************
; // program entry point
; // see glibc/sysdeps/i386/elf/start.S
; **************************************************************************/
GLOBAL _start
;__LEXEC000__
_start:
;;;; int3
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
@@ -89,27 +60,6 @@ _start:
;;
call main ; push address of decompress subroutine
decompress:
;__LXUNF000__
jmps decompr0
;; 2+ address of decompress subroutine
;; unfilter(upx_byte *, length)
pop edx ; return address
pop eax ; upx_byte *, same as addvalue
pop ecx ; length
pusha ; save C-convention ebx, ebp, esi, edi; also eax, edx
xchg eax, edi ; edi= pointer
push dword ('?'<<8) | 0x0f ; cto8_0f (cto8 byte is modified)
%ifdef __MRUBYTE0__
xor ebx, ebx ; zero
%else ;__MRUARB00__ (also __MRUBITS0__)
mov ebx, 'NMRU' ; modified N_MRU or N_MRU -1
%endif ;__LXMRU010__
xor edx, edx ; zero
;__LXUNF010__
jmpn unf0
;__LXELF010__
; /*************************************************************************
; // C callable decompressor
@@ -120,7 +70,9 @@ decompress:
%define OUTP dword [esp+8*4+12]
%define OUTS dword [esp+8*4+16]
decompr0:
;__LEXEC009__
;; empty section for commonality with l_lx_exec86.asm
;__LEXEC010__
pusha
; cld
@@ -129,15 +81,13 @@ decompr0:
or ebp, byte -1
;;; align 8
%ifdef NRV2B
%include "n2b_d32.ash"
%elifdef NRV2D
%include "n2d_d32.ash"
%else
%error
%endif
%include "n2b_d32.ash"
%include "n2d_d32.ash"
%include "macros.ash"
cjt32 0
;__LEXEC015__
; eax is 0 from decompressor code
;xor eax, eax ; return code
@@ -158,191 +108,17 @@ decompr0:
popa
ret
;__LXUNF020__
;; continuation of entry prolog for unfilter
unf0:
;__LXMRU020__
push edx ; tail
push ebx ; n_mru or n_mru1
;__LXUNF025__
mov esi, esp
ctojr32
ckt32 dl
;__LEXEC017__
popa
ret
%define n_mru [esi]
%define n_mru1 [esi]
%define tail [esi + 4*1]
%define cto8_0f [esi + 4*2]
%define cto8 [esi + 4*2 +1]
%define addvalue [esi + 4*3 + 7*4]
%ifdef __MRUBITS1__
inc ebx ; n_mru1 ==> n_mru
%endif ;__LXMRU030__
unf1: ; allocate and clear mru[]
push edx ; zero
%ifdef __MRUBYTE1__
dec bl
%else ;__MRUARB10__
dec ebx
%endif ;__LXMRU040__
jnz unf1 ; leaves 0=='hand'
%define tmp ebp
%define jc eax
%define hand ebx
%define hand_l al
%define kh edx
%define kh_l dl
;__LXUNF030__
calltrickloop:
mov al, [edi]
inc edi
%ifndef __LXNJMP00__
sub al, 0x80 ; base of Jcc <d32>
cmp al, 0x8f - 0x80 ; span of Jcc <d32>
ja ct2 ; not Jcc <d32>
mov edx, [edi] ; often unaligned
cmp dx, cto8_0f
jne unfcount
mov byte [edi -1], dl ; 0x0f prefix
add al, 0x80 ; reconstitute Jcc
dec ecx
mov byte [edi], al ; Jcc opcode
inc edi
jmps lxunf
ct2:
sub al, 0xE8 - 0x80 ; base of JMP/CALL <d32>
cmp al, 0xE9 - 0xE8 ; span of JMP/CALL <d32>
%else ;__LXNJMP10__
sub al, 0xE8 ; base of JMP/CALL <d32>
cmp al, 0xE9 - 0xE8 ; span of JMP/CALL <d32>
%endif ;__LXMRU050__
ja unfcount
mov al, [edi]
cmp al, cto8
je lxunf
unfcount:
dec ecx
jg calltrickloop
mov edi,esp ; clear mru[] portion of stack
%ifdef __MRUBYTE2__
mov ecx, 3+ 256 ; unused, tail, ct8_0f
%elifdef __MRUBITS2__
mov ecx, n_mru1
add ecx, byte 1+ 3 ; n_mru1, tail, ct8_0f
%else ;__MRUARB20__
mov ecx, n_mru
add ecx, byte 3 ; n_mru, tail, ct8_0f
%endif ;__LXMRU060__
xor eax,eax
rep
stosd
mov esp,edi
popa
push ecx
push eax
push edx
ret
lxunf:
mov eax, [edi]
shr ax, 8
rol eax, 16
xchg al, ah
;__LXMRU065__
shr jc, 1 ; eax= jc, or mru index
jnc mru4 ; not 1st time for this jc
%ifdef __MRUBYTE3__
dec hand_l
%else ;__MRUARB30__
dec hand
%ifdef __MRUBITS3__
and hand, n_mru1
%else ;__MRUARB40__
jge mru3
add hand, n_mru
mru3:
%endif
%endif ;__LXMRU070__
mov [esp + 4*hand], jc ; 1st time: mru[hand] = jc
jmps unf_store
mru4: ; not 1st time for this jc
lea kh, [jc + hand] ; kh = jc + hand
%ifdef __MRUBYTE4__
movzbl kh, kh_l
%elifdef __MRUBITS4__
and kh, n_mru1
%else ;__MRUARB50__
cmp kh, n_mru
jb mru5
sub kh, n_mru
mru5:
%endif ;__LXMRU080__
mov jc, [esp + 4*kh] ; jc = mru[kh]
%ifdef __MRUBYTE5__
dec hand_l
%else ;__MRUARB60__
dec hand
%ifdef __MRUBITS5__
and hand, n_mru1
%else ;__MRUARB70__
jge mru6
add hand, n_mru
mru6:
%endif
%endif ;__LXMRU090__
mov tmp, [esp + 4*hand] ; tmp = mru[hand]
test tmp,tmp
jnz mru8
push jc ; ran out of registers
mov eax, tail
%ifdef __MRUBYTE6__
dec al
%else ;__MRUARB80__
dec eax
%ifdef __MRUBITS6__
and eax, n_mru1
%else ;__MRUARB90__
jge mru7
add eax, n_mru
mru7:
%endif
%endif ;__LXMRU100__
xor tmp,tmp
mov tail, eax
xchg [4+ esp + 4*eax], tmp ; tmp = mru[tail]; mru[tail] = 0
pop jc
mru8:
mov [esp + 4*kh ], tmp ; mru[kh] = tmp
mov [esp + 4*hand], jc ; mru[hand] = jc
;__LXUNF040__
unf_store:
sub eax, edi
sub ecx, byte 4
add eax, addvalue
mov [edi], eax
add edi, byte 4
jmps unfcount
;__LXELF020__
;__LEXEC020__
%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
@@ -366,7 +142,7 @@ unfold:
push eax ; &destination
; mmap a page to hold the decompressed program
xor ecx,ecx
xor ecx, ecx
push ecx
push ecx
mov ch, PAGE_SIZE >> 8
@@ -390,94 +166,12 @@ unfold:
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
eof:
; __XTHEENDX__
section .data
dd -1
dw eof
; vi:ts=8:et:nowrap
+1 -1
View File
@@ -27,7 +27,7 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
/*ENTRY(_start)*/
SECTIONS
{
/* 0x00401000: l_lx_elf86.asm assumes 1 page up from 64KB boundary */
+86 -86
View File
@@ -101,12 +101,19 @@ static uint32_t ascii5(char *p, uint32_t v, unsigned n)
do {
unsigned char d = v % 32;
if (d >= 26) d -= 43; // 43 == 'Z' - '0' + 1
*--p += d;
*--p = (d += 'A');
v /= 32;
} while (--n > 0);
return v;
}
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);
}
#if defined(__i386__)
# define SET2(p, c0, c1) \
@@ -125,6 +132,51 @@ static uint32_t ascii5(char *p, uint32_t v, unsigned n)
#endif
// go_self is a separate subroutine to spread the burden of local arrays.
// Otherwise the size of the stack frame in upx_main exceeds 128 bytes,
// which causes too many offsets to expand from 1 byte to 4.
static int
go_self(char const *tmpname, char *argv[], char *envp[])
{
// FIXME: why not use "/proc/self/fd/XX"? *BSD doesn't have it?
// Open the temp file.
int const fdi = open(tmpname, O_RDONLY, 0);
if (0 <= fdi) {
// 17 chars for "/proc/PPPPP/fd/XX" should be enough, but we
// play safe in case there will be 32-bit pid_t at some time.
//char procself_buf[17+1];
char procself_buf[31+1];
// Compute name of temp fdi.
SET4(procself_buf + 0, '/', 'p', 'r', 'o');
SET4(procself_buf + 4, 'c', '/', 0 , 0 );
{
char *const procself = upx_itoa(procself_buf + 6, getpid());
SET4(procself, '/', 'f', 'd', '/');
upx_itoa(procself + 4, fdi);
}
// Check for working /proc/self/fd/X by accessing the
// temp file again, now via temp fdi.
if (UPX2 == access(procself_buf, R_OK | X_OK)) {
// 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);
// NOTE: if we get here we've lost.
}
// The proc filesystem isn't working. No problem.
close(fdi);
}
return fdi;
}
/*************************************************************************
// UPX & NRV stuff
**************************************************************************/
@@ -153,59 +205,29 @@ void upx_main(
f_expand *const f_decompress
)
{
// file descriptors
int fdi, fdo;
Elf32_Phdr const *const phdr = (Elf32_Phdr const *)
(my_ehdr->e_phoff + (char const *)my_ehdr);
struct Extent xi = { phdr[1].p_memsz, (char *)phdr[1].p_vaddr };
char *next_unmap = (char *)(PAGE_MASK & (unsigned)xi.buf);
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;
// 17 chars for "/proc/PPPPP/fd/XX" should be enough, but we
// play safe in case there will be 32-bit pid_t at some time.
//char procself_buf[17+1];
char procself_buf[31+1];
char *procself;
// file descriptor
int fdo;
// decompression buffer
unsigned char *buf;
static struct MallocArgs {
char *ma_addr;
size_t ma_length;
int ma_prot;
int ma_flags;
int ma_fd;
off_t ma_offset;
} malloc_args = {
#if defined(USE_MMAP_FO)
0, 0, PROT_READ | PROT_WRITE, MAP_SHARED, 0, 0
#else
0, 0, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0
#endif
};
#if defined(USE_MMAP_FO)
static struct MallocArgs scratch_page = {
0, -PAGE_MASK, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0
};
#endif
char *tmpname;
Elf32_Phdr const *const phdr = (Elf32_Phdr const *)
(my_ehdr->e_phoff + (char const *)my_ehdr);
struct Extent xi = { phdr[1].p_memsz, (char *)phdr[1].p_vaddr };
char *next_unmap = (char *)(PAGE_MASK & (unsigned)xi.buf);
struct p_info header;
// temporary file name
char tmpname_buf[20];
//
// ----- 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++ = '/';
//
@@ -226,7 +248,7 @@ void upx_main(
// 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)
if (header.p_progid != UPX3)
goto error1;
@@ -234,13 +256,17 @@ void upx_main(
// ----- Step 2: prepare temporary output file -----
//
tmpname = tmpname_buf;
SET4(tmpname + 0, '/', 't', 'm', 'p');
SET4(tmpname + 4, '/', 'u', 'p', 'x');
// Compute name of temporary output file in tmpname[].
// Protect against Denial-of-Service attacks.
{
char *p = tmpname_buf + sizeof(tmpname_buf) - 1;
// Compute the last 4 characters (20 bits) from getpid().
uint32_t r = ascii5(p, (uint32_t)pid, 4); p-=4;
uint32_t r = ascii5(p, (uint32_t)getpid(), 4); *p = '\0'; p -= 4;
// Provide 4 random bytes from our program id.
r ^= header.p_progid;
@@ -254,7 +280,7 @@ void upx_main(
r ^= ((uint32_t) tv.tv_usec) << 12; // shift into high-bits
#else
// using adjtimex() may cause portability problems
static struct timex tx;
struct timex tx;
adjtimex(&tx);
r ^= (uint32_t) tx.time.tv_sec;
r ^= ((uint32_t) tx.time.tv_usec) << 12; // shift into high-bits
@@ -294,23 +320,23 @@ void upx_main(
//
#if defined(USE_MMAP_FO)
// mmap()ed output file.
malloc_args.ma_fd = fdo;
// FIXME: packer could set ma_length
malloc_args.ma_length = header.p_filesize;
buf = mmap((int *)&malloc_args);
// FIXME: packer could set length
buf = do_mmap(0, header.p_filesize,
PROT_READ | PROT_WRITE, MAP_SHARED, fdo, 0);
if ((unsigned long) buf >= (unsigned long) -4095)
goto error;
// Decompressor can overrun the output by 3 bytes.
// Defend against SIGSEGV by using a scratch page.
scratch_page.ma_addr = buf + (PAGE_MASK & (header.p_filesize + ~PAGE_MASK));
mmap((int *)&scratch_page);
// FIXME: packer could set address delta
do_mmap(buf + (PAGE_MASK & (header.p_filesize + ~PAGE_MASK)),
-PAGE_MASK, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 );
#else
// Temporary decompression buffer.
// FIXME: packer could set ma_length
malloc_args.ma_length = (header.p_blocksize + OVERHEAD + ~PAGE_MASK) & PAGE_MASK;
buf = mmap((int *)&malloc_args);
// FIXME: packer could set length
buf = do_mmap(0, (header.p_blocksize + OVERHEAD + ~PAGE_MASK) & PAGE_MASK,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 );
if ((unsigned long) buf >= (unsigned long) -4095)
goto error;
#endif
@@ -429,34 +455,9 @@ void upx_main(
// 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)
if (0 > go_self(tmpname, argv, envp))
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);
// NOTE: 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 -----
@@ -474,7 +475,7 @@ void upx_main(
if (fork() == 0)
{
// Sleep 3 seconds, then remove the temp file.
static const struct timespec ts = { UPX4, 0 };
struct timespec ts; ts.tv_sec = UPX4; ts.tv_nsec = 0;
nanosleep(&ts, 0);
unlink(tmpname);
}
@@ -500,4 +501,3 @@ void upx_main(
/*
vi:ts=4:et:nowrap
*/
+64 -83
View File
@@ -33,34 +33,13 @@
%define jmps jmp short
%define jmpn jmp near
; 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
;__LEXEC000__
_start:
;;;; int3
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
@@ -85,19 +64,24 @@ _start:
xor ebx, ebx ; PER_LINUX
int 0x80
%endif
call main ; push address of decompress subroutine
decompress:
; /*************************************************************************
; // 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]
%define INP dword [esp+8*4+8]
%define INS dword [esp+8*4+12]
%define OUTP dword [esp+8*4+16]
%define OUTS dword [esp+8*4+20]
decompress:
;__LEXEC009__
mov eax, 'NMRU' ; free slot in following 'pusha'
;__LEXEC010__
pusha
push byte '?' ; cto8 (sign extension does not matter)
; cld
mov esi, INP
@@ -105,75 +89,81 @@ decompress:
or ebp, byte -1
;;; align 8
%ifdef NRV2B
%include "n2b_d32.ash"
%elifdef NRV2D
%include "n2d_d32.ash"
%else
%error
%endif
%include "n2b_d32.ash"
%include "n2d_d32.ash"
%include "macros.ash"
cjt32 0
;__LEXEC015__
; eax is 0 from decompressor code
;xor eax, eax ; return code
; check compressed size
mov edx, INP
add edx, INS
cmp esi, edx
cmp edx, esi
jz .ok
dec eax
.ok:
xchg [8*4 + esp], eax ; store success/failure, fetch NMRU
; write back the uncompressed size
sub edi, OUTP
mov edx, OUTS
mov [edx], edi
; write back the uncompressed size, and prepare for unfilter
mov edx, OUTS
mov ecx, edi
mov edi, OUTP
sub ecx, edi ; ecx= uncompressed size
mov [edx], ecx
mov [7*4 + esp], eax
pop edx ; cto8
;__LEXEC110__ Jcc and/or possible n_mru
push edi ; addvalue
push byte 0x0f
pop ebx
mov bh, dl ; ebx= 0,,cto8,0x0F
;__LEXEC100__ 0!=n_mru
xchg eax, ebx ; eax= ct08_0f; ebx= n_mru {or n_mru1}
;;LEXEC016 bug in APP: jmp and target must be in same .asx
;; jmpn lxunf0 ; logically belongs here
ctojr32
ckt32 dl
;__LEXEC017__
popa
ret
;__LEXEC020__
%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 ; &fold_begin = src
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
mov ecx, PAGE_MASK
push esi ; &dst
mov ecx, ebp ; &decompress
and ecx, dword PAGE_MASK ; &my_elfhdr
mov ebx, ecx ; save &my_elfhdr for later
mov ebx, ebp ; &decompress
and ebx, ecx ; &my_elfhdr
neg ecx ; ecx= PAGE_SIZE
cld
lodsd ; sz_uncompressed
lodsd ; sz_compressed
;; Compressed code now begins at fold_begin.
;; We want decompressed code to begin at fold_begin, too.
;; Move the compressed code to the high end of the page.
;; Assume non-overlapping so that forward movsb is OK.
lea edi, [-PAGE_MASK + ecx] ; high end of page
add ecx, [p_filesz + szElf32_Ehdr + ecx] ; beyond src
sub ecx, esi ; srclen
push ecx ; srclen
sub edi, ecx
push edi ; &src
cld
rep movsb
lea edi, [ecx + ebx] ; high end of page
push eax ; srclen (of both movsb and decompress)
sub edi, eax ; dst of movsb
push edi ; &src for decompression (after movsb)
xchg ecx, eax ; ecx= len of movsb
rep movsb
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop eax ; discard &src
pop eax ; discard srclen
@@ -188,23 +178,14 @@ unfold:
main:
pop ebp ; &decompress
push eax ; place to store dstlen
push esp ; &dstlen
push eax ; sz_uncompressed (junk, actually)
push esp ; &sz_uncompressed
call unfold
fold_begin: ;; this label is known to the Makefile
pop eax ; discard &dstlen
pop eax ; discard dstlen
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
push ebp ; argument: &decompress
push ebx ; argument: &my_elfhdr
push edx ; argument: envp
push ecx ; argument: argv
EXTERN upx_main
call upx_main ; Call the UPX main function
hlt ; Crash if somehow upx_main does return
eof:
; __XTHEENDX__
section .data
dd -1
dw eof
; vi:ts=8:et:nowrap
+1 -1
View File
@@ -27,7 +27,7 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
/*ENTRY(_start)*/
SECTIONS
{
/* 0x08048000: customary Linux/x86 Elf .text start */
+15 -134
View File
@@ -30,37 +30,13 @@
BITS 32
SECTION .text
%define jmps jmp short
%define jmpn jmp near
; 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
;__LEXEC000__
_start:
;;;; int3
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
@@ -79,7 +55,9 @@ _start:
;; end
;; Step through the code; remember that <Enter> repeats the previous command.
;;
call main ; push address of decompress subroutine
decompress:
; /*************************************************************************
; // C callable decompressor
@@ -90,7 +68,7 @@ _start:
%define OUTP dword [esp+8*4+12]
%define OUTS dword [esp+8*4+16]
decompress:
;__LEXEC010__
pusha
; cld
@@ -99,15 +77,13 @@ decompress:
or ebp, byte -1
;;; align 8
%ifdef NRV2B
%include "n2b_d32.ash"
%elifdef NRV2D
%include "n2d_d32.ash"
%else
%error
%endif
%include "n2b_d32.ash"
%include "n2d_d32.ash"
%include "macros.ash"
cjt32 0
;__LEXEC015__
; eax is 0 from decompressor code
;xor eax, eax ; return code
@@ -128,15 +104,13 @@ decompress:
popa
ret
;__LEXEC020__
%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
@@ -145,7 +119,6 @@ decompress:
%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:
@@ -186,104 +159,12 @@ unfold:
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
eof:
; __XTHEENDX__
section .data
dd -1
dw eof
; vi:ts=8:et:nowrap
+12 -1
View File
@@ -27,18 +27,29 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
/*ENTRY(_start)*/
SECTIONS
{
/* 0x00800000: avoid 0x00400000 for shell itself being compressed */
. = 0x00800000 + SIZEOF_HEADERS;
. = ALIGN(0x80);
/*
.text : {
*(.text)
*(.data)
}
*/
.data : { /* put everything together in one Phdr */
*(.text)
*(.rodata)
*(.data)
*(.bss)
*(COMMON)
}
/* 0x08048000: customary Linux/x86 Elf .text start */
/*
. = 0x08048000 + (0xfff & .);
.data : {
}
*/
}
+355
View File
@@ -168,6 +168,53 @@ ctend:
%endmacro
;; call/jump/jcc trick; also used more than once (and/or optionally), so
;; ecx has byte count (not count of applied instances), and
;; edi points to buffer.
%macro ckt32 1 ; param: where is cto8 (dl, bl, or literal)
;__CKLLTR00__
mov esi, edi ; base of block
jmps ckstart
ckloop3:
mov al, [edi]
inc edi
;__CKLLTR10__ Jcc only
cmp al, 0x80 ; lo of 6-byte Jcc
jb ckloop2
cmp al, 0x8f ; hi of 6-byte Jcc
ja ckloop2
cmp byte [edi -2], 0x0F ; prefix of 6-byte Jcc
je ckmark
ckloop2:
;__CKLLTR20__
sub al, 0xE8
cmp al, 0xE9 - 0xE8
ja ckcount
ckmark:
cmp byte [edi], %1 ; cto8
jnz ckcount
mov eax, [edi]
shr ax, 8
rol eax, 16
xchg al, ah
sub eax, edi
add eax, esi
mov [edi], eax
add edi, byte 4
ckstart:
sub ecx, byte 4
;__CKLLTR30__ Jcc only
mov al, [edi]
inc edi
loop ckloop2 ; prefix cannot overlap previous displacement
;__CKLLTR40__
ckcount:
dec ecx
jg ckloop3
ckend:
%endmacro
;; =============
;; ============= 32-BIT RELOCATIONS
@@ -213,4 +260,312 @@ reloc_endx:
%endmacro
;; =============
;; ============= 32-BIT CALL TRICK UNFILTER WITH MostRecentlyUsed BUFFER
;; =============
;;;; names of pseudo-sections for addLoader:
;; LXUNFnnn Linux unfilter
;; LXMRUnnn MostRecentlyUsed recoding of destinations
;; MRUARBnn arbitrary number of entries in wheel
;; MRUBITSn power of 2 entries in wheel (smaller code)
;; MRUBYTEn 256 entries in wheel (smallest code)
%macro ctojr32 0
;; I got confused by the syntactic sugar of the fake %ifdefs.
;; I can read the section name more easily when it is at the left margin.
;; Also, some of the logic to select the sections is not that simple,
;; and any mismatch between the logic and the %ifdefs is very confusing.
;; Instead, I use comments after the section name, and blank lines for grouping.
;__LXUNF000__ enter at +0 for decompression; +2 for unfiltering
jmps decompr0
;__LXUNF002__
;; 2+ address of decompress subroutine
;; unfilter(upx_byte *, length, cto8)
lxunfilter:
pop edx ; return address
pop eax ; upx_byte *, same as addvalue
pop ecx ; length
xchg eax, edi ; edi= pointer; eax= saved_edi
pusha ; save C-convention ebx, ebp, esi, edi; also eax, edx
; at most one of the next 2
;__MRUBYTE0__ 256==n_mru
xor ebx, ebx ; zero
;__LXMRU005__ 0!=n_mru
mov ebx, 'NMRU' ; modified N_MRU or N_MRU -1
;__LXMRU006__ 0!=n_mru
push byte 0x0f ; prefix of 6-byte Jcc <d32>
pop eax
mov ah, [esp + 8*4] ; cto8
;__LXMRU007__ 0==n_mru
push byte 0x0f ; prefix of 6-byte Jcc <d32>
pop ebx
mov bh, [esp + 8*4] ; cto8
;__LXUNF008__
mov dl, [esp + 8*4] ; cto8
;__LXUNF010__
jmpn lxunf0
decompr0:
;; These %define are only if 0!=n_mru;
;; else 0x0F==bl && cto8==bh==dh && 0xE8==dl && addvalue==esi .
%define n_mru [esi]
%define n_mru1 [esi]
%define tail [esi + 4*1]
%define cto8_e8e9 [esi + 4*2]
%define cto8_0f [esi + 4*3]
%define addvalue [esi + 4*4]
%define tmp ebp
%define hand ebx
%define hand_l bl
%define kh edx
%define kh_l dl
;__LXJCC010__
lxunf2: ; have seen 0x80..0x8f of possible recoded 6-byte Jcc <d32>
movzx ebp, word [edi] ; 2 bytes, zero-extended
;__LXMRU045__ 0!=n_mru
sub ebp, cto8_0f
;__LXMRU046__ 0==n_mru
sub ebp, ebx
;__LXJCC020__ 0==n_mru, or Jcc excluded ('sub' of equals clears Carry)
jne unfcount
;__LXJCC021__ 0!=n_mru and Jcc participates; must set Carry
sub ebp, byte 1 ; set Carry iff in range
jnb unfcount
;__LXJCC023__ found Jcc; re-swap 0x8Y opcode and 0x0f prefix
mov byte [edi -1], bl ; 0x0f prefix
dec ecx ; preserve Carry
mov byte [edi], al ; Jcc opcode
inc edi ; preserve Carry
;__LXUNF037__
%define jc eax
lxunf: ; in: Carry set iff we should apply mru and 0!=n_mru
mov eax, [edi] ; BE32 displacement with cto8 in low 8 bits
;__LXUNF386__ 0!=n_mru && 386
pushf
;__LXUNF387__ ==386
shr ax, 8
rol eax, 16
xchg al, ah
;__LXUNF388__ 0!=n_mru && 386
popf
jnc unf_store ; do not apply mru
;__LXUNF486__ >=486
mov al, byte 0
bswap eax ; preserve Carry (2-byte instruction)
;__LXUNF487__ 0!=n_mru && >=486
jnc unf_store ; do not apply mru
;__LXMRU065__ 0!=n_mru
shr jc, 1 ; eax= jc, or mru index
jnc mru4 ; not 1st time for this jc
;__MRUBYTE3__
dec hand_l
;__MRUARB30__
dec hand
;__MRUBITS3__
and hand, n_mru1
;__MRUARB40__
jge mru3
add hand, n_mru
mru3:
;__LXMRU070__
mov [esp + 4*hand], jc ; 1st time: mru[hand] = jc
jmps unf_store
mru4: ; not 1st time for this jc
lea kh, [jc + hand] ; kh = jc + hand
;__MRUBYTE4__
movzx kh, kh_l
;__MRUBITS4__
and kh, n_mru1
;__MRUARB50__
cmp kh, n_mru
jb mru5
sub kh, n_mru
mru5:
;__LXMRU080__
mov jc, [esp + 4*kh] ; jc = mru[kh]
;__MRUBYTE5__
dec hand_l
;__MRUARB60__
dec hand
;__MRUBITS5__
and hand, n_mru1
;__MRUARB70__
jge mru6
add hand, n_mru
mru6:
;__LXMRU090__
mov tmp, [esp + 4*hand] ; tmp = mru[hand]
test tmp,tmp
jnz mru8
push jc ; ran out of registers
mov eax, tail
;__MRUBYTE6__
dec al
;__MRUARB80__
dec eax
;__MRUBITS6__
and eax, n_mru1
;__MRUARB90__
jge mru7
add eax, n_mru
mru7:
;__LXMRU100__
xor tmp,tmp
mov tail, eax
xchg [4+ esp + 4*eax], tmp ; tmp = mru[tail]; mru[tail] = 0
pop jc
mru8:
mov [esp + 4*kh ], tmp ; mru[kh] = tmp
mov [esp + 4*hand], jc ; mru[hand] = jc
;__LXUNF040__
unf_store:
sub eax, edi
sub ecx, byte 4
; one of the next2
;__LXMRU110__ 0!=n_mru
add eax, addvalue
;__LXMRU111__ 0==n_mru
add eax, esi ; addvalue (same as initial pointer)
;__LXUNF041__
mov [edi], eax
add edi, byte 4
jmps unfcount
;__LXUNF042__
lxunf0: ;; continuation of entry prolog for unfilter
;__LEXEC016__ bug in APP: jmp and label must be in same .asx/.asy
jmp lxunf0 ; this instr does not really go here!
;__LXMRU010__ 0!=n_mru
push eax ; cto8_0f
;__LXJMPA00__ only JMP, and not CALL, is filtered
mov al, 0xE9
;__LXCALLB0__ only CALL, or both CALL and JMP are filtered
mov al, 0xE8
;__LXUNF021__ common tail
push eax ; cto8_e8e9
push byte 0 ; tail
push ebx ; n_mru or n_mru1
mov esi, esp ; flat model "[esi]" saves a byte over "[ebp]"
;__LXMRU022__ 0==n_mru
pop esi ; addvalue
mov edx, ebx ; dh= cto8
;__LXJMPA01__ only JMP, and not CALL, is filtered
mov dl, 0xE9
;__LXCALLB1__ only CALL, or both CALL and JMP are filtered
mov dl, 0xE8
;__MRUBITS1__
inc hand ; n_mru1 ==> n_mru
;__LXMRU030__
lxunf1: ; allocate and clear mru[]
push byte 0
; one of the next 2, if n_mru
;__MRUBYTE1__
dec hand_l
;__MRUARB10__
dec hand
;__LXMRU040__ 0!=n_mru
jnz lxunf1 ; leaves 0=='hand'
;__LXUNF030__
lxctloop:
movzx eax, word [edi] ; 2 bytes, zero extended
inc edi
;__LXJCC000__
cmp al, 0x80 ; lo of Jcc <d32>
jb lxct1
cmp al, 0x8f ; hi of Jcc <d32>
jbe lxunf2
lxct1:
;__LXCJ0MRU__ 0==n_mru
sub eax, edx
;__LXCJ1MRU__ 0!=n_mru
sub eax, cto8_e8e9
; both CALL and JMP are filtered
;__LXCALJMP__
sub eax, byte 1+ (0xE9 - 0xE8) ; set Carry iff in range (result: -2, -1)
; only CALL, or only JMP, is filtered
;__LXCALL00__ 0==n_mru
je lxunf
;__LXCALL01__ 0!=n_rmu
sub eax, byte 1 ; set Carry iff in range
;__LXCJ2MRU__ 0==n_mru, or apply mru to all that are filtered here
jb lxunf ; only Carry (Borrow) matters
;__LXCJ4MRU__ 0!=n_mru, but apply mru only to subset of filtered here
jnb unfcount ; was not filtered anyway: do not unfilter
;we will unfilter, and 0!=n_mru, but should we apply mru?
;__LXCJ6MRU__ apply mru to JMP only (0xFF==al)
jpe lxct3 ; jump if even number of 1 bits in al
;__LXCJ7MRU__ apply mru to CALL only (0xFE==al)
jpo lxct3 ; jump if odd number of 1 bits in al
;__LXCJ8MRU__ do not apply mru to one or both
clc
lxct3:
jmps lxunf
;__LXUNF034__
unfcount:
dec ecx
jg lxctloop
;__LXMRU055__
mov edi, esp ; clear mru[] portion of stack
;__MRUBYTE2__
mov ecx, 4+ 256 ; unused, tail, cto8_e8e9, cto8_0f
;__MRUBITS2__
mov ecx, n_mru1
add ecx, byte 1+ 4 ; n_mru1, tail, cto8_e8e9, cto8_0f
;__MRUARB20__
mov ecx, n_mru
add ecx, byte 4 ; n_mru, tail, cto8_e8e9, cto8_0f
;__LXMRU057__
xor eax, eax
rep
stosd
mov esp, edi
;__LXMRU058__ 0==n_mru
push esi
;__LXUNF035__
popa
xchg eax, edi
push ecx
push eax
push edx
ret
%endmacro
; vi:ts=8:et:nowrap