Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Minimal Mach-o 64 binary

I thinks this is a strange question, but now I prepare to hand-made a minimal Mach-O 64 binary, like the same problem on ELF (http://timelessname.com/elfbin/).

But currently I still sucks on how to debug my binary. otool does NOT show me the error, but I get the suck how to debug the binary. The following is the binary I make in hex view. In the current stage I've no idea how to continue. Any suggestion? or I should stop this stupid things...

0000000: cffa edfe 0700 0001 0300 0080 0200 0000  ................
0000010: 0900 0000 0002 0000 8500 0000 0000 0000  ................
0000020: 1900 0000 4800 0000 5f5f 5041 4745 5a45  ....H...__PAGEZE
0000030: 524f 0000 0000 0000 0000 0000 0000 0000  RO..............
0000040: 0000 0000 0100 0000 0000 0000 0000 0000  ................
0000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0000060: 0000 0000 0000 0000 1900 0000 9800 0000  ................
0000070: 5f5f 5445 5854 0000 0000 0000 0000 0000  __TEXT..........
0000080: 0010 0000 0000 0000 0010 0000 0000 0000  ................
0000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000a0: 0700 0000 0500 0000 0100 0000 0000 0000  ................
00000b0: 5f5f 7465 7874 0000 0000 0000 0000 0000  __text..........
00000c0: 5f5f 5445 5854 0000 0000 0000 0000 0000  __TEXT..........
00000d0: 1010 0000 0000 0000 1000 0000 0000 0000  ................
00000e0: 2002 0000 0100 0000 0000 0000 0000 0000   ...............
00000f0: 0004 0080 0000 0000 0000 0000 0000 0000  ................
0000100: 1900 0000 4800 0000 5f5f 4c49 4e4b 4544  ....H...__LINKED
0000110: 4954 0000 0000 0000 0000 0000 0000 0000  IT..............
0000120: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0000130: 0000 0000 0000 0000 0700 0000 0100 0000  ................
0000140: 0000 0000 0000 0000 2200 0080 3000 0000  ........"...0...
0000150: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0000160: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0000170: 0000 0000 0000 0000 0200 0000 1800 0000  ................
0000180: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0000190: 0b00 0000 5000 0000 0000 0000 0000 0000  ....P...........
00001a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00001e0: 1b00 0000 1800 0000 506f 7765 7265 6420  ........Powered
00001f0: 6279 2063 6d6a 0000 2400 0000 1000 0000  by cmj..$.......
0000200: 000a 0a00 000a 0a00 2800 0080 1800 0000  ........(.......
0000210: 2002 0000 0000 0000 0000 0000 0000 0000   ...............
0000220: 48c7 c001 0000 0248 c7c7 0400 0000 0f05  H......H........
0000230: 0a                                       .

[UPDATE] My environment is Mac OSX 10.10 which the online information does not workable in my case (e.g. https://gist.github.com/softboysxp/1084476)

like image 596
cmj Avatar asked Dec 11 '22 21:12

cmj


1 Answers

You cannot go below the 4096 byte limit since Yosemite 10.10.5. Its Mach-O kernel checks are more restrictive now. Alternatively to dyld and LC_MAIN, you can go for LC_UNIXTHREAD and obviously keeping your LC_SEGMENT64. Sections are not necessary, but dropping them will make tracking the binary harder.

Since El Capitan, PAGEZERO with nonzero size is required for 64-bit executables. Here is a working HelloWorld example, valid on Sierra 10.12.2 assembled with NASM or YASM

; A minimal Mach-o x64 executable for OS X Sierra
; $ nasm -f bin -o tiny_hello tiny_hello.s
; $ chmod +x tiny_hello
; Constants (For readability)
%define MH_MAGIC_64                    0xfeedfacf
%define CPU_ARCH_ABI64                0x01000000
%define    CPU_TYPE_I386                0x00000007
%define CPU_TYPE_X86_64                CPU_ARCH_ABI64 | CPU_TYPE_I386
%define CPU_SUBTYPE_LIB64            0x80000000
%define CPU_SUBTYPE_I386_ALL        0x00000003
%define MH_EXECUTE                    0x2
%define MH_NOUNDEFS                    0x1
%define LC_SEGMENT_64                0x19
%define LC_UNIXTHREAD                0x5 
%define VM_PROT_READ                0x1
%define VM_PROT_WRITE                0x2
%define VM_PROT_EXECUTE                0x4
%define x86_THREAD_STATE64            0x4
%define    x86_EXCEPTION_STATE64_COUNT    42
%define SYSCALL_CLASS_SHIFT            24
%define SYSCALL_CLASS_MASK            (0xFF << SYSCALL_CLASS_SHIFT)
%define SYSCALL_NUMBER_MASK            (~SYSCALL_CLASS_MASK)  
%define SYSCALL_CLASS_UNIX            2
%define SYSCALL_CONSTRUCT_UNIX(syscall_number) \
            ((SYSCALL_CLASS_UNIX << SYSCALL_CLASS_SHIFT) | \
             (SYSCALL_NUMBER_MASK & (syscall_number)))
%define SYS_exit                    1
%define SYS_write                    4
; NASM directive, not compiled
; Use RIP-Relative addressing for x64
BITS    64
;DEFAULT    REL
%define __origin 0x100000000
org __origin
; Mach-O header
DD        MH_MAGIC_64                                        ; magic
DD        CPU_TYPE_X86_64                                    ; cputype
DD        CPU_SUBTYPE_LIB64 | CPU_SUBTYPE_I386_ALL        ; cpusubtype
DD        MH_EXECUTE                                        ; filetype
DD        3                                                ; ncmds
DD        __COMMANDSend  - __COMMANDSstart                ; sizeofcmds
DD        MH_NOUNDEFS                                        ; flags
DD        0x0                                                ; reserved
__COMMANDSstart:

___PAGEZEROstart:
        DD        LC_SEGMENT_64                                    ; cmd
        dd         ___PAGEZEROend - ___PAGEZEROstart                ; command size
hello_str:
        db         '__PAGEZERO',0x0,0,0,0,0,0 ; segment name (pad to 16 bytes)
        DQ        0x0                                                ; vmaddr
        DQ        __origin                                        ; vmsize
        DQ        0                                                ; fileoff
        DQ        0                                                ; filesize
        DD        0                                                 ; maxprot
        DD        0                                                ; initprot
        DD        0x0                                                ; nsects
        DD        0x0                                                ; flags
___PAGEZEROend:
; Segment and Sections
___TEXTstart:
        DD        LC_SEGMENT_64                                    ; cmd
        dd ___TEXTend - ___TEXTstart    ; command size

        db '__TEXT',0,0,0,0,0,0,0,0,0,0 ; segment name (pad to 16 bytes)
        DQ        __origin                                        ; vmaddr
        DQ        ___codeend - __origin                ; vmsize
        DQ        0                                                ; fileoff
        DQ        ___codeend - __origin                    ; filesize
        DD        VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE    ; maxprot
        DD        VM_PROT_READ | VM_PROT_EXECUTE                            ; initprot
        DD        0x0                                                ; nsects
        DD        0x0                                                ; flags
___TEXTend:
__UNIX_THREADstart:
; UNIX Thread Status
DD        LC_UNIXTHREAD                                    ; cmd
DD        __UNIX_THREADend - __UNIX_THREADstart             ; cmdsize
DD        x86_THREAD_STATE64                                ; flavor
DD        x86_EXCEPTION_STATE64_COUNT                        ; count
DQ        0x0, 0x0, 0x00, 0x0                                ; rax, rbx , rcx , rdx
DQ        0x01, hello_str, 0x00, 0x00                        ; rdi = STDOUT, rsi = address of hello_str,  rbp, rsp
DQ        0x00, 0x00                                        ; r8 and r9
DQ        0x00, 0x00, 0x00, 0x00, 0x00, 0x00                ; r10, r11, r12, r13, r14, r15
DQ         ___codestart, 0x00, 0x00, 0x00, 0x00            ; rip, rflags, cs, fs, gs
__UNIX_THREADend:
__COMMANDSend:
___codestart:                                                    ; 24 bytes
    ; rdi and rsi have already been set in the initial state
    mov        rdx, 11
    mov        rax, SYSCALL_CONSTRUCT_UNIX(SYS_write)
    syscall
    mov            rdi, rax
    mov            rax, SYSCALL_CONSTRUCT_UNIX(SYS_exit)
    syscall
___codeend:
    times 4096-($-$$) DB  0;
    filesize    EQU    $-$$
like image 148
Kamil.S Avatar answered Jan 19 '23 06:01

Kamil.S