otx is a tool used to disassemble Mach-O binaries on OS X 10.0-10.4. It is an enhancement on top of otool to add additional symbol information to its disassembled output.

The main site and SVN repository (http://otx.osxninja.com/) appears to be long dead. I've seen a few repos on GitHub but has anyone maintained or updated otx to work on modern versions of Mac OS?

1 Answer 1


The most up to date fork I have found of otx is Cai's. I have tried the CLI interface of his v1.7: Build 566 release on macOS 10.11.6 and it runs fine for basic disassembly, albeit on invoking it using -o to 'check the executable for obfuscation' against a little test code I wrote, it terminates with a

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[X8664Processor verifyNops:numFound:]: unrecognized selector sent to instance 0x7fb7e5806200'

In my opinion there are better suited tools available today to disassemble binaries on OSX, among which even otool nowadays does not seem like it lacks functionality compared to otx for ad-hoc disassembly.

Let's have a quick look by disassembling the section of a code which reads (essentially the 32bit version of 32-__builtin_clz(n)):

static uint8_t f1_u32(uint32_t n) {
    return n ? 1 + f1_u32(n/2) : 0;

Using otool -t -d -vV -j -q -H -P ./kk 2>/dev/null | grep -A24 "^_f1_u32:" we get:

0000000100000de0    55  pushq   %rbp
0000000100000de1    48 89 e5    movq    %rsp, %rbp
0000000100000de4    48 83 ec 10     subq    $0x10, %rsp
0000000100000de8    89 7d fc    movl    %edi, -0x4(%rbp)
0000000100000deb    83 7d fc 00     cmpl    $0x0, -0x4(%rbp)
0000000100000def    0f 84 1b 00 00 00   je  0x100000e10
0000000100000df5    8b 45 fc    movl    -0x4(%rbp), %eax
0000000100000df8    c1 e8 01    shrl    $0x1, %eax
0000000100000dfb    89 c7   movl    %eax, %edi
0000000100000dfd    e8 de ff ff ff  callq   _f1_u32
0000000100000e02    0f b6 f8    movzbl  %al, %edi
0000000100000e05    83 c7 01    addl    $0x1, %edi
0000000100000e08    89 7d f8    movl    %edi, -0x8(%rbp)
0000000100000e0b    e9 0a 00 00 00  jmp 0x100000e1a
0000000100000e10    31 c0   xorl    %eax, %eax
0000000100000e12    89 45 f8    movl    %eax, -0x8(%rbp)
0000000100000e15    e9 00 00 00 00  jmp 0x100000e1a
0000000100000e1a    8b 45 f8    movl    -0x8(%rbp), %eax
0000000100000e1d    88 c1   movb    %al, %cl
0000000100000e1f    0f b6 c1    movzbl  %cl, %eax
0000000100000e22    48 83 c4 10     addq    $0x10, %rsp
0000000100000e26    5d  popq    %rbp
0000000100000e27    c3  retq
0000000100000e28    0f 1f 84 00 00 00 00 00     nopl    (%rax,%rax)

Using ./otx -d ./kk 2>/dev/null | grep -A26 "^_f1_u32:", this is the result:

    +0  0000000100000de0  55                 pushq    %rbp
    +1  0000000100000de1  4889e5             movq     %rsp,         %rbp
    +4  0000000100000de4  4883ec10           subq     $0x10,        %rsp
    +8  0000000100000de8  897dfc             movl     %edi,         -0x4(%rbp)
   +11  0000000100000deb  837dfc00           cmpl     $0x0,         -0x4(%rbp)
   +15  0000000100000def  0f841b000000       je       0x100000e10
   +21  0000000100000df5  8b45fc             movl     -0x4(%rbp),   %eax
   +24  0000000100000df8  c1e801             shrl     $0x1,         %eax
   +27  0000000100000dfb  89c7               movl     %eax,         %edi
   +29  0000000100000dfd  e8deffffff         callq    _f1_u32
   +34  0000000100000e02  0fb6f8             movzbl   %al,          %edi
   +37  0000000100000e05  83c701             addl     $0x1,         %edi
   +40  0000000100000e08  897df8             movl     %edi,         -0x8(%rbp)
   +43  0000000100000e0b  e90a000000         jmp      0x100000e1a   Anon4
   +48  0000000100000e10  31c0               xorl     %eax,         %eax
   +50  0000000100000e12  8945f8             movl     %eax,         -0x8(%rbp)
   +53  0000000100000e15  e900000000         jmp      0x100000e1a   Anon4

    +0  0000000100000e1a  8b45f8             movl     -0x8(%rbp),   %eax
    +3  0000000100000e1d  88c1               movb     %al,          %cl
    +5  0000000100000e1f  0fb6c1             movzbl   %cl,          %eax
    +8  0000000100000e22  4883c410           addq     $0x10,        %rsp
   +12  0000000100000e26  5d                 popq     %rbp
   +13  0000000100000e27  c3                 retq
   +14  0000000100000e28  0f1f840000000000   nopl     (%rax,%rax)

Besides cosmetic differences, we actually get (and expect) very similar output.

Unbeknownst of your agenda, in recent times I have found myself using radare2 or the hopper GUI tool rather than fiddling with otool or otx when it comes to disassembly.

In hopper, you even get a decent pseudo code out of the disassembly (could be even better if hopper interpreted the & 0xff as a hint towards an unsigned variable in this case):

int _f1_u32(int arg0) {
    var_4 = arg0;
    if (var_4 != 0x0) {
            var_8 = (_f1_u32(var_4 >> 0x1) & 0xff) + 0x1;
    } else {
            var_8 = 0x0;
    rax = var_8 & 0xff;
    return rax;
  • Thanks for the answer. I was looking for an update to otx for legacy reasons, but for disassembling modern executables radare2 and Hopper seem to be better choices. Thanks!
    – JAL
    Commented Jan 3, 2017 at 16:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.