1、加固
加固是为了增加应用的安全性,防止应用被破解、盗版、二次打包、注入、反编译等。常见的加固方式有数据加密(字符串、网络数据、敏感数据等)、应用加壳(二进制加密)、代码混淆(类名、方法名、代码逻辑等)。
2、代码混淆
iOS程序可以通过class-dump、Hopper、IDA等获取类名、方法名、以及分析程序的执行逻辑。如果进行代码混淆,可以加大别人分析难度。
iOS的代码混淆方案有:
源码混淆:混淆类名、方法名、协议名等。
LLVM中间代码IR的混淆:自己编写Pass或使用 ollvm 来实现,但是容易产生Bug。
3、源码混淆
可以通过宏定义的方式来进行代码混淆:
@interface Person : NSObject
- (void)run;
- (void)setupName:(NSString *)name age:(int)age no:(int)no;
@end
在.pch文件中添加类名、方法名和参数名的宏定义:
#ifndef PrefixHeader_pch
#define PrefixHeader_pch
#define Person alfjaskl
#define run fasdf
#define setupName gsdh
#define age alfja
#define no flasjdf
#endif
编译后通过Hopper分析可执行文件,看到的就是混淆后的代码:
源码混淆有以下注意点:
1、不能混淆系统方法
混淆后系统方法调用时会因为找不到方法实现而报错
2、不能混淆init开头的初始化方法
例如混淆下面的初始化方法
-(instancetype)asdfas:(NSString *)name {
if (self = [super init]) {
}
return self;
}
会报错: ! Cannot assign to ‘self’ outside of a method in the init family ,原因是对self赋值必须在init开头的方法中进行。
3、混淆属性是需要额外的注意set方法
#define age alfja
@property (nonatomic, assign) int age;
- (void)setAlfja:(int)alfja {
}
4、如果xib、storyboard中用到了混淆的内容,需要手动修正
xib不会自动替换宏定义内容,需要手动修改。
5、可以考虑把混淆的符号都加上前缀,跟系统自带的符号进行区分
@interface XLPerson : NSObject
- (void)xl_run;
- (void)xl_setupName:(NSString *)name xl_age:(int)age xl_no:(int)no;
#define XLPerson alfjaskl
#define xl_run fasdf
#define xl_setupName gsdh
#define xl_age alfja
#define xl_no flasjdf
6、添加无用代码
do {
// 源码
break;
} while(1);
添加无用代码可以增加阅读源码的难度。
建议:
给需要混淆的符号加上一个特定的前缀。不要对整个项目进行混淆,审核会被拒。
小工具:
MJCodeObfuscation,可以对指定文件夹、指定前缀代码进行混淆。
4、ios-class-guard
ios-class-guard,是基于class-dump的扩展,用class-dump扫描出可执行文件的类名、方法名、属性名等并做替换,会更新xib和storyboard的名字等等。
它会对可执行文件进行扫描,把所有代码都进行混淆,生成混淆头文件(宏定义)和符号映射表。但是由于长时间未更新,已经不适用最新的iOS项目,所以不推荐使用。
5、字符串加密
源代码中的字符串很容易被破解:
- (void)viewDidLoad {
[super viewDidLoad];
NSString *str = @"abcdefg123";
NSLog(@"str = %@", str);
}
很多时候,可执行文件中的字符串信息,对破解者来说,非常关键,是破解的捷径之一。为了加大破解、逆向难度,可以考虑对字符串进行加密。字符串的加密技术有很多种,可以根据自己的需要自行制定算法。
通过异或( ^ )的方式对字符串进行加密解密:
const char *str = "abc123";
// 进行异或操作
for (int i = 0; i < strlen(str); i++) {
NSLog(@"%d", str[i] ^ 7);
}
// 102 101 100 54 53 52
char strNew[] = {102, 101, 100, 54, 53, 52, 0};
NSMutableString *str1 = [NSMutableString string];
for (int i = 0; i < strlen(strNew); i++) {
[str1 appendFormat:@"%c", strNew[i] ^ 7];
}
NSLog(@"str1 = %@", str1);
小工具:
MJCodeObfuscation,可以对指定字符串进行加密。
用法一:输入字符串,点击“加密”,得到加密后的字符串。导入MJEncryptString文件夹。 用法二:点击“选择目录”,会自动扫描目录下的所有字符串进行加密,得到字符串加密文件,导入即可使用。