Mach-o MH_EXECUTE rewrite; work-in-progress

On amd64, otool and lldb accept the results.
The entry point points to the unfilter and uncompress routines.
Somehow _start has been lost.

	modified:   p_mach.cpp
	modified:   p_mach.h
	modified:   p_mach_enum.h
	modified:   stub/amd64-darwin.macho-entry.h
	modified:   stub/src/amd64-darwin.macho-entry.S
	modified:   stub/src/amd64-darwin.macho-upxmain.c
	modified:   stub/src/i386-darwin.macho-upxmain.c
	modified:   stub/src/powerpc-darwin.macho-upxmain.c
	modified:   stub/tmp/amd64-darwin.macho-entry.bin.dump
This commit is contained in:
John Reiser
2017-12-03 23:17:55 -08:00
parent e633c51b50
commit 4f6979967d
9 changed files with 901 additions and 750 deletions
File diff suppressed because it is too large Load Diff
+76
View File
@@ -31,23 +31,99 @@
;
*/
NBPW= 8
#include "arch/amd64/macros.S"
#include "arch/amd64/regs.h"
mlc_cmd = 0
mlc_cmdsize = 4
mseg_segname = 8
mseg_vmsize = 4+4+16+NBPW
mseg_initprot = 4+4+16+(4*NBPW)+4
/*************************************************************************
// program entry point
// see glibc/sysdeps/amd64/elf/start.S
**************************************************************************/
MAP_FIXED = 0x10
MAP_PRIVATE = 0x02
MAP_ANON = 0x1000
PROT_READ = 1
PROT_WRITE = 2
PROT_EXEC = 4
MAP_ANON_FD = -1
SYS_mmap =0xc5
SYS_mprotect =0x4a
SYS_munmap =0x49
#define __c4(a,b,c,d) (((a)<<(0*8)) | ((b)<<(1*8)) | ((c)<<(2*8)) | ((d)<<(3*8)))
#define __c8(a,b,c,d,e,f,g,h) (__c4(a,b,c,d) | (__c4(e,f,g,h) << 32))
section AMD64BXX
0: .word 9f - 0b
#include "arch/amd64/bxx.S"
9:
// FYI: Following the env[] vector there is another vector apple[] of strings.
// Contents from one actual instance on MacOS 10.13 HighSierra:
// "executable_path=<rooted_path>"
// "pfz=0x7ffffff84000"
// "stack_guard=0x850795b0f36900c2"
// "malloc_entropy=0x94a87434eb9e2c1,0xf6814219485392e8"
// "main_stack=0x7ffeefc00000,0x800000,0x7ffeebc00000,0x4000000"
// "executable_file=0x1000008,0x2209ce"
// when %rsp was 0x7ffeefbffaf0.
section MACHMAINX
_start: .globl _start
// int3
lea -2*4+_start(%rip),%rbp; movl (%rbp),%eax; sub %rax,%rbp // &Mach_header64
mov mhdr_ncmds(%rbp),%r12d
lea sz_Mach_header64(%rbp),%rbx // ptr
L20:
cmpl $LC_SEGMENT_64,mlc_cmd(%rbx); jne L50
cmpl $__c4('T','E','X','T'),2+mseg_segname(%rbx); jne L40
sub %arg1l,%arg1l // 0 addr
mov %arg1,%arg6 // 0 off_t
lea -1(%rdi),%arg5 // MAP_ANON_FD
mov $MAP_PRIVATE|MAP_ANON,%sys4l
mov $PROT_WRITE|PROT_READ,%arg3l
mov mseg_vmsize(%rbx),%arg2
mov $SYS_mmap,%eax; syscall
mov %rax,%r15 // vmaddr
movq mseg_vmsize(%rbx),%arg3
movq mseg_vmaddr(%rbx),%arg2
mov %rax,%arg1
call memcpy
movl mseg_initprot,%arg3l
movq mseg_vmsize(%rbx),%arg2
mov %rax,%arg1
mov $SYS_mprotect,%eax; syscall
sub 2*NBPW(%rsp),%r15 // reloc
call goto_clone
jmp L50
goto_clone:
addq %r15,(%rsp) // retaddr += reloc
ret
memcpy:
mov %arg3,%rcx; shr $3,%rcx; rep movsq
ret
L40:
movabsq $__c8('L','I','N','K','E','D','I','T'),%rcx; cmp %rcx,2+mseg_segname(%rbx); jne L50
L50:
mov mlc_cmdsize(%rbx),%eax; add %rax,%rbx
sub $1,%ebp; jne L20
call main // push &decompress
ret_main:
+47 -25
View File
@@ -29,10 +29,11 @@
<jreiser@users.sourceforge.net>
*/
#include <stdio.h>
#include <stdlib.h>
#define __WORDSIZE 64
#include "include/darwin.h"
typedef unsigned char * Addr;
#ifndef DEBUG /*{*/
#define DEBUG 0
#endif /*}*/
@@ -184,16 +185,16 @@ done:
typedef struct {
size_t size; // must be first to match size[0] uncompressed size
void *buf;
Addr buf;
} Extent;
DEBUG_STRCON(STR_xread, "xread %%p(%%x %%p) %%p %%x\\n")
DEBUG_STRCON(STR_xreadfail, "xreadfail %%p(%%x %%p) %%p %%x\\n")
static void
xread(Extent *x, void *buf, size_t count)
xread(Extent *x, Addr buf, size_t count)
{
unsigned char *p=x->buf, *q=buf;
Addr p=x->buf, q=buf;
size_t j;
DPRINTF((STR_xread(), x, x->size, x->buf, buf, count));
if (x->size < count) {
@@ -285,7 +286,7 @@ unpackExtent(
// compressible and is stored in its uncompressed form.
// Read and check block sizes.
xread(xi, (unsigned char *)&h, sizeof(h));
xread(xi, (Addr)&h, sizeof(h));
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);
@@ -328,7 +329,7 @@ ERR_LAB
}
static void
upx_bzero(unsigned char *p, size_t len)
upx_bzero(Addr p, size_t len)
{
if (len) do {
*p++= 0;
@@ -484,8 +485,8 @@ typedef union {
#define MAP_ANON_FD -1
#define MAP_FAILED ((void *) -1)
extern void *mmap(void *, size_t, unsigned, unsigned, int, off_t);
ssize_t pread(int, void *, size_t, off_t);
extern void *mmap(void *, size_t, unsigned, unsigned, int, off_t_upx_stub);
ssize_t pread(int, void *, size_t, off_t_upx_stub);
extern void bswap(void *, unsigned);
DEBUG_STRCON(STR_mmap,
@@ -496,7 +497,7 @@ DEBUG_STRCON(STR_do_xmap,
static uint64_t // entry address
do_xmap(
Mach_header64 const *const mhdr,
off_t const fat_offset,
off_t_upx_stub const fat_offset,
Extent *const xi,
int const fdi,
Mach_header64 **mhdrpp,
@@ -514,12 +515,12 @@ do_xmap(
fdi, mhdr, xi, (xi? xi->size: 0), (xi? xi->buf: 0), f_unf));
for ( j=0; j < mhdr->ncmds; ++j,
(sc = (Mach_segment_command const *)(sc->cmdsize + (void const *)sc))
(sc = (Mach_segment_command const *)(sc->cmdsize + (unsigned char const *)sc))
) if (LC_SEGMENT_64==sc->cmd && sc->vmsize!=0) {
Extent xo;
size_t mlen = xo.size = sc->filesize;
unsigned char *addr = xo.buf = base + (unsigned char *)sc->vmaddr;
unsigned char *haddr = sc->vmsize + addr;
Addr addr = xo.buf = base + (Addr)sc->vmaddr;
Addr haddr = sc->vmsize + addr;
size_t frag = (int)(uint64_t)addr &~ PAGE_MASK;
addr -= frag;
mlen += frag;
@@ -531,10 +532,10 @@ do_xmap(
unsigned const flags = (addr ? MAP_FIXED : 0) | MAP_PRIVATE |
((xi || 0==sc->filesize) ? MAP_ANON : 0);
int const fdm = ((0==sc->filesize) ? MAP_ANON_FD : fdi);
off_t const offset = sc->fileoff + fat_offset;
off_t_upx_stub const offset = sc->fileoff + fat_offset;
DPRINTF((STR_mmap(), addr, mlen3, prot, flags, fdm, offset));
unsigned char *mapa = mmap(addr, mlen3, prot, flags, fdm, offset);
Addr mapa = (Addr)mmap(addr, mlen3, prot, flags, fdm, offset);
if (MAP_FAILED == mapa) {
err_exit(8);
}
@@ -593,7 +594,7 @@ ERR_LAB
return entry;
}
static off_t
static off_t_upx_stub
fat_find(Fat_header *fh) // *fh suffers bswap()
{
Fat_arch *fa = (Fat_arch *)(1+ fh);
@@ -628,11 +629,11 @@ upx_main(
)
{
uint64_t entry;
off_t fat_offset = 0;
off_t_upx_stub fat_offset = 0;
Extent xi, xo, xi0;
xi.buf = CONST_CAST(unsigned char *, 1+ (struct p_info const *)(1+ li)); // &b_info
xi.buf = CONST_CAST(Addr, 1+ (struct p_info const *)(1+ li)); // &b_info
xi.size = sz_compressed - (sizeof(struct l_info) + sizeof(struct p_info));
xo.buf = (unsigned char *)mhdr;
xo.buf = (Addr)mhdr;
xo.size = ((struct b_info const *)(void const *)xi.buf)->sz_unc;
xi0 = xi;
@@ -650,7 +651,7 @@ upx_main(
unsigned j;
for (j=0; j < mhdr->ncmds; ++j,
(lc = (Mach_load_command const *)(lc->cmdsize + (void const *)lc))
(lc = (Mach_load_command const *)(lc->cmdsize + (unsigned char const *)lc))
) if (LC_LOAD_DYLINKER==lc->cmd) {
char const *const dyld_name = ((Mach_lc_str const *)(1+ lc))->offset +
(char const *)lc;
@@ -694,6 +695,15 @@ typedef struct {
uint32_t data[2]; // because cmdsize >= 16
} Mach_command; // generic prefix
// Go to the clone.
extern void goto_clone(ptrdiff_t reloc);
//{
// add %arg1,(%rsp) // relocate return address
// ret
//}
extern void *memcpy(void *, void const *, size_t);
//
// Build on Mac OS X: (where gcc is really clang)
// gcc -o amd64-darwin.macho-upxmain.exe \
@@ -718,6 +728,7 @@ main(int argc, char *argv[])
Mach_header64 const *mhdr0 = (Mach_header64 const *)((~0ul<<16) & (unsigned long)&main);
Mach_command const *ptr = (Mach_command const *)(1+ mhdr0);
ptrdiff_t reloc = 0;
f_unfilter *f_unf;
f_expand *f_exp;
char *payload;
@@ -728,11 +739,22 @@ main(int argc, char *argv[])
ptr = (Mach_command const *)(ptr->cmdsize + (char const *)ptr))
if (LC_SEGMENT_64==ptr->cmd) {
Mach_segment_command const *const seg = (Mach_segment_command const *)ptr;
// Compare 8 characters
// Compare 4 bytes
if (*(int const *)(&"__TEXT"[2]) == *(int const *)(&seg->segname[2])) {
Addr const vmaddr = (Addr)mmap(0, seg->vmsize, PROT_WRITE | PROT_READ,
MAP_PRIVATE | MAP_ANON, MAP_ANON_FD, 0);
memcpy(vmaddr, (void const *)seg->vmaddr, seg->vmsize);
mprotect(vmaddr, seg->vmsize, seg->initprot);
reloc = vmaddr - (Addr)mhdr0;
ptr = (Mach_command const *)(reloc + (Addr)ptr);
goto_clone(reloc);
} else
// Compare 8 bytes
if (*(long const *)(&"__LINKEDIT"[2]) == *(long const *)(&seg->segname[2])) {
f_unf = (f_unfilter *)(sizeof(unsigned short) + seg->vmaddr);
f_exp = (f_expand *)(*(unsigned short const *)seg->vmaddr + seg->vmaddr);
unsigned const *q = (unsigned const *)seg->vmaddr;
Addr const vm2 = (Addr)(seg->vmaddr + reloc);
f_unf = (f_unfilter *)(sizeof(unsigned short) + vm2);
f_exp = (f_expand *)(*(unsigned short const *)vm2 + vm2);
unsigned const *q = (unsigned const *)vm2;
while (!(paysize = *--q)) /*empty*/ ;
payload = (char *)(-paysize + (char const *)q);
break;
@@ -743,8 +765,8 @@ main(int argc, char *argv[])
(Mach_header64 *)mhdr, sizeof(mhdr),
f_exp, f_unf, (Mach_header64 **)&argv[-2]);
munmap(payload, paysize); // leaving __LINKEDIT
argv[-1] = (char *)(long)argc;
munmap(payload, paysize); // leaving __LINKEDIT
asm("lea -2*8(%1),%%rsp; jmp *%0" : : "r" (entry), "r" (argv));
return 0;
}
+1
View File
@@ -29,6 +29,7 @@
<jreiser@users.sourceforge.net>
*/
#define __WORDSIZE 32
#include <stdio.h>
#include <stdlib.h>
#include "include/darwin.h"
@@ -29,6 +29,7 @@
<jreiser@users.sourceforge.net>
*/
#define __WORDSIZE 32
#include <stdio.h>
#include <stdlib.h>
#include "include/darwin.h"
+23 -14
View File
@@ -3,19 +3,19 @@ file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn Flags
0 AMD64BXX 0000004c 0000000000000000 0000000000000000 00000040 2**0 CONTENTS, READONLY
1 MACHMAINX 00000005 0000000000000000 0000000000000000 0000008c 2**0 CONTENTS, RELOC, READONLY
2 MACH_UNC 00000008 0000000000000000 0000000000000000 00000091 2**0 CONTENTS, READONLY
3 NRV_HEAD 00000067 0000000000000000 0000000000000000 00000099 2**0 CONTENTS, READONLY
4 NRV2E 000000b7 0000000000000000 0000000000000000 00000100 2**0 CONTENTS, RELOC, READONLY
5 NRV2D 0000009e 0000000000000000 0000000000000000 000001b7 2**0 CONTENTS, RELOC, READONLY
6 NRV2B 00000090 0000000000000000 0000000000000000 00000255 2**0 CONTENTS, RELOC, READONLY
7 LZMA_ELF00 00000064 0000000000000000 0000000000000000 000002e5 2**0 CONTENTS, RELOC, READONLY
8 LZMA_DEC10 000009f7 0000000000000000 0000000000000000 00000349 2**0 CONTENTS, READONLY
9 LZMA_DEC20 000009f7 0000000000000000 0000000000000000 00000d40 2**0 CONTENTS, READONLY
10 LZMA_DEC30 00000014 0000000000000000 0000000000000000 00001737 2**0 CONTENTS, READONLY
11 NRV_TAIL 00000000 0000000000000000 0000000000000000 0000174b 2**0 CONTENTS, READONLY
12 MACHMAINY 00000011 0000000000000000 0000000000000000 0000174b 2**0 CONTENTS, READONLY
13 MACHMAINZ 00000041 0000000000000000 0000000000000000 0000175c 2**0 CONTENTS, READONLY
1 MACHMAINX 000000b7 0000000000000000 0000000000000000 0000008c 2**0 CONTENTS, RELOC, READONLY
2 MACH_UNC 00000008 0000000000000000 0000000000000000 00000143 2**0 CONTENTS, READONLY
3 NRV_HEAD 00000067 0000000000000000 0000000000000000 0000014b 2**0 CONTENTS, READONLY
4 NRV2E 000000b7 0000000000000000 0000000000000000 000001b2 2**0 CONTENTS, RELOC, READONLY
5 NRV2D 0000009e 0000000000000000 0000000000000000 00000269 2**0 CONTENTS, RELOC, READONLY
6 NRV2B 00000090 0000000000000000 0000000000000000 00000307 2**0 CONTENTS, RELOC, READONLY
7 LZMA_ELF00 00000064 0000000000000000 0000000000000000 00000397 2**0 CONTENTS, RELOC, READONLY
8 LZMA_DEC10 000009f7 0000000000000000 0000000000000000 000003fb 2**0 CONTENTS, READONLY
9 LZMA_DEC20 000009f7 0000000000000000 0000000000000000 00000df2 2**0 CONTENTS, READONLY
10 LZMA_DEC30 00000014 0000000000000000 0000000000000000 000017e9 2**0 CONTENTS, READONLY
11 NRV_TAIL 00000000 0000000000000000 0000000000000000 000017fd 2**0 CONTENTS, READONLY
12 MACHMAINY 00000011 0000000000000000 0000000000000000 000017fd 2**0 CONTENTS, READONLY
13 MACHMAINZ 00000044 0000000000000000 0000000000000000 0000180e 2**0 CONTENTS, READONLY
SYMBOL TABLE:
0000000000000000 l d NRV_HEAD 0000000000000000 NRV_HEAD
0000000000000000 l d LZMA_DEC30 0000000000000000 LZMA_DEC30
@@ -32,11 +32,20 @@ SYMBOL TABLE:
0000000000000000 l d LZMA_DEC20 0000000000000000 LZMA_DEC20
0000000000000000 l d NRV_TAIL 0000000000000000 NRV_TAIL
0000000000000000 g MACHMAINX 0000000000000000 _start
0000000000000000 *UND* 0000000000000000 mhdr_ncmds
0000000000000000 *UND* 0000000000000000 sz_Mach_header64
0000000000000000 *UND* 0000000000000000 LC_SEGMENT_64
0000000000000000 *UND* 0000000000000000 mseg_vmaddr
0000000000000011 g MACHMAINY 0000000000000000 end_decompress
RELOCATION RECORDS FOR [MACHMAINX]:
OFFSET TYPE VALUE
0000000000000001 R_X86_64_PC32 MACHMAINZ+0x0000000000000037
0000000000000003 R_X86_64_PC32 _start+0xfffffffffffffff4
0000000000000010 R_X86_64_32S mhdr_ncmds
0000000000000017 R_X86_64_32S sz_Mach_header64
000000000000001e R_X86_64_32 LC_SEGMENT_64
0000000000000056 R_X86_64_32S mseg_vmaddr
00000000000000b3 R_X86_64_PC32 MACHMAINZ+0x000000000000003a
RELOCATION RECORDS FOR [NRV2E]:
OFFSET TYPE VALUE