Obfuscation #2: Playing entrypoint hide & seek game with dyld

Load command 9
        cmd LC_UNIXTHREAD
    cmdsize 80
     flavor i386_THREAD_STATE
      count i386_THREAD_STATE_COUNT
	    eax 0x00000000 ebx    0x00000000 ecx 0x00000000 edx 0x00000000
	    edi 0x00000000 esi    0x00000000 ebp 0x00000000 esp 0x00000000
	    ss  0x00000000 eflags 0x00000000 eip 0x186b2662 cs  0x00000000
	    ds  0x00000000 es     0x00000000 fs  0x00000000 gs  0x00000000

This is from the header of my crackme and that entrypoint is a random value. When the entrypoint is the original and valid one, IDA is more or less smart and uses that information if the headers are mangled (just the offsets). Instead of modifying the entrypoint to some stub I wanted to use an invalid value. A good place for this is dyld, who is responsible for jumping to the program’s entrypoint. The interesting code snippet is (from dyld/src/dyldStartup.s):

 # call dyldbootstrap::start(app_mh, argc, argv, slide)
 call    L__dyld_start_picbase
L__dyld_start_picbase:
 popl    %ebx            # set %ebx to runtime value of picbase
 movl    __dyld_start_static_picbase-L__dyld_start_picbase(%ebx), %eax
 subl    %eax, %ebx      # slide = L__dyld_start_picbase - [__dyld_start_static_picbase]
 pushl   %ebx            # param4 = slide
 lea     12(%ebp),%ebx
 pushl   %ebx            # param3 = argv
 movl    8(%ebp),%ebx
 pushl   %ebx            # param2 = argc
 movl    4(%ebp),%ebx
 pushl   %ebx            # param1 = mh
 call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKcl

 # clean up stack and jump to result
 movl    %ebp,%esp       # restore the unaligned stack pointer
 addl    $8,%esp         # remove the mh argument, and debugger end
                                #  frame marker
 movl    $0,%ebp         # restore ebp back to zero
 jmp     *%eax           # jump to the entry point

What we need is to restore the eax value to the real entrypoint and everything will be fine. One easy way to accomplish this is to set a breakpoint at the jmp eax address, fix the eax value and continue normal execution. Another way is to modify the jmp to an absolute address. The jmp is just two bytes long – not enough for this. But there should be enough alignment space above _dyld_start. Example:

8FE01010                   _offset_to_dyld_all_image_infos:
8FE01010 00 44 04 00                       db 0,44h,4,0 ; add     [esp+eax+0], al
8FE01010                   ; ---------------------------------------------------------------------------
8FE01014 00 00 00 00 00 00+                dd 5 dup(0)
8FE01028 0F 1F 84 00 00 00+                align 10h
8FE01030
8FE01030                   ; =============== S U B R O U T I N E =======================================
8FE01030
8FE01030
8FE01030                                   public __dyld_start
8FE01030                   __dyld_start    proc near
8FE01030 6A 00                             push    0
8FE01032 89 E5                             mov     ebp, esp
8FE01034 83 E4 F0                          and     esp, 0FFFFFFF0h
8FE01037 E8 00 00 00 00                    call    $+5
8FE0103C
8FE0103C                   loc_8FE0103C:                           ; DATA XREF: __data:__dyld_start_static_picbase
8FE0103C 5B                                pop     ebx
8FE0103D 8B 83 64 1C 04 00                 mov     eax, ds:(__dyld_start_static_picbase - 8FE0103Ch)[ebx]
8FE01043 29 C3                             sub     ebx, eax
8FE01045 53                                push    ebx
8FE01046 8D 5D 0C                          lea     ebx, [ebp+0Ch]
8FE01049 53                                push    ebx
8FE0104A 8B 5D 08                          mov     ebx, [ebp+8]
8FE0104D 53                                push    ebx
8FE0104E 8B 5D 04                          mov     ebx, [ebp+4]
8FE01051 53                                push    ebx
8FE01052 E8 4F 05 00 00                    call    __ZN13dyldbootstrap5startEPK12macho_headeriPPKcl
8FE01057 89 EC                             mov     esp, ebp
8FE01059 83 C4 08                          add     esp, 8
8FE0105C BD 00 00 00 00                    mov     ebp, 0
8FE01061 FF E0                             jmp     eax
8FE01061                   __dyld_start    endp

Modify the jmp eax to a negative offset into the slack space and modify that space to jump into the real entrypoint. The only piece left in this puzzle is ASLR. The dyld address can be easily found, especially if we give a base value where to start searching from (refer to the dyld randomization article). Having the dyld address, you can find its symbol table. I used **dyld_start_static_picbase **symbol for 32 bit (64 bit is **dyld_start_static**). While writing this I can’t remember why I have used this symbol instead of dyld_start.
The final step is to compute the real address of the jmp eax. I used an hash of the last bytes, which should be stable enough for this:

 # clean up stack and jump to result
 movl    %ebp,%esp       # restore the unaligned stack pointer
 addl    $8,%esp         # remove the mh argument, and debugger end
                         #  frame marker
 movl    $0,%ebp         # restore ebp back to zero
 jmp     *%eax           # jump to the entry point

Now we have the interesting address and can use one of the solutions above or something else you can come up with.
The problem with this approach is that it requires a constructor to manipulate dyld’s code before it is executed. Yesterday’s spoofing article and lots of junk functions could help to hide our intentions.

Have fun,
fG!