1、加固

加固是为了增加应用的安全性,防止应用被破解、盗版、二次打包、注入、反编译等。常见的加固方式有数据加密(字符串、网络数据、敏感数据等)、应用加壳(二进制加密)、代码混淆(类名、方法名、代码逻辑等)。

2、代码混淆

iOS程序可以通过class-dump、Hopper、IDA等获取类名、方法名、以及分析程序的执行逻辑。如果进行代码混淆,可以加大别人分析难度。
iOS的代码混淆方案有:
源码混淆:混淆类名、方法名、协议名等。
LLVM中间代码IR的混淆:自己编写Pass或使用 ollvm 来实现,但是容易产生Bug。

3、源码混淆

可以通过宏定义的方式来进行代码混淆:

  1. @interface Person : NSObject
  2. - (void)run;
  3. - (void)setupName:(NSString *)name age:(int)age no:(int)no;
  4. @end

在.pch文件中添加类名、方法名和参数名的宏定义:

  1. #ifndef PrefixHeader_pch
  2. #define PrefixHeader_pch
  3. #define Person alfjaskl
  4. #define run fasdf
  5. #define setupName gsdh
  6. #define age alfja
  7. #define no flasjdf
  8. #endif

编译后通过Hopper分析可执行文件,看到的就是混淆后的代码:截屏2022-06-09 14.32.41.png
源码混淆有以下注意点:
1、不能混淆系统方法
混淆后系统方法调用时会因为找不到方法实现而报错
2、不能混淆init开头的初始化方法
例如混淆下面的初始化方法

  1. -(instancetype)asdfas:(NSString *)name {
  2. if (self = [super init]) {
  3. }
  4. return self;
  5. }

会报错: ! Cannot assign to ‘self’ outside of a method in the init family ,原因是对self赋值必须在init开头的方法中进行。
3、混淆属性是需要额外的注意set方法

  1. #define age alfja
  2. @property (nonatomic, assign) int age;
  3. - (void)setAlfja:(int)alfja {
  4. }

4、如果xib、storyboard中用到了混淆的内容,需要手动修正
xib不会自动替换宏定义内容,需要手动修改。
5、可以考虑把混淆的符号都加上前缀,跟系统自带的符号进行区分

  1. @interface XLPerson : NSObject
  2. - (void)xl_run;
  3. - (void)xl_setupName:(NSString *)name xl_age:(int)age xl_no:(int)no;
  1. #define XLPerson alfjaskl
  2. #define xl_run fasdf
  3. #define xl_setupName gsdh
  4. #define xl_age alfja
  5. #define xl_no flasjdf

6、添加无用代码

  1. do {
  2. // 源码
  3. break;
  4. } while(1);

添加无用代码可以增加阅读源码的难度。
建议:
给需要混淆的符号加上一个特定的前缀。不要对整个项目进行混淆,审核会被拒。
小工具
MJCodeObfuscation,可以对指定文件夹、指定前缀代码进行混淆。

4、ios-class-guard

ios-class-guard,是基于class-dump的扩展,用class-dump扫描出可执行文件的类名、方法名、属性名等并做替换,会更新xib和storyboard的名字等等。
它会对可执行文件进行扫描,把所有代码都进行混淆,生成混淆头文件(宏定义)和符号映射表。但是由于长时间未更新,已经不适用最新的iOS项目,所以不推荐使用。

5、字符串加密

源代码中的字符串很容易被破解:

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. NSString *str = @"abcdefg123";
  4. NSLog(@"str = %@", str);
  5. }

截屏2022-06-09 15.25.38.png
很多时候,可执行文件中的字符串信息,对破解者来说,非常关键,是破解的捷径之一。为了加大破解、逆向难度,可以考虑对字符串进行加密。字符串的加密技术有很多种,可以根据自己的需要自行制定算法。
通过异或( ^ )的方式对字符串进行加密解密:

  1. const char *str = "abc123";
  2. // 进行异或操作
  3. for (int i = 0; i < strlen(str); i++) {
  4. NSLog(@"%d", str[i] ^ 7);
  5. }
  6. // 102 101 100 54 53 52
  1. char strNew[] = {102, 101, 100, 54, 53, 52, 0};
  2. NSMutableString *str1 = [NSMutableString string];
  3. for (int i = 0; i < strlen(strNew); i++) {
  4. [str1 appendFormat:@"%c", strNew[i] ^ 7];
  5. }
  6. NSLog(@"str1 = %@", str1);

小工具
MJCodeObfuscation,可以对指定字符串进行加密。

用法一:输入字符串,点击“加密”,得到加密后的字符串。导入MJEncryptString文件夹。 用法二:点击“选择目录”,会自动扫描目录下的所有字符串进行加密,得到字符串加密文件,导入即可使用。

6、工具

WHC_ConfuseSoftware
confuse