常用的加固方式
- URL编码加密 对iOS app中出现的URL进行编码加密,防止URL被静态分析
- 本地数据加密 对NSUserDefaults,sqlite存储文件数据加密,保护iOS app的帐号和关键信息。
- 网络传输数据加密 对iOS app客户端传输数据提供加密方案,有效防止通过网络接口的拦截获取
- 对方法名和方法体进行混淆,保证源码被逆向后无法解析代码
- 程序结构混排加密 对逻辑结构进行打乱混排,保证源码可读性降到最低
一、URL编码加密
1.背景介绍 a. iOS 下URL加解密,项目使用AFNetworking. b. 虽然是使用HTTPS,但是从安全方面考虑,在很多情况下还是需要对url的参数进行加密的. c. 不管是get请求还是post请求,都可以对后边的参数进行加密。
2.加密方式 a. 加密:首先对字符串记性AES128加密,然后进行base64加密"=="特殊处理(主要是为了去除特殊字符) b. 其中base64加解密使用 GTMBase64添加两个方法 c. 解密:先base64解密,然后在AES128解密即可还原数据
二、关键字符串加密/混淆
很多时候,可执行文件中的字符串信息,本地NSUserDefaults,sqlite存储文件数据,对破解者来说,非常关键,是破解的捷径之一。为了加大破解、逆向难度,可以考虑对关键字符串进行加密。字符串的加密技术有很多种,可以根据自己的需要自行制定算法
三、代码混淆
iOS程序可以通过class-dump、Hopper、IDA等获取类名、方法名、以及分析程序的执行逻辑。如果进行代码混淆,可以加大别人的分析难度
可通过宏定义的方式对程序进行混淆,例
#ifndef MJCodeObfuscation_h
#define MJCodeObfuscation_h
// 混淆类名
#define ZJHPerson CsPTLrkanhBbQAPL
// 混淆属性
#define zjh_name HrZLzcgSoPhwMBwW
// 混淆方法名
#define zjh_test _DU_TJLoLaiRpXAv
#define zjh_run KmJHtapxjqnqLtGp
// 可以使用正常的方法名替换原有方法名,减少特殊字符的使用
// 避免大量使用特殊字符,导致审核被拒,如
#define showAlertView dismissSheetView
#endif
*注意点
- 不能混淆系统方法
- 不能混淆init开头的等初始化方法
- 混淆属性时需要额外注意set方法
- 如果xib、storyboard中用到了混淆的内容,需要手动修正
- 可以考虑把需要混淆的符号都加上前缀,跟系统自带的符号进行区分
- 混淆过多可能会被AppStore拒绝上架,需要说明用途
- 可以使用正常的方法名替换原有方法名,减少特殊字符的使用
- 建议给需要混淆的符号加上了一个特定的前缀
四、网络数据加密
1、对称加密
需要对加密和解密使用相同密钥的加密算法。由于其速度快,对称性加密通常在消息发送方需要加密大量数据时使用。对称性加密也称为密钥加密。常用的非对称加密有DES和AES。
优点:对称加密算法的优点是算法公开、计算量小、加密速度快、加密效率高。
缺点:在数据传送前,发送方和接收方必须商定好秘钥,然后使双方都能保存好秘钥。其次如果一方的秘钥被泄露,那么加密信息也就不安全了.
2、非对称加密
非对称加密算法需要两个密钥来进行加密和解密,这两个秘钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥)。
优点:与对称加密相比,其安全性更好:对称加密的通信双方使用相同的秘钥,如果一方的秘钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存的,不需要像对称加密那样在通信之前要先同步秘钥。
缺点:非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
3、传输data加密
在传输 Data 的时候可以对其加密,首先将data转换为byte, 然后对byte进行操作,比如将所有字符与 0xA8 异或。这样比人截取data,看到的是一推乱码
五、越狱手机防护
我们知道手机越狱会大大增加项目被破解或者窃取用户信息的风险
下面是检测手机是否越狱的代码!
六、反调试
1、利用ptrace防护debugserver
为了方便应用软件的开发和调试,UNX的早期版本就提供了一种对运行中的进程进行跟踪和控制的手段,那就是系统调用 ptrace。通过 ptrace,可以对另一个进程实现调试跟踪。同时 ptrace 提供了一个非常有用的参数,那就是 PT_DENY_ATTACH,这个参数用于告诉系统阻止调试器依附。所以,最常用的反调试方案就是通过调用 ptrace 来实现反调试。
//把ptrace.h导入工程。ptrace头文件不能直接导入app工程,可以新建命令行工程,
//然后#import <sys/ptrace.h>进入到ptrace.h,
//把内容全部复制到自己工程中新建的header文件MyPtrace.h中,
//那么自己的工程想调用ptrace就可以导入MyPtrace.h直接进行调用.
- (void)viewDidLoad {
[super viewDidLoad];
ptrace(PT_DENY_ATTACH, 0, 0, 0);
}
2、反ptrace ,让别人的ptrace失效
就是如果别人的的app进行了ptrace防护,那么你怎么让他的ptrace不起作用,进行调试他的app呢?
由于ptrace是系统函数,那么我们可以用fishhook来hook住ptrace函数,然后让他的app调用我们自己的ptrace函数
注入动态库meryinDylib
在meryinDylib中hook住ptrace函数
3、针对2,要想别人hook自己的app的ptrace失效
思路:别人hook ptrace的时候,自己的ptrace已经调用
想要自己函数调用在最之前:自己写一个framework库
在库中写入ptrace(PT_DENY_ATTACH, 0, 0, 0);
库加载顺序:
自己写的库>别人注入的库
自己的库加载顺序:按照 Link Binary Libraries的顺序加载
4、针对3,要想别人hook自己的app的ptrace失效
思路:别人hook ptrace的时候,自己的ptrace已经调用
想要自己函数调用在最之前:自己写一个framework库
在库中写入ptrace(PT_DENY_ATTACH, 0, 0, 0);
库加载顺序:
自己写的库>别人注入的库
自己的库加载顺序:按照 Link Binary Libraries的顺序加载
七、反注入
反注入主要还是一种注入检测机制,即检测当前有没有其他模块注入。曾经出现过一种主
动防止注入的方法,但该方法现在已经没有用了。
1、restrict防注入
当旧版的dyld检测到存在 __RESTRICT,__restrict 这样的 section 时, DYLD_INSERT_LIBRARIES
环境变量会被忽略,导致注入失败。因此,在 Xcode 的编译设置选项 “Other Linker flags” 中加
上 -Wl,-sectcreate,__RESTRICT,__restrict,/dev/null 参数,就能达到反注入的效果。
在新版的 dyld 及 iOS10 的测试中发现,该方法已经没有用了,dyld 已经不检测这个 section
了,而且 opool 带 unrestrct 的功能。所以,这个方法现在已经没有实际的用处了。
2、注入检测
从另一个角度来分析,可以通过注入检测的方式来判断有没有进行注入。和调试检测一样,
具体的应对措施由我们自己制定。注入检测可以判断加载模块中有没有一些不在正常加载列表
中的模块,使用 _dyld_get_image_name 获取模块名,然后进行对比,具体如下
int AMCheckInjector() {
int count = _dyld_image_count();
if(count>0) {
for (int i = 0; i < count; 1++) {
const char* dyld = _dyld_get_image_name(i);
// 或者发现其他不在白名单内的库是以load command方式注入的
if(strstr(dyld,"DynamicLibraries")) {
return 1;
}
}
}
return 0;
}