Skip to content

Instantly share code, notes, and snippets.

@TooTallNate
Created July 9, 2011 04:05
Show Gist options
  • Save TooTallNate/1073294 to your computer and use it in GitHub Desktop.
Save TooTallNate/1073294 to your computer and use it in GitHub Desktop.
low-level objc runtime apis
*
!*.m
!Makefile
// To compile: gcc -o array array.m -lobjc -framework Foundation
#include <objc/runtime.h>
#include <dlfcn.h>
#include <stdio.h>
int main() {
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY);
if (sdl_library == NULL) {
printf("Got dlopen error!\n");
} else {
printf("dlopen successful!\n");
// Set up an NSAutoreleasePool
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool");
id pool = class_createInstance(nsautoreleasepool, 0);
SEL initSel = sel_registerName("init");
id poolAfterInit = objc_msgSend(pool, initSel);
// Create an NSMutableArray
Class nsmutablearray = objc_getClass("NSMutableArray");
// Regular way to create an NSMutableArray,
// equivalent to [[NSMutableArray alloc] initWithCapacity: 10]
id array = objc_msgSend(nsmutablearray, sel_registerName("alloc"));
id arrayAfterInit = objc_msgSend(array, sel_registerName("initWithCapacity:"), 10);
// Alternative, shorthand way of creating an NSMutableArray,
// equivalent to [NSMutableArray arrayWithCapacity: 10]
//id arrayAfterInit = objc_msgSend(nsmutablearray, sel_registerName("arrayWithCapacity:"), 10);
// Add an NSString and the nsma class reference to the array
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"test");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), nsmutablearray);
// Print out the length and debug printout
NSLog(@"%d", objc_msgSend(arrayAfterInit, sel_registerName("count")));
NSLog(@"%@", arrayAfterInit);
}
return 0;
}
#import <Foundation/Foundation.h>
#include <objc/runtime.h>
#include <Block.h>
#include <dlfcn.h>
#include <stdio.h>
int main() {
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY);
if (sdl_library == NULL) {
printf("Got dlopen error!\n");
} else {
printf("dlopen successful!\n");
// Set up an NSAutoreleasePool
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool");
id pool = class_createInstance(nsautoreleasepool, 0);
SEL initSel = sel_registerName("init");
id poolAfterInit = objc_msgSend(pool, initSel);
// Create an NSMutableArray
Class nsmutablearray = objc_getClass("NSMutableArray");
// Regular way to create an NSMutableArray,
// equivalent to [[NSMutableArray alloc] initWithCapacity: 10]
id array = objc_msgSend(nsmutablearray, sel_registerName("alloc"));
id arrayAfterInit = objc_msgSend(array, sel_registerName("initWithCapacity:"), 10);
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"a");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"b");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"c");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"d");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"e");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"f");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"g");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"h");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"i");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"j");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"k");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"l");
id b = ^(id x, NSUInteger index, BOOL *stop){
NSLog(@"%@", x);
};
NSLog(@"%@", b);
objc_msgSend(arrayAfterInit, sel_registerName("enumerateObjectsUsingBlock:"), b);
}
return 0;
}
#import <Foundation/Foundation.h>
#include <objc/runtime.h>
#include <Block.h>
#include <dlfcn.h>
#include <stdio.h>
struct __block_literal_1 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_1 *, id obj, NSUInteger idx, BOOL *stop);
struct __block_descriptor_1 *descriptor;
};
// This is the regular C function we are turning into a Block.
void __block_invoke_1(struct __block_literal_1 *_block, id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"%d: %@", idx, obj);
}
static struct __block_descriptor_1 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1) };
int main() {
printf("sizeof(int): %lu\n", sizeof(int));
printf("sizeof(void *): %lu\n", sizeof(void *));
printf("sizeof(void (*)()): %lu\n", sizeof(void (*)()));
printf("sizeof(struct __block_descriptor *): %lu\n", sizeof(struct __block_descriptor *));
printf("sizeof(__block_literal_1): %lu\n", sizeof(struct __block_literal_1));
printf("sizeof(__block_descriptor_1): %lu\n", sizeof(struct __block_descriptor_1));
printf(" calculated: %lu\n", sizeof(void*)+sizeof(int)+sizeof(int)+sizeof(void (*)())+sizeof(struct __block_descriptor_1 *));
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY);
if (sdl_library == NULL) {
printf("Got dlopen error!\n");
} else {
printf("dlopen successful!\n");
// Set up an NSAutoreleasePool
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool");
id pool = class_createInstance(nsautoreleasepool, 0);
SEL initSel = sel_registerName("init");
id poolAfterInit = objc_msgSend(pool, initSel);
// Create an NSMutableArray
Class nsmutablearray = objc_getClass("NSMutableArray");
// Regular way to create an NSMutableArray,
// equivalent to [[NSMutableArray alloc] initWithCapacity: 10]
id array = objc_msgSend(nsmutablearray, sel_registerName("alloc"));
id arrayAfterInit = objc_msgSend(array, sel_registerName("initWithCapacity:"), 10);
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"a");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"b");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"c");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"d");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"e");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"f");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"g");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"h");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"i");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"j");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"k");
objc_msgSend(arrayAfterInit, sel_registerName("addObject:"), @"l");
struct __block_literal_1 _block_literal = {
&_NSConcreteStackBlock,
//&_NSConcreteGlobalBlock,
(1<<29),
0,
__block_invoke_1,
&__block_descriptor_1
};
id b = (id)&_block_literal;
NSLog(@"%@", b);
objc_msgSend(arrayAfterInit, sel_registerName("enumerateObjectsUsingBlock:"), b);
}
return 0;
}
#include <objc/runtime.h>
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char **argv) {
dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", RTLD_LAZY);
dlopen("/System/Library/Frameworks/AppKit.framework/AppKit", RTLD_LAZY);
dlopen("/System/Library/Frameworks/Cocoa.framework/Cocoa", RTLD_LAZY);
char * className = argc == 2 ? argv[1] : "NSMutableArray";
Class NSMA = objc_getClass(className);
if (!NSMA) {
printf("Could not load Class: %s\n", className);
return 1;
}
const char *name = class_getName(NSMA);
printf("class_getName: %s\n", name);
int version = class_getVersion(NSMA);
printf("class_getVersion: %d\n", version);
const char *weakIvarLayout = class_getWeakIvarLayout(NSMA);
printf("class_getWeakIvarLayout: %s\n", weakIvarLayout);
BOOL isMetaClass = class_isMetaClass(NSMA);
printf("class_isMetaClass: %s\n", isMetaClass ? "yes" : "no");
// get the metaclass
id metaclass = NSMA->isa;
isMetaClass = class_isMetaClass(metaclass);
printf("class_isMetaClass(isa): %s\n", isMetaClass ? "yes" : "no");
// Look up the Ivars
unsigned int i = 0;
unsigned int numIvars = 999999;
Ivar *ivars = NULL;
ivars = class_copyIvarList(NSMA, &numIvars);
printf("\nNum ivars: %d\n", numIvars);
for (; i<numIvars; i++) {
Ivar ivar = ivars[i];
const char *ivarName = ivar_getName(ivar);
printf(" %s (%s)\n", ivarName, ivar_getTypeEncoding(ivar));
}
free(ivars);
// Copy the Property List
unsigned int numProps = 999999;
objc_property_t *props = NULL;
props = class_copyPropertyList(NSMA, &numProps);
printf("\nNum props: %d\n", numProps);
for (i=0; i<numProps; i++) {
}
free(props);
// Copy Protocol List
unsigned int numProtocols = 9999999;
Protocol **ps = class_copyProtocolList(NSMA, &numProtocols);
printf("\nNum Protocols: %d\n", numProtocols);
for (i=0; i<numProtocols; i++) {
Protocol *p = ps[i];
printf(" %s\n", protocol_getName(p));
}
free(ps);
// Copy Method List (instance methods)
unsigned int numMethods = 99999999;
Method * methods = NULL;
methods = class_copyMethodList(NSMA, &numMethods);
printf("\nNum Instance Methods: %d\n", numMethods);
for (i=0; i<numMethods; i++) {
Method m = methods[i];
SEL name = method_getName(m);
printf(" %s (%s)\n", sel_getName(name), method_getTypeEncoding(m));
}
free(methods);
// Copy Method List (class methods)
numMethods = 0;
methods = NULL;
methods = class_copyMethodList(metaclass, &numMethods);
printf("\nNum Class Methods: %d\n", numMethods);
for (i=0; i<numMethods; i++) {
Method m = methods[i];
SEL name = method_getName(m);
printf(" %s (%s)\n", sel_getName(name), method_getTypeEncoding(m));
}
free(methods);
// get superclass
Class superclass = NSMA;
printf("\nWalking inheritance chain:\n");
printf(" %s\n", name);
unsigned int numClasses = 0;
do {
printf(" ");
numClasses++;
superclass = class_getSuperclass(superclass);
for (i=0; i<numClasses; i++) {
printf(" ");
}
printf("↳ %s\n", class_getName(superclass));
} while(superclass);
return 0;
}
#include <objc/runtime.h>
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char **argv) {
dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY);
unsigned int i, n;
Protocol **ps = NULL;
ps = objc_copyProtocolList(&n);
printf("Num Protocols: %d\n", n);
// Do stuff with `classes`
for (i=0; i<n; i++) {
Protocol *p = ps[i];
printf("%s\n", protocol_getName(p));
}
free(ps);
return 0;
}
// To compile: gcc -o getClassList getClassList.m -lobjc -framework Foundation
#import <Foundation/Foundation.h>
#include <objc/runtime.h>
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char **argv) {
dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", RTLD_LAZY);
dlopen("/System/Library/Frameworks/AppKit.framework/AppKit", RTLD_LAZY);
int i = 0;
int numClasses;
Class * classes = NULL;
numClasses = objc_getClassList(NULL, 0);
printf("Num classes: %d\n", numClasses);
if (numClasses > 0 ) {
classes = malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
// Do stuff with `classes`
for (i=0; i<numClasses; i++) {
Class c = classes[i];
printf("%s\n", class_getName(c));
}
free(classes);
}
return 0;
}
// To compile: gcc -o hello hello.m -lobjc
#include <objc/runtime.h>
#include <dlfcn.h>
#include <stdio.h>
int main() {
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY);
if (sdl_library == NULL) {
printf("Got dlopen error!\n");
} else {
printf("dlopen successful!\n");
// Set up an NSAutoreleasePool
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool");
id pool = class_createInstance(nsautoreleasepool, 0);
SEL initSel = sel_registerName("init");
id poolAfterInit = objc_msgSend(pool, initSel);
// Set up a NSString with the contents "Hello World" from a C string
Class nsstring = objc_getClass("NSString");
SEL stringUTF8sel = sel_registerName("stringWithUTF8String:");
id hello = objc_msgSend(nsstring, stringUTF8sel, "Hello World\n");
// Print it back out as a C string
printf("%s", (char *)objc_msgSend(hello, sel_registerName("UTF8String")));
}
return 0;
}
CC = gcc
SRC_FILES = $(wildcard *.m)
OUT_FILES = $(SRC_FILES:.m=)
.PHONY: all
all: $(OUT_FILES)
%: %.m
$(CC) -g -lobjc -framework Foundation -o $@ $<
.PHONY: clean
clean:
rm -f $(OUT_FILES)
rm -rf $(SRC_FILES:.m=.dSYM)
// To compile: gcc -o scriptingbridge scriptingbridge.m -lobjc -framework Foundation
#import <Foundation/Foundation.h>
#include <objc/runtime.h>
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char **argv) {
dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY);
dlopen("/System/Library/Frameworks/ScriptingBridge.framework/Versions/Current/ScriptingBridge", RTLD_LAZY);
// Set up an NSAutoreleasePool
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool");
id pool = class_createInstance(nsautoreleasepool, 0);
SEL initSel = sel_registerName("init");
id poolAfterInit = objc_msgSend(pool, initSel);
// Create an instance of the local iTunes installation
Class sbapplication = objc_getClass("SBApplication");
id itunes = objc_msgSend(sbapplication, sel_registerName("applicationWithBundleIdentifier:"), @"com.apple.iTunes");
// Is iTunes running?
id running = objc_msgSend(itunes, sel_registerName("isRunning"));
NSLog(@"iTunes Running: %d", running);
// Print out the name of the iTunes application
id name = objc_msgSend(itunes, sel_registerName("name"));
NSLog(@"Name: %@", name);
// Print out the current volume
NSInteger curVol = (NSInteger) objc_msgSend(itunes, sel_registerName("soundVolume"));
NSLog(@"Current Volume: %d", curVol);
// If an argument was passed, assume it's an integer and set iTunes' volume
if (argc > 1) {
NSInteger volToSet = atoi(argv[1]);
objc_msgSend(itunes, sel_registerName("setSoundVolume:"), volToSet);
NSLog(@"Set Volume to: %d", volToSet);
}
return 0;
}
// To compile: gcc -o array array.m -lobjc -framework Foundation
#import <Foundation/Foundation.h>
#include <objc/runtime.h>
#include <dlfcn.h>
#include <stdio.h>
int main() {
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY);
if (sdl_library == NULL) {
printf("Got dlopen error!\n");
} else {
printf("dlopen successful!\n");
}
printf("sizeof(Class): %lu\n", sizeof(Class));
printf("sizeof(Method): %lu\n", sizeof(Method));
printf("sizeof(unsigned long int): %lu\n", sizeof(unsigned long int));
printf("sizeof(struct int, void*): %lu\n", sizeof(struct test { int test; void * ptr; }));
printf("sizeof(struct int, int, void*): %lu\n", sizeof(struct test2 { int test; int test2; void * ptr; }));
printf("sizeof(struct void*, int, int, void*): %lu\n", sizeof(struct test3 { void *ptr2; int test2; void * ptr; }));
return 0;
}
#include <objc/runtime.h>
#include <objc/objc-exception.h>
#include <dlfcn.h>
#include <stdio.h>
void uncaughtExceptionHandler (id exception) {
fprintf(stderr, "Inside uncaughtException handler!!!!\n");
fprintf(stderr, "Exception Type: %s\n", (const char *)objc_msgSend(objc_msgSend(exception, sel_registerName("name")), sel_registerName("UTF8String")));
fprintf(stderr, "Exception Reason: %s\n", (const char *)objc_msgSend(objc_msgSend(exception, sel_registerName("reason")), sel_registerName("UTF8String")));
}
int main() {
void *sdl_library = dlopen("/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation", RTLD_LAZY);
if (sdl_library == NULL) {
printf("Got dlopen error!\n");
} else {
printf("dlopen successful!\n");
// Set up an NSAutoreleasePool
Class nsautoreleasepool = objc_getClass("NSAutoreleasePool");
id pool = class_createInstance(nsautoreleasepool, 0);
SEL initSel = sel_registerName("init");
id poolAfterInit = objc_msgSend(pool, initSel);
// Set up an uncaughtException handler
objc_setUncaughtExceptionHandler((objc_uncaught_exception_handler)uncaughtExceptionHandler);
// Intentionally throw an exception, by sending a bad selector to an object
Class nsobject = objc_getClass("NSObject");
SEL badSel = sel_registerName("badSelector");
objc_msgSend(nsobject, badSel);
}
return 0;
}
@sancarn
Copy link

sancarn commented Mar 6, 2023

Realise this was created a long time ago but is a really useful resource.

objc_msgSend appears to have a odd definition where the params are just inserted wherever. Do you know if it's possible to send parameters gradually to an object by repeatedly sending objc_msgSend() (or some other function) for parameters instead?

id itunesPre = objc_msgSend(sbapplication, sel_registerName("applicationWithBundleIdentifier:"));
id itunes = objc_msgSend(itunesPre, @"com.apple.iTunes")

Additionally, do you know how to send a named parameter?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment