Put upx stub loader at high end of ELF output file on linux,
and allow for block-by-block specification of filter and parameters. linker.cpp linker.h mem.cpp mem.h p_elf.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 p_unix.h packer.cpp packer.h stub/fold_elf86.asm stub/fold_exec86.asm stub/fold_sh86.asm 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_sh.c stub/l_lx_sh86.asm stub/l_lx_sh86.lds stub/linux.hh committer: jreiser <jreiser> 981084316 +0000
This commit is contained in:
+17
-11
@@ -26,7 +26,10 @@
|
||||
|
||||
%define szElf32_Ehdr 0x34
|
||||
%define szElf32_Phdr 8*4
|
||||
%define e_entry (16 + 2*2 + 4)
|
||||
%define p_memsz 5*4
|
||||
%define szl_info 12
|
||||
%define szp_info 12
|
||||
%define a_val 4
|
||||
|
||||
%define __NR_munmap 91
|
||||
@@ -34,7 +37,7 @@
|
||||
;; control just falls through, after this part and compiled C code
|
||||
;; are uncompressed.
|
||||
|
||||
fold_begin:
|
||||
fold_begin: ; enter: %ebx= &Elf32_Ehdr of this program
|
||||
; patchLoader will modify to be
|
||||
; dword sz_uncompressed, sz_compressed
|
||||
; byte compressed_data...
|
||||
@@ -45,6 +48,7 @@ fold_begin:
|
||||
; 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 PAGE_SIZE ( 1<<12)
|
||||
%define OVERHEAD 2048
|
||||
%define MAX_ELF_HDR 512
|
||||
|
||||
@@ -53,18 +57,19 @@ fold_begin:
|
||||
mov edi, esp
|
||||
call do_auxv
|
||||
|
||||
mov eax, [p_memsz + 2*szElf32_Phdr + szElf32_Ehdr + ebx] ; size of PT_DYNAMIC
|
||||
sub esp, dword MAX_ELF_HDR + OVERHEAD
|
||||
mov ecx, [e_entry + ebx] ; beyond compressed data
|
||||
push esp ; argument: temp space
|
||||
lea eax, [szElf32_Ehdr + 3*szElf32_Phdr + szl_info + szp_info + ebx + eax] ; 1st &b_info
|
||||
push edi ; argument: AT_next
|
||||
sub ecx, eax ; length of compressed data
|
||||
push ebp ; argument: &decompress
|
||||
push edx ; argument: my_elfhdr
|
||||
add edx, [p_memsz + szElf32_Ehdr + edx]
|
||||
push edx ; argument: uncbuf
|
||||
push ecx ; argument: sz_compressed
|
||||
push eax ; argument: 1st &b_info
|
||||
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
|
||||
call upx_main ; entry = upx_main(b1st_info, sz_cpr, &decompress, AT_next, tmp_ehdr)
|
||||
add esp, dword 5*4 + MAX_ELF_HDR + OVERHEAD ; remove 5 params, temp space
|
||||
push eax ; save entry address
|
||||
|
||||
mov edi, [a_val + edi] ; AT_PHDR
|
||||
@@ -90,9 +95,10 @@ EXTERN make_hatch
|
||||
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
|
||||
xor ecx, ecx ; 0
|
||||
mov ch, PAGE_SIZE>>8 ; 0x1000
|
||||
add ecx, [p_memsz + szElf32_Ehdr + ebx] ; length to unmap
|
||||
mov bh, 0 ; from 0x401000 to 0x400000
|
||||
push byte __NR_munmap
|
||||
pop eax
|
||||
jmp edx ; unmap ourselves via escape hatch, then goto entry
|
||||
|
||||
@@ -27,18 +27,26 @@
|
||||
;; control just falls through, after this part and compiled C code
|
||||
;; are uncompressed.
|
||||
|
||||
fold_begin: ;; this label is known to the Makefile
|
||||
%define szElf32_Ehdr 0x34
|
||||
%define szElf32_Phdr 8*4
|
||||
%define e_entry (16 + 2*2 + 4)
|
||||
%define p_vaddr 2*4
|
||||
%define p_memsz 5*4
|
||||
%define szl_info 12
|
||||
%define szp_info 12
|
||||
|
||||
fold_begin: ; enter: %ebx= &Elf32_Ehdr of this program
|
||||
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
|
||||
lea edx, [esp+eax*4+4] ; envp = &argv[argc + 1]
|
||||
mov esi, [e_entry + ebx]
|
||||
add ebx, szElf32_Ehdr + szElf32_Phdr + szl_info
|
||||
sub esi, ebx ; length
|
||||
lea edi, [2 + ebp] ; f_unfilter, maybe
|
||||
pusha ; (f_unf, cprLen, f_decpr, xx, cprSrc, envp, argv, argc)
|
||||
EXTERN upx_main
|
||||
call upx_main ; Call the UPX main function
|
||||
hlt ; Crash if somehow upx_main does return
|
||||
|
||||
+23
-18
@@ -30,11 +30,15 @@
|
||||
BITS 32
|
||||
SECTION .text
|
||||
|
||||
fold_begin:
|
||||
; patchLoader will modify to be
|
||||
; dword sz_uncompressed, sz_compressed
|
||||
; byte compressed_data...
|
||||
%define szElf32_Ehdr 0x34
|
||||
%define szElf32_Phdr 8*4
|
||||
%define e_entry (16 + 2*2 + 4)
|
||||
%define p_memsz 5*4
|
||||
%define szl_info 12
|
||||
%define szp_info 12
|
||||
|
||||
fold_begin: ; enter: %ebx= uncDst
|
||||
; also edx= szElf32_Ehdr + 2*szElf32_Phdr + &Elf32_Ehdr
|
||||
pop eax ; discard &sz_uncompressed
|
||||
pop eax ; discard sz_uncompressed
|
||||
|
||||
@@ -48,39 +52,40 @@ fold_begin:
|
||||
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
|
||||
call do_auxv ; edi= &AT_NEXT
|
||||
|
||||
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
|
||||
|
||||
xchg eax, ebx ; eax= uncDst
|
||||
lea edx, [szl_info + szp_info + edx] ; cprSrc
|
||||
mov ecx, [ edx] ; sz_unc
|
||||
mov ebx, [4+ edx] ; sz_cpr
|
||||
mov esi, eax ; extra copy of uncDst
|
||||
pusha ; (&AT_NEXT,uncDst,f_decpr,&ehdr,{sz_cpr,cprSrc},{sz_unc,uncDst})
|
||||
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
|
||||
call upx_main ; entry = upx_main(...)
|
||||
pop ecx ; junk
|
||||
push eax ; save entry address
|
||||
popa ; edi= entry address; esi= uncDst
|
||||
add esp, dword MAX_ELF_HDR + OVERHEAD ; remove 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"
|
||||
push esi ; &"-c"
|
||||
|
||||
inc ecx
|
||||
push edx ; argv[0] is duplicate of $0
|
||||
|
||||
push ecx ; new argc
|
||||
push eax ; save entry address
|
||||
push edi ; 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.
|
||||
|
||||
+19
-28
@@ -120,18 +120,12 @@ unpackExtent(
|
||||
)
|
||||
{
|
||||
while (xo->size) {
|
||||
unsigned cto8;
|
||||
struct {
|
||||
int32_t sz_unc; // uncompressed
|
||||
int32_t sz_cpr; // compressed
|
||||
} h;
|
||||
struct b_info h;
|
||||
// Note: if h.sz_unc == h.sz_cpr then the block was not
|
||||
// compressible and is stored in its uncompressed form.
|
||||
|
||||
// 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);
|
||||
@@ -144,7 +138,7 @@ unpackExtent(
|
||||
ERR_LAB
|
||||
}
|
||||
if (h.sz_cpr > h.sz_unc
|
||||
|| h.sz_unc > (int32_t)xo->size ) {
|
||||
|| h.sz_unc > xo->size ) {
|
||||
err_exit(5);
|
||||
}
|
||||
// Now we have:
|
||||
@@ -162,7 +156,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, cto8);
|
||||
(*f_unf)(xo->buf, out_len, h.b_cto8);
|
||||
}
|
||||
xi->buf += h.sz_cpr;
|
||||
xi->size -= h.sz_cpr;
|
||||
@@ -322,46 +316,43 @@ ERR_LAB
|
||||
**************************************************************************/
|
||||
|
||||
void *upx_main(
|
||||
char *const uncbuf,
|
||||
Elf32_Ehdr const *const my_ehdr,
|
||||
char /*const*/ *const b1st_info,
|
||||
unsigned const sz_compressed,
|
||||
f_expand *const f_decompress,
|
||||
Elf32_auxv_t *const av,
|
||||
Elf32_Ehdr *const ehdr
|
||||
) __asm__("upx_main");
|
||||
|
||||
void *upx_main(
|
||||
char *const uncbuf,
|
||||
Elf32_Ehdr const *const my_ehdr, // to get compressed size and data
|
||||
char /*const*/ *const b1st_info,
|
||||
unsigned const sz_compressed,
|
||||
f_expand *const f_decompress,
|
||||
Elf32_auxv_t *const av,
|
||||
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR+OVERHEAD]
|
||||
)
|
||||
{
|
||||
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) };
|
||||
struct Extent xi = { 0, b1st_info }; // location of 1st b_info
|
||||
|
||||
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
|
||||
// sizeof(Ehdr+Phdrs), uncompressed
|
||||
size_t const sz_elfhdrs = ((size_t *)xi.buf)[0];
|
||||
|
||||
// sizeof(Ehdr+Phdrs), compressed; including b_info header
|
||||
size_t const sz_pckhdrs = sizeof(struct b_info) + ((size_t *)xi.buf)[1];
|
||||
|
||||
(void)uncbuf; // used by l_lx_sh.c
|
||||
// Uncompress Ehdr and Phdrs.
|
||||
xo.size = sz_elfhdrs; xo.buf = (char *)ehdr;
|
||||
xi.size = 2*sizeof(size_t) + sz_pckhdrs;
|
||||
xo.size = sz_elfhdrs; xo.buf = (char *)ehdr;
|
||||
xi.size = sz_pckhdrs;
|
||||
unpackExtent(&xi, &xo, f_decompress, 0);
|
||||
|
||||
// Prepare to decompress the Elf headers again, into the first PT_LOAD.
|
||||
xi.buf -= 2*sizeof(size_t) + sz_pckhdrs;
|
||||
xi.size = ((Elf32_Phdr const *)(1 + my_ehdr))->p_filesz - lsize;
|
||||
xi.buf -= sz_pckhdrs;
|
||||
xi.size = sz_compressed;
|
||||
|
||||
// av[0].a_un.a_val is set again by do_xmap if PT_PHDR is present
|
||||
// av[0].a_un.a_val is set again by do_xmap if PT_PHDR is present.
|
||||
// Caller of upx_main assumes that AT_PHDR will be set into av[0] .
|
||||
av[0].a_type = AT_PHDR; av[0].a_un.a_ptr = 1+(Elf32_Ehdr *)phdr->p_vaddr;
|
||||
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
|
||||
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;
|
||||
|
||||
@@ -116,7 +116,6 @@ decompress:
|
||||
|
||||
;__LEXEC020__
|
||||
|
||||
%define PAGE_MASK (~0<<12)
|
||||
%define PAGE_SIZE ( 1<<12)
|
||||
|
||||
%define MAP_FIXED 0x10
|
||||
@@ -126,7 +125,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:
|
||||
@@ -135,10 +133,7 @@ unfold:
|
||||
lodsd
|
||||
push eax ; sz_uncompressed (junk, actually)
|
||||
push esp ; &sz_uncompressed
|
||||
mov eax, ebp ; &decompress
|
||||
and eax, dword PAGE_MASK ; &my_elfhdr
|
||||
mov edx, eax ; need my_elfhdr later
|
||||
mov ah,0 ; round down to 64KB boundary
|
||||
mov eax, 0x400000
|
||||
push eax ; &destination
|
||||
|
||||
; mmap a page to hold the decompressed program
|
||||
@@ -148,16 +143,19 @@ unfold:
|
||||
mov ch, PAGE_SIZE >> 8
|
||||
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
|
||||
push byte PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
push ecx
|
||||
push ecx ; length
|
||||
push eax ; destination
|
||||
mov ebx, esp ; address of parameter vector for __NR_mmap
|
||||
push byte __NR_mmap
|
||||
pop eax
|
||||
mov ebx, esp
|
||||
int 0x80
|
||||
xchg eax, ebx
|
||||
mov bh, PAGE_SIZE>>8 ; ebx= 0x401000
|
||||
add esp, byte 6*4 ; discard args to mmap
|
||||
|
||||
lodsd
|
||||
push eax ; sz_compressed
|
||||
lodsd ; junk cto8, algo, unused[2]
|
||||
push esi ; &compressed_data
|
||||
call ebp ; decompress(&src, srclen, &dst, &dstlen)
|
||||
pop eax ; discard &compressed_data
|
||||
|
||||
+10
-4
@@ -28,17 +28,23 @@
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
/*ENTRY(_start)*/
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FILEHDR PHDRS ;
|
||||
data PT_LOAD ; /* for setting brk(0) */
|
||||
null PT_NULL; /* changed to PT_DYNAMIC for ldd */
|
||||
}
|
||||
SECTIONS
|
||||
{
|
||||
/* 0x00401000: l_lx_elf86.asm assumes 1 page up from 64KB boundary */
|
||||
. = 0x00401000 + SIZEOF_HEADERS;
|
||||
. = ALIGN(0x80);
|
||||
. = 0x00401000 + SIZEOF_HEADERS + 12; /* 12==sizeof(l_info) */
|
||||
.text : {
|
||||
*(.text)
|
||||
*(.data)
|
||||
}
|
||||
} : text
|
||||
/* 0x08048000: customary Linux/x86 Elf .text start */
|
||||
/* PackLinuxI386::buildLinuxLoader will overwrite the address anyway. */
|
||||
. = 0x08048000 + (0xfff & .);
|
||||
.data : {
|
||||
}
|
||||
} : data
|
||||
}
|
||||
|
||||
+33
-20
@@ -139,7 +139,7 @@ do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
|
||||
static int
|
||||
go_self(char const *tmpname, char *argv[], char *envp[])
|
||||
{
|
||||
// FIXME: why not use "/proc/self/fd/XX"? *BSD doesn't have it?
|
||||
// Old FreeBSD does not have /proc/self, so use /proc/<pid> instead.
|
||||
|
||||
// Open the temp file.
|
||||
int const fdi = open(tmpname, O_RDONLY, 0);
|
||||
@@ -181,6 +181,11 @@ go_self(char const *tmpname, char *argv[], char *envp[])
|
||||
// UPX & NRV stuff
|
||||
**************************************************************************/
|
||||
|
||||
typedef void f_unfilter(
|
||||
nrv_byte *, // also addvalue
|
||||
nrv_uint,
|
||||
unsigned cto8 // junk in high 24 bits
|
||||
);
|
||||
typedef int f_expand(
|
||||
const nrv_byte *src, nrv_uint src_len,
|
||||
nrv_byte *dst, nrv_uint *dst_len );
|
||||
@@ -193,16 +198,24 @@ typedef int f_expand(
|
||||
**************************************************************************/
|
||||
|
||||
void upx_main(
|
||||
char *argv[],
|
||||
f_unfilter *const f_unf,
|
||||
unsigned cprLen,
|
||||
f_expand *const f_decompress,
|
||||
int junk2,
|
||||
char /*const*/ *cprSrc,
|
||||
char *envp[],
|
||||
Elf32_Ehdr const *const my_ehdr,
|
||||
f_expand *const f_decompress
|
||||
char *argv[],
|
||||
int argc
|
||||
) __asm__("upx_main");
|
||||
void upx_main(
|
||||
char *argv[],
|
||||
f_unfilter *const f_unf,
|
||||
unsigned cprLen,
|
||||
f_expand *const f_decompress,
|
||||
int junk,
|
||||
char /*const*/ *cprSrc,
|
||||
char *envp[],
|
||||
Elf32_Ehdr const *const my_ehdr,
|
||||
f_expand *const f_decompress
|
||||
char *argv[],
|
||||
int argc
|
||||
)
|
||||
{
|
||||
// file descriptor
|
||||
@@ -213,9 +226,7 @@ void upx_main(
|
||||
|
||||
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 };
|
||||
struct Extent xi = { cprLen, cprSrc };
|
||||
|
||||
char *next_unmap = (char *)(PAGE_MASK & (unsigned)xi.buf);
|
||||
struct p_info header;
|
||||
@@ -223,6 +234,8 @@ void upx_main(
|
||||
// temporary file name
|
||||
char tmpname_buf[20];
|
||||
|
||||
(void)junk;
|
||||
|
||||
//
|
||||
// ----- Step 0: set /proc/self using /proc/<pid> -----
|
||||
//
|
||||
@@ -347,18 +360,13 @@ void upx_main(
|
||||
|
||||
for (;;)
|
||||
{
|
||||
struct {
|
||||
int32_t sz_unc; // uncompressed
|
||||
int32_t sz_cpr; // compressed
|
||||
} h;
|
||||
// Note: if h.sz_unc == h.sz_cpr then the block was not
|
||||
// compressible and is stored in its uncompressed form.
|
||||
struct b_info h;
|
||||
int i;
|
||||
|
||||
// Read and check block sizes.
|
||||
{
|
||||
register char *__d0, *__d1;
|
||||
__asm__ __volatile__( "movsl; movsl"
|
||||
__asm__ __volatile__( "movsl; movsl; movsl"
|
||||
: "=&D" (__d0), "=&S" (__d1)
|
||||
: "0" (&h), "1" (xi.buf)
|
||||
: "memory");
|
||||
@@ -373,9 +381,10 @@ void upx_main(
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
if (h.sz_cpr <= 0)
|
||||
goto error;
|
||||
if (h.sz_cpr > h.sz_unc || h.sz_unc > (int32_t)header.p_blocksize)
|
||||
// Note: if sz_unc == sz_cpr then the block was not
|
||||
// compressible and is stored in its uncompressed form.
|
||||
|
||||
if (h.sz_cpr > h.sz_unc || h.sz_cpr > header.p_blocksize)
|
||||
goto error;
|
||||
// Now we have:
|
||||
// assert(h.sz_cpr <= h.sz_unc);
|
||||
@@ -387,6 +396,9 @@ void upx_main(
|
||||
i = (*f_decompress)(xi.buf, h.sz_cpr, buf, &out_len);
|
||||
if (i != 0 || out_len != (nrv_uint)h.sz_unc)
|
||||
goto error;
|
||||
// Right now, unfilter is combined with decompression.
|
||||
// (*f_unfilter)(buf, out_len, cto8);
|
||||
(void)f_unf;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -486,6 +498,7 @@ void upx_main(
|
||||
waitpid(-1, (int *)0, 0);
|
||||
|
||||
// Execute the original program.
|
||||
(void)argc;
|
||||
execve(tmpname, argv, envp);
|
||||
|
||||
|
||||
|
||||
+38
-33
@@ -138,49 +138,53 @@ decompress:
|
||||
|
||||
;__LEXEC020__
|
||||
|
||||
%define PAGE_MASK (~0<<12)
|
||||
%define PAGE_SIZE ( 1<<12)
|
||||
|
||||
%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
|
||||
|
||||
; Decompress the rest of this loader, and jump to it
|
||||
unfold:
|
||||
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
|
||||
mov ecx, PAGE_MASK
|
||||
push esi ; &dst
|
||||
mov ebx, ebp ; &decompress
|
||||
and ebx, ecx ; &my_elfhdr
|
||||
neg ecx ; ecx= PAGE_SIZE
|
||||
|
||||
cld
|
||||
lodsd ; sz_uncompressed
|
||||
lodsd ; sz_compressed
|
||||
lodsd
|
||||
push eax ; sz_uncompressed (junk, actually)
|
||||
push esp ; &sz_uncompressed
|
||||
mov eax, 0x400000
|
||||
push eax ; &destination
|
||||
|
||||
;; 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, [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
|
||||
pop eax ; &dst == fold_begin
|
||||
|
||||
;; icache lookahead of compressed code after "call unfold" is still there.
|
||||
;; Synchronize with dcache of decompressed code.
|
||||
pushf
|
||||
push cs
|
||||
push eax
|
||||
iret ; back to fold_begin!
|
||||
; mmap a page to hold the decompressed program
|
||||
xor ecx, ecx
|
||||
push ecx
|
||||
push ecx
|
||||
mov ch, PAGE_SIZE >> 8
|
||||
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
|
||||
push byte PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
push ecx ; length
|
||||
push eax ; destination
|
||||
mov ebx, esp ; address of parameter vector for __NR_mmap
|
||||
push byte __NR_mmap
|
||||
pop eax
|
||||
int 0x80
|
||||
xchg eax, ebx
|
||||
mov bh, PAGE_SIZE>>8 ; ebx= 0x401000
|
||||
add esp, byte 6*4 ; discard args to mmap
|
||||
|
||||
lodsd
|
||||
push eax ; sz_compressed
|
||||
lodsd ; junk cto8, algo, unused[2]
|
||||
push esi ; &compressed_data
|
||||
call ebp ; decompress(&src, srclen, &dst, &dstlen)
|
||||
pop eax ; discard &compressed_data
|
||||
pop eax ; discard sz_compressed
|
||||
ret ; &destination
|
||||
main:
|
||||
pop ebp ; &decompress
|
||||
push eax ; sz_uncompressed (junk, actually)
|
||||
push esp ; &sz_uncompressed
|
||||
call unfold
|
||||
|
||||
eof:
|
||||
@@ -190,3 +194,4 @@ eof:
|
||||
dw eof
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
|
||||
|
||||
@@ -30,9 +30,8 @@ OUTPUT_ARCH(i386)
|
||||
/*ENTRY(_start)*/
|
||||
SECTIONS
|
||||
{
|
||||
/* 0x08048000: customary Linux/x86 Elf .text start */
|
||||
. = 0x08048000 + SIZEOF_HEADERS;
|
||||
. = ALIGN(0x80); /* room for Ehdr, 2*Phdr, l_info */
|
||||
/* 0x00401000: l_lx_exec86.asm assumes 1 page up from 64KB boundary */
|
||||
. = 0x00401000 + SIZEOF_HEADERS + 12; /* 12==sizeof(l_info) */
|
||||
.data : { /* put everything together in one Phdr */
|
||||
*(.text)
|
||||
*(.rodata)
|
||||
|
||||
+18
-35
@@ -114,10 +114,7 @@ unpackExtent(
|
||||
)
|
||||
{
|
||||
while (xo->size) {
|
||||
struct {
|
||||
int32_t sz_unc; // uncompressed
|
||||
int32_t sz_cpr; // compressed
|
||||
} h;
|
||||
struct b_info h;
|
||||
// Note: if h.sz_unc == h.sz_cpr then the block was not
|
||||
// compressible and is stored in its uncompressed form.
|
||||
|
||||
@@ -135,7 +132,7 @@ unpackExtent(
|
||||
ERR_LAB
|
||||
}
|
||||
if (h.sz_cpr > h.sz_unc
|
||||
|| h.sz_unc > (int32_t)xo->size ) {
|
||||
|| h.sz_unc > xo->size ) {
|
||||
err_exit(5);
|
||||
}
|
||||
// Now we have:
|
||||
@@ -272,48 +269,34 @@ ERR_LAB
|
||||
**************************************************************************/
|
||||
|
||||
void *upx_main(
|
||||
char *const uncbuf,
|
||||
Elf32_Ehdr const *const my_ehdr,
|
||||
f_expand *const f_decompress,
|
||||
Elf32_auxv_t *const av,
|
||||
Elf32_Ehdr *const ehdr
|
||||
unsigned const junk,
|
||||
f_expand *const f_decompress,
|
||||
Elf32_Ehdr *const ehdr, // temp char[MAX_ELF_HDR]
|
||||
struct Extent xi,
|
||||
struct Extent xo
|
||||
) __asm__("upx_main");
|
||||
|
||||
void *upx_main(
|
||||
char *const uncbuf, // place to put decompressed shell script
|
||||
Elf32_Ehdr const *const my_ehdr, // to get compressed size and data
|
||||
f_expand *const f_decompress,
|
||||
Elf32_auxv_t *const av,
|
||||
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR]
|
||||
unsigned const junk,
|
||||
f_expand *const f_decompress,
|
||||
Elf32_Ehdr *const ehdr, // temp char[MAX_ELF_HDR]
|
||||
struct Extent xi,
|
||||
struct Extent xo
|
||||
)
|
||||
{
|
||||
// 'fn' and 'efn' must not suffer constant-propagation by gcc
|
||||
// UPX2 = offset to name_of_shell
|
||||
// UPX3 = strlen(name_of_shell)
|
||||
char * /*const*/ volatile fn = UPX2 + xo.buf; // past "-c" and "#!"
|
||||
char * /*const*/ volatile efn = UPX3 + fn; // &terminator
|
||||
Elf32_Addr entry;
|
||||
size_t const lsize = sizeof(struct p_info) +
|
||||
*(unsigned short const *)(0x7c + (char const *)my_ehdr);
|
||||
struct Extent xi = { // describe compressed shell script
|
||||
((Elf32_Phdr const *)(1 + my_ehdr))->p_filesz - lsize,
|
||||
lsize + CONST_CAST(char *, my_ehdr)
|
||||
};
|
||||
struct Extent xo = { ((struct p_info *)xi.buf)[-1].p_filesize, uncbuf };
|
||||
|
||||
// Allocate space for decompressed shell script.
|
||||
// "1+": guarantee '\0' terminator at end of decompressed script
|
||||
if (xo.buf != do_mmap(xo.buf, 1+3+xo.size, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0)) {
|
||||
err_exit(20);
|
||||
ERR_LAB
|
||||
}
|
||||
|
||||
// Uncompress shell script
|
||||
xo.buf += 3; // leave room for "-c" argument
|
||||
(void)junk;
|
||||
unpackExtent(&xi, &xo, f_decompress);
|
||||
|
||||
{ // Map shell program
|
||||
// 'fn' and 'efn' must not suffer constant-propagation by gcc
|
||||
// UPX2 = 3 + offset to name_of_shell
|
||||
// UPX3 = strlen(name_of_shell)
|
||||
char * /*const*/ volatile fn = UPX2 + uncbuf; // past "-c" and "#!"
|
||||
char * /*const*/ volatile efn = UPX3 + fn; // &terminator
|
||||
char const c = *efn; *efn = 0; // terminator
|
||||
entry = getexec(fn, ehdr, av);
|
||||
*efn = c; // replace terminator character
|
||||
|
||||
+27
-21
@@ -106,12 +106,8 @@ decompress:
|
||||
|
||||
;__LEXEC020__
|
||||
|
||||
%define PAGE_MASK (~0<<12)
|
||||
%define PAGE_SIZE ( 1<<12)
|
||||
|
||||
%define szElf32_Ehdr 0x34
|
||||
%define p_memsz 5*4
|
||||
|
||||
%define MAP_FIXED 0x10
|
||||
%define MAP_PRIVATE 0x02
|
||||
%define MAP_ANONYMOUS 0x20
|
||||
@@ -120,42 +116,52 @@ decompress:
|
||||
%define PROT_EXEC 4
|
||||
%define __NR_mmap 90
|
||||
|
||||
%define szElf32_Ehdr 0x34
|
||||
%define szElf32_Phdr 8*4
|
||||
%define e_entry (16 + 2*2 + 4)
|
||||
%define p_memsz 5*4
|
||||
%define szl_info 12
|
||||
%define szp_info 12
|
||||
%define p_filesize 4
|
||||
|
||||
; Decompress the rest of this loader, and jump to it
|
||||
unfold:
|
||||
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
|
||||
cld
|
||||
lodsd
|
||||
push eax ; sz_uncompressed (junk, actually)
|
||||
push eax ; sz_uncompressed of folded stub (junk, actually)
|
||||
push esp ; &sz_uncompressed
|
||||
mov eax, ebp ; &decompress
|
||||
and eax, dword PAGE_MASK ; &my_elfhdr
|
||||
mov edx, eax ; need my_elfhdr later
|
||||
add eax, [p_memsz + szElf32_Ehdr + eax]
|
||||
mov edx, 0x00800000 ; origin of this program
|
||||
mov eax, [p_memsz + szElf32_Ehdr + edx] ; length of loaded pages
|
||||
add eax, edx
|
||||
add edx, szElf32_Ehdr + 2*szElf32_Phdr ; convenient ptr
|
||||
push eax ; &destination
|
||||
|
||||
; mmap a page to hold the decompressed program
|
||||
xor ecx,ecx
|
||||
push ecx
|
||||
push ecx
|
||||
mov ch, PAGE_SIZE >> 8
|
||||
; mmap space for unfolded stub, and uncompressed script
|
||||
mov ecx, [szl_info + p_filesize + edx] ; script size
|
||||
add ecx, 1+ 3+ (3 -1)+ PAGE_SIZE ; '\0' + "-c" + decompr_overrun + stub
|
||||
|
||||
push eax ; offset (ignored when MAP_ANONYMOUS)
|
||||
push eax ; fd (ignored when MAP_ANONYMOUS)
|
||||
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
|
||||
push byte PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
push ecx
|
||||
push ecx ; length
|
||||
push eax ; destination
|
||||
mov ebx, esp ; address of parameter vector for __NR_mmap
|
||||
push byte __NR_mmap
|
||||
pop eax
|
||||
mov ebx, esp
|
||||
int 0x80
|
||||
lea ebx, [3+ PAGE_SIZE + eax] ; place for uncompressed script
|
||||
add esp, byte 6*4 ; discard args to mmap
|
||||
|
||||
lodsd
|
||||
push eax ; sz_compressed
|
||||
push eax ; sz_compressed of folded stub
|
||||
lodsd ; junk cto8, algo, unused[2]
|
||||
push esi ; &compressed_data
|
||||
call ebp ; decompress(&src, srclen, &dst, &dstlen)
|
||||
pop ecx ; discard &compressed_data
|
||||
pop ecx ; discard sz_compressed
|
||||
pop ecx ; &destination
|
||||
jmp ecx ; goto fold_begin at p_vaddr + p_memsz
|
||||
pop eax ; discard &compressed_data
|
||||
pop eax ; discard sz_compressed
|
||||
ret ; &destination
|
||||
main:
|
||||
pop ebp ; &decompress
|
||||
call unfold
|
||||
|
||||
@@ -46,10 +46,4 @@ SECTIONS
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
/* 0x08048000: customary Linux/x86 Elf .text start */
|
||||
/*
|
||||
. = 0x08048000 + (0xfff & .);
|
||||
.data : {
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -88,6 +88,15 @@ typedef unsigned int nrv_uint32;
|
||||
|
||||
|
||||
// From ../p_unix.h
|
||||
struct b_info { // 12-byte header before each compressed block
|
||||
unsigned sz_unc; // uncompressed_size
|
||||
unsigned sz_cpr; // compressed_size
|
||||
unsigned char b_method; // compression algorithm
|
||||
unsigned char b_ftid; // filter id
|
||||
unsigned char b_cto8; // filter parameter
|
||||
unsigned char b_unused;
|
||||
};
|
||||
|
||||
struct l_info // 12-byte trailer in header for loader (offset 116)
|
||||
{
|
||||
uint32_t l_checksum;
|
||||
|
||||
Reference in New Issue
Block a user