完整性校验
通过检测SignerIdentity判断是Mach-O文件否被篡改
原理是:SignerIdentity的值在info.plist中是不存在的,开发者不会加上去,苹果也不会,只是当ipa包被反编译后篡改文件再次打包,需要伪造SignerIdentity。
NSBundle *bundle = [NSBundle mainBundle];
NSDictionary *info = [bundle infoDictionary];
if ([info objectForKey:@"SignerIdentity"] != nil)
{
return YES;
}
return NO;
参考:https://www.jianshu.com/p/91aa49c45677
越狱检测
参照念茜大神的方法:iOS安全攻防(二十):越狱检测的攻与防,很详细的讲述了检测的办法,不过经过测试,发现有的方法在未越狱的设备上也会检测成越狱,可以在使用的时候过滤掉这些方法。
双击home键后app缩略视图模糊处理
有时候双击home键,app展示启动app记录,会有可能暴露敏感信息,可以在app退至后台时做一个模糊处理,然后进入前台后移除模糊效果。
实现如下:
@interface AppDelegate ()
@property(nonatomic,strong)UIVisualEffectView *effectView;
@end
@implementation AppDelegate
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self.window addSubview:self.effectView];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[self.effectView removeFromSuperview];
}
-(UIVisualEffectView *)effectView
{
if (!_effectView)
{
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
_effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
_effectView.frame = self.window.bounds;
}
return _effectView;
}
...
@end
方法名混淆
也是参照念茜大神的方法:iOS安全攻防(二十三):Objective-C代码混淆.
明文字符串混淆
参考这篇文章:iOS字符串硬编码混淆.
可能作者的步骤描述的不是很清楚,我在这里简单描述一下:
1.在项目的.pch
文件中,添加如下代码
#include "GolobalCFile.h"
//字符串混淆加密 和 解密的宏开关
//#define ggh_confusion
#ifdef ggh_confusion
#define confusion_NSSTRING(string) [NSString stringWithUTF8String:decryptConstString(string)]
#define confusion_CSTRING(string) decryptConstString(string)
#else
#define confusion_NSSTRING(string) @string
#define confusion_CSTRING(string) string
#endif
其中decryptConstString定义在c文件GolobalCFile中
/*
* 字符串混淆解密函数,将char[] 形式字符数组和 aa异或运算揭秘
* 如果没有经过混淆,请关闭宏开关
*/
extern char* decryptConstString(char* string)
{
char* origin_string = string;
while(*string) {
*string ^= 0xAA;
string++;
}
return origin_string;
}
2.打开终端Terminal,cd到你的工程根目录;
3.执行如下混淆脚本(执行之前将脚本里面的工程名字改为你的工程名字):
python .../confusion.py
将如下脚本写在一个文件里confusion.py。在终端执行即可。
#!/usr/bin/env python
# encoding=utf8
# -*- coding: utf-8 -*-
# 本脚本用于对源代码中的字符串进行加密
# 替换所有字符串常量为加密的char数组,形式((char[]){1, 2, 3, 0})
import importlib
import os
import re
import sys
# 替换字符串为((char[]){1, 2, 3, 0})的形式,同时让每个字节与0xAA异或进行加密
def replace(match):
string = match.group(2) + '\x00'
replaced_string = '((char []) {' + ', '.join(["%i" % ((ord© ^ 0xAA) if c != '\0' else 0) for c in list(string)]) + '})'
return match.group(1) + replaced_string + match.group(3)
# 修改源代码,加入字符串加密的函数
def obfuscate(file):
with open(file, 'r') as f:
code = f.read()
f.close()
code = re.sub(r'(confusion_NSSTRING\(|confusion_CSTRING\()"(.*?)"(\))', replace, code)
code = re.sub(r'//#define ggh_confusion', '#define ggh_confusion', code)
with open(file, 'w') as f:
f.write(code)
f.close()
#读取源码路径下的所有.h和.m 文件
def openSrcFile(path):
print("开始处理路径: "+ path +" 下的所有.h和.m文件")
# this folder is custom
for parent,dirnames,filenames in os.walk(path):
#case 1:
# for dirname in dirnames:
# print((" parent folder is:" + parent).encode('utf-8'))
# print((" dirname is:" + dirname).encode('utf-8'))
#case 2
for filename in filenames:
extendedName = os.path.splitext(os.path.join(parent,filename))
if (extendedName[1] == '.h' or extendedName[1] == '.m'):
print("处理源代码文件: "+ os.path.join(parent,filename))
obfuscate(os.path.join(parent,filename))
#源码路径
srcPath = '../StringDecodeDemo'
if __name__ == '__main__':
print("本脚本用于对源代码中被标记的字符串进行加密")
if len(srcPath) > 0:
openSrcFile(srcPath)
else:
print("请输入正确的源代码路径")
sys.exit()
执行完成后查看你的代码,会发现用confusion_NSSTRING和confusion_CSTRING 写的明文字符串都被编码。这样就达到了混淆的效果。
4.由于代码被混淆不利于以后项目迭代,所以需要解码。方法同编码,在终端执行
如下脚本:
#!/usr/bin/env python
# encoding=utf8
# -*- coding: utf-8 -*-
# 本脚本用于对源代码中的字符串进行解密
# 替换所有加密的char数组为字符串常量,""
import importlib
import os
import re
import sys
# 替换((char[]){1, 2, 3, 0})的形式为字符串,同时让每个数组值与0xAA异或进行解密
def replace(match):
string = match.group(2)
decodeConfusion_string = ""
for numberStr in list(string.split(',')):
if int(numberStr) != 0:
decodeConfusion_string = decodeConfusion_string + "%c" % (int(numberStr) ^ 0xAA)
# replaced_string = '\"' + "".join(["%c" % ((int© ^ 0xAA) if int© != 0 else '\0') for c in string.split(',')]) + '\"'
replaced_string = '\"' + decodeConfusion_string + '\"'
print("replaced_string = " + replaced_string)
return match.group(1) + replaced_string + match.group(3)
# 修改源代码,加入字符串加密的函数
def obfuscate(file):
with open(file, 'r') as f:
code = f.read()
f.close()
code = re.sub(r'(confusion_NSSTRING\(|confusion_CSTRING\()\(\(char \[\]\) \{(.*?)\}\)(\))', replace, code)
code = re.sub(r'[/]*#define ggh_confusion', '//#define ggh_confusion', code)
with open(file, 'w') as f:
f.write(code)
f.close()
#读取源码路径下的所有.h和.m 文件
def openSrcFile(path):
print("开始处理路径: "+ path +" 下的所有.h和.m文件")
# this folder is custom
for parent,dirnames,filenames in os.walk(path):
#case 1:
# for dirname in dirnames:
# print((" parent folder is:" + parent).encode('utf-8'))
# print((" dirname is:" + dirname).encode('utf-8'))
#case 2
for filename in filenames:
extendedName = os.path.splitext(os.path.join(parent,filename))
#读取所有.h和.m 的源文件
if (extendedName[1] == '.h' or extendedName[1] == '.m'):
print("处理代码文件:"+ os.path.join(parent,filename))
obfuscate(os.path.join(parent,filename))
#源码路径
srcPath = '../StringDecodeDemo'
if __name__ == '__main__':
print("字符串解混淆脚本,将被标记过的char数组转为字符串,并和0xAA异或。还原代码")
if len(srcPath) > 0:
openSrcFile(srcPath)
else:
print("请输入正确的源代码路径!")
sys.exit()
即可解码明文。
为了不那么麻烦,可以打包前将工程拷贝一份,这样就可以只需要编码,不用解码。
以上脚本和代码均在文末Demo中。
反编译
在混淆了函数名以后,当然要检验一下成果了,这里就需要反编译我们的app了,有个很方便的工具Class-dump
,这里有篇文章详细的描述了安装和使用方法:Objective-C Class-dump 安装和使用方法(原创).
另外还有一个反编译、反汇编和调试神器:Hopper。可以查看源码。
疑问
1.执行脚本文件时报如下错误
confusion.py: Permission denied
解决方法:
1、打开终端。
2、cd到目标文件夹。
3、输入 chmod 755 你的文件名.sh。
Demo
本文demo:iOS_CodeEncrypt