Files
upx/src/stub/src/amd64-linux.elf-fold.S
T

240 lines
7.1 KiB
ArmAsm

/* amd64-linux.elf-fold.S -- linkage to C code to process Elf binary
*
* This file is part of the UPX executable compressor.
*
* Copyright (C) 2000-2024 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.com> <ezerotven+github@gmail.com>
*
* John F. Reiser
* <jreiser@users.sourceforge.net>
*/
NBPW= 8
#include "arch/amd64/macros.S"
#include "arch/amd64/regs.h"
PATH_MAX= 4096 // /usr/include/linux/limits.h
PAGE_SHIFT= 12 // /usr/include/sys/user.h
PAGE_SIZE= 1 << PAGE_SHIFT
PAGE_MASK= ~0 << PAGE_SHIFT
sz_b_info= 12
sz_unc= 0
sz_cpr= 4
sz_l_info= 12
sz_p_info= 12
MAP_PRIVATE= 0x02
MAP_FIXED= 0x10
PROT_READ= 0x1
O_RDONLY= 0
OVERHEAD=2048
/* 64-bit mode only! */
__NR_read= 0
__NR_write= 1
__NR_open= 2
__NR_close= 3
__NR_mmap= 9
__NR_mprotect= 10
__NR_munmap= 11
__NR_brk= 12
__NR_exit= 60
__NR_readlink= 89
// IN: [ADRX,+LENX): compressed data; [ADRU,+LENU): expanded fold (w/ upx_main)
// %rbx= 4+ &O_BINFO; %rbp= f_exp; %r14= ADRX; %r15= LENX;
// rsp/ elfaddr,%fd,ADRU,LENU,rdx,%entry, argc,argv,0,envp,0,auxv,0,strings
fold_begin:
//// int3 // DEBUG only
call L90
.asciz "/proc/self/exe"; .byte 0 // 16 bytes in all
#include "arch/amd64/bxx.S"
L90:
pop %rdx // "/proc/self/eax"
push %r14 // ADRX
push %r15 // LENX
lea 16(%rdx),%rax; push %rax # &amdbxx: f_unf
unmap_all_pages= (1<<1)
is_ptinterp= (1<<0)
push %rsp; pop %rsi
testb $unmap_all_pages,-4(%rbx); jnz 0f; sub $PATH_MAX,%rsp; 0:
push %rsp; pop %rdi
push $10; pop %rcx; rep movsq # f_unf,LENX,ADRX,elfaddr,%fd,ADRU,LENU,rdx,%entry,argc
xor %eax,%eax
0:
cmpq %rax,(%rsi); movsq; jne 0b # move past argv
movq %rdi,%r14 # remember &new_env[0]
testb $unmap_all_pages,-4(%rbx); jnz 0f; stosq; 0: # space for new_env[0]
0:
cmpq %rax,(%rsi); movsq; jne 0b # move past env
mov %rdi,%r12 # &new Elf64_auxv
push %rsi; pop %arg4 # &old_auxv in case no_env_pse
0:
cmpq %rax,(%rsi); movsq; movsq; jne 0b # move past auxv
mov %rdi,%r15 # beyond auxv
mov %rsi,%r13 # beginning of strings
sub %r15,%r12 # -length of auxv
testb $unmap_all_pages,-4(%rbx); jz env_pse
mov %rdi,%r14; jmp no_env_pse # beyond auxv
env_pse:
push %rdx; pop %arg1 # "/proc/self/exe"
push $O_RDONLY; pop %arg2
call open; mov %rax,4*NBPW(%rsp) # fd
movl $-1+ PATH_MAX,%arg3l # buflen
mov %r15,%arg2 # buffer (beyond auxv)
// %arg1 persists from open()
push $ __NR_readlink; pop %rax; syscall; testl %eax,%eax; jns 0f
// readlink() failed. Set the result equal to the argument.
push %arg1; pop %arg2 # result= "/proc/self/exe"
push $15; pop %rax # 1+ strlen( )
0:
xchg %eax,%ecx # %ecx= byte count
std
lea -1(%r13),%rdi # dst last byte
movb $0,%al; stosb # terminate
lea -1(%arg2,%rcx),%rsi # src last byte
rep movsb # slide up
sub $3,%rdi; movl $('='<<24)|(' '<<16)|(' '<<8)|(' '<<0),(%rdi) # env var name
mov %rdi,(%r14) # new_env[0]
and $~0<<3,%rdi # align
mov %r15,%rcx
sub %rsp,%rcx # byte count
mov %ecx,%eax
xor %edi,%eax
xor $NBPW,%eax
and $NBPW,%eax
sub %rax,%rdi # keep 16-byte alignment of %rsp
mov %rdi,%r14 # end of new auxv
sub $NBPW,%rdi # &last qword of new auxv
lea -NBPW(%r15),%rsi # &last qword of old auxv
shr $3,%rcx; rep movsq
lea NBPW(%rdi),%rsp
cld
lea (%r14,%r12),%arg4 # &new Elf64_auxv
no_env_pse:
movl -4(%rbx),%eax; and $is_ptinterp,%eax; add %rax,%arg4
pop %arg6 # f_unf
pop %arg2 # LENX
pop %arg1 # ADRX
pop %rax # elfaddr
subq $ OVERHEAD,%rsp
movq %rsp,%arg3 # &ELf64_Ehdr temporary space
push %rax; mov %rax,%r13 # elfaddr 7th arg
movq %rbp,%arg5 # &decompress: f_expand
call upx_main # Out: %rax= entry
/* entry= upx_main(b_info *arg1, total_size arg2, Elf64_Ehdr *arg3,
Elf32_Auxv_t *arg4, f_decompr arg5, f_unf arg6,
Elf64_Addr elfaddr )
*/
// rsp/ elfaddr,{OVERHEAD},fd,ADRU,LENU,rdx,%entry, argc,argv,0,envp,0,auxv,0,strings
addq $1*NBPW+OVERHEAD,%rsp # also discard elfaddr
movq %rax,4*NBPW(%rsp) # entry
pop %rbx # fd
sz_Ehdr= 8*NBPW
e_type= 16
ET_EXEC= 2
sz_Phdr= 7*NBPW
p_memsz= 5*NBPW
// Discard pages of compressed data (includes [ADRX,+LENX) )
movq p_memsz+sz_Phdr+sz_Ehdr(%r13),%arg2 # Phdr[C_TEXT= 1].p_memsz
//cmpw $ET_EXEC, e_type(%r13); jne 1f
movq %r13,%arg1; call brk // also sets the brk
1:
movq %r13,%arg1; call munmap # discard C_TEXT compressed data
// Map 1 page of /proc/self/exe so that the symlink does not disappear.
test %ebx,%ebx; js no_pse_map
subq %arg6,%arg6 # 0 offset
mov %ebx,%arg5l # fd
push $MAP_PRIVATE; pop %arg4
push $PROT_READ; pop %arg3
mov $PAGE_SIZE,%arg2l
subl %arg1l,%arg1l # 0
call mmap
mov %ebx,%edi # fd
call close
no_pse_map:
pop %arg1 # ADRU: unfolded upx_main etc.
pop %arg2 # LENU
push $__NR_munmap; pop %rax
jmp *-NBPW(%r14) # goto: syscall; pop %rdx; ret
mmap: .globl mmap
movb $ __NR_mmap,%al
movq %arg4,%sys4
sysgo: # NOTE: kernel demands 4th arg in %sys4, NOT %arg4
movzbl %al,%eax
syscall
cmpq $ PAGE_MASK,%rax; jc no_fail
orq $~0,%rax # failure; IGNORE errno
no_fail:
ret
Pprotect: .globl Pprotect
movl $~PAGE_MASK,%ecx // frag mask
and %edi,%ecx // frag
sub %rcx,%rdi
add %rcx,%rsi
jmp mprotect
exit: .globl exit
movb $ __NR_exit,%al; 5: jmp 5f
brk: .globl brk
movb $ __NR_brk,%al; 5: jmp 5f
close: .globl close
movb $ __NR_close,%al; 5: jmp 5f
open: .globl open
movb $ __NR_open,%al; 5: jmp 5f
munmap: .globl munmap
movb $ __NR_munmap,%al; 5: jmp 5f
mprotect: .globl mprotect
movb $ __NR_mprotect,%al; 5: jmp 5f
write: .globl write
mov $__NR_write,%al; 5: jmp 5f
read: .globl read
movb $ __NR_read,%al; 5: jmp sysgo
my_bkpt: .globl my_bkpt
int3 // my_bkpt
ret
/* vim:set ts=8 sw=8 et: */