Articles by fG!

You are currently browsing fG!’s articles.

I smile when I think about this “feature”! I liked it so much that things got out of control and I wrote a crackme to show it. It happens because Apple doesn’t follow their own documentation/specification and the reversing tools of the trade do. The result is that IDA terminates, disassemblers output the wrong disassembly, strings are messed up, lldb disassembles the wrong code (not gdb), class-dump will fail, and the reverser looks at a weird Mach-O header.

In the end, it’s just a funny illusion :-)

If you try to load the crackme into IDA, it will complain of negative sizes and/or offsets. Otool also outputs weird stuff such as sections past end of file. The problem applies to the section command and a few of its fields. The 32 bits version of this structure is:

struct section { /* for 32-bit architectures */
	char		sectname[16];	/* name of this section */
	char		segname[16];	/* segment this section goes in */
	uint32_t	addr;		/* memory address of this section */
	uint32_t	size;		/* size in bytes of this section */
	uint32_t	offset;		/* file offset of this section */
	uint32_t	align;		/* section alignment (power of 2) */
	uint32_t	reloff;		/* file offset of relocation entries */
	uint32_t	nreloc;		/* number of relocation entries */
	uint32_t	flags;		/* flags (section type and attributes)*/
	uint32_t	reserved1;	/* reserved (for offset or index) */
	uint32_t	reserved2;	/* reserved (for count or sizeof) */
};

Let’s start with the one that produces the “best” results: offset. The definition at the reference document is:
“An integer specifying the offset to this section in the file.”

My interpretation of this isĀ (should be?) the offset (anywhere) in the file where the code/data for the section is located at. That makes sense right? It’s an offset so in theory it can be located anywhere in the file – it doesn’t need to be sequential or in a specific order. Once again, it’s open for some kind of abuse :-)

What happens if you change the offset value to somewhere else?
IDA, for example, will respect the content of the offset field and try to read the data pointed by it. Want to do a simple test? Grab a normal file, change the cstring section offset, save and load into IDA. Voila, the strings are now “obfuscated” because IDA is reading the wrong data.

That is fun, right? And if you try to run the modified binary, it works fine! That is, sort of, unexpected. Try the same trick with the text section. Now it’s the program code that is all wrong and it still runs fine. Hum…

What is happening? That is the fun part. I think that a good picture for this is that the kernel loads and maps the binary in a linear way from the disk and ignores the offset field.
The execve() system call is explained in detail starting page 812 in the great Mac OS X Internals book. The exec_mach_imgact() function (bsd/kern/kern_exec.c) calls load_machfile(), which is responsible for load executable, handle certain mach-o load commands, etc.
@bsd/kern/kern_exec.c

        /*
         * Actually load the image file we previously decided to load.
         */
        lret = load_machfile(imgp, mach_header, thread, map, &load_result);

Inside load_machfile(), we have a call to parse the new binary, parse_machfile().
@bsd/kern/mach_loader.c

        lret = parse_machfile(vp, map, thread, header, file_offset, macho_size,
                              0, result);

We can find there a nice description of this function:

/*
 * The file size of a mach-o file is limited to 32 bits; this is because
 * this is the limit on the kalloc() of enough bytes for a mach_header and
 * the contents of its sizeofcmds, which is currently constrained to 32
 * bits in the file format itself.  We read into the kernel buffer the
 * commands section, and then parse it in order to parse the mach-o file
 * format load_command segment(s).  We are only interested in a subset of
 * the total set of possible commands.
 */

Scrolling down that function you can observe a cycle that will process a subset of all possible commands. The section commands are found inside a LC_SEGMENT/LC_SEGMENT_64 command, so you are interested in giving a look at load_segment(). There you can observe that verifications are only done at segment command level, never at section level (that’s why we can’t mangle the segment command :-) ).
When parse_machfile() returns, all parsing is done, linker is loaded and soon the program entrypoint will be called. The binary was mapped as it is found in the disk (why I picture it in a linear way) and the section info wasn’t used for anything. There’s an implicit assumption that the binary will be formatted correctly.

Is this behaviour correct? In my opinion, it’s not. The kernel does not respect the Mach-O specification. Or am I abusing my interpretation of the docs and the implicit assumption is correct? In a age of so much distrust (and wasted money) regarding user input this kind of assumptions should be made explicit and verified accordingly.

By the way, you should continue to read about the full load sequence – there’s another fun trick hidden in the crackme ;-) .

You can also change the flags, size, section and segment names, and the order of the sections. That will confuse the tools and you, the reverser. What you need to do is to make the same assumption as the kernel and ignore those fields. That seems a bit odd, right?

I hope you have enjoyed this one and motivates you to spend some time with xnu and dyld.

Have fun,
fG!

Update:
This is a small PoC that implements the trick described above. The code is only for 32bits, non-fat binaries, console targets. If applied to Objective-C the target will not load because not all sections can be mangled.

manglemacho.c.gz
SHA256(manglemacho.c.gz)= d79a612b72130732d7e47b2925fba7fc0b63824622d05f08e7f33641d522a8b5

Update 2:
As a matter of fact, all the fields in each section can be 0, without any adverse consequences (except the mod_init_func). I had played with this and didn’t took any notes. If there’s no further obfuscation IDA is smart (in some cases) and can disassemble because of the valid entrypoint. IDA is more confused if we play with the offset and sizes fields.
Set the second argument in this improved version to something if you want to zero all fields.

