Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

basic darwin support for shellcrafter #2161

Merged
merged 16 commits into from
Feb 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ The table below shows which release corresponds to each branch, and what date th
- [#2323][2323] Retry failed lookups after one week in libcdb
- [#2325][2325] Match against local system libc first in libcdb
- [#2336][2336] Add `ELF.stripped` and `ELF.debuginfo` properties
- [#2161][2161] Add basic support for darwin shellcraft/asm/disasm/run_shellcode/run_assembly
- [#2161][2161] Fix freebsd amd64 SyscallABI
- [#2160][2161] Fix invalid shellcraft.mov on arm64
- [#2284][2161] Fix invalid shellcraft.pushstr_array on arm64

[2242]: https://github.com/Gallopsled/pwntools/pull/2242
[2277]: https://github.com/Gallopsled/pwntools/pull/2277
Expand All @@ -105,6 +109,7 @@ The table below shows which release corresponds to each branch, and what date th
[2323]: https://github.com/Gallopsled/pwntools/pull/2323
[2325]: https://github.com/Gallopsled/pwntools/pull/2325
[2336]: https://github.com/Gallopsled/pwntools/pull/2336
[2161]: https://github.com/Gallopsled/pwntools/pull/2161

## 4.12.0 (`beta`)

Expand Down Expand Up @@ -1105,4 +1110,4 @@ are mentioned here.
- Added a lots of shellcodes
- Stuff we forgot
- Lots of documentation fixes
- Lots of bugfixes
- Lots of bugfixes
45 changes: 39 additions & 6 deletions pwnlib/abi.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ def default():
(32, 'mips', 'linux'): linux_mips,
(32, 'powerpc', 'linux'): linux_ppc,
(64, 'powerpc', 'linux'): linux_ppc64,
(32, 'riscv32', 'linux'): linux_riscv32,
(64, 'riscv64', 'linux'): linux_riscv64,
(32, 'i386', 'freebsd'): freebsd_i386,
(64, 'aarch64', 'freebsd'): freebsd_aarch64,
(64, 'amd64', 'freebsd'): freebsd_amd64,
Expand All @@ -58,6 +60,8 @@ def default():
(64, 'powerpc', 'freebsd'): freebsd_ppc64,
(32, 'i386', 'windows'): windows_i386,
(64, 'amd64', 'windows'): windows_amd64,
(64, 'amd64', 'darwin'): darwin_amd64,
(64, 'aarch64', 'darwin'): darwin_aarch64,
}[(context.bits, context.arch, context.os)]

@staticmethod
Expand All @@ -76,6 +80,8 @@ def syscall():
(64, 'aarch64', 'linux'): linux_aarch64_syscall,
(32, 'powerpc', 'linux'): linux_ppc_syscall,
(64, 'powerpc', 'linux'): linux_ppc64_syscall,
(32, 'riscv32', 'linux'): linux_riscv32_syscall,
(64, 'riscv64', 'linux'): linux_riscv64_syscall,
(32, 'i386', 'freebsd'): freebsd_i386_syscall,
(64, 'amd64', 'freebsd'): freebsd_amd64_syscall,
(64, 'aarch64', 'freebsd'): freebsd_aarch64_syscall,
Expand All @@ -85,6 +91,8 @@ def syscall():
(64, 'aarch64', 'freebsd'): freebsd_aarch64_syscall,
(32, 'powerpc', 'freebsd'): freebsd_ppc_syscall,
(64, 'powerpc', 'freebsd'): freebsd_ppc64_syscall,
(64, 'amd64', 'darwin'): darwin_amd64_syscall,
(64, 'aarch64', 'darwin'): darwin_aarch64_syscall,
}[(context.bits, context.arch, context.os)]

@staticmethod
Expand All @@ -99,13 +107,18 @@ def sigreturn():
(32, 'arm', 'linux'): linux_arm_sigreturn,
(32, 'thumb', 'linux'): linux_arm_sigreturn,
(64, 'aarch64', 'linux'): linux_aarch64_sigreturn,
(32, 'riscv32', 'linux'): linux_riscv32_sigreturn,
(64, 'riscv64', 'linux'): linux_riscv64_sigreturn,
(32, 'i386', 'freebsd'): freebsd_i386_sigreturn,
(64, 'amd64', 'freebsd'): freebsd_amd64_sigreturn,
(32, 'arm', 'freebsd'): freebsd_arm_sigreturn,
(32, 'thumb', 'freebsd'): freebsd_arm_sigreturn,
(64, 'aarch64', 'freebsd'): freebsd_aarch64_sigreturn,
(64, 'amd64', 'darwin'): darwin_amd64_sigreturn,
(64, 'aarch64', 'darwin'): darwin_aarch64_sigreturn,
}[(context.bits, context.arch, context.os)]


class SyscallABI(ABI):
"""
The syscall ABI treats the syscall number as the zeroth argument,
Expand All @@ -115,6 +128,7 @@ def __init__(self, *a, **kw):
super(SyscallABI, self).__init__(*a, **kw)
self.syscall_register = self.register_arguments[0]


class SigreturnABI(SyscallABI):
"""
The sigreturn ABI is similar to the syscall ABI, except that
Expand All @@ -132,6 +146,8 @@ class SigreturnABI(SyscallABI):
linux_mips = ABI('$sp', ['$a0','$a1','$a2','$a3'], 4, 0)
linux_ppc = ABI('sp', ['r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10'], 4, 0)
linux_ppc64 = ABI('sp', ['r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10'], 8, 0)
linux_riscv32 = ABI('sp', ['a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7'], 8, 0)
linux_riscv64 = ABI('sp', ['a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7'], 8, 0)

sysv_i386 = linux_i386
sysv_amd64 = linux_amd64
Expand All @@ -140,24 +156,33 @@ class SigreturnABI(SyscallABI):
sysv_mips = linux_mips
sysv_ppc = linux_ppc
sysv_ppc64 = linux_ppc64
sysv_riscv32 = linux_riscv32
sysv_riscv64 = linux_riscv64

# Docs: https://man7.org/linux/man-pages/man2/syscall.2.html
linux_i386_syscall = SyscallABI('esp', ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp'], 4, 0)
linux_amd64_syscall = SyscallABI('rsp', ['rax', 'rdi', 'rsi', 'rdx', 'r10', 'r8', 'r9'], 8, 0)
linux_arm_syscall = SyscallABI('sp', ['r7', 'r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6'], 4, 0)
linux_aarch64_syscall = SyscallABI('sp', ['x8', 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6'], 16, 0)
linux_arm_syscall = SyscallABI('sp', ['r7', 'r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6'], 4, 0)
linux_aarch64_syscall = SyscallABI('sp', ['x8', 'x0', 'x1', 'x2', 'x3', 'x4', 'x5'], 16, 0)
linux_mips_syscall = SyscallABI('$sp', ['$v0','$a0','$a1','$a2','$a3'], 4, 0)
linux_ppc_syscall = ABI('sp', ['r0', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9'], 4, 0)
linux_ppc64_syscall = ABI('sp', ['r0', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9'], 8, 0)
linux_ppc_syscall = SyscallABI('sp', ['r0', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9'], 4, 0)
linux_ppc64_syscall = SyscallABI('sp', ['r0', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8'], 8, 0)
linux_riscv32_syscall = SyscallABI('sp', ['a7', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5'], 4, 0)
linux_riscv64_syscall = SyscallABI('sp', ['a7', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5'], 8, 0)

linux_i386_sigreturn = SigreturnABI('esp', ['eax'], 4, 0)
linux_amd64_sigreturn = SigreturnABI('rsp', ['rax'], 4, 0)
linux_amd64_sigreturn = SigreturnABI('rsp', ['rax'], 8, 0)
linux_arm_sigreturn = SigreturnABI('sp', ['r7'], 4, 0)
linux_aarch64_sigreturn = SigreturnABI('sp', ['x8'], 16, 0)
linux_riscv32_sigreturn = SigreturnABI('sp', ['a7'], 4, 0)
linux_riscv64_sigreturn = SigreturnABI('sp', ['a7'], 8, 0)

sysv_i386_sigreturn = linux_i386_sigreturn
sysv_amd64_sigreturn = linux_amd64_sigreturn
sysv_arm_sigreturn = linux_arm_sigreturn
sysv_aarch64_sigreturn = linux_aarch64_sigreturn
sysv_riscv32_sigreturn = linux_riscv32_sigreturn
sysv_riscv64_sigreturn = linux_riscv64_sigreturn

freebsd_i386 = sysv_i386
freebsd_amd64 = sysv_amd64
Expand All @@ -168,7 +193,7 @@ class SigreturnABI(SyscallABI):
freebsd_ppc64 = sysv_ppc64

freebsd_i386_syscall = SyscallABI('esp', ['eax'], 4, 0)
freebsd_amd64_syscall = SyscallABI('rsp', ['rax','rdi','rsi','rdx','rcx','r8','r9'], 8, 0)
freebsd_amd64_syscall = SyscallABI('rsp', ['rax','rdi','rsi','rdx','r10','r8','r9'], 8, 0)
freebsd_arm_syscall = SyscallABI('sp', ['r7', 'r0', 'r1', 'r2', 'r3'], 8, 0)
freebsd_aarch64_syscall = SyscallABI('sp', ['x8', 'x0', 'x1', 'x2', 'x3'], 16, 0)
freebsd_mips_syscall = SyscallABI('$sp', ['$v0','$a0','$a1','$a2','$a3'], 4, 0)
Expand All @@ -182,3 +207,11 @@ class SigreturnABI(SyscallABI):

windows_i386 = ABI('esp', [], 4, 0)
windows_amd64 = ABI('rsp', ['rcx','rdx','r8','r9'], 32, 32)

darwin_aarch64 = sysv_aarch64
darwin_aarch64_syscall = SyscallABI('sp', ['x16', 'x0', 'x1', 'x2', 'x3', 'x4', 'x5'], 16, 0)
darwin_aarch64_sigreturn = SigreturnABI('sp', ['x16'], 16, 0)

darwin_amd64 = sysv_amd64
darwin_amd64_syscall = SyscallABI('rsp', ['rax', 'rdi', 'rsi', 'rdx', 'r10', 'r8', 'r9'], 8, 0)
darwin_amd64_sigreturn = SigreturnABI('rsp', ['rax'], 8, 0)
63 changes: 63 additions & 0 deletions pwnlib/asm.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ def cpp(shellcode):
]
return _run(cmd, code).strip('\n').rstrip() + '\n'


@LocalContext
def make_elf_from_assembly(assembly,
vma=None,
Expand Down Expand Up @@ -651,6 +652,68 @@ def make_elf(data,

return retval


@LocalContext
def make_macho_from_assembly(shellcode):
return make_macho(shellcode, is_shellcode=True)


@LocalContext
def make_macho(data, is_shellcode=False):
prefix = []
if context.arch == 'amd64':
prefix = [
'.intel_syntax noprefix',
]
prefix.extend([
'.text',
'.global _start',
'_start:',
'.p2align 2',
])
code = ''
code += '\n'.join(prefix) + '\n'
if is_shellcode:
code += cpp(data)
else:
code += '.string "%s"' % ''.join('\\x%02x' % c for c in bytearray(data))

log.debug('Assembling\n%s' % code)

tmpdir = tempfile.mkdtemp(prefix = 'pwn-asm-')
step1 = path.join(tmpdir, 'step1')
step2 = path.join(tmpdir, 'step2')
step3 = path.join(tmpdir, 'step3')

with open(step1, 'w') as fd:
fd.write(code)

assembler = [
'/usr/bin/as',
]
asflags = [
'-mmacosx-version-min=11.0',
'-o', step2, step1,
]
_run(assembler + asflags)

linker = [
'/usr/bin/ld',
]
ldflags = [
'-macos_version_min', '11.0',
'-l', 'System',
'-e', '_start',
'-L', '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib',
'-o', step3, step2,
]
_run(linker + ldflags)

os.chmod(step3, 0o755)

return step3


@LocalContext
def asm(shellcode, vma = 0, extract = True, shared = False):
r"""asm(code, vma = 0, extract = True, shared = False, ...) -> str
Expand Down
Empty file.
Loading