iOS - 程序加固APP安全防护

截屏2022-04-02 下午4.18.40.png

常用的加固方式

  1. URL编码加密 对iOS app中出现的URL进行编码加密,防止URL被静态分析
  2. 本地数据加密 对NSUserDefaults,sqlite存储文件数据加密,保护iOS app的帐号和关键信息。
  3. 网络传输数据加密 对iOS app客户端传输数据提供加密方案,有效防止通过网络接口的拦截获取
  4. 对方法名和方法体进行混淆,保证源码被逆向后无法解析代码
  5. 程序结构混排加密 对逻辑结构进行打乱混排,保证源码可读性降到最低

一、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,看到的是一推乱码

五、越狱手机防护

我们知道手机越狱会大大增加项目被破解或者窃取用户信息的风险

下面是检测手机是否越狱的代码!

image
image
image

六、反调试

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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容