Skip to content

Instantly share code, notes, and snippets.

@kam800
Created May 28, 2018 07:25
Show Gist options
  • Save kam800/e1f1fa143257c733a20aea2974929ab8 to your computer and use it in GitHub Desktop.
Save kam800/e1f1fa143257c733a20aea2974929ab8 to your computer and use it in GitHub Desktop.
# This snippet shows how to enable dyld `closured` and how to fix `read` implementation in dyld using lldb.
# Following text is a bash/lldb command mix and it contains the relevant stdout content and my comments.
// `DYLD_PRINT_WARNINGS=1` environment variable will print dyld logs
$ DYLD_PRINT_WARNINGS=1 lldb /Users/kamil.borzym/tmp/TestMacApp.app/Contents/MacOS/TestMacApp
(lldb) process launch --stop-at-entry
(lldb) image list
[ 0] D355CCB5-8584-33E3-8DF7-7BA95BAD41AF 0x0000000100000000 /Users/kamil.borzym/tmp/TestMacApp.app/Contents/MacOS/TestMacApp
[ 1] AFAB4EFA-7020-34B1-BBEF-0F26C6D3CA36 0x000000010070d000 /usr/lib/dyld
// see the dyld base address -> 0x000000010070d000
(lldb) image lookup -s dyld::sEnableClosures
1 symbols match 'dyld::sEnableClosures' in /usr/lib/dyld:
Address: dyld[0x000000000004dde8] (dyld.__DATA.__bss + 88)
Summary: dyld`dyld::sEnableClosures
// write '1' to dyld base address + dyld::sEnableClosures offset
(lldb) memory write --size 1 0x000000010070d000+0x000000000004dde8 1
// now dyld::sEnableClosures == 1
(lldb) breakpoint set --shlib dyld --name read --auto-continue true
Breakpoint 1: where = dyld`read, address = 0x000000010073e890
// use `read` address -> 0x000000010073e890 to see assembly
(lldb) dis --address 0x000000010073e890
dyld`read:
0x10073e890 <+0>: movl $0x2000003, %eax ; imm = 0x2000003
0x10073e895 <+5>: movq %rcx, %r10
0x10073e898 <+8>: syscall
0x10073e89a <+10>: jae 0x10073e8a4 ; <+20>
0x10073e89c <+12>: movq %rax, %rdi
0x10073e89f <+15>: jmp 0x10073da6d ; cerror
0x10073e8a4 <+20>: retq
0x10073e8a5 <+21>: nop
0x10073e8a6 <+22>: nop
0x10073e8a7 <+23>: nop
// `retq` instruction address -> 0x10073e8a4
// declare variables used in breakpoint command script
(lldb) expr int $fd;
(lldb) expr unsigned long $buf;
(lldb) expr ssize_t $count;
(lldb) expr ssize_t $ret;
(lldb) expr ssize_t $partial;
(lldb) expr int $guard;
(lldb) breakpoint command add 1
> expr $fd = $arg1
> expr $buf = $arg2
> expr $count = $arg3
> expr $ret = 0
> expr $guard = 4
// invoke `read` in loop until all expected bytes are read or error occured too many times
> expr do { $partial = (ssize_t)read($fd, $buf, $count); if ($partial <= 0) { $guard -= 1; } else { $buf += $partial; $count -= $partial; $ret += $partial; } } while ($count > 0 && $guard >= 0)
> expr if ($guard <= 0) { $ret = -1 }
// set `read` return value as a sum off all nested `read` return values
> register write rax `$ret`
// quit from current `read` – jump to the `retq` instruction at the end of the `read` function
> register write rip 0x10073e8a4
> DONE
(lldb) c
Process 86647 resuming
dyld: found closure 0x7fffd35c3d20 in dyld shared cache
dyld: closure 0x7fffd35c3d20 not used because current cache on disk and in memory cache have UUID mismatches
// voilà, all closured output has been read
dyld: closured return 0x10082e000 for /Users/kamil.borzym/tmp/TestMacApp.app/Contents/MacOS/TestMacApp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment