📄 elf-to-mem.txt
字号:
Decompressing ELF Directly to Memory on Linux/x86 Copyright (C) 2000-2007 John F. Reiser jreiser@BitWagon.comReferences: <elf.h> definitions for the ELF file format /usr/src/linux/fs/binfmt_elf.c what Linux execve() does with ELF objdump --private-headers a.elf dump the Elf32_Phdr http://www.cygnus.com/pubs/gnupro/5_ut/b_Usingld/ldLinker_scripts.html how to construct unusual ELF using /bin/ldThere is exactly one immovable object: In all of the Linux kernel,only the execve() system call sets the initial value of "the brk(0)",the value that is manipulated by system call 45 (__NR_brk in/usr/include/asm/unistd.h). For "direct to memory" decompression,there will be no execve() except for the execve() of the decompressorprogram itself. So, the decompressor program (which contains thecompressed version of the original executable) must have the samebrk() as the original executable. So, the second PT_LOADELF "segment" of the compressed program is used only to set the brk(0).See src/p_lx_elf.cpp, function PackLinuxElf32::generateElfHdr.All of the decompressor's code, and all of the compressed imageof the original executable, reside in the first PT_LOAD of thedecompressor program.The decompressor program stub is just under 2K bytes when linked.After linking, the decompressor code is converted to an initializedarray, and #included into the compilation of the compressor;see src/stub/l_le_n2b.h. To make self-contained compressedexecutables even smaller, the compressor also compresses all but thestartup and decompression subroutine of the decompressor itself,saving a few hundred bytes. The startup code first decompresses therest of the decompressor, then jumps to it. A nonstandard linkerscript src/stub/l_lx_elf86.lds places both the .text and .dataof the decompressor into the same PT_LOAD at 0x00401000. Thecompressor includes the compressed bytes of the original executableat the end of this first PT_LOAD.At runtime, the decompressed stub lives at 0x00400000. In order for thedecompressed stub to work properly at an address that is differentfrom its link-time address, the compiled code must contain no absoluteaddresses. So, the data items in l_lx_elf.c must be only parametersand automatic (on-stack) local variables; no global data, no static data,and no string constants. Use "size l_le_n2b.o l_6e_n2b.o" to checkthat both data and bss have length zero. Also, the '&' operatormay not be used to take the address of a function.The address 0x00400000 was chosen to be out of the way of the usualload address 0x08048000, and to minimize fragmentation in kernelpage tables; one page of page tables covers 4MB. The address0x00401000 was chosen as 1 page up from a 64KB boundary, tomake the startup code and its constants smaller.Decompression of the executable begins by decompressing the Elf32_Ehdrand Elf32_Phdr, and then uses the Ehdr and Phdrs to control decompressionof the PT_LOAD segments.Subroutine do_xmap() of src/stub/l_lx_elf.c performs the"virtual execve()" using the compressed data as source, and storesthe decompressed bytes directly into the appropriate virtual addresses.Before transferring control to the PT_INTERP "program interpreter",minor tricks are required to setup the Elf32_auxv_t entries,clear the free portion of the stack (to compensate for ld-linux.so.2assuming that its automatic stack variables are initialized to zero),and remove (all but 4 bytes of) the decompression program (andcompressed executable) from the address space.Because the UPX runtime stub removes all traces of the compressed filefrom the address space, then the Linux kernel erases the symlink/proc/self/exe. Linux stores the pathname argument that was specifiedto execve() immediately after the '\0' which terminates the characterstring of the last environment variable [as of execve()]. This is truefor at least all Linux 2.6, 2.4, and 2.2 kernels. The pathname is not"bound" to the file as strongly as /proc/self/exe (the file may be changedwithout affecting the pathname), but the pathname does provide someinformation. The pathname may be relative to the working directory,so look before any chdir().The Elf formats for Linux add an environment variable named " " [threespaces] which saves the results of readlink("/proc/self/exe",,) beforethe runtime stub unmaps all its pages. As of 2006-10-03 this worksfor linux/elf386 and linux/ElfAMD.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -