2019独角兽企业重金招聘Python工程师标准>>>

背景

公司需要做一系列的壳版本,壳版本如果内容雷同提交到App Store会有被拒绝的风险,其中有一种解决方案是在壳版本中注入混淆的代码,防止被苹果检测到内容太过雷同而导致审核被拒绝,本文是针对这个场景,使用shell脚本进行半自动批量添加和删除混淆代码。

shell实战的系列文章
iOS使用shell脚本注入混淆内容
iOS使用Shell脚本批量修改类名称
iOS使用shell脚本批量修改属性

结果

使用方法

  • 打开测试工程

测试工程位于项目目录下面的DevPods/InjectedContentKit/Example/目录下,打开InjectedContentKit.xcworkspace即可

  • 执行命令

在命令行中进入到项目目录下面的DevPods/InjectedContentKit/Example/injectContentShell子目录,在我的电脑对应的目录为/Users/aron/git-repo/YTTInjectedContentKit/DevPods/InjectedContentKit/Example/injectContentShell,然后执行./injectedContentShell.sh脚本文件批量添加混淆内容,脚本开头的to_process_file_dir变量配置的是需要修改的类所在目录,脚本会自动检测该配置是否正确,正确会显示菜单项页面,否则会提示用户输入需要修改的类所在目录,输入正确之后才会显示菜单项页面。菜单项有三个选项,第一个为删除注入内容,第二个为添加注入内容,第三为退出脚本执行,输入对应的编号即可执行相应的功能

➜  injectContentShell git:(master) ./injectedContentShell.sh
/usr/local/bin/sed
testresult = 0
lrwxr-xr-x 1 aron admin 29 2 13 10:28 /usr/local/bin/sed -> ../Cellar/gnu-sed/4.4/bin/sed
testresult = 82
检测到使用gun sed
目录存在 /Users/aron/git-repo/YTTInjectedContentKit/DevPods/InjectedContentKit/Example/injectContentShell/../injectedContentKit/Business
检测到配置文件存在 /Users/aron/git-repo/YTTInjectedContentKit/DevPods/InjectedContentKit/Example/injectContentShell/injectedContentConfig.cfg
开始读取配置文件.../Users/aron/git-repo/YTTInjectedContentKit/DevPods/InjectedContentKit/Example/injectContentShell/../injectedContentKit/Business
read_implement_file_recursively
// ......省略选项菜单1. 删除注入内容2. 添加注入内容0. Exit menuEnter option: 2// ......
>>>>>>>内容添加完成 Hit any key to continue选项菜单1. 删除注入内容2. 添加注入内容0. Exit menuEnter option: 1/Users/aron/git-repo/YTTInjectedContentKit/DevPods/InjectedContentKit/Example/injectContentShell/../injectedContentKit/Business/ICKXibTestViewController.m
>>>>>>>[[GameDetailDataComposer new] loadDataWithBlock:nil];
// ......省略
pattern_str = \[\[WriterDataComposer new\] loadWithType:MMLoadTypeMore completionBlock:nil\];内容删除完成

处理结果

添加注入内容到源码中的结果

把注入内容从源码中删除的结果

本文的Demo代码YTTInjectedContentKit

分析

在开始做之前,对步骤流程做了一些构思如下:

初始步骤流程

  • 步骤一:手动处理
    混淆注入类列表
    混淆注入类对应的方法列表

  • 步骤二:配置化
    步骤一的形成配置化

  • 步骤三:自动化
    扫描对应的类和类对应的方法列表,形成对应的配置文件
    从配置文件中读取配置注入到对应的目标类中

  • 步骤四:自动目标文件的处理
    目标文件的查找规则:哪些是需要注入的目标文件
    目标文件的注入规则:目标文件中需要在什么位置进行注入

  • 步骤五:注入内容自身配置
    注入内容需要在不同环境下变换不同的形态,包括类名,方法名等

后面在实现的过程中发现步骤三和步骤五不好实现,所有简化了这部分的流程,最终只保留了以下几个步骤:

优化的步骤流程

  • 步骤一:手动处理
    混淆注入类列表
    混淆注入类对应的方法列表

  • 步骤二:配置化
    步骤一的形成配置化

  • 步骤三:自动目标文件的处理
    目标文件的查找规则:哪些是需要注入的目标文件
    目标文件的注入规则:目标文件中需要在什么位置进行注入

以及在实现过程中遇到了一些细节需要处理,这些细节部分作为自步骤如下:

  • 子步骤:
    步骤三-1:检查时候安装gun-sed,mac下的sed和gun sed 会有差别,所有统一使用gun sed
    步骤三-2:用户指定目标位置,需要用户输入
    步骤三-3:删除所有的注入内容

实现

步骤一:手动处理

整理一份注入的内容这部分工作是需要手动处理的,这部分的内容应该是具备自完备性的,可以被多个项目做为依赖导入,所以把这些内容作为一个pod库比较合适,也很方便在pod库的测试项目中测试该库的自完备性。库里面的内容可以是任意的,在我实践的过程中,我是把一个旧的项目的网络接口模块作为了这部分内容,因为这部分内容相对的比较独立和容易抽取。

下图是我从旧的项目中提取的一些类作为混淆类

以及我在测试工程中测试混淆的接口调用,在测试工程中测试混淆代码的调用以确保编译链接无误以及确保库的自完备性。

#import "ICKViewController.h"
#import <InjectedContentKit.h>@implementation ICKViewController- (void)viewDidLoad
{[super viewDidLoad];[[GameDetailDataComposer new] loadDataWithBlock:nil];[[PubSearchDataComposer new] loadSuggestionWithCompletionBlock:nil];[[WriterDataComposer new] loadWithType:MMLoadTypeMore completionBlock:nil];
}- (void)didReceiveMemoryWarning
{[super didReceiveMemoryWarning];// Dispose of any resources that can be recreated.
}@end

步骤二:配置化

配置文件其实就是把测试工程总的接口调用代码拷贝一份到单独的配置文件中,配置文件如下

    [[GameDetailDataComposer new] loadDataWithBlock:nil];[[PubSearchDataComposer new] loadSuggestionWithCompletionBlock:nil];[[WriterDataComposer new] loadWithType:MMLoadTypeMore completionBlock:nil];

步骤三:自动目标文件的处理

这个是最核心的部分,主要包含了以下内容:

  • 配置文件路径配置和需要注入的源码文件夹的配置
  • 读取配置文件的注入内容
  • 读取源码文件夹下的源码实现文件(XXX.m)
  • 把注入内容添加到源码中指定的位置
  • 从源码从把注入的内容删除

完整的脚本如下,里面有比较完整的注释,阅读起来应该不会有太大难度:

文本的插入和删除部分使用的是shell中的sed(stream editor)工具,特别滴在mac中sed命令和标准的sed命令有差别,脚本中也会有做这部分的检测,如果机器上安装的不是标准的gun sed程序会自动通过brew安装gun sed

