2019-03-04 09:27:21 Bolted_snail 阅读数 4372

  • 最近公司扫描App漏洞,提出要给App做代码混淆加固,以提高反编译逆向难度。对于Android应用直接用360安全加固即可;但对于iOS应用,虽然360也提供了免费的加固方法,但前提是项目的enable bitcode必须设置为YES。但我们项目中引入的很多框架包括百度地图等并不支持enable bitcode设置为YES。如果enable bitcode设置为NO,并且是本地部署的话(企业证书),360安全加固iOS是收费的,收费标准是30万/年。其他的一些平台也是收费的。所以只能考虑自己去做了。
  • 360 iOS加固指南

自己创建脚本文件进行代码混淆

  • 混淆原理 : 代码编译阶段将符号(方法名、属性名等)替换成随机生成的字符串
  • 我们需要创建四个文件如下:
    在这里插入图片描述
    其中PrefixHeader.pch宏文件中导入CodeObfuscation.h,这样项目在编译的时候就会将CodeObfuscation.h中定义的宏及方法名替换为对应随机生成的字符串。
#ifndef PrefixHeader_pch
#define PrefixHeader_pch
#import "CodeObfuscation.h"
#endif /* PrefixHeader_pch */

其中confuse.sh脚本文件是最重要的,是用来在程序编译的时候将func.list中的方法名替换成随机生成的字符串,并且保存在CodeObfuscation.h中。其脚本为:

TABLENAME=symbols
SYMBOL_DB_FILE="$PROJECT_DIR/CodeObfuscation/symbols"
STRING_SYMBOL_FILE="$PROJECT_DIR/CodeObfuscation/func.list"
HEAD_FILE="$PROJECT_DIR/CodeObfuscation/CodeObfuscation.h"
export LC_CTYPE=C

#维护数据库方便日后作排重
createTable()
{
echo "create table $TABLENAME(src text, des text);" | sqlite3 $SYMBOL_DB_FILE
}

insertValue()
{
echo "insert into $TABLENAME values('$1' ,'$2');" | sqlite3 $SYMBOL_DB_FILE
}

query()
{
echo "select * from $TABLENAME where src='$1';" | sqlite3 $SYMBOL_DB_FILE
}

ramdomString()
{
openssl rand -base64 64 | tr -cd 'a-zA-Z' |head -c 16
}

rm -f $SYMBOL_DB_FILE
rm -f $HEAD_FILE
createTable

touch $HEAD_FILE
echo '#ifndef CodeObfuscation_h
#define CodeObfuscation_h' >> $HEAD_FILE
echo "//confuse string at `date`" >> $HEAD_FILE
cat "$STRING_SYMBOL_FILE" | while read -ra line; do
if [[ ! -z "$line" ]]; then
ramdom=`ramdomString`
echo $line $ramdom
insertValue $line $ramdom
echo "#define $line $ramdom" >> $HEAD_FILE
fi
done
echo "#endif" >> $HEAD_FILE
sqlite3 $SYMBOL_DB_FILE .dump

func.list文件就是用来存放要被混淆的方法和属性名的。如:
在这里插入图片描述
CodeObfuscation.h本身是一个空头文件,在编译过后会生成func.list添加属性和方法对应生成的随机字符串。下图是编译后CodeObfuscation.h的内容:
CodeObfuscation.h
示例:

#import "ViewController.h"
#import "NSArray+Extension.h"

@interface ViewController ()
@property (nonatomic, copy) NSString *title1;
@property (nonatomic, copy) NSString *imgsrc;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title1 = @"";
    self.imgsrc = @"";
    
    NSLog(@"%@",[NSArray getPropertiesFromClass:[self class]]);
    NSLog(@"%@",[NSArray getMethodsFromClass:[self class]]);
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (void) test{
    
}
- (void) test1{
    
}
- (void) test2{
    
}
- (void) test3{
    
}
- (void) test4{
    
}

@end

打印出运行时的属性和方法名:
在这里插入图片描述
结果可见,CodeObfuscation.h中的生成的随机字符串和真正打印出来的并不一致,这是因为每次运行时,CodeObfuscation.h都会重新生成新的随机字符串,这时替换属性和方法名的是上一次生成的随机字符串。

  • 注意事项:
    1. 属性方法名需要去重。
    2. 代码混淆后不能再上架appstore。
    3. 代码混淆不能对静态库进行混淆。
    4. 系统自带的属性和方法不能混淆,只能混淆自定义的方法和属性。
  • 具体步骤可参考:iOS代码混淆教程

iOS代码自动混淆

  • 上面的方法会有有一些问题,就是每次创建了新的属性和方法都得添加到func.list文件中,比较繁琐,不利于维护。其实我们可以让方法属性自动添加func.list中。所以我们要从.m和.h文件中抽取属性和方法了,但是如何屏蔽系统的属性和方法名,所以我们要将自己定义的属性和方法名全部添加一个前缀。
  • confuse.sh中添加新的脚本,修改后的脚本如下:
