1/* 2; i386-linux.shlib-init.S -- Linux shared library init & decompressor (Elf binary) 3; 4; This file is part of the UPX executable compressor. 5; 6; Copyright (C) 1996-2020 Markus Franz Xaver Johannes Oberhumer 7; Copyright (C) 1996-2020 Laszlo Molnar 8; Copyright (C) 2000-2020 John F. Reiser 9; All Rights Reserved. 10; 11; UPX and the UCL library are free software; you can redistribute them 12; and/or modify them under the terms of the GNU General Public License as 13; published by the Free Software Foundation; either version 2 of 14; the License, or (at your option) any later version. 15; 16; This program is distributed in the hope that it will be useful, 17; but WITHOUT ANY WARRANTY; without even the implied warranty of 18; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19; GNU General Public License for more details. 20; 21; You should have received a copy of the GNU General Public License 22; along with this program; see the file COPYING. 23; If not, write to the Free Software Foundation, Inc., 24; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 25; 26; Markus F.X.J. Oberhumer Laszlo Molnar 27; <markus@oberhumer.com> <ezerotven+github@gmail.com> 28; 29; John F. Reiser 30; <jreiser@users.sourceforge.net> 31; 32*/ 33 34#include "arch/i386/macros.S" 35 36 37/************************************************************************* 38// program entry point 39// see glibc/sysdeps/i386/elf/start.S 40**************************************************************************/ 41 42section LEXEC000 43// .long . // compress-time virtual address (detect runtime relocation) 44// .long user DT_INIT 45// .long &escape_hatch 46// .long &{p_info; b_info; compressed data} 47_start: .globl _start 48 //// int3 49 push eax; pusha 50 mov ebp,esp 51o_uinit= 8*4 // beyond saved registers 52//o_reloc= 6*4 // saved ecx 53 54 call main // push address of decompress subroutine 55decompress: 56 57// /************************************************************************* 58// // C callable decompressor 59// **************************************************************************/ 60 61// /* Offsets to parameters, allowing for {pusha + call} */ 62#define O_INP (8*4 +1*4) 63#define O_INS (8*4 +2*4) 64#define O_OUTP (8*4 +3*4) 65#define O_OUTS (8*4 +4*4) 66#define O_PARAM (8*4 +5*4) 67 68#define INP dword ptr [esp+O_INP] 69#define INS dword ptr [esp+O_INS] 70#define OUTP dword ptr [esp+O_OUTP] 71#define OUTS dword ptr [esp+O_OUTS] 72#define PARM dword ptr [esp+O_PARAM] 73 74section LEXEC009 75 //; empty section for commonality with l_lx_exec86.asm 76section LEXEC010 77 pusha 78 // cld 79 80 mov esi, INP 81 mov edi, OUTP 82 83 or ebp, -1 84//;; align 8 85 86#include "arch/i386/nrv2b_d32.S" 87#include "arch/i386/nrv2d_d32.S" 88#include "arch/i386/nrv2e_d32.S" 89#include "arch/i386/lzma_d.S" 90 cjt32 0 91 92section LEXEC015 93 // eax is 0 from decompressor code 94 //xor eax, eax ; return code 95 96// check compressed size 97 mov edx, INP 98 add edx, INS 99 cmp esi, edx 100 jz .ok 101 dec eax 102.ok: 103 104// write back the uncompressed size 105 sub edi, OUTP 106 mov edx, OUTS 107 mov [edx], edi 108 109 mov [7*4 + esp], eax 110 popa 111 ret 112 113 ctojr32 114 ctok32 edi, dl 115section LEXEC017 116 popa 117 ret 118 119section LEXEC020 120 121#define PAGE_SIZE ( 1<<12) 122PAGE_MASK= -PAGE_SIZE // AND clears the offset within page 123 124#define MAP_FIXED 0x10 125#define MAP_PRIVATE 0x02 126#define MAP_ANONYMOUS 0x20 127#define PROT_READ 1 128#define PROT_WRITE 2 129#define PROT_EXEC 4 130#define __NR_mmap 90 131#define __NR_munmap 91 132#define __NR_mprotect 125 133#define szElf32_Ehdr 0x34 134#define p_memsz 5*4 135sz_p_info = 3*4 136sz_l_info = 3*4 137sz_b_info=3*4 138 sz_unc= 0 139 sz_cpr= 4 140 b_method= 8 141 142#define __NR_write 4 143#define __NR_exit 1 144 145#define pushsbli .byte 0x6a, /* push sign-extended byte to long immediate*/ 146 147msg_SELinux: 148 pushsbli L71 - L70 149 pop edx // length 150 call L71 151L70: 152 .ascii "PROT_EXEC|PROT_WRITE failed.\n" 153L71: 154 pop ecx // message text 155 push 2 // fd stderr 156 pop ebx 157 push __NR_write; pop eax; int 0x80 158die: 159 mov bl, 127 // only low 7 bits matter! 160 push __NR_exit; pop eax; int 0x80 161 162main: 163// 1. allocate temporary pages 164// 2. copy to temporary pages: 165// fragment of page below dst; compressed src; 166// decompress+unfilter; supervise 167// 3. mmap destination pages for decompressed data 168// 4. create escape hatch 169// 5. jump to temporary pages 170// 6. uncompress 171// 7. unfilter 172// 8. mprotect decompressed pages 173// 9 setup args for unmap of temp pages 174// 10. jump to escape hatch 175// 11. unmap temporary pages 176// 12. goto user DT_INIT 177 178 pop edx // &decompress 179 180 lea esi,[edx + _start - decompress - 4*4] 181 mov ecx,esi 182 lodsd; sub ecx,eax; //mov [ebp+o_reloc],ecx 183 lodsd; add eax,ecx; mov [ebp+o_uinit],eax // reloc DT_INIT for step 12 184 lodsd; add eax,ecx; push eax // reloc &hatch for step 10 185p_hatch= -1*4 186 lodsd; add eax,ecx; xchg eax,edi // &l_info; also destination for decompress 187 lea esi,[edi + sz_l_info + sz_p_info] // &b_info 188 189 push eax; push eax // param space: munmap temp pages step 9 190p_unmap= -3*4 191 192 lodsd; lodsd; add esi,eax; lodsd // skip unpack helper block 193 194 lodsd // eax=dstlen 195 mov ebx,edi 196 and ebx,~PAGE_MASK // ebx= fragment 197 add eax,ebx // extend to page-aligned 198 sub edi,ebx 199 push eax; push edi // params: mprotect restored pages step 8 200p_mprot= -5*4 201 sub eax,ebx // restore 202 add edi,ebx 203 204 movzx ecx, byte ptr [esi+b_method-4+1]; push ecx // ftid 205 movzx ecx, byte ptr [esi+b_method-4+2]; push ecx // cto8 206 push eax; mov ecx,esp // dstlen also for unfilter step 7 207 push edi // dst param for unfilter step 7 208p_unflt= -9*4 209 push edx // &decompress 210o_uncpr= -10*4 211 212 lodsd; xchg eax,edx // edx= srclen 213 lodsd; push eax // method,filter,cto,junk 214 push ecx // &dstlen 215 push edi // dst 216 push edx // srclen 217 push esi // src; arglist ready for decompress step 6 218p_uncpr= -15*4 219 220 mov eax,[ebp+o_uncpr] // &decompress 221 add edx,[eax-4] // l_d_cpr + l_f_unc 222 223 call L220 224supervise: 225 // Allocate pages for result of decompressing. 226 // These replace the compressed source and the following hole. 227 push 0; push 0 228 push MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED 229 push PROT_READ|PROT_WRITE 230 push [ebp+p_mprot+4] // dstlen 231 push [ebp+p_mprot] // dst 232 mov ecx,ebx // save fragment 233 mov ebx,esp 234 push __NR_mmap; pop eax; int 0x80 235 cmp eax,[ebx]; je 0f; hlt; 0: 236 add esp,6*4 237 238 // Restore fragment of page below dst 239 xchg eax,edi 240 mov esi,[ebp+p_unmap] 241 add ecx,3; shr ecx,2 // FIXME: is this safe? 242 rep movsd 243 244 call [ebp+o_uncpr] // decompress 245// decompression can overrun dst by 3 bytes on i386; construct hatch now 246 pop eax; pop eax // discard src, srclen 247 pop eax // dst 248 pop ecx // &dstlen 249 pop edx // discard method,filter,cto,junk 250 add eax,[ecx] // dst += dstlen 251 mov dword ptr [eax],0xc36180cd // "int 0x80; popa; ret" 252 mov [esp + p_hatch - o_uncpr],eax // hatch at end of .text 253//o_uncpr 254 pop eax // &decompress 255//p_unflt 256 cmp word ptr [esp+3*4],0; je 0f // 0==ftid ==> no filter 257 add eax,2; call eax // unfilter {i386 f_unf==(2+f_unc)} 2580: 259 add esp,4*4 260//p_mprot 261 pop ebx // dst including fragment 262 pop ecx // dstlen 263 push PROT_READ|PROT_EXEC; pop edx 264 push __NR_mprotect; pop eax; int 0x80 265//p_unmap 266 pop ebx // &temp pages 267 pop ecx // length 268 push __NR_munmap; pop eax 269//p_hatch 270 ret // goto escape hatch 271//hatch: 272 int 0x80 // munmap temporary pages 273 popa 274 ret // goto user DT_INIT 275 276L220: 277 pop esi // &supervise 278 add edx,[esi-4] // total length to allocate 279 add edx,ebx // include fragment 280 281 // Allocate pages to hold temporary copy. 282 push 0; push 0 283 push MAP_PRIVATE|MAP_ANONYMOUS 284 push PROT_READ|PROT_WRITE|PROT_EXEC 285 push edx // length with fragment 286 push 0 // addr 287 mov ecx,ebx // save fragment 288 mov ebx,esp // & vec 289 push __NR_mmap; pop eax; int 0x80 290 cmp eax,PAGE_MASK; jb 0f; hlt; 0: 291 add esp,6*4 292 mov ebx,ecx // save fragment 293 294 mov [ebp+p_unmap ],eax // addr 295 mov [ebp+p_unmap+4],edx // length with fragment 296 xchg eax,edi // edi= dst 297 xchg eax,esi // eax= &supervise 298//p_uncpr 299 mov esi,[ebp+p_mprot] 300 add ecx,3; shr ecx,2 // FIXME: is this safe? 301 rep movsd // copy the fragment 302 303 pop esi // &src data (after fragment) 304 pop ecx; push ecx // length 305 push edi // &copied data (after fragment) 306 add ecx,3; shr ecx,2 307 rep movsd // copy compressed data 308 309 mov esi,[ebp+o_uncpr] 310 mov [ebp+o_uncpr],edi 311 mov ecx,[esi-4] 312 rep movsb 313 314//o_super 315 xchg eax,esi // esi= &supervise 316 push edi // &copied 317 mov ecx,[esi-4] 318 rep movsb 319 320 ret // goto copied supervise: 321 322// empty sections for commonality with non-shlib 323section LUNMP000 324section LUNMP001 325section LEXEC025 326section LEXECDYN 327 328/* vim:set ts=8 sw=8 et: */ 329