#!/bin/bash############## 配置# 需处理文件目录
# mark: TODO
to_process_file_dir="$(pwd)/../injectedContentKit/Business000"
# 配置文件
cfg_file="$(pwd)/injectedContentConfig.cfg"############## 工具类方法
function printHighlightMessage {echo -e "\033[31m $1 \033[0m"
}# 检查是否安装gunsed
# mac安装gunSed  http://blog.csdn.net/sun_wangdong/article/details/71078083
which_sed=`which sed`
echo $which_sed
echo "testresult = $(expr $which_sed : '.*/gnu-sed/')"
if [[ $(expr $which_sed : '.*/gnu-sed/') -gt 0 ]]; thenecho "检测到使用gun sed"
elseif [ ! `which brew` ]thenecho 'Homebrew not found. Trying to install...'ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" \|| exit 1fiecho 'Trying to install gun sed...'brew install gnu-sed --with-default-names || exit 1# 设置局部环境变量echo "set PATH...."source ./set-gun-sed-path.shecho "set PATH done"#mark: echo 颜色选项 http://www.jb51.net/article/43968.htmecho "请手动执行命令,然后重新执行"command="PATH=\"/usr/local/Cellar/gnu-sed/4.4/bin:\$PATH\""printHighlightMessage $commandecho ""exit 1
fi# 循环检测输入的文件夹
function checkInputDestDir {echo -n "请输入需处理源码目录: "read pathif [[ -d $path ]]; thento_process_file_dir=$pathelseecho -n "输入的目录无效,"checkInputDestDirfi
}# 需处理源码目录检查
if [[ -d $to_process_file_dir ]]; thenecho "需处理源码目录存在 $to_process_file_dir"
elseecho "请确认需处理源码目录是否存在 $to_process_file_dir"checkInputDestDir
fi# mark: p261
# 配置文件检查
if [[ -f $cfg_file ]]; thenecho "检测到配置文件存在 $cfg_file"
elseecho "请确认配置文件是否存在 $cfg_file"exit 1
fi# 读取配置文件
echo "开始读取配置文件..."declare -a config_content_array
cfg_line_count=0
# mark: p291
IFS_OLD=$IFS
IFS=$'\n'
# 删除文件行首的空白字符 http://www.jb51.net/article/57972.htm
for line in $(cat $cfg_file | sed 's/^[ \t]*//g')
doif [[ ${#line} -eq 0 ]]; thenecho "blank line"elseconfig_content_array[$cfg_line_count]=$lineficfg_line_count=$[ $cfg_line_count + 1 ]
done
IFS=${IFS_OLD}echo ""# 读取需要处理目标文件
declare -a implement_source_file_array
implement_source_file_count=0# mark: p384
# 递归函数读取目录下的所有.m文件
function read_implement_file_recursively {echo "read_implement_file_recursively"if [[ -d $1 ]]; thenfor item in $(ls $1); doitemPath="$1/${item}"if [[ -d $itemPath ]]; then# 目录echo "处理目录 ${itemPath}"read_implement_file_recursively $itemPathecho "处理目录结束====="else # 文件echo "处理文件 ${itemPath}"if [[ $(expr $item : '.*\.m') -gt 0 ]]; thenecho ">>>>>>>>>>>>mmmmmmm"implement_source_file_array[$implement_source_file_count]=${itemPath}implement_source_file_count=$[ implement_source_file_count + 1 ];fiecho ""fidoneelseecho "err:不是一个目录"fi
}echo ${to_process_file_dir}
read_implement_file_recursively ${to_process_file_dir}# 处理目标文件,添加配置文件中注入的内容
function addInjectedContent {# implement_source_file_array# ${#config_content_array[@]}injected_content_index=0for(( i=0;i<${#implement_source_file_array[@]};i++)) do file=${implement_source_file_array[i]}; echo ${file}injected_content=${config_content_array[$injected_content_index]};injected_content_index=$[ $injected_content_index + 1 ]echo ">>>>>>>${injected_content}"# mark: sed 命令中使用变量 http://blog.csdn.net/lepton126/article/details/36374933sed -i '/^- \(.*\)/{a\ '"$injected_content"'}' ${file}done;message="内容添加完成"printHighlightMessage $message
}# 处理目标文件,删除配置文件中注入的内容
function removeInjectedContent {for(( i=0;i<${#implement_source_file_array[@]};i++)) do file=${implement_source_file_array[i]}; echo ${file}for(( j=0;j<${#config_content_array[@]};j++)) do pattern_str=${config_content_array[$j]};echo ">>>>>>>${pattern_str}"# mark: sed 命令中使用变量 http://blog.csdn.net/lepton126/article/details/36374933substring="["replacement="\["pattern_str=${pattern_str//$substring/$replacement}substring="]"replacement="\]"pattern_str=${pattern_str//$substring/$replacement}echo "pattern_str = $pattern_str"#pattern_str="[CardDataComposer new]"sed -i '/'"$pattern_str"'/ {d}' ${file}donedone;message="内容删除完成"printHighlightMessage $message
}function genMunu {clearechoecho -e "\t\t\t选项菜单\n"echo -e "\t1. 删除注入内容"echo -e "\t2. 添加注入内容"echo -e "\t0. Exit menu\n\n"echo -en "\t\tEnter option: "read -n 1 option
}while [[ 1 ]]; dogenMunucase $option in0 )echo ""echo "Bye"exit 0;;1 )# 删除配置文件中注入的内容removeInjectedContent;;2 )# 添加配置文件中注入的内容addInjectedContent;;h )genMunu;;* )echo "Wrong!!";;esacechoecho -en "\n\n\tHit any key to continue"read -n 1 linedone

总结

以上就是基于shell脚本,从混淆内容注入和把混淆内容删除两方面做了一个半自动化的实现步骤,如果不妥之处,还请不吝赐教。

转载于:https://my.oschina.net/FEEDFACF/blog/1621956

iOS使用shell脚本注入混淆内容相关推荐

  1. iOS使用shell脚本批量修改属性

    背景 公司需要做一系列的壳版本,壳版本如果内容雷同提交到App Store会有被拒绝的风险,除了我在上一篇文章中说道的在壳版本中注入混淆的代码,防止被苹果检测到内容太过雷同而导致审核被拒绝.还有另一种 ...

  2. shell脚本发邮件内容html,Shell发送邮件以HTML展示

    有时候,监控一个系统需要在系统出现警告时通过shell发送邮件来通知相关的负责人.本文讲讲如何shell发送邮件. 一种是普通邮件,通过附件描述详细报告:一种是高级邮件(哈哈),本来就是告警,还不赶快 ...

  3. shell脚本发邮件内容html,[转]Shell脚本中发送html邮件的方法

    作为运维人员,免不了要编写一些监控脚本,并将监控结果及时的发送出来.那么通过邮件发送是比较常用的一种通知方式了.通常的,如果需要发送的内容是简单的文本文件,那么使用/bin/mailx就可以了,但是如 ...

  4. ios 执行shell脚本

    一.由于ios中没有 cocoa的NSTask 所以要在cocoa touch SDK中执行shell 只能用系统调用 int system(const char * string); 例如:syst ...

  5. 【Linux】《Linux命令行与shell脚本编程大全 (第4版) 》笔记-汇总 ( Chapter17-ChapterB )

    十七.创建函数 bash shell 提供了用户自定义函数功能,可以将 shell 脚本代码放入函数中封装起来. 函数是一个脚本代码块,你可以为其命名并在脚本中的任何位置重用它.每当需要在脚本中使用该 ...

  6. shell脚本的规范

    shell脚本的规范 1.脚本的解释器 shell脚本开头(第一行)会指出由哪个程序(解释器)来解释脚本中的内容.这一行必须在脚本顶端的第一行,如果不是第一行则为注释.不管写什么脚本最好养成好习惯,都 ...

  7. 监控mysql的shell脚本_监控MySQL主从状态的shell脚本

    分享一个Linux下,监控MySQL主从状态及配合企业微信机器人报警的Shell脚本 SLAVE_IP:为监控的主机IP USER:为msyql用户 PASSWORD:为mysql密码 WHEREIS ...

  8. shell实例第18讲:利用gzexe加密shell脚本

    利用gzexe加密shell脚本 gzexe_test.sh内容如下: #!/bin/bashecho "gzexe test!" 结果: 使用gzexe加密shell脚本命令:g ...

  9. linux 并行执行脚本,在bash / linux中并行运行shell脚本

    我有一个shell脚本job.sh. 内容如下: #!/bin/bash table=$1 sqoop job --exec ${table} 现在当我做./job.sh table1 该脚本成功执行 ...

最新文章

  1. 常用器件选型——电源篇
  2. ASP.NET 视频截图功能的C#代码
  3. ubuntu18.04中tomcat8.5启动时报找不到JAVA_HOME和JRE_HOME
  4. qq浏览器插件_惊艳与吐槽:QQ浏览器升级到 Chromium70 内核以后
  5. 个人练习-jq 鼠标移上移出查看图片(放大)提示
  6. hssfrow 单元格样式_poi导出excel单元格中画斜线_AnyReport报表
  7. 湖大计算机学院博士后李晓灿,李蕊-湖大信息科学与工程学院
  8. MySQL的MHA高可用配置及故障切换
  9. (论文加源码)基于DEAP的脑电情绪识别(CNN,RNN和两种不同的注意力机制)
  10. MySQL--必知必会补充知识
  11. 伙伴云品牌升级:logo换新,调性更潮
  12. 从底层了解ASP.NET体系结构
  13. 周慧敏张曼玉关之琳赵雅芝 风华绝代不畏岁月
  14. 信息系统成本与质量管理
  15. java购物商城_基于javaweb实现的简单购物商城
  16. unity中将多个图片进行椭圆排序
  17. 荐9个可以帮助你的公众号
  18. 川渝交界处今晨发生5级地震
  19. poi setFontFamily设置微软雅黑有问题??
  20. 如何快速检查钢网开口面积比是否符合 IPC7525?

热门文章

  1. 用Java编写的密码翻译问题
  2. poj2376 区间贪心 挑战程序设计竞赛
  3. Python爬虫之puppeteer之遇到的bug及解决方法
  4. python 文件按行读写
  5. 栈应用:实现二进制转八进制、十进制、十六进制
  6. 基础数据结构——是否同一棵二叉搜索树
  7. .Net中json序列化与反序列化
  8. [原创]django+ldap实现统一认证部分一(django-auth-ldap实践)
  9. 【Android】完善Android学习(二:API 2.3.4)
  10. C++ 接收数量不定的函数参数