TABLENAME=symbols
SYMBOL_DB_FILE="symbols"
STRING_SYMBOL_FILE="$PROJECT_DIR/AutoScript/func.list"
CONFUSE_FILE="$PROJECT_DIR/AutoCodeConfusion"  
HEAD_FILE="$PROJECT_DIR/AutoScript/AutocodeObfuscation.h"

export LC_CTYPE=C

#取以.m或.h结尾的文件以+号或-号开头的行 |去掉所有+号或-号|用空格代替符号|n个空格跟着<号 替换成 <号|开头不能是IBAction|用空格split字串取第二部分|排序|去重复|删除空行|删掉以init开头的行>写进func.list
grep -h -r -I  "^[-+]" $CONFUSE_FILE  --include '*.[mh]' |sed "s/[+-]//g"|sed "s/[();,: *\^\/\{]/ /g"|sed "s/[ ]*</</"| sed "/^[ ]*IBAction/d"|awk '{split($0,b," "); print b[2]; }'| sort|uniq |sed "/^$/d"|sed -n "/^hj_/p" >$STRING_SYMBOL_FILE


#维护数据库方便日后作排重,一下代码来自念茜的微博
createTable()
{
echo "create table $TABLENAME(src text, des text);" | sqlite3 $SYMBOL_DB_FILE
}

insertValue()
{
echo "insert into $TABLENAME values('$1' ,'$2');" | sqlite3 $SYMBOL_DB_FILE
}

query()
{
echo "select * from $TABLENAME where src='$1';" | sqlite3 $SYMBOL_DB_FILE
}

ramdomString()
{
openssl rand -base64 64 | tr -cd 'a-zA-Z' |head -c 16

}

rm -f $SYMBOL_DB_FILE
rm -f $HEAD_FILE
createTable

touch $HEAD_FILE
echo '#ifndef AutocodeObfuscation_h
#define AutocodeObfuscation_h' >> $HEAD_FILE
echo "//confuse string at `date`" >> $HEAD_FILE
cat "$STRING_SYMBOL_FILE" | while read -ra line; do
if [[ ! -z "$line" ]]; then
ramdom=`ramdomString`
echo $line $ramdom
insertValue $line $ramdom
echo "#define $line $ramdom" >> $HEAD_FILE
fi
done
echo "#endif" >> $HEAD_FILE
sqlite3 $SYMBOL_DB_FILE .dump

在这里插入图片描述
添加了收集方法的脚本后,我们不需要再手动的去添加方法到func.list中了。程序编译后会自动将hj_开头的方法添加到func.list中。


2017-09-13 11:22:16 yinghaiyixun 阅读数 733

众所周知的是大部分iOS代码一般不会做加密加固,因为iOS APP一般是通过AppStore发布的,而且苹果的系统难以攻破,所以在iOS里做代码加固一般是一件出力不讨好的事情。万事皆有例外,不管iOSadr还是js,加密的目的是为了代码的安全性,虽然现在开源畅行,但是不管个人开发者还是大厂皆有保护代码安全的需求,所以iOS代码加固有了生存的土壤。下面简单介绍下iOS代码加密的几种方式。

iOS代码加密的几种方式

1.字符串加密

字符串会暴露APP的很多关键信息,攻击者可以根据从界面获取的字符串,快速找到相关逻辑的处理函数,从而进行分析破解。加密字符串可以增加攻击者阅读代码的难度以及根据字符串静态搜索的难度。

一般的处理方式是对需要加密的字符串加密,并保存加密后的数据,再在使用字符串的地方插入解密算法。简单的加密算法可以把NSString转为byte或者NSData的方式,还可以把字符串放到后端来返回,尽量少的暴露页面信息。下面举个简单例子,把NSString转为16进制的字符串:

iOS代码加密.png

2.符号混淆

符号混淆的中心思想是将类名、方法名、变量名替换为无意义符号,提高应用安全性;防止敏感符号被class-dump工具提取,防止IDA Pro等工具反编译后分析业务代码。目前市面上的IOS应用基本上是没有使用类名方法名混淆的。

a. 别名

在编写代码的时候直接用别名可能是最简单的一种方式,也是比较管用的一种方式。因为你的app被破解后,假如很容易就能从你的类名中寻找到蛛丝马迹,那离hook只是一步之遥,之前微信抢红包的插件应该就是用hook的方式执行的。

b.C重写

编写别名的方式不是很易读,而且也不利于后续维护,这时你可能需要升级一下你的保护方式,用C来重写你的代码吧。这样把函数名隐藏在结构体中,用函数指针成员的形式存储,编译后,只留下了地址,去掉了名字和参数表,让他们无从下手(copy from 念茜)。如下例子:

iOS代码加密1.png

c.脚本处理

稍微高级一点的是脚本扫描处理替换代码,因为要用到linux命令来编写脚本,可能会有一点门槛,不过学了之后你就可以出去吹嘘你全栈工程师的名头啦。。。

linux脚本比较常用的几个命令如下:

iOS代码加密2.png

脚本混淆替换是用上述几个命令扫描出来需要替换的字符串,比如方法名,类名,变量名,并做替换,如果你能熟练应用上述几个命令,恭喜你,已经了解了脚本的一点皮毛了。

如以下脚本搜索遍历了代码目录下的需要混淆的关键字:

iOS代码加密3.png

替换的方式可以直接扫描文件并对文件中的所有内容替换,也可以采用define的方式定义别名。例如:

iOS代码加密4.png

d.开源项目ios-class-guard

该项目是基于class-dump的扩展,和脚本处理类似,是用class-dump扫描出编译后的类名、方法名、属性名等并做替换,只是不支持隐式C方法的替换,有兴趣的同学可以使用下。

3.代码逻辑混淆

代码逻辑混淆有以下几个方面的含义:

对方法体进行混淆,保证源码被逆向后该部分的代码有很大的迷惑性,因为有一些垃圾代码的存在;

对应用程序逻辑结构进行打乱混排,保证源码可读性降到最低,这很容易把破解者带到沟里去;

它拥有和原始的代码一样的功能,这是最最关键的。

一般使用obfuscator-llvm来做代码逻辑混淆,或许会对该开源工具做个简单介绍。

iOS加密可能市场很小,但是存在必有道理,在越狱/开源/极客的眼中,你的APP并没有你想像的那么安全,如果希望你的代码更加安全,就应给iOS代码加密。

2019-07-30 11:07:49 ajian6 阅读数 321

前言

最近一直在看Python,也很喜欢Python的灵活性;今天主要想说的是iOS的代码混淆,为什么想做代码混淆?为了APP的安全,为了防止别人破壳轻易破解我们代码;还有就是做 马甲包 了,我们知道马甲包的市场需求很大,但是不能花费过多的精力在开发上,毕竟只是个马甲,没必要花费太多的成本!

混淆工具

网上搜了一下,开源免费的混淆都在转载 念茜大姐大 的 sh脚本 的混淆方法,或者在念茜的脚本基础上二次开发,大家去看过就知道念茜的这篇博客是在14年写的,那时我刚做iOS没多久 ,而且那时候中国区审核还没有那么严格,若果你现在还使用那种方法进行混淆,你肯定会收到苹果的 2.3.1 大礼包 ,所以我们还是探索别的混淆方法吧,不要再挖坟了!

我这里主要是通过Python写的混淆工具,具体功能有方法混淆、属性混淆、类名混淆、添加垃圾代码、删除注释、修改资源文件Hash值、 加密字符串 、翻新资源名、 模拟人工混淆 、混淆文件名、混淆文件目录、混淆词库、混淆日志、映射列表、图片压缩、爬虫服务,具体的如下:

软件界面

1.下载地址:

链接: pan.baidu.com/s/1esdfDdjO… 密码:2lbr

:clap::clap::clap:进群免费拿邀请码:clap::clap::clap:365152048:clap::clap::clap:

2.教学视频:

链接: pan.baidu.com/s/1pqUkgU8Y… 密码:9sll

开始混淆

import addRubbishCode    as addCode
import cunfusionObjName  as conObjN
import confusionFun      as conFunc
import cunfusionProperty as conPro
import confusionLog      as conLog
import deleteNotes       as delNot
import updateSourceHash  as updHash
import encryptString     as encStr
import sourceName        as soName
import missFolder
from singletonModel import ZFJPersoninfo

def start_fun(file_dir, funMap = {}):
	personinfo = ZFJPersoninfo()
	personinfo.isMissing = True
	if len(file_dir) == 0:
		return
	if int(funMap['property']) > 0:
		# 混淆属性
		conLog.tips('*' * 30 + 'Fun:开始混淆属性' + '*' * 30)
		conPro.startConfusionPro(file_dir)

	if int(funMap['funName']) > 0:
		# 混淆方法
		conLog.tips('*' * 30 + 'Fun:开始混淆方法' + '*' * 30)
		conFunc.startConfusionFun(file_dir)

	if int(funMap['objName']) > 0:
		# 混淆类名
		conLog.tips('*' * 30 + 'Fun:开始混淆类名' + '*' * 30)
		prefix = funMap['funNamePrefix'].replace('0', '')  #-添加类名前缀
		personinfo.prefix = prefix #前缀存到单利里面
		fixObjName = funMap['fixObjName'] #-自动修复过滤文件夹中引用的类名
		conObjN.startObfuscatedObjName(file_dir, prefix)

	if int(funMap['souHashKey']) > 0:
		# 修改资源文件的hash值 
		conLog.tips('*' * 30 + 'Fun:修改资源HASH值' + '*' * 30)
		updHash.startUpdateSourceHash(file_dir)

	if int(funMap['upSouName']) > 0:
		# 翻新资源文件名
		conLog.tips('*' * 30 + 'Fun:翻新资源文件名' + '*' * 30)
		soName.startSourceName(file_dir)

	if int(funMap['encryStr']) > 0:
		# 加密明文字符串
		conLog.tips('*' * 30 + 'Fun:加密明文字符串' + '*' * 30)
		encStr.startEncryptStr(file_dir)

	if int(funMap['rubbishCode']) > 0:
		# 垃圾代码
		conLog.tips('*' * 30 + 'Fun:添加垃圾代码' + '*' * 30)
		amount = int(funMap['rubbishLine']) # -添加行数
		addCode.startAddRubbishCode(file_dir, amount)

	if int(funMap['deleteNotes']) > 0:
		# 混淆或者删除注释
		conLog.tips('*' * 30 + 'Fun:开始删除注释' + '*' * 30)
		delNot.startDeleteNotes(file_dir)

	if int(funMap['missFolder']) > 0:
		# 混淆文件夹名
		conLog.tips('*' * 30 + 'Fun:开始混淆文件夹名' + '*' * 30)
		missFolder.startMissFolder(file_dir)

	conLog.tips('*' * 30 + 'End:混淆结束' + '*' * 30)
	personinfo.isMissing = False
Python资源分享qun 881982657 ,内有安装包,PDF,学习视频,这里是Python学习者的聚集地,零基础,进阶,都欢迎

复制代码

混淆日志

混淆的部分日志,混淆的时候回通过import logging自动生成混淆日志《 ZFJ混淆日志.log 》,便于开发者修改部分报错:

忽略路径

我们在混淆的时候,没必要全部进行混淆,特别是第三方库,或者Pods管理的第三方库;毕竟混淆的越多问题也就越多,所以我添加了混淆忽略文件:open_file_folder:,如下图:

import confusionLog as conLog
 
ignore_Files = ['/Pods/', '/Vendor/', '/LIB/', '/Util/']
conLog.tips('已忽略的路径 === ' + str(ignore_Files))
 
# 判断是否是忽略的文件夹
def isIgnoreFiles(tmp_path):
	# if '+' in tmp_path:
	# 	return True
	for item in ignore_Files:
		if item in tmp_path:
			return True
	return False
Python资源分享qun 881982657 ,内有安装包,PDF,学习视频,这里是Python学习者的聚集地,零基础,进阶,都欢迎


复制代码

特别说明

混淆以后肯定会有或多或少的报错,所以要求使用者必须会iOS开发技能,一般报错都是因为一下两点:

1.方法名相同,被多次混淆覆盖;

2.忽略的文件夹中包含了已被混淆的类或者方法;

3.图片如果不显示,可能原因是代码中图片名采用的是拼接的,手动替换一下就可以了;

4.如果发现文本丢失,一般是在文本中有<*** 注释 *>类型的注释了,找到原项目替换一下;

5.如果使用混淆工程目录因为PCH和Infor.plist报错,需要手动到project.pbxproj修改路径(详见路径混淆部分);

6.如果出现项目路径修改了,但是本地实体路径没有修改,自己手动把本地路径修改一下;

7.utf-8编码错误和[Errno 13] Permission denied权限错误不用管;

以上错误都可以在日志文件中找到对应的混淆字段,然后手动替换上去就行!

还有就是,该混淆工具目前只适用于OC项目工程,不支持swift项目,但是我打算等OC混淆工具全部OK以后(包括图形界面),会把swift的混淆加进去的!

混淆结果

1.函数混淆

2.属性混淆

3.类名混淆

4.添加垃圾代码

垃圾代码的调用与实现

5.去除注释

6.修改Hash值

针对项目中的资源文件,我们可以通过修改Hash的方式来进行混淆,运行如下:

:high_brightness:Tips:已忽略的路径 === ['/Pods/', '/Vendor/', '/LIB/', '/Util/']
:tada:Infor:[UPdHash OK] /Users/zhangfujie/Desktop/Obfuscated/GUEG_MJ/GUEG/GUEG/Assets.xcassets/MainWeb_Back_Icon.imageset/fanhui-4.png
:tada:Infor:[UPdHash Meg] Old:dd03889c2e8647b9377d08775333557ff11425dd<->New:4a72c7b640882ae436b18868aa021331169db3fa
:tada:Infor:[UPdHash OK] /Users/zhangfujie/Desktop/Obfuscated/GUEG_MJ/GUEG/GUEG/Assets.xcassets/AppIcon.appiconset/60.png
:tada:Infor:[UPdHash Meg] Old:2d73347848d7168c09c48efe28a7ac5a9ec7411b<->New:551483123b5cc2c4c5ff2f5bf876db0d075261a1
:tada:Infor:[UPdHash OK] /Users/zhangfujie/Desktop/Obfuscated/GUEG_MJ/GUEG/GUEG/Assets.xcassets/AppIcon.appiconset/58.png
:tada:Infor:[UPdHash Meg] Old:c0c671fe3707bca8c5accdcadd8aa9f4f1f2726c<->New:d022db1c1f99c263b69bc09c09bc52dd1fa97fb5
:tada:Infor:[UPdHash OK] /Users/zhangfujie/Desktop/Obfuscated/GUEG_MJ/GUEG/GUEG/Assets.xcassets/AppIcon.appiconset/120-1.png
:tada:Infor:[UPdHash Meg] Old:5a6a7ec42d7489be18888828c1a9caba0da688ca<->New:8bbddfbbbed9023e4537e9e6caeed79c88ef8955
:tada:Infor:[UPdHash OK] /Users/zhangfujie/Desktop/Obfuscated/GUEG_MJ/GUEG/GUEG/Assets.xcassets/AppIcon.appiconset/120.png
:tada:Infor:[UPdHash Meg] Old:5a6a7ec42d7489be18888828c1a9caba0da688ca<->New:dcc4b47092bca1d6a6bb6d7bd671a0ef7ce2f4da
:tada:Infor:[UPdHash OK] /Users/zhangfujie/Desktop/Obfuscated/GUEG_MJ/GUEG/GUEG/Assets.xcassets/AppIcon.appiconset/180.png
:tada:Infor:[UPdHash Meg] Old:fee9220dbba52040517a0f77ffe8335e9300a64b<->New:d28a9118e1cf4a2ce9fc2805184ad42e20500c95
:tada:Infor:[UPdHash OK] /Users/zhangfujie/Desktop/Obfuscated/GUEG_MJ/GUEG/GUEG/Assets.xcassets/AppIcon.appiconset/GUEG_ICON.png
:tada:Infor:[UPdHash Meg] Old:07ed6c66ec7d5550bfa1e32b4848687417027c90<->New:fb780d87591cc86dd0fd24cdfa41e76a091ad657
:tada:Infor:[UPdHash OK] /Users/zhangfujie/Desktop/Obfuscated/GUEG_MJ/GUEG/GUEG/Assets.xcassets/AppIcon.appiconset/80.png
:tada:Infor:[UPdHash Meg] Old:ca3b3f61fc4c391515fe895d81360d15ec598049<->New:769ebf182fbb3a3fd69c46c3a595c1669c505f63
:tada:Infor:[UPdHash OK] /Users/zhangfujie/Desktop/Obfuscated/GUEG_MJ/GUEG/GUEG/Assets.xcassets/AppIcon.appiconset/40.png
:tada:Infor:[UPdHash Meg] Old:1bb7908a2ba1295fa69ad476a81003f2f413a3a8<->New:10793e67b27cdf5ad1ee4b9d37aecc62074b8ffc
:tada:Infor:[UPdHash OK] /Users/zhangfujie/Desktop/Obfuscated/GUEG_MJ/GUEG/GUEG/Assets.xcassets/AppIcon.appiconset/87.png
......等等......
Python资源分享qun 881982657 ,内有安装包,PDF,学习视频,这里是Python学习者的聚集地,零基础,进阶,都欢迎

6.加密字符串

编译前的代码如下:

- (void)uiConfig{
    ZFJView *zfjView = [[ZFJView alloc] initWithZFJ:@"ZFJ1128"];
    zfjView.backgroundColor = [UIColor yellowColor];
    zfjView.frame = CGRectMake(100, 100, 150, 150);
    [zfjView setZFJViewTitleLab];
    [zfjView setZFJViewTitleLab:@"aaaaaa"];
    [zfjView setZFJViewTitleLab:@"aaa" efg:@"dscvdscsd"];
    [zfjView setZFJViewTitleLab:@"ddscvsdv" efg:@"cdsvdfbdf" hijk:@"cdvsvbdsbdfgnfdhnhdg"];
    [self.view addSubview:zfjView];
    
    [ZFJView svdsvfdsvfdvbzdfb];
}
复制代码
编译后的代码如下:

- (void)uiConfig{
    ZFJView *zfjView = [[ZFJView alloc] initWithZFJ:ZFJ_NSSTRING(((char []) {240, 236, 224, 155, 155, 152, 146, 0}))];
    zfjView.backgroundColor = [UIColor yellowColor];
    zfjView.frame = CGRectMake(100, 100, 150, 150);
    [zfjView setZFJViewTitleLab];
    [zfjView setZFJViewTitleLab:ZFJ_NSSTRING(((char []) {203, 203, 203, 203, 203, 203, 0}))];
    [zfjView setZFJViewTitleLab:ZFJ_NSSTRING(((char []) {203, 203, 203, 0})) efg:ZFJ_NSSTRING(((char []) {206, 217, 201, 220, 206, 217, 201, 217, 206, 0}))];
    [zfjView setZFJViewTitleLab:ZFJ_NSSTRING(((char []) {206, 206, 217, 201, 220, 217, 206, 220, 0})) efg:ZFJ_NSSTRING(((char []) {201, 206, 217, 220, 206, 204, 200, 206, 204, 0})) hijk:ZFJ_NSSTRING(((char []) {201, 206, 220, 217, 220, 200, 206, 217, 200, 206, 204, 205, 196, 204, 206, 194, 196, 194, 206, 205, 0}))];
    [self.view addSubview:zfjView];
    
    [ZFJView svdsvfdsvfdvbzdfb];
}
Python资源分享qun 881982657 ,内有安装包,PDF,学习视频,这里是Python学习者的聚集地,零基础,进阶,都欢迎

加密混淆反编译前后Hopper对比如下:

我们可以看到再通过Hopper看不到硬编码了!:+1::+1::+1:

8.翻新资源名

找到工程中的图片资源并翻新,然后自动替换代码中的引用。

9.混淆工程目录

说明:如果你的项目包含PCH,还有自带的Info.plist,需要你手动到project.pbxproj修改路径;

10.图片压缩工具

ZFJObsLib集成图片压缩工具,支持一键生成iOS开发三套图标,也支持自定义压缩尺寸,还可以移除Alpha通道,转成RGB图片模式;实现逻辑可参考: zfj1128.blog.csdn.net/article/det…具体如下图:

2018-03-19 15:01:00 weixin_30924079 阅读数 4

iOS 安全

  • 众所周知的是大部分iOS代码一般不会做加密加固,因为iOS APP一般是通过AppStore发布的,而且苹果的系统难以攻破,所以在iOS里做代码加固一般是一件出力不讨好的事情。万事皆有例外,不管iOS、adr还是js,加密的目的是为了代码的安全性,虽然现在开源畅行,但是不管个人开发者还是大厂皆有保护代码安全的需求,所以iOS代码加固有了生存的土壤。下面简单介绍下iOS代码加密的几种方式。

iOS代码加密的几种方式

1.字符串加密

  • 字符串会暴露APP的很多关键信息,攻击者可以根据从界面获取的字符串,快速找到相关逻辑的处理函数,从而进行分析破解。加密字符串可以增加攻击者阅读代码的难度以及根据字符串静态搜索的难度。
  • 一般的处理方式是对需要加密的字符串加密,并保存加密后的数据,再在使用字符串的地方插入解密算法。简单的加密算法可以把NSString转为byte或者NSData的方式,还可以把字符串放到后端来返回,尽量少的暴露页面信息。

2.符号混淆

  • 符号混淆的中心思想是将类名、方法名、变量名替换为无意义符号,提高应用安全性;防止敏感符号被class-dump工具提取,防止IDA Pro等工具反编译后分析业务代码。目前市面上的IOS应用基本上是没有使用类名方法名混淆的。

  • a. 别名
    • 在编写代码的时候直接用别名可能是最简单的一种方式,也是比较管用的一种方式。因为你的app被破解后,假如很容易就能从你的类名中寻找到蛛丝马迹,那离hook只是一步之遥,之前微信抢红包的插件应该就是用hook的方式执行的。
  • b.C重写
    • 编写别名的方式不是很易读,而且也不利于后续维护,这时你可能需要升级一下你的保护方式,用C来重写你的代码吧。这样把函数名隐藏在结构体中,用函数指针成员的形式存储,编译后,只留下了地址,去掉了名字和参数表,让他们无从下手(copy from 念茜)。如下例子:
// 原始代码
@interface XXUtil : NSObject

+ (BOOL)isVerified;
+ (BOOL)isNeedSomething;
+ (void)resetPassword:(NSString *)password;

@end
// 加密后
//XXUtil.h
#import <Foundation/Foundation.h>

typedef struct _util {
    BOOL (*isVerified)(void);
    BOOL (*isNeedSomething)(void);
    void (*resetPassword)(NSString *password);
}XXUtil_t ;

#define XXUtil ([_XXUtil sharedUtil])

@interface _XXUtil : NSObject

+ (XXUtil_t *)sharedUtil;
@end
//XXUtil.m
#import "XXUtil.h"

static BOOL _isVerified(void)
{
    //bala bala ...
    return YES;
}

static BOOL _isNeedSomething(void)
{
    //bala bala ...
    return YES;
}

static void _resetPassword(NSString *password)
{
    //bala bala ...
}

static XXUtil_t * util = NULL;
@implementation _XXUtil

+(XXUtil_t *)sharedUtil
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        util = malloc(sizeof(XXUtil_t));
        util->isVerified = _isVerified;
        util->isNeedSomething = _isNeedSomething;
        util->resetPassword = _resetPassword;
    });
    return util;
}

+ (void)destroy
{
    util ? free(util): 0;
    util = NULL;
}
@end
// 最后根据xcode指错,纠正
[XXUtil isVerified];
// 改为 
XXUtil->isVerified();
  • c.脚本处理
    • 稍微高级一点的是脚本扫描处理替换代码,因为要用到linux命令来编写脚本,可能会有一点门槛,不过学了之后你就可以出去吹嘘你全栈工程师的名头啦。。。

    • 脚本混淆替换是用上述几个命令扫描出来需要替换的字符串,比如方法名,类名,变量名,并做替换。

    • 替换的方式可以直接扫描文件并对文件中的所有内容替换,也可以采用define的方式定义别名。

  • d.开源项目ios-class-guard
    该项目是基于class-dump的扩展,和脚本处理类似,是用class-dump扫描出编译后的类名、方法名、属性名等并做替换,只是不支持隐式C方法的替换,有兴趣的同学可以使用下。

3.代码逻辑混淆

  • 代码逻辑混淆有以下几个方面的含义:对方法体进行混淆,保证源码被逆向后该部分的代码有很大的迷惑性,因为有一些垃圾代码的存在;对应用程序逻辑结构进行打乱混排,保证源码可读性降到最低,这很容易把破解者带到沟里去;它拥有和原始的代码一样的功能,这是最最关键的。一般使用obfuscator-llvm来做代码逻辑混淆,或许会对该开源工具做个简单介绍。

4.加固SDK

  • adr中一般比较常见的加固等操作,iOS也有一些第三方提供这样的服务,但是没有真正使用过,不知道效果如何。

  • 当然还有一些第三方服务的加固产品,基本上都是采用了以上一种或几种混淆方式做的封装,如果想要直接可以拿来使用的服务,可以采用下,常用的一些服务如下:

几维安全

  • iOS加密可能市场很小,但是存在必有道理,在越狱/开源/极客的眼中,你的APP并没有你想像的那么安全,如果希望你的代码更加安全,就应给iOS代码加密。

转载于:https://www.cnblogs.com/ShaoYinling/p/8602260.html

2019-11-26 10:58:07 u011516972 阅读数 18

文章目录

 

  • 最近公司扫描 App 漏洞,提出要给 App 做代码混淆加固,以提高反编译逆向难度。对于 Android 应用直接用 360 安全加固即可;但对于 iOS 应用,虽然 360 也提供了免费的加固方法,但前提是项目的 enable bitcode 必须设置为 YES。但我们项目中引入的很多框架包括百度地图等并不支持 enable bitcode 设置为 YES。如果 enable bitcode 设置为 NO,并且是本地部署的话(企业证书),360 安全加固 iOS 是收费的,收费标准是 30 万 / 年。其他的一些平台也是收费的。所以只能考虑自己去做了。
  • 360 iOS 加固指南

自己创建脚本文件进行代码混淆

  • 混淆原理 : 代码编译阶段将符号(方法名、属性名等)替换成随机生成的字符串
  • 我们需要创建四个文件如下:
    在这里插入图片描述
    其中 PrefixHeader.pch 宏文件中导入 CodeObfuscation.h, 这样项目在编译的时候就会将 CodeObfuscation.h 中定义的宏及方法名替换为对应随机生成的字符串。
#ifndef PrefixHeader_pch
#define PrefixHeader_pch
#import "CodeObfuscation.h"
#endif /* PrefixHeader_pch */

其中 confuse.sh 脚本文件是最重要的,是用来在程序编译的时候将 func.list 中的方法名替换成随机生成的字符串,并且保存在 CodeObfuscation.h 中。其脚本为:

TABLENAME=symbols
SYMBOL_DB_FILE="$PROJECT_DIR/CodeObfuscation/symbols"
STRING_SYMBOL_FILE="$PROJECT_DIR/CodeObfuscation/func.list"
HEAD_FILE="$PROJECT_DIR/CodeObfuscation/CodeObfuscation.h"
export LC_CTYPE=C

#维护数据库方便日后作排重
createTable()
{
echo "create table $TABLENAME(src text, des text);" | sqlite3 $SYMBOL_DB_FILE
}

insertValue()
{
echo "insert into $TABLENAME values('$1' ,'$2');" | sqlite3 $SYMBOL_DB_FILE
}

query()
{
echo "select * from $TABLENAME where src='$1';" | sqlite3 $SYMBOL_DB_FILE
}

ramdomString()
{
openssl rand -base64 64 | tr -cd 'a-zA-Z' |head -c 16
}

rm -f $SYMBOL_DB_FILE
rm -f $HEAD_FILE
createTable

touch $HEAD_FILE
echo '#ifndef CodeObfuscation_h
#define CodeObfuscation_h' >> $HEAD_FILE
echo "//confuse string at `date`" >> $HEAD_FILE
cat "$STRING_SYMBOL_FILE" | while read -ra line; do
if [[ ! -z "$line" ]]; then
ramdom=`ramdomString`
echo $line $ramdom
insertValue $line $ramdom
echo "#define $line $ramdom" >> $HEAD_FILE
fi
done
echo "#endif" >> $HEAD_FILE
sqlite3 $SYMBOL_DB_FILE .dump

func.list 文件就是用来存放要被混淆的方法和属性名的。如:
在这里插入图片描述
CodeObfuscation.h 本身是一个空头文件,在编译过后会生成 func.list 添加属性和方法对应生成的随机字符串。下图是编译后 CodeObfuscation.h 的内容:
CodeObfuscation.h
示例:

#import "ViewController.h"
#import "NSArray+Extension.h"

@interface ViewController ()
@property (nonatomic, copy) NSString *title1;
@property (nonatomic, copy) NSString *imgsrc;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title1 = @"";
    self.imgsrc = @"";
    
    NSLog(@"%@",[NSArray getPropertiesFromClass:[self class]]);
    NSLog(@"%@",[NSArray getMethodsFromClass:[self class]]);
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (void) test{
    
}
- (void) test1{
    
}
- (void) test2{
    
}
- (void) test3{
    
}
- (void) test4{
    
}

@end

打印出运行时的属性和方法名:
在这里插入图片描述
结果可见,CodeObfuscation.h 中的生成的随机字符串和真正打印出来的并不一致,这是因为每次运行时,CodeObfuscation.h 都会重新生成新的随机字符串,这时替换属性和方法名的是上一次生成的随机字符串。

  • 注意事项:
    1. 属性方法名需要去重。
    2. 代码混淆后不能再上架 appstore。
    3. 代码混淆不能对静态库进行混淆。
    4. 系统自带的属性和方法不能混淆,只能混淆自定义的方法和属性。
  • 具体步骤可参考:iOS 代码混淆教程

iOS 代码自动混淆

  • 上面的方法会有有一些问题,就是每次创建了新的属性和方法都得添加到 func.list 文件中,比较繁琐,不利于维护。其实我们可以让方法属性自动添加 func.list 中。所以我们要从.m 和.h 文件中抽取属性和方法了,但是如何屏蔽系统的属性和方法名,所以我们要将自己定义的属性和方法名全部添加一个前缀。
  • 在 confuse.sh 中添加新的脚本,修改后的脚本如下:
TABLENAME=symbols
SYMBOL_DB_FILE="symbols"
STRING_SYMBOL_FILE="$PROJECT_DIR/AutoScript/func.list"
CONFUSE_FILE="$PROJECT_DIR/AutoCodeConfusion"  
HEAD_FILE="$PROJECT_DIR/AutoScript/AutocodeObfuscation.h"

export LC_CTYPE=C

#取以.m或.h结尾的文件以+号或-号开头的行 |去掉所有+号或-号|用空格代替符号|n个空格跟着<号 替换成 <号|开头不能是IBAction|用空格split字串取第二部分|排序|去重复|删除空行|删掉以init开头的行>写进func.list
grep -h -r -I  "^[-+]" $CONFUSE_FILE  --include '*.[mh]' |sed "s/[+-]//g"|sed "s/[();,: *\^\/\{]/ /g"|sed "s/[ ]*</</"| sed "/^[ ]*IBAction/d"|awk '{split($0,b," "); print b[2]; }'| sort|uniq |sed "/^$/d"|sed -n "/^hj_/p" >$STRING_SYMBOL_FILE


#维护数据库方便日后作排重,一下代码来自念茜的微博
createTable()
{
echo "create table $TABLENAME(src text, des text);" | sqlite3 $SYMBOL_DB_FILE
}

insertValue()
{
echo "insert into $TABLENAME values('$1' ,'$2');" | sqlite3 $SYMBOL_DB_FILE
}

query()
{
echo "select * from $TABLENAME where src='$1';" | sqlite3 $SYMBOL_DB_FILE
}

ramdomString()
{
openssl rand -base64 64 | tr -cd 'a-zA-Z' |head -c 16

}

rm -f $SYMBOL_DB_FILE
rm -f $HEAD_FILE
createTable

touch $HEAD_FILE
echo '#ifndef AutocodeObfuscation_h
#define AutocodeObfuscation_h' >> $HEAD_FILE
echo "//confuse string at `date`" >> $HEAD_FILE
cat "$STRING_SYMBOL_FILE" | while read -ra line; do
if [[ ! -z "$line" ]]; then
ramdom=`ramdomString`
echo $line $ramdom
insertValue $line $ramdom
echo "#define $line $ramdom" >> $HEAD_FILE
fi
done
echo "#endif" >> $HEAD_FILE
sqlite3 $SYMBOL_DB_FILE .dump

在这里插入图片描述
添加了收集方法的脚本后,我们不需要再手动的去添加方法到 func.list 中了。程序编译后会自动将 hj_开头的方法添加到 func.list 中。

源代码下载地址:https://github.com/housenkui/HSKConfuse

另送一份:iOS 脚本打包 傻瓜版,无需改变配置 github 地址

WKWebView 获取 JS 端的 console.log 日志

 

iOS代码混淆初探

阅读数 94

iOS代码混淆

阅读数 7383

没有更多推荐了,返回首页