#import #include #include void* sel_lookUpByName(const char* name); @interface Foo : NSObject @end @implementation Foo - (void)bar { NSLog(@"Invoke instance method original bar in Foo"); } - (void)tobehijacked:(NSString*)input { NSLog(@"Invoke tobehijacked method %@ from Foo", input); } @end @interface Bar : NSObject @end @implementation Bar static int x; + (void)load { x = 1; printf("Invoke +load method\n"); } - (void)dummy { NSLog(@"Static value check after +load should be 1: x=%d", x); } @end @interface FakeNSDateFormatter : NSDateFormatter { } @end @implementation FakeNSDateFormatter - (NSDate*)dateFromString:(NSString*)dateString { NSLog(@"Hijacked the NSDateFormatter"); return [super dateFromString:dateString]; } @end __attribute__((constructor)) static void hmmge(int argc, char** argv) { printf("Invoke C constructor\n"); printf("Checking for arguments to be passed correctly\n"); printf(" argc=%d\n", argc); for (int i = 0; i < argc; i++) { printf(" argv[%d]=%s\n", i, argv[i]); } NSLog(@"Using Objective-C in C constructor"); NSLog(@"Test static Objective-C class is initialized and +load completed"); Bar *bar = [[Bar alloc] init]; [bar dummy]; } int main(int argc, const char * argv[], char* envp[]) { @autoreleasepool { NSLog(@"Invoke main()"); // Foo bar using Objective-C syntax Foo *foo = [[Foo alloc] init]; [foo bar]; // Foo bar with selector and msgSend NSLog(@"Directly call \"bar\" %p through objc_msgSend %p with object foo %p", @selector(bar), objc_msgSend, foo); typedef void (*barfunc)(id, SEL); barfunc bar_ = (barfunc)&objc_msgSend; bar_(foo, @selector(bar)); NSString *dummyinput = @"dummy input"; [foo tobehijacked:dummyinput]; NSLog(@"The above invocation should be hijacked with input at %p", dummyinput); NSString *dateString = @"2024-01-01T00:00:00.000Z"; // NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; // [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"]; // NSDate *date = [dateFormatter dateFromString:dateString]; // this is to test the idea for hooking, // basically, we create a middle-class inherits the class to be used // // example using NSDateFormatter: // - Create a FakeNSDateFormatter inherits NSDateFormatter // - Have an overloaded function that calls [super inherited] // - The internal struct class_t has superclass points to NSDateFormatter // FakeNSDateFormatter *dateFormatter = [[FakeNSDateFormatter alloc] init]; // [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"]; // NSDate *date = [dateFormatter dateFromString:dateString]; // NSLog(@"Test hijacked/hooked Objective-C result %@", date); NSLog(@"Selector \"dateFromString:\" using @selector %p", @selector(dateFromString:)); NSLog(@"Selector \"bar:\" using @selector %p", @selector(bar:)); NSLog(@"Selector \"dummy\" using @selector %p", @selector(dummy)); NSLog(@"[Bar dummy] implementation is at %p\n", [foo methodForSelector:@selector(bar:)]); } printf("Selector lookup 'dateFromString:' addr: %p\n", sel_lookUpByName("dateFromString:")); printf("Selector lookup 'bar:' addr: %p\n", sel_lookUpByName("bar:")); printf("Selector lookup 'dummy' addr: %p\n", sel_lookUpByName("dummy")); printf("Test if arguments are passed correctly to main(argc, argv, env)\n"); printf(" argc=%d\n", argc); for (int i = 0; i < argc; i++) { printf(" argv[%d]=%s\n", i, argv[i]); } while (*envp) { printf(" env[]=%s\n", *envp); envp++; } return 0; }