I developed this funny trick while trying to find a solution for a problem in a project. It is pretty easy to implement and fun.

The trick consists in abusing the offset field in the dylib_command and pointing it to somewhere else. From the Mach-O File Format Reference document, the command structures are:

struct dylib_command                                          
{
 uint_32 cmd;
 uint_32 cmdsize;
 struct dylib dylib;
}

struct dylib
{
	union lc_str name; 
	uint_32 timestamp;
	uint_32 current_version;
	uint_32 compatibility_version;
}

union lc_str
{
	uint32_t offset;
#ifndef __LP64__
	char *ptr;
#endif
}

The definition of the offset field is:
“A long integer. A byte offset from the start of the load command that contains this string to the start of the string data.”

Usually this field is always 0x18 (24 bytes). This means that the library name string is located after the dylib_command command, with a size of 24 bytes. Right now your evil brain should be interpreting that definition as “an offset (anywhere) that contains the start of the string data”. If not, don’t worry, evilness takes practice.

What happens if you put the string somewhere else and change the offset to point there? GDB crashes, otool can’t recognize the offset and so on.

otool:

Load command 20
          cmd LC_LOAD_DYLIB
      cmdsize 88
         name ?(bad offset 28548)
   time stamp 2 Thu Jan  1 01:00:02 1970
      current version 30.0.0
compatibility version 1.0.0

GDB:

GNU gdb 6.3.50-20050815 (Apple version gdb-1344 + reverse.put.as patches v0.3) (Mon Aug 22 00:31:56 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...gdb-i386-apple-darwin(68831) malloc: *** mmap(size=18446744073709506560) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug

Fun stuff, right? 😄
The problem with the debugger attach is that I assumed GDB would also crash if attached and forgot to try if it was true. It is a minor problem – the crackme is designed to resist a debugger attach.

The next trick is even more fun but requires some time to write the post. I didn’t took all the notes and I need to “rediscover” it to show you where the problem is.

Enjoy,
fG!