Skip to content

Instantly share code, notes, and snippets.

@duraki
Forked from zliuva/gist:1084476
Created July 31, 2023 21:32
Show Gist options
  • Save duraki/424af289d0121cc518b635429f094d3b to your computer and use it in GitHub Desktop.
Save duraki/424af289d0121cc518b635429f094d3b to your computer and use it in GitHub Desktop.

Revisions

  1. softboysxp revised this gist Dec 21, 2012. 1 changed file with 10 additions and 4 deletions.
    14 changes: 10 additions & 4 deletions gistfile2.asm
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@

    ; c.f.
    ; http://osxbook.com/blog/2009/03/15/crafting-a-tiny-mach-o-executable/ ( the original tiny mach-o executable )
    ; http://feiri.de/macho/ ( improved version, using a very clever trick to put code inside the load command itself)
    ; http://feiri.de/macho/ ( improved version, using a very clever trick to put code inside the load command itself)

    ; Constants (For readability)

    @@ -34,6 +34,10 @@
    %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)
    @@ -116,10 +120,12 @@ start: ; depending on the code generation size may vary a little bit
    mov rax, SYSCALL_CONSTRUCT_UNIX(SYS_write)
    syscall

    xor rdi, rdi
    mov rax, SYSCALL_CONSTRUCT_UNIX(SYS_exit)
    syscall
    ; the call to exit is optional now since the glue code in dyld will take care of it for us
    ;xor rdi, rdi
    ;mov rax, SYSCALL_CONSTRUCT_UNIX(SYS_exit)
    ;syscall

    ret ; returns from "main", the glue code will take care of the rest
    end:
    filesize EQU $-$$

  2. softboysxp revised this gist Dec 21, 2012. 2 changed files with 1 addition and 5 deletions.
    2 changes: 1 addition & 1 deletion gistfile1.asm
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    ; A minimal Mach-o x64 executable for OS X
    ; A minimal Mach-o x64 executable for OS X (also see below Mountain Lion version)
    ;
    ; $ nasm -f bin -o tiny_hello tiny_hello.s
    ; $ chmod +x tiny_hello
    4 changes: 0 additions & 4 deletions gistfile2.asm
    Original file line number Diff line number Diff line change
    @@ -34,10 +34,6 @@
    %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)
  3. softboysxp renamed this gist Dec 21, 2012. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. softboysxp revised this gist Dec 21, 2012. 1 changed file with 129 additions and 0 deletions.
    129 changes: 129 additions & 0 deletions gistfile2.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,129 @@
    ; A minimal Mach-o x64 executable for OS X (using LC_MAIN in Mountain Lion)
    ;
    ; $ nasm -O0 -f bin -o tiny_hello tiny_hello.s
    ; $ chmod +x tiny_hello
    ; $ ./tiny_hello
    ; Hello World!
    ; $

    ; c.f.
    ; http://osxbook.com/blog/2009/03/15/crafting-a-tiny-mach-o-executable/ ( the original tiny mach-o executable )
    ; http://feiri.de/macho/ ( improved version, using a very clever trick to put code inside the load command itself)

    ; 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_REQ_DYLD 0x80000000
    %define LC_LOAD_DYLIB 0xc
    %define LC_LOAD_DYLINKER 0xe
    %define LC_SEGMENT_64 0x19
    %define LC_MAIN 0x28 | LC_REQ_DYLD

    %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

    ; 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 4 ; ncmds
    DD start - load_commands ; sizeofcmds
    DD MH_NOUNDEFS ; flags
    DD 0x0 ; reserved

    ; Load commands
    load_commands:

    ; Segment and Sections
    DD LC_SEGMENT_64 ; cmd
    DD 72 ; cmdsize

    ; store our message in segname
    hello_str:
    DB 'Hello, World!', 0x0A ; segname
    len EQU $-hello_str
    DB 0x00, 0x00 ; last 2-byte of segname

    DQ 0x0 ; vmaddr
    DQ 0x1000 ; vmsize
    DQ 0 ; fileoff
    DQ filesize ; filesize
    DD VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE ; maxprot
    DD VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE ; initprot
    DD 0x0 ; nsects
    DD 0x0 ; flags

    ; In Mountain Lion, LC_MAIN is used to replace LC_UNIXTHREAD
    ; LC_MAIN is of fixed size 24 bytes, hence we cannot embed code into the command itself
    ; instead we simply pad the code at the end

    ; must use dyld to use LC_MAIN
    DD LC_LOAD_DYLINKER ; cmd
    DD 28 ; cmdsize (must be multiples of 4)
    DD 12 ; lc_str.offset
    DB '/usr/lib/dyld', 0x00, 0x00, 0x00 ; pad to multiples of 4

    ; must link to libSystem
    DD LC_LOAD_DYLIB ; cmd
    DD 52 ; cmdsize
    DD 24 ; lc_str.offset
    DD 2 ; timestamp
    DD 0xA90300 ; current_version
    DD 0x010000 ; compatibility_version
    DB '/usr/lib/libSystem.B.dylib', 0x00, 0x00 ; pad to multiples of 4

    ; Entry Point Command
    DD LC_MAIN ; cmd
    DD 24 ; cmdsize
    DQ start ; entry point
    DQ 0 ; stack size

    start: ; depending on the code generation size may vary a little bit
    mov rdi, 0x01
    mov rsi, hello_str
    mov rdx, len
    mov rax, SYSCALL_CONSTRUCT_UNIX(SYS_write)
    syscall

    xor rdi, rdi
    mov rax, SYSCALL_CONSTRUCT_UNIX(SYS_exit)
    syscall

    end:
    filesize EQU $-$$

  5. softboysxp revised this gist Dec 20, 2012. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions gistfile1.asm
    Original file line number Diff line number Diff line change
    @@ -95,6 +95,13 @@ DD x86_EXCEPTION_STATE64_COUNT ; count
    ; Somehow the OS X loader will clear rax-rdx regardless of the initial state
    ; Thus we can use these 32 bytes to store our code
    ; The original code is 35 bytes, thus we split the syscalls, store the 2nd part below and uses a jmp
    ;
    ; note: depending on NASM versions, the generated code may vary in size and the padding length has to be adjusted
    ; the NASM shipped with Xcode 4.0 on Lion generates 64 bit movs ("movq") and a short jump (24 bytes)
    ; nasm is broken in Mountain Lion and Xcode 4.3 (only i386 binary shipped, however ML is 64-bit only)
    ; NASM 2.10.04 built from nasm.us by default enables optimization to generate 32 bit movs ("movl") hence more bytes needs to be padded
    ; however when -O0 is specified, NASM 2.10 will generate movqs but with long jump (27 bytes), hence only 5, instead of 8 bytes needs to be padded
    ;
    start: ; 24 bytes
    ; rdi and rsi have already been set in the initial state
    mov rdx, len
  6. softboysxp revised this gist Jul 16, 2011. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.asm
    Original file line number Diff line number Diff line change
    @@ -103,7 +103,7 @@ start: ; 24 bytes
    jmp next

    DB 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; 8 bytes padding
    DQ 0x01, hello_str, 0x00, 0x00 ; rdi = STDOUT, rsi = 0x0 (since we map text section to 0), rbp, rsp
    DQ 0x01, hello_str, 0x00, 0x00 ; rdi = STDOUT, rsi = address of hello_str, rbp, rsp

    ; The exit syscall is 15 bytes, we use the inital sate of r8 and r9 to store the code
    next: ; 15 bytes
  7. softboysxp revised this gist Jul 16, 2011. 1 changed file with 28 additions and 31 deletions.
    59 changes: 28 additions & 31 deletions gistfile1.asm
    Original file line number Diff line number Diff line change
    @@ -59,7 +59,7 @@ DD CPU_TYPE_X86_64 ; cputype
    DD CPU_SUBTYPE_LIB64 | CPU_SUBTYPE_I386_ALL ; cpusubtype
    DD MH_EXECUTE ; filetype
    DD 2 ; ncmds
    DD text - load_commands ; sizeofcmds
    DD end - load_commands ; sizeofcmds
    DD MH_NOUNDEFS ; flags
    DD 0x0 ; reserved

    @@ -68,55 +68,52 @@ load_commands:

    ; Segment and Sections
    DD LC_SEGMENT_64 ; cmd
    DD 152 ; cmdsize
    DB '__TEXT', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
    0x00, 0x00, 0x00, 0x00 ; segname
    DD 72 ; cmdsize

    ; store our message in segname
    hello_str:
    DB 'Hello, World!', 0x0A ; segname
    len EQU $-hello_str
    DB 0x00, 0x00 ; last 2-byte of segname

    DQ 0x0 ; vmaddr
    DQ 0x1000 ; vmsize
    DQ 0 ; fileoff
    DQ filesize ; filesize
    DD VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE ; maxprot
    DD VM_PROT_READ | VM_PROT_EXECUTE ; initprot
    DD 0x1 ; nsects
    DD 0x0 ; flags

    DB '__text', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
    0x00, 0x00, 0x00, 0x00 ;sectname
    DB '__TEXT', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
    0x00, 0x00, 0x00, 0x00 ; segname
    DQ text ; addr
    DQ end - text ; size
    DQ text ; offset
    DD 0x0 ; align
    DD 0x0 ; reloff
    DD 0x0 ; nreloc
    DD 0x0 ; nsects
    DD 0x0 ; flags
    DD 0x0 ; reserved1
    DD 0x0 ; reserved2

    ; UNIX Thread Status
    DD LC_UNIXTHREAD ; cmd
    DD 184 ; cmdsize
    DD x86_THREAD_STATE64 ; flavor
    DD x86_EXCEPTION_STATE64_COUNT ; count
    DQ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp
    DQ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; r8, r9, r10, r11, r12, r13, r14, r15
    DQ start, 0x00, 0x00, 0x00, 0x00 ; rip, rflags, cs, fs, gs

    text:
    hello_str: DB 'Hello, World!', 0x0A
    len EQU $-hello_str
    start:
    mov rdx, len
    lea rsi, [hello_str]
    mov rdi, 1
    mov rax, SYSCALL_CONSTRUCT_UNIX(SYS_write)
    ; The following should be rax-rdx ( 8 * 4 = 32 bytes)
    ; Somehow the OS X loader will clear rax-rdx regardless of the initial state
    ; Thus we can use these 32 bytes to store our code
    ; The original code is 35 bytes, thus we split the syscalls, store the 2nd part below and uses a jmp
    start: ; 24 bytes
    ; rdi and rsi have already been set in the initial state
    mov rdx, len
    mov rax, SYSCALL_CONSTRUCT_UNIX(SYS_write)
    syscall
    jmp next

    DB 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; 8 bytes padding
    DQ 0x01, hello_str, 0x00, 0x00 ; rdi = STDOUT, rsi = 0x0 (since we map text section to 0), rbp, rsp

    ; The exit syscall is 15 bytes, we use the inital sate of r8 and r9 to store the code
    next: ; 15 bytes
    xor rdi, rdi
    mov rax, SYSCALL_CONSTRUCT_UNIX(SYS_exit)
    syscall
    DB 0x00 ; 1 byte padding

    DQ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; r10, r11, r12, r13, r14, r15
    DQ start, 0x00, 0x00, 0x00, 0x00 ; rip, rflags, cs, fs, gs

    end:
    filesize EQU $-$$
  8. softboysxp renamed this gist Jul 15, 2011. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  9. softboysxp created this gist Jul 15, 2011.
    122 changes: 122 additions & 0 deletions tiny_hello.s
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,122 @@
    ; A minimal Mach-o x64 executable for OS X
    ;
    ; $ nasm -f bin -o tiny_hello tiny_hello.s
    ; $ chmod +x tiny_hello
    ; $ ./tiny_hello
    ; Hello World!
    ; $

    ; c.f.
    ; http://osxbook.com/blog/2009/03/15/crafting-a-tiny-mach-o-executable/ ( the original tiny mach-o executable )
    ; http://feiri.de/macho/ ( improved version, using a very clever trick to put code inside the load command itself)

    ; 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

    ; 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 2 ; ncmds
    DD text - load_commands ; sizeofcmds
    DD MH_NOUNDEFS ; flags
    DD 0x0 ; reserved

    ; Load commands
    load_commands:

    ; Segment and Sections
    DD LC_SEGMENT_64 ; cmd
    DD 152 ; cmdsize
    DB '__TEXT', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
    0x00, 0x00, 0x00, 0x00 ; segname
    DQ 0x0 ; vmaddr
    DQ 0x1000 ; vmsize
    DQ 0 ; fileoff
    DQ filesize ; filesize
    DD VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE ; maxprot
    DD VM_PROT_READ | VM_PROT_EXECUTE ; initprot
    DD 0x1 ; nsects
    DD 0x0 ; flags

    DB '__text', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
    0x00, 0x00, 0x00, 0x00 ;sectname
    DB '__TEXT', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
    0x00, 0x00, 0x00, 0x00 ; segname
    DQ text ; addr
    DQ end - text ; size
    DQ text ; offset
    DD 0x0 ; align
    DD 0x0 ; reloff
    DD 0x0 ; nreloc
    DD 0x0 ; flags
    DD 0x0 ; reserved1
    DD 0x0 ; reserved2

    ; UNIX Thread Status
    DD LC_UNIXTHREAD ; cmd
    DD 184 ; cmdsize
    DD x86_THREAD_STATE64 ; flavor
    DD x86_EXCEPTION_STATE64_COUNT ; count
    DQ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp
    DQ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; r8, r9, r10, r11, r12, r13, r14, r15
    DQ start, 0x00, 0x00, 0x00, 0x00 ; rip, rflags, cs, fs, gs

    text:
    hello_str: DB 'Hello, World!', 0x0A
    len EQU $-hello_str
    start:
    mov rdx, len
    lea rsi, [hello_str]
    mov rdi, 1
    mov rax, SYSCALL_CONSTRUCT_UNIX(SYS_write)
    syscall

    xor rdi, rdi
    mov rax, SYSCALL_CONSTRUCT_UNIX(SYS_exit)
    syscall

    end:
    filesize EQU $-$$