1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

Mach-o MH_EXECUTE rewrite; work-in-progress

The stub for amd64 gets into the de-compressed folded code.
	modified:   p_mach.cpp
	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/tmp/amd64-darwin.macho-entry.bin.dump
This commit is contained in:
John Reiser 2017-12-06 17:04:47 -08:00
parent 4f6979967d
commit c6d6378005
5 changed files with 706 additions and 816 deletions

View File

@ -356,11 +356,8 @@ void PackMachI386::addStubEntrySections(Filter const *ft)
void PackMachAMD64::addStubEntrySections(Filter const * /*ft*/)
{
if (my_filetype==Mach_header::MH_DYLIB) {
addLoader("MACHMAINX", NULL);
}
else {
addLoader("AMD64BXX", NULL);
addLoader("MACHMAINX", NULL); // different for MY_DYLIB vs MH_EXECUTE
if (my_filetype==Mach_header::MH_EXECUTE) {
addLoader("MACH_UNC", NULL);
}
//addLoader(getDecompressorSections(), NULL);
@ -372,10 +369,7 @@ void PackMachAMD64::addStubEntrySections(Filter const * /*ft*/)
: NULL), NULL);
if (hasLoaderSection("CFLUSH"))
addLoader("CFLUSH");
addLoader("MACHMAINY,IDENTSTR,+40,MACHMAINZ", NULL);
if (my_filetype!=Mach_header::MH_EXECUTE) {
addLoader("FOLDEXEC", NULL);
}
addLoader("MACHMAINY,IDENTSTR,+40,MACHMAINZ,FOLDEXEC", NULL);
}
void PackMachPPC32::addStubEntrySections(Filter const * /*ft*/)
@ -562,6 +556,8 @@ PackMachBase<T>::compare_segment_command(void const *const aa, void const *const
#define PAGE_MASK64 (~(upx_uint64_t)0<<12)
#define PAGE_SIZE64 ((upx_uint64_t)0-PAGE_MASK64)
// Note: "readelf --segments" ==> "otool -hl" or "otool -hlv" etc. (Xcode on MacOS)
template <class T>
void PackMachBase<T>::pack4(OutputFile *fo, Filter &ft) // append PackHeader
{
@ -954,9 +950,10 @@ off_t PackMachBase<T>::pack3(OutputFile *fo, Filter &ft) // append loader
disp = len - sz_mach_headers; // backward offset to start of compressed data
fo->write(&disp, sizeof(disp));
len += sizeof(disp);
segTEXT.vmsize = segLINK.vmaddr - segTEXT.vmaddr; // must protect this much
threado_setPC(entryVMA= len + segTEXT.vmaddr);
return segTEXT.vmsize = super::pack3(fo, ft);
return super::pack3(fo, ft);
}
off_t PackDylibI386::pack3(OutputFile *fo, Filter &ft) // append loader
@ -1329,6 +1326,7 @@ void PackMachBase<T>::pack1(OutputFile *const fo, Filter &/*ft*/) // generate e
segLINK.initprot = Mach_command::VM_PROT_READ;
// Adjust later: .vmaddr .vmsize .fileoff .filesize
unsigned gap = 0;
if (my_filetype == Mach_header::MH_EXECUTE) {
unsigned cmdsize = mhdro.sizeofcmds;
Mach_header const *const ptr0 = (Mach_header const *)stub_main;
@ -1355,11 +1353,13 @@ void PackMachBase<T>::pack1(OutputFile *const fo, Filter &/*ft*/) // generate e
pos += cmdsize;
fo->write((char const *)ptr1, cmdsize);
sz_mach_headers = fo->getBytesWritten();
gap = 400 + threado_size();
secTEXT.addr = gap + pos;
break;
}
}
}
sz_mach_headers = fo->getBytesWritten();
}
else if (my_filetype == Mach_header::MH_DYLIB) {
Mach_command const *ptr = (Mach_command const *)rawmseg;
@ -1393,13 +1393,13 @@ void PackMachBase<T>::pack1(OutputFile *const fo, Filter &/*ft*/) // generate e
fo->write(&linkitem, sizeof(linkitem));
fo->write(rawmseg, mhdri.sizeofcmds);
sz_mach_headers = fo->getBytesWritten();
unsigned gap = secTEXT.offset - sz_mach_headers;
MemBuffer filler(gap);
memset(filler, 0, gap);
fo->write(filler, gap);
sz_mach_headers += gap;
gap = secTEXT.offset - sz_mach_headers;
}
sz_mach_headers = fo->getBytesWritten();
MemBuffer filler(gap);
memset(filler, 0, gap);
fo->write(filler, gap);
sz_mach_headers += gap;
memset((char *)&linfo, 0, sizeof(linfo));
fo->write(&linfo, sizeof(linfo));
@ -1971,12 +1971,13 @@ bool PackMachBase<T>::canPack()
fsm.segZERO.nsects = 0;
fsm.segZERO.flags = 0;
unsigned const slop = 400;
fsm.segTEXT.cmd = fsm.segZERO.cmd;
fsm.segTEXT.cmdsize = sizeof(Mach_segment_command)
+ sizeof(Mach_section_command);
strncpy(fsm.segTEXT.segname, "__TEXT", sizeof(fsm.segTEXT.segname));
fsm.segTEXT.vmaddr = fsm.segZERO.vmsize; // dummy?
fsm.segTEXT.vmsize = 0;
fsm.segTEXT.vmaddr = fsm.segZERO.vmsize;
fsm.segTEXT.vmsize = slop + threado_size() + sizeof(fsm); // dummy
fsm.segTEXT.fileoff = 0;
fsm.segTEXT.filesize = fsm.segTEXT.vmsize; // dummy
fsm.segTEXT.maxprot = VM_PROT_EXECUTE | VM_PROT_READ;
@ -1986,7 +1987,7 @@ bool PackMachBase<T>::canPack()
strncpy(fsm.secTEXT.sectname, "__text", sizeof(fsm.secTEXT.sectname));
memcpy(fsm.secTEXT.segname, fsm.segTEXT.segname, sizeof(fsm.secTEXT.segname));
unsigned const d = 400 + fsm.mhdri.sizeofcmds;
unsigned const d = slop + fsm.mhdri.sizeofcmds;
fsm.secTEXT.addr = fsm.segTEXT.vmaddr + d; // dummy
fsm.secTEXT.size = fsm.segTEXT.vmsize - d; // dummy
fsm.secTEXT.offset = d; // dummy