manglemacho_v0.3.c.gz
SHA256(manglemacho_v0.3.c.gz)= 4b33dc5f43bbb9114e6a8c18dba8894ca44b991cd69a5e5e54bfdcd03607fc9c

I developed this funny trick while trying to find a solution for a problem in a freelance 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, the command structures are:

struct dylib_command              struct dylib                            union lc_str
{                                 {                                       {
 uint_32 cmd;                      union lc_str name;                      uint32_t offset;
 uint_32 cmdsize;                  uint_32 timestamp;                      #ifndef __LP64__
 struct dylib dylib;               uint_32 current_version;                char *ptr;
}                                  uint_32 compatibility_version;          #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 0×18 (24 bytes). This means that the library name string is located after the dylib_command command, whose size is 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!

This Sunday I received a valid keygen solution for my crackme. Congratulations to the reverser who wishes to remain anonymous.

When the solution is available our brain stops thinking and goes into lazy mode. So, my question is when do you want to have me starting to explain some of the tricks used in that crackme? Right now? Next week? In a month?

I did some questions to the keygen author to better understand his attack. From some of his statements I think he attacked from the vector I imagined, which is probably the fastest way to attack this.

Let me know your vote on this.

Have fun,
fG!

My first OS X crackme is finally “ready”, after a long wait and some unnecessary teasing. “Ready” means that it is good enough to be released and hopefully give you some trouble to reverse and crack it. I still have many more ideas to implement and some areas could be more polished – it was time to take an executive decision and freeze the code. There are some assumptions (economists love this term :-) ) due to the crackme nature – if it was an application more fun games could be played. I hope I haven’t missed any simple hole/bug. It’s not an easy task to build something that you are constantly cracking and thinking about ways to defeat it. I haven’t cracked it myself but I have a few neat ideas on how to approach it. The real interest is to read and learn about your approaches and solutions.

This crackme started as a PoC for some tricks I found while working on a project. The original idea was to create something to demonstrate the issues but it got out of control and evolved into a crackme (I hate to lose and love a good challenge!). Two issues were sort of disclosed during an interview with the fruity company since my interest with overflows is almost 0 ;-) . The impact of this is that the crackme is certified to run on OS X 10.6.8 up to 10.7.2. Newer Lion releases is a question mark. It is 32bits only and has no ASLR, due to coding time restrictions. As a matter of fact, I started the PoC with ASLR support, which poses no big problems to the concepts behind this crackme.
The code does nothing malicious or destructive so it’s safe to run! It is only hostile to your reversing efforts ;-)

The challenge is to find the valid name/key pair and keygen it if you wish so. Use the “-h” argument for help. The crackme will accept the name and key via command line parameters, to make your life easier. Run with no parameters for the usual crackme questions.
I will disclose details as soon a solution is sent to me by mail or comment. If you wish to remain anonymous or keep the solution private just tell me.

Probably forgetting about some stuff so this post might be updated soon.

There are two or three little things taken from other people and proper credit will be given in due time.

This should be an advanced crackme with some unusual stuff in OS X (at least for me :-) ). I hope you enjoy reversing it and learn/develop some new tricks.
Hint: it is quite amusing that Apple doesn’t follow its own specifications ;-)

Have fun,
fG!

fg_crackme_nr1.gz
SHA256(fg_crackme_nr1.gz)= 9116e336f3979c1c68e63bec2868d193b6ccbf031e3521bdcdb7e14034c3c636

This is a OS X port of kad’s checkidt utility featured at Phrack #59. It requires /dev/kmem to be active since task_for_pid on kernel task is prohibited since Snow Leopard.
I have added an option to calculate the sysent address via the IDT. The code is not very fail proof because it uses the opcode hex values. Disassembly is probably a better option. This is just a PoC written some time ago so there are some ugly things inside.
The concept to retrieve sysent is the following:

get idt -> get location of interrupt 0×80 -> get address of LO_UNIX_SCALL -> get address of unix_syscall -> get location of sysent

Some of the information that the original code retrieves in Linux is meaningless in OS X. Maybe one of these days I will do a major cleanup. If you do it first feel free to send it. The 64bits code state is unknown and untested – my machines do not run 64bits kernels :-/.

Enjoy,
fG!

checkidtv1.2.c.gz
SHA256(checkidtv1.2.c.gz)= fe663c83c81c0db11e661f3bf2596a323dcc1df342941067c804eda94a5086c3

Here is a small update to gdbinit with a new command, “skip”.
This command will skip over the current instruction, without executing it. Usually I do it manually by set $pc=newvalue but this involves copy&paste and mouse movements and gets boring after a while. It’s great to skip over calls while you are trying some stuff and analysing some program behavior.
By default it will not execute the command at the new address. You can change this by modifying the configuration variable on top of gdbinit.

This command uses a little hack that Hopper’s author told me – the $_ variable will hold the last address, so we can disassemble 2 lines and compute the difference to retrieve the instruction size. Gdb has no command to retrieve the instruction size at a given address.
I did some (incomplete) work to add a new command for this. Being an economist, I can’t avoid this dilemma – to invest or not (more) time into gdb. Gdb source is a boring mess and LLDB is improving. I am thinking to try to create an initial LLDB port of gdbinit. This should allow me to understand its true potential as reversing debugger and take a decision where to invest time & resources.

Have fun,
fG!

gdbinit744.gz
SHA256(gdbinit744.gz)= 2b223998571069f00edebd606d055c5b370ede5a8cb2b2fe69093c310e32c547

« Older entries