objective-c runtime安全措施之二:反注入
5016 点击·0 回帖
![]() | ![]() | |
![]() | 《O'Reilly.Hacking.and.Securing.ios.Applications>>读书笔记 反注入:在类函数被调用前做完整性检测(预防应用自定义函数或apple标准库函数被修改或替换) 原理:调用dladdr()函数检查类方法的基本信息是否合法 例子1:检查Foundation框架类中NSMutableURLRequest基类(用于改变URL请求)的setHTTPBody方法的基本信息 #include <dlfcn.h> #include <objc/objc.h> #include <objc/runtime.h> #include <stdio.h> #include <string.h> int main() { Dl_info info; IMP imp = class_getMethodImplementation( objc_getClass("NSMutableURLRequest"), sel_registerName("setHTTPBody:")); printf("pointer %p\n", imp); 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"); } } 在Mac OS上使用gcc编译 $ gcc -o main main.m -lobjc -framework Foundation 然后运行该程序和观察输出,这些信息(地址空间、文件名、符号名)可以确认该函数来源、是否合法 $ ./main pointer 0x7fff8e7aba62 dli_fname: /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation dli_sname: -[NSMutableURLRequest(NSMutableHTTPURLRequest) setHTTPBody:] dli_fbase: 0x7fff8e633000 dli_saddr: 0x7fff8e7aba62 例子2:使用dladdr函数检查类中的所有方法的通用代码 #include <dlfcn.h> #include <stdio.h> #include <objc/objc.h> #include <objc/runtime.h> #include <stdlib.h> #include <errno.h> #include <string.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]; printf("validating [ %s %s ]\n", (const char *) class_getName(aClass), (const char *) method_getName(m)); imp = method_getImplementation(m); if (!imp) { printf("error: method_getImplementation(%s) failed\n", (const char *) method_getName(m)); free(methods); return NO; } if (! dladdr(imp, ;info)) { printf("error: dladdr() failed for %s\n", (const char *)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 *) method_getName(m)); if (strncmp(info.dli_sname + (strlen(info.dli_sname) - strlen(buf)), buf, strlen(buf))) { goto FAIL; } } return YES; FAIL: printf("method %s failed integrity test:\n", (const char *)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; } 【注意】 1. 重命名检查函数(例如不要用validate_methods这样具有明显意义的名字) 2. 在应用的多处加入检查函数,任何与敏感数据交互的方法在执行前都需要检查 3. 例子中的logging和printf语句只是用来调试,代码正式发布前要移除 4. 验证完整性只是提高了攻击的门槛,不能完全防御黑客,需要综合应用多种技巧,例如思路一中的反调试技巧,及马上要介绍的反汇编技巧。 作者 danqingd | |
![]() | ![]() |