使用dladdr方法可以獲得一個函數所在的模塊.從而判斷該函數是否被替換掉。
#include <dlfcn.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdio.h>
#include <string.h>
+ (void)test {
Dl_info info;
IMP imp;
Method orginalMethod = class_getClassMethod([NSObject class], @selector(load));
imp = method_getImplementation(orginalMethod);
if (dladdr(imp, &info)) {
printf("dli_fname: %s\n", info.dli_fname);
printf("dli_sname: %s\n", info.dli_sname);
printf("dli_fbase: %p\n", info.dli_fbase);
printf("dli_saddr: %p\n", info.dli_saddr);
} else {
printf("error: can't find that symbol.\n");
}
}
====================================================
dli_fname: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework/Foundation
dli_sname: +[NSObject(NSObject) load]
dli_fbase: 0x7fff25888000 //模塊地址
dli_saddr: 0x7fff2591bb43 //函數地址
通過該方法驗證指定類的方法是否都來自指定模塊(可以根據實際情況自定義修改),建議使用inline方式編譯,像這樣以內聯函數的形式編譯,攻擊者必須修改每一處調用該函數的的地方:
#include <dlfcn.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdio.h>
#include <string.h>
static inline BOOL validate_methods(const char *cls,const char *fnamePre) __attribute__ ((always_inline));
BOOL validate_methods(const char *cls,const char *fnamePre){
Class aClass = objc_getClass(cls);
Method *methods;
unsigned int nMethods;
Dl_info info;
IMP imp;
Method m;
if(!aClass)
return NO;
methods = class_copyMethodList(aClass, &nMethods);
while (nMethods--) {
m = methods[nMethods];
imp = method_getImplementation(m);
if(!imp){
free(methods);
return NO;
}
if(!dladdr(imp, &info)){
free(methods);
return NO;
}
/*Validate image path*/
if(!strstr(info.dli_fname, fnamePre)){
printf("%s \n", info.dli_fname);
printf("%s \n", info.dli_sname);
goto FAIL;
}
}
return YES;
FAIL:
printf("method %s failed integrity test:\n",sel_getName(method_getName(m)));
printf(" dli_fname:%s\n",info.dli_fname);
printf(" dli_sname:%s\n",info.dli_sname);
printf(" dli_fbase:%p\n",info.dli_fbase);
printf(" dli_saddr:%p\n",info.dli_saddr);
free(methods);
return NO;
}
當然,我們可以查看幾個常見的關鍵函數地址:
Dl_info info;
if (dladdr(exit, &info)) {
printf("dli_fname: %s\n", info.dli_fname);
printf("dli_sname: %s\n", info.dli_sname);
printf("dli_fbase: %p\n", info.dli_fbase);
printf("dli_saddr: %p\n", info.dli_saddr);
} else {
printf("error: can't find that symbol.\n");
}
if (dladdr(syscall, &info)) {
printf("dli_fname: %s\n", info.dli_fname);
printf("dli_sname: %s\n", info.dli_sname);
printf("dli_fbase: %p\n", info.dli_fbase);
printf("dli_saddr: %p\n", info.dli_saddr);
} else {
printf("error: can't find that symbol.\n");
}
if (dladdr(sysctl, &info)) {
printf("dli_fname: %s\n", info.dli_fname);
printf("dli_sname: %s\n", info.dli_sname);
printf("dli_fbase: %p\n", info.dli_fbase);
printf("dli_saddr: %p\n", info.dli_saddr);
} else {
printf("error: can't find that symbol.\n");
}
================================================
dli_fname: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/libsystem_c.dylib
dli_sname: exit
dli_fbase: 0x7fff51a76000
dli_saddr: 0x7fff51ad0046
dli_fname: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/libsystem_kernel.dylib
dli_sname: __syscall
dli_fbase: 0x7fff51b5a000
dli_saddr: 0x7fff51b5c9f0
dli_fname: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/system/libsystem_c.dylib
dli_sname: sysctl
dli_fbase: 0x7fff51a76000
dli_saddr: 0x7fff51aa1304