浅谈IOS如何对app进⾏安全加固
⽬录
防⽌ tweak 依附
1.限制⼆进制⽂件头内的段
2.setuid 和 setgid
检测越狱设备上是否有针对性 tweak
防 http 抓包
混淆(或者加密)硬编码的明⽂字符串
使⽤ Swift 开发
使⽤静态内连 C 函数
使⽤ block
代码混淆
其他⽅法
注意事项
防⽌ tweak 依附
通常来说,我们要分析⼀个 app,最开始⼀般是砸壳,
$ DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /path/to/XXX.app/XXX
然后将解密之后的⼆进制⽂件扔给类似 hopper 这样的反编译器处理。直接将没有砸壳的⼆进制⽂件扔个 hopper 反编译出来的内容是⽆法阅读的(被苹果加密了)。所以说砸壳是破解分析 app 的第⼀步。对于这⼀步的防范,有两种⽅式。
1.限制⼆进制⽂件头内的段
通过在 Xcode ⾥⾯⼯程配置 build setting 选项中将
-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null
添加到 "Other Linker Flags"(注意这⾥我在项⽬中碰到了⼀个问题,在 iPod touch iOS 9.3 的设备上,使⽤了 swift 的项⽬会导致莫名奇妙的 swift 标准库⽆法到,⽽在 iOS 10 的设备上没有这个问题。之前并没有以为是因为添加了这个的原因,直到⽹上搜了所有解决⽅案,⽐如这个 SO Post 都没有效果的时候,我才发现是这个设置的原因)
2.setuid 和 setgid
Apple 不接受调⽤这两个函数的 app,因为它可以通过查看符号表来判断您的⼆进制运⾏⽂件是否包含这两个函数
检测越狱设备上是否有针对性 tweak
⼀般来说在越狱⼿机上,我们会使⽤ TheOS 创建 tweak 类型的⼯程。然后针对我们要分析的类,使⽤提供的 logify.pl 命令⽣成的 mk ⽂件来打印该类所有⽅法的⼊参和出参。这对分析 app 的运⾏⽅式有很⼤的帮助。当然,我们也可以⾃⼰创建某个类的 mk,来 hook 某个函数,让它以我们想要的⽅式运⾏,⽐如说对于⼀些做了证书绑定的 app,如果它⽤的框架是AFNetWorking 的话,那么我们可以创建⼀个 mk ⽂件,hook AFSecurityPolicy 类的下列⽅法:
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain
让这个⽅法永远返回 YES,那么⼤多数的应⽤所做的证书绑定也就失效了。⽤过 TheOS 的 tweak 模版的话,你会发现这种⽅式相当简单快速。
对于这⼀步的防范,可以在⼯程的 main 函数⾥⾯加⼊⼀层判断,⾸先读取 /Library/MobileSubstrate/DynamicLibraries 下所有的 plist ⽂件的内容,查看是否某个 plist 含有你的 app 的 bundle id,是的话,可以判定有⼈想利⽤ tweak 攻击你的 app,这时候你可以采取⽐如说将 app 给 crash 掉,或者限制某些功能等⽅式来应对。
具体原理可以查看参考资料4,简单来说,就是 MobileSubstrate 在 app 加载到内存的时候会先去检查
/Library/MobileSubstrate/DynamicLibraries 下⾯是否有需要加载的 tweak,有的话就加载,怎么判断有没有?就是根据 plist ⾥⾯的 bundle ID 判断的。
代码参考如下
static __inline__ __attribute__((always_inline)) int anti_tweak()
{
uint8_t lmb[] = {'S', 'u', 'b', 's', 't', 'r', 'a', 't', 'e', '/', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 0, };
NSString *dir = [NSString stringWithFormat:@"/%@/%@%s%@", @"Library", @"Mobile", lmb, @"Libraries"];
NSArray *dirFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:nil];
url编码和utf8区别NSArray *plistFiles = [dirFiles filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:
[NSString stringWithFormat:@"%@ %@%@ '.%@%@'",@"self", @"EN", @"DSWITH", @"pli", @"st"]]];
int cnt = 0;
for (NSString *file in plistFiles) {
NSString *filePath = [dir stringByAppendingPathComponent:file];
NSString *fileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
if (fileContent && [fileContent rangeOfString:[[NSBundle mainBundle] bundleIdentifier]].location != NSNotFound) {
cnt ++;
}
}
// 返回有针对本 app 的 tweak 数量,为 0 说明没有
return cnt;
}
防 http 抓包
通常破解⼀个 app,我们会抓包。这样的话,我们的 app 所有接⼝,接⼝数据都会暴露在逆向⼈员的眼⽪底下。这时候,我们可以限制 http 抓包。⽅式很简单,就是将 NSURLSessionConfiguration 的 connectionProxyDictionary 设置成空的字典,因为这个属性就是⽤来控制会话的可⽤代理的。可⽤参见官⽅⽂档,也就是参考资料5。下⾯是对于 AFNetWorking 的使⽤⽅法:
// 继承 AFHTTPSessionManager,重写下列⽅法
- (instancetype)initWithServerHost:(PDLServerHost*)serverHost {
#ifdef DEBUG
// debug 版本的包仍然能够正常抓包
self = [super initWithBaseURL:serverHost.baseURL];
#else
// 由于使⽤ ephemeralSessionConfiguration session 发起的请求不带 cookie 和使⽤缓存等
NSURLSessionConfiguration *conf = [NSURLSessionConfiguration ephemeralSessionConfiguration];
self = [super initWithBaseURL:serverHost.baseURL sessionConfiguration:conf];
#endif
return self;
}
但是由于 OC ⽅法很容易被 hook,避免抓包是不可能的,所以,个⼈认为最好的⽅式是对请求参数进⾏加密(最好是⾮对称加密,⽐如 RSA)
混淆(或者加密)硬编码的明⽂字符串
对于被砸壳的⼆进制⽂件,逆向分析⼈员分析代码有⼀条重要线索,也就是被硬编码的明⽂字符串。⽐如说,你的 app 被⼈抓包了,某些数据请求接⼝也被⼈发现了,那么很简单,逆向⼈员可以直接拷贝特征⽐较明显的字符串到 hopper 中搜索,通过查看该字符串被引⽤的地⽅,可以很快的到相应的逻辑代码。
对于这⼀步的防范,需要做的就是对硬编码的明⽂进⾏加密或混淆。有个开源代码可以⽤,UAObfuscatedString,但是这个开源混淆代码写出来的字符串是相当长的(也就是⿇烦),同时不⽀持加密。最近我写了⼀个⼯具,可以在编译期间加密所有代码中的明⽂字符串,在 app 运⾏的时候解密字符串。这个⼯具的特点如下:
1.简单,开发⼈员可以硬编码明⽂字符串,所有的加密会在编译开始时⾃动处理
2.可以⾃定义加密或者混淆⽅式,(为了不影响 app 运⾏效率,需要提供⼀个简单快速的加密或混淆⽅式)提⾼解密难度
使⽤ Swift 开发
Swift 是⽬前⽐较新的开发 iOS 语⾔,由于 Swift ⽬前还不是很稳定,越狱开源社区对这个的⽀持也不是很即时,⽐如说class-dump ⼯具⽬前就不⽀持含有 Swift 的⼆进制⽂件。 TheOS 也是最近才开始⽀持 Swift,但是还没有加到主分⽀上(可以参见Features)。所以⽬前来看,⾄少 Swift 可能⽐纯 OC 的⼯程要安全⼀点点。当然,等 Swift ⽇趋稳定,以及越狱开源社区的逐渐⽀持,这⼀点优势可能就不明显了。
使⽤静态内连 C 函数
由于 OC 语⾔的动态性,导致 OC 的代码是最容易被破解分析的。在安全性上,更推荐使⽤ C 语⾔写成的函数。但是 C 语⾔的函数也是可以被 hook 的,主要有3种⽅式:
1.使⽤ Facebook 开源的fishhook
2.使⽤ MobileSubstrate 提供的 hook C 语⾔函数的⽅法
void MSHookFunction(void* function, void* replacement, void** p_original);
3.使⽤ mach_override,关于mach_override 和 fishhook的区别请看 mach_override 和 fishhook 区别
由于上⾯这三种⽅式可以 hook C 函数。要想不被 hook 解决⽅法是使⽤静态内联函数,这样的话需要被 hook 的函数没有统⼀的⼊⼝,逆向⼈员想要破解只能去理解该函数的逻辑。
使⽤ block
严格来说使⽤ block 并不能很⼤程度提⾼安全性,因为逆向⼈员只要到使⽤该 block 的⽅法,⼀般来说在其附近就会有block 内代码的逻辑。
但是个⼈认为使⽤ block 的安全性是⽐直接使⽤ oc ⽅法是要⾼的。在我的逆向分析 app 的经验中,对于使⽤了 block 的⽅法,⽬前我还不知道到怎么 hook (有知道的话,可以在 blog 上提个 issue 告诉我,先谢过)同时对于含有嵌套的 block 或者是作为参数传递的 block,处理起来就更加复杂了。所以,如果能将内敛 C 函数,嵌套 block , block 类型参数组合起来的话,安全性应该是会有⼀定提升。
代码混淆
代码混淆的⽅式有⼏种:
添加⽆⽤⼜不影响逻辑的代码⽚段,迷糊逆向⼈员
对关键的类、⽅法,命名成与真实意图⽆关的名称
个⼈认为最好的⼀个加密混淆⼯具是ios-class-guard,不过⽬前这个项⽬已经停⽌维护了。但是这种⽅式的混淆我觉得才是最终极的⽅案。
其他⽅法
⽐如 ptrace 反调试等(不过据说已经可以很容易被绕过)
// see iphonedevwiki/index.php/Crack_prevention for detail
static force_inline void disable_gdb() {
#ifndef DEBUG
typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
#ifndef PT_DENY_ATTACH
#define PT_DENY_ATTACH 31
#endif
// this trick can be worked around,
// see stackoverflow/questions/7034321/implementing-the-pt-deny-attach-anti-piracy-code
void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
ptrace_ptr_t ptrace_ptr = dlsym(handle, [@"".a.c.e UTF8String]);
ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
dlclose(handle);
#endif
}
注意事项
通过了解 OC 的运⾏时特性和 mach-o ⼆进制⽂件的结构,借助现有的⼯具,你会发现 hook ⽅法是很简单就能完成的。虽然上⾯我提到了⼀些提⾼安全性的⼏个⽅案,但是,所有这些⽅式只是增加了逆向⼈员的逆向难度,并不能让 app 变的坚不可摧。不过采取⼀定的措施肯定⽐什么措施都不采取来的
安全。
以上就是浅谈IOS如何对app进⾏安全加固的详细内容,更多关于IOS如何对app进⾏安全加固的资料请关注其它相关⽂章!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。