#import <dlfcn.h>
#import <objc/runtime.h>
- (void)main
{
//__start__
NSArray *array = @[@"obj1"];
NSLog(@"description1:%@",array.description);
//动态方法的处理在objective-c的动态特性一文中有做介绍
SEL suppIOSEL = NSSelectorFromString(@"mydescription");
IMP suppIOIMP = imp_implementationWithBlock(^(id _self) {
NSLog(@"mydescription:%@",_self);
return _self;
});
ReplaceMethod(NSArray.class, NSSelectorFromString(@"description"), suppIOSEL, suppIOIMP);
NSLog(@"description2:%@",array.description);
//__end__
IMP imp = class_getMethodImplementation(objc_getClass("NSArray"),
sel_registerName("description"));
Dl_info info;
if (dladdr(imp, &info)) {
NSLog(@"dli_fname: %s\n", info.dli_fname);
NSLog(@"dli_sname: %s\n", info.dli_sname);
NSLog(@"dli_fbase: %d\n", (int)info.dli_fbase);
NSLog(@"dli_saddr: %d\n", (int)info.dli_saddr);
} else {
NSLog(@"error: can't find that symbol.\n");
}
}
void ReplaceMethod(Class c, SEL orig, SEL newSel, IMP impl) {
Method method = class_getInstanceMethod(c, orig);
if (!class_addMethod(c, newSel, impl, method_getTypeEncoding(method))) {
}else SwizzleMethod(c, orig, newSel);
}
static void SwizzleMethod(Class c, SEL orig, SEL new) {
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if (class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
}else {
method_exchangeImplementations(origMethod, newMethod);
}
}
然后运行该程序和观察输出,这些信息(地址空间、文件名、符号名)可以确认该函数来源、是否合法
#import <dlfcn.h>
#import <objc/runtime.h>
static inline BOOL validate_methods(const char *, const char *) __attribute__((always_inline));
BOOL validate_methods(const char *cls, const char *fname) {
Class aClass = objc_getClass(cls);
Method *methods;
unsigned int nMethods;
Dl_info info;
IMP imp;
char buf[128];
Method m;
if (!aClass)
return NO;
methods = class_copyMethodList(aClass, &nMethods);
while(nMethods--) {
m = methods[nMethods];
NSLog(@"validating [ %s %s ]\n",
(const char *) class_getName(aClass),
(const char *) sel_getName(method_getName(m)));
imp = method_getImplementation(m);
if (!imp) {
NSLog(@"error: method_getImplementation(%s) failed\n",
(const char *) sel_getName(method_getName(m)));
free(methods);
return NO;
}
if (!dladdr(imp, &info)) {
NSLog(@"error: dladdr() failed for %s\n",
(const char *) sel_getName(method_getName(m)));
free(methods);
return NO;
}
/* Validate image path */
if (strcmp(info.dli_fname, fname))
goto FAIL;
/* Validate class name in symbol */
snprintf(buf, sizeof(buf), "[%s ",
(const char *) class_getName(aClass));
if (strncmp(info.dli_sname+1, buf, strlen(buf)))
{
snprintf(buf, sizeof(buf), "[%s(",
(const char *) class_getName(aClass));
if (strncmp(info.dli_sname+1, buf, strlen(buf)))
goto FAIL;
}
/* Validate selector in symbol */
snprintf(buf, sizeof(buf), " %s]",
(const char *) sel_getName(method_getName(m)));
if (strncmp(info.dli_sname + (strlen(info.dli_sname) - strlen(buf)),
buf, strlen(buf)))
{
goto FAIL;
}
}
return YES;
FAIL:
NSLog(@"method %s failed integrity test:\n",
(const char *) sel_getName(method_getName(m)));
NSLog(@"dli_fname: %s\n", info.dli_fname);
NSLog(@"dli_sname: %s\n", info.dli_sname);
NSLog(@"dli_fbase: %d\n", (int)info.dli_fbase);
NSLog(@"dli_saddr: %d\n", (int)info.dli_saddr);
free(methods);
return NO;
}
- (void)main
{
NSString *root = @"";
IF_SIMULATOR(root = [[NSProcessInfo processInfo] environment][@"IPHONE_SIMULATOR_ROOT"];)
const char* fname = [[root stringByAppendingPathComponent:
@"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"]
fileSystemRepresentation];
BOOL isValidate = validate_methods("NSArray", fname);
....
}
【注意】