File diff suppressed because it is too large Load Diff

View File

@ -37,11 +37,20 @@ NBPW= 8
#include "arch/amd64/regs.h"
mlc_cmd = 0
LC_SEGMENT_64= 0x19
mlc_cmdsize = 4
mseg_segname = 8
mseg_vmsize = 4+4+16+NBPW
mseg_initprot = 4+4+16+(4*NBPW)+4
sz_Mach_header64= 8*4
mhdr_ncmds= 4*4
sz_Mach_segment= 2*4 + 16 + 4*NBPW + 4*4
mseg_segname= 2*4
mseg_vmaddr= 2*4 + 16
mseg_vmsize= 2*4 + 16 + NBPW
mseg_initprot= 2*4 + 16 + (4*NBPW) + 4
msec_addr= 2*16
msec_size= 2*16 + NBPW
/*************************************************************************
// program entry point
@ -56,9 +65,10 @@ PROT_WRITE = 2
PROT_EXEC = 4
MAP_ANON_FD = -1
SYS_mmap =0xc5
SYS_mprotect =0x4a
SYS_munmap =0x49
SYSBASE= 0x02000000
SYS_mmap =0xc5 + SYSBASE
SYS_mprotect =0x4a + SYSBASE
SYS_munmap =0x49 + SYSBASE
#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))
@ -78,52 +88,51 @@ SYS_munmap =0x49
// "executable_file=0x1000008,0x2209ce"
// when %rsp was 0x7ffeefbffaf0.
// Notes:
// Command-line debugger from Xcode: lldb foo; "process launch -s"
section MACHMAINX
_start: .globl _start
// int3
#define r_cmdp rbx
#define r_ncmds r12d
#define r_reloc r15
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
push %rbp // P_01 &Mach_header64 before argc
mov mhdr_ncmds(%rbp),%r_ncmds
lea sz_Mach_header64(%rbp),%r_cmdp // ptr
L20:
cmpl $LC_SEGMENT_64,mlc_cmd(%rbx); jne L50
cmpl $__c4('T','E','X','T'),2+mseg_segname(%rbx); jne L40
cmpl $LC_SEGMENT_64,mlc_cmd(%r_cmdp); jne L50
cmpl $__c4('T','E','X','T'),2+mseg_segname(%r_cmdp); jne L40
sub %arg1l,%arg1l // 0 addr
mov %arg1,%arg6 // 0 off_t
lea -1(%rdi),%arg5 // MAP_ANON_FD
lea -1(%arg1),%arg5 // MAP_ANON_FD
mov $MAP_PRIVATE|MAP_ANON,%sys4l
mov $PROT_WRITE|PROT_READ,%arg3l
mov mseg_vmsize(%rbx),%arg2
mov mseg_vmsize(%r_cmdp),%arg2
movl sz_unc+FOLD(%rip),%eax
add %rax,%arg2; mov %arg2,%r14
mov $SYS_mmap,%eax; syscall
mov %rax,%r15 // vmaddr
mov %rax,%r_reloc // vmaddr
sub %rbp,%r_reloc // reloc
push %rax // P_02
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
// Copy only compression data, not Macho headers
movl msec_size + sz_Mach_segment(%r_cmdp),%ecx
movq msec_addr + sz_Mach_segment(%r_cmdp),%rsi
mov %rax,%rdi
add $7,%ecx; shr $3,%ecx; rep movsq
jmp L60 // break;
goto_clone:
addq %r15,(%rsp) // retaddr += reloc
ret
memcpy:
mov %arg3,%rcx; shr $3,%rcx; rep movsq
addq %r_reloc,(%rsp) // retaddr += reloc
ret
L40: // not TEXT
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
L50: // not LC_SEGMENT64
mov mlc_cmdsize(%r_cmdp),%eax; add %rax,%r_cmdp
sub $1,%r_ncmds; jne L20
L60:
call main // push &decompress
ret_main:
@ -269,36 +278,32 @@ sz_b_info= 12
// Decompress the rest of this loader, and jump to it.
unfold:
pop %rbx // &{ b_info:{sz_unc, sz_cpr, 4{byte}}, compressed_data...}
mov sz_cpr(%rbx),%ecx
lea -1+ sz_b_info(%rcx,%rbx),%rsi // &hi_byte folded original
#if 0
mov sz_unc(%rbx),%edi
#else
// sz_unc == 0
mov (%rbx),%edi
#endif
lea GAP + NO_LAP -1+ sz_b_info(%rdi,%rbx),%rdi // &hi_byte folded copy
std; rep movsb // copy descending
pop %rsi // &{ b_info:{sz_unc, sz_cpr, 4{byte}}, compressed_fold...}
lea GAP (%rbx),%arg3 // &unfolded
mov %rbx,%rsi // &b_info
lea 1(%rdi),%arg1 // &lo_byte folded copy
push %arg3 // return to unfolded code
cld
lodsl; push %rax // allocate slot on stack
movq %rsp,%arg4 // &len_dst ==> used by lzma for EOF
lodsl; push %rax // sz_cpr XXX: 4GB
pop %rcx // P_02
push %rdi; pop %arg3 // dst
push %rdi // P_03 entry addr to folded stub
push %rcx // P_04 &copied data
lodsl; push %rax // P_05 allocate slot on stack
movq %rsp,%arg4 // &dstlen ==> used by lzma for EOF
lodsl; push %rax // P_06 sz_cpr XXX: 4GB
lodsl; movzbl %al,%arg5l // b_method
pop %arg2 // sz_cpr
call *%rbp // decompress(&src, srclen, &dst, &dstlen, b_info.misc)
pop %rcx // discard len_dst
push %rsi; pop %arg1 // src
pop %arg2 // P_06 sz_cpr
call *%rbp // decompress(src, srclen, dst, &dstlen, b_info.misc)
pop %rcx // P_05 discard len_dst
push $PROT_EXEC|PROT_READ; pop %arg3
mov %r14,%arg2 // len
pop %arg1 // P_04 &copied data
mov $SYS_mprotect,%rax; syscall
lea -4+ _start - ret_main(%rbp),%rbx // &total_length for fold:
ret
ret // P_03
main:
pop %rbp // &decompress
call unfold
FOLD:
// compressed fold_elf86 follows
/* vim:set ts=8 sw=8 et: */

View File

@ -689,86 +689,4 @@ ERR_LAB
return entry;
}
typedef struct {
uint32_t cmd;
uint32_t cmdsize;
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 \
// -Os -fPIC -fno-stack-protector \
// amd64-darwin.macho-upxmain.c \
// amd64-darwin.macho-upxsubr.S \
// -Wl,-pagezero_size,0xf0000000 \
// -Wl,-no_pie \
// -Wl,-no_uuid \
// -Wl,-no_function_starts \
// -Wl,-bind_at_load \
// -Wl,-headerpad,0x400 \
//
//# -Wl,-unexported_symbols_list unexport-upxload.txt \
//# strip -u -r amd64-darwin.macho-upxmain.exe
int
main(int argc, char *argv[])
{
// Entry via JMP (with no parameters) instead of CALL
asm("movl 1*8(%%rbp),%0; leaq 2*8(%%rbp),%1" : "=r" (argc), "=r" (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;
size_t paysize;
unsigned j;
for (j=0; j < mhdr0->ncmds; ++j,
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 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])) {
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;
}
}
char mhdr[16384];
uint64_t entry = upx_main((struct l_info const *)payload, paysize,
(Mach_header64 *)mhdr, sizeof(mhdr),
f_exp, f_unf, (Mach_header64 **)&argv[-2]);
argv[-1] = (char *)(long)argc;
munmap(payload, paysize); // leaving __LINKEDIT
asm("lea -2*8(%1),%%rsp; jmp *%0" : : "r" (entry), "r" (argv));
return 0;
}
/* vim:set ts=4 sw=4 et: */

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 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
1 MACHMAINX 00000082 0000000000000000 0000000000000000 0000008c 2**0 CONTENTS, RELOC, READONLY
2 MACH_UNC 00000008 0000000000000000 0000000000000000 0000010e 2**0 CONTENTS, READONLY
3 NRV_HEAD 00000067 0000000000000000 0000000000000000 00000116 2**0 CONTENTS, READONLY
4 NRV2E 000000b7 0000000000000000 0000000000000000 0000017d 2**0 CONTENTS, RELOC, READONLY
5 NRV2D 0000009e 0000000000000000 0000000000000000 00000234 2**0 CONTENTS, RELOC, READONLY
6 NRV2B 00000090 0000000000000000 0000000000000000 000002d2 2**0 CONTENTS, RELOC, READONLY
7 LZMA_ELF00 00000064 0000000000000000 0000000000000000 00000362 2**0 CONTENTS, RELOC, READONLY
8 LZMA_DEC10 000009f7 0000000000000000 0000000000000000 000003c6 2**0 CONTENTS, READONLY
9 LZMA_DEC20 000009f7 0000000000000000 0000000000000000 00000dbd 2**0 CONTENTS, READONLY
10 LZMA_DEC30 00000014 0000000000000000 0000000000000000 000017b4 2**0 CONTENTS, READONLY
11 NRV_TAIL 00000000 0000000000000000 0000000000000000 000017c8 2**0 CONTENTS, READONLY
12 MACHMAINY 00000011 0000000000000000 0000000000000000 000017c8 2**0 CONTENTS, READONLY
13 MACHMAINZ 00000036 0000000000000000 0000000000000000 000017d9 2**0 CONTENTS, READONLY
SYMBOL TABLE:
0000000000000000 l d NRV_HEAD 0000000000000000 NRV_HEAD
0000000000000000 l d LZMA_DEC30 0000000000000000 LZMA_DEC30
@ -32,20 +32,13 @@ 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
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
000000000000003f R_X86_64_PC32 MACHMAINZ+0x0000000000000032
000000000000007e R_X86_64_PC32 MACHMAINZ+0x000000000000002c
RELOCATION RECORDS FOR [NRV2E]:
OFFSET TYPE VALUE