ce5f9f95ea
alignments at the end of the file so that we do not depend on gas defaults.
208 lines
6.8 KiB
ArmAsm
208 lines
6.8 KiB
ArmAsm
/*
|
|
; i386-bsd.elf-fold.asm -- linkage to C code to process Elf binary
|
|
;
|
|
; This file is part of the UPX executable compressor.
|
|
;
|
|
; Copyright (C) 2000-2013 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> <ml1050@users.sourceforge.net>
|
|
;
|
|
; John F. Reiser
|
|
; <jreiser@users.sourceforge.net>
|
|
;
|
|
*/
|
|
|
|
#include "arch/i386/macros.S"
|
|
|
|
#define PAGE_SIZE ( 1<<12)
|
|
#define szElf32_Ehdr 0x34
|
|
#define szElf32_Phdr 8*4
|
|
#define e_type 16
|
|
#define e_entry (16 + 2*2 + 4)
|
|
#define p_memsz 5*4
|
|
#define szb_info 12
|
|
#define szl_info 12
|
|
#define szp_info 12
|
|
#define a_type 0
|
|
#define a_val 4
|
|
#define sz_auxv 8
|
|
|
|
#define __NR_munmap 73
|
|
|
|
// control just falls through, after this part and compiled C code
|
|
// are uncompressed.
|
|
|
|
fold_begin: // enter: %ebx= &Elf32_Ehdr of this program
|
|
// patchLoader will modify to be
|
|
// dword sz_uncompressed, sz_compressed
|
|
// byte compressed_data...
|
|
|
|
// ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance.
|
|
// Move argc,argv,envp down to make room for Elf_auxv table.
|
|
// Linux kernel 2.4.2 and earlier give only AT_HWCAP and AT_PLATFORM
|
|
// because we have no PT_INTERP. Linux kernel 2.4.5 (and later?)
|
|
// give not quite everything. It is simpler and smaller code for us
|
|
// to generate a "complete" table where Elf_auxv[k -1].a_type = k.
|
|
// On second thought, that wastes a lot of stack space (the entire kernel
|
|
// auxv, plus those slots that remain empty anyway). So try for minimal
|
|
// space on stack, without too much code, by doing it serially.
|
|
|
|
#define AT_NULL 0
|
|
#define AT_IGNORE 1
|
|
#define AT_PHDR 3
|
|
#define AT_PHENT 4
|
|
#define AT_PHNUM 5
|
|
#define AT_PAGESZ 6
|
|
#define AT_BASE 7
|
|
#define AT_ENTRY 9
|
|
|
|
#define ET_DYN 3
|
|
|
|
sub ecx, ecx
|
|
mov edx, (1<<AT_PHDR) | (1<<AT_PHENT) | (1<<AT_PHNUM) | (1<<AT_PAGESZ) | (1<<AT_BASE) | (1<<AT_ENTRY)
|
|
mov esi, esp
|
|
mov edi, esp
|
|
call do_auxv // clear bits in edx according to existing auxv slots
|
|
|
|
mov esi, esp
|
|
L50:
|
|
shr edx, 1 // Carry = bottom bit
|
|
sbb eax, eax // -1 or 0
|
|
sub ecx, eax // count of 1 bits that remained in edx
|
|
lea esp, [esp + sz_auxv * eax] // allocate one auxv slot, if needed
|
|
test edx,edx
|
|
jne L50
|
|
|
|
mov edi, esp
|
|
call do_auxv // move; fill new auxv slots with AT_IGNORE
|
|
|
|
#define OVERHEAD 2048
|
|
#define MAX_ELF_HDR 512
|
|
|
|
sub esp, MAX_ELF_HDR + OVERHEAD // alloca
|
|
push ebx // start of unmap region (&Elf32_Ehdr of this stub)
|
|
|
|
// Cannot pre-round .p_memsz because kernel requires PF_W to setup .bss,
|
|
// but strict SELinux (or PaX, grsecurity) prohibits PF_W with PF_X.
|
|
mov edx, [p_memsz + szElf32_Ehdr + ebx] // phdr[0].p_memsz
|
|
lea edx, [-1 + 2*PAGE_SIZE + edx + ebx] // 1 page for round, 1 for unfold
|
|
and edx, 0-PAGE_SIZE
|
|
|
|
push edx // end of unmap region
|
|
sub eax, eax // 0
|
|
cmp word ptr [e_type + ebx], ET_DYN
|
|
jne L53
|
|
xchg eax, edx // dynbase for ET_DYN; assumes mmap(0, ...) is placed after us!
|
|
L53:
|
|
push eax // dynbase
|
|
|
|
mov eax, [e_entry + ebx] // end of compressed data
|
|
mov esi, [-2*4 + eax] // length of compressed data
|
|
sub eax, esi // 1st &b_info
|
|
mov ebx, [ eax] // length of uncompressed ELF headers
|
|
mov ecx, [4+ eax] // length of compressed ELF headers
|
|
add ecx, szb_info
|
|
lea edx, [3*4 + esp] // &tmp
|
|
pusha // (AT_table, sz_cpr, f_expand, &tmp_ehdr, {sz_unc, &tmp}, {sz_cpr, &b1st_info} )
|
|
inc edi // swap with above 'pusha' to inhibit auxv_up for PT_INTERP
|
|
.extern upx_main
|
|
call upx_main // returns entry address
|
|
add esp, (8 +1)*4 // remove 8 params from pusha, also dynbase
|
|
pop ecx // end of unmap region
|
|
pop ebx // start of unmap region (&Elf32_Ehdr of this stub)
|
|
add esp, MAX_ELF_HDR + OVERHEAD // un-alloca
|
|
pop edx // bread crumb size in pages
|
|
shl edx,12
|
|
add ebx,edx // start of unmap region
|
|
|
|
push eax // save entry address as ret.addr
|
|
push 0 // 'leave' uses this to clear ebp
|
|
mov ebp,esp // frame
|
|
|
|
sub ecx, ebx
|
|
sub eax,eax // 0, also AT_NULL
|
|
push ecx // length to unmap
|
|
push ebx // start of unmap region (&Elf32_Ehdr of this stub)
|
|
push eax // fake ret.addr
|
|
|
|
dec edi // auxv table
|
|
.byte 0x3c // "cmpb al, ..." like "jmp 1+L60" but 1 byte shorter
|
|
L60:
|
|
scasd // a_un.a_val etc.
|
|
scasd // a_type
|
|
jne L60 // not AT_NULL
|
|
// edi now points at [AT_NULL]a_un.a_ptr which contains result of make_hatch()
|
|
push dword ptr [edi] // &escape hatch
|
|
|
|
xor edi,edi
|
|
xor esi,esi
|
|
xor edx,edx
|
|
xor ecx,ecx
|
|
xor ebx,ebx
|
|
mov al, __NR_munmap // eax was 0 from L60
|
|
ret // goto escape hatch: int 0x80; leave; ret
|
|
|
|
// called twice:
|
|
// 1st with esi==edi, ecx=0, edx= bitmap of slots needed: just update edx.
|
|
// 2nd with esi!=edi, ecx= slot_count: move, then append AT_IGNORE slots
|
|
// entry: esi= src = &argc; edi= dst; ecx= # slots wanted; edx= bits wanted
|
|
// exit: edi= &auxtab; edx= bits still needed
|
|
do_auxv:
|
|
// cld
|
|
lodsd; stosd // argc can be zero
|
|
|
|
L10: // move argv
|
|
lodsd; stosd
|
|
test eax,eax
|
|
jne L10
|
|
|
|
L20: // move envp
|
|
lodsd; stosd
|
|
test eax,eax
|
|
jne L20
|
|
|
|
push edi // return value
|
|
L30: // process auxv
|
|
lodsd // a_type
|
|
stosd
|
|
cmp eax, 32
|
|
jae L32 // prevent aliasing by 'btr' when 32<=a_type
|
|
btr edx, eax // no longer need a slot of type eax [Carry only]
|
|
L32:
|
|
test eax, eax // AT_NULL ?
|
|
lodsd
|
|
stosd
|
|
jnz L30 // a_type != AT_NULL
|
|
|
|
sub edi, 8 // backup to AT_NULL
|
|
add ecx, ecx // two words per auxv
|
|
inc eax // convert 0 to AT_IGNORE
|
|
rep stosd // allocate and fill
|
|
dec eax // convert AT_IGNORE to AT_NULL
|
|
stosd // re-terminate with AT_NULL
|
|
stosd
|
|
|
|
pop edi // &auxtab
|
|
ret
|
|
|
|
.balign 4,0
|
|
// vi:ts=8:et:nowrap
|
|
|