Objektif-C
(Mungkin hanya jika dikompilasi dengan dentang di Mac OS X)
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
void unusedFunction(void) {
printf("huh?\n");
exit(0);
}
int main() {
NSString *string;
string = (__bridge id)(void*)0x2A27; // Is this really valid?
NSLog(@"%@", [string stringByAppendingString:@"foo"]);
return 0;
}
@interface MyClass : NSObject
@end
@implementation MyClass
+ (void)load {
Class newClass = objc_allocateClassPair([NSValue class], "MyClass2", 0);
IMP imp = class_getMethodImplementation(self, @selector(unusedMethod));
class_addMethod(object_getClass(newClass), _cmd, imp, "");
objc_registerClassPair(newClass);
[newClass load];
}
- (void)unusedMethod {
Class class = [self superclass];
IMP imp = (IMP)unusedFunction;
class_addMethod(class, @selector(doesNotRecognizeSelector:), imp, "");
}
@end
Kode ini menggunakan beberapa trik untuk sampai ke fungsi yang tidak digunakan. Pertama adalah nilai 0x2A27. Ini adalah penunjuk yang ditandai untuk bilangan bulat 42, yang menyandikan nilai dalam penunjuk untuk menghindari mengalokasikan objek.
Berikutnya adalah MyClass
. Itu tidak pernah digunakan, tetapi runtime memanggil +load
metode ketika itu dimuat, sebelumnya main
. Ini secara dinamis membuat dan mendaftarkan kelas baru, menggunakan NSValue
sebagai superclass-nya. Itu juga menambahkan +load
metode untuk kelas itu, menggunakan MyClass
's -unusedMethod
sebagai implementasinya. Setelah pendaftaran, ia memanggil metode memuat di kelas baru (untuk beberapa alasan itu tidak dipanggil secara otomatis).
Karena metode beban kelas baru menggunakan implementasi yang sama dengan unusedMethod
, yang secara efektif disebut. Dibutuhkan superkelas itu sendiri, dan ditambahkan unusedFunction
sebagai implementasi untuk doesNotRecognizeSelector:
metode kelas itu . Metode ini awalnya merupakan metode instance on MyClass
, tetapi sedang dipanggil sebagai metode kelas pada kelas baru, demikian self
juga objek kelas baru. Oleh karena itu, superclass adalah NSValue
, yang juga merupakan superclass untuk NSNumber
.
Akhirnya, main
lari. Dibutuhkan nilai pointer dan menempelkannya dalam NSString *
variabel (pemain __bridge
dan pertama yang void *
memungkinkan ini untuk digunakan dengan atau tanpa ARC). Kemudian, ia mencoba memanggil stringByAppendingString:
variabel itu. Karena sebenarnya angka, yang tidak menerapkan metode itu, doesNotRecognizeSelector:
metode ini disebut sebagai gantinya, yang perjalanan melalui hirarki kelas untuk NSValue
mana ia diimplementasikan menggunakan unusedFunction
.
Catatan: ketidakcocokan dengan sistem lain adalah karena penggunaan penunjuk yang ditandai, yang saya tidak percaya telah dilaksanakan oleh implementasi lain. Jika ini diganti dengan nomor yang biasanya dibuat, sisa kode harus bekerja dengan baik.