Swift之代碼混淆的調研實施小記


背景:

最近做APP備案,需要對項目做一系列對優化改進,其中就包括了代碼混淆,顧名思義,混淆是為了代碼安全,是為了增加逆向破解的難度與復雜度。

目前市面上,免費和付費都有,一些公司對APP加固已經做成了產業,形成了一整套的解決方案,不過收費也是杠杠的,我也聯系了其中一家,收費大概是【一年】【單APP】價格是2W(多APP價格可以再商量,應該會便宜點吧),當然這是他們號稱的整個加固策略解決方案的價格。

 

說明:

不過呢,因為一些原因,我就暫時從開源的一些免費方案尋找解決處理,而且我們目前只是針對代碼混淆安全性上的需求,所以就有了本篇文章。

進行了一些調研之后,我發現其實很多項目的早期混淆,大多是基於念茜大大的思路做的延伸擴展,基本思路為下:

寫一個腳本,將項目中的一些敏感方法名集中寫在一個名叫func.list的文件中,逐一#define成隨機字符

原文地址:https://blog.csdn.net/yiyaaixuexi/article/details/29201699  有興趣可以看一下

 

用這種方式,需要新建兩個文件,一個混淆腳本,一個fun函數列表,用於添加你所需要混淆的方法,然后在Build Phases里添加執行Run Script

 

因為她這篇文章寫的比較早,后面也有很多朋友對此基礎上,做了一些優化更新,基本網上也都能搜到,甚至有些朋友直接做成了mac工具,直接拖動項目路徑,配置一下前綴等關鍵詞,就能一鍵混淆。

比如:iOS_NQConfuseTool ,不過這個工具填的參數比較多,出了問題就容易不響應了,囧,可以了解下,不是特別推薦

 

正文:

其實最開始我想象中的方案,是不用通過前綴來判別的,因為我想,對老項目太不友好了,還得針對類名、方法名一大堆慢慢加前綴什么的,工作量太大了,因此,我就在想,有沒有更好的只能混淆方案呢?

結果是還真被我找到了,就是我的理解力不夠,最終還是沒能實現,且聽我說完。

這個工具就是:swiftshield

 

在發現這個工具時,我就在想,太好了,這個牛逼啊,功能強大,使用簡單

不過我按照他的描述配置后,發現沒起作用,在終端運行后,會提示我swiftshield沒找到,目前暫還沒找到解決方案,因此有搞定的朋友千萬記得給我留個言,在線等。。。

 

不過即使生活qj了你,你還得過日子啊,此路不通,換條路繼續,只不過路沒這么好走罷了

 

我重新找到了一個方案,雖然不是智能一鍵混淆,但操作起來還是相對比較便捷的

思路:也是通過腳本實現前綴識別替換。

這個方案操作起來大概分以下幾個步驟:

1、創建一個空 confuseAndBuild.sh文件,拖動到項目根目錄(名字自己取)

2、將下面的腳本拷貝進去,注意:腳本的前綴是需要配置的,改成你自己的就行,腳本默認是"hunxiao_"

這是腳本!!!

#!/bin/bash

#  confuseAndBuild.sh
#  ConfuseSwift
#

# ⚠️聲明
# 1. 請將該腳本放在Xcode的Project工程的根目錄。
# 2. 當前版本未配置完整Xcode環境變量,僅支持混淆功能,不支持framework編譯,若需編譯請用Xcode運行該腳本。

# ⚠️教程
# https://www.jianshu.com/p/be751f780d94
# 直接在終端cd到confuseAndBuild.sh上一層目錄,然后運行./confuseAndBuild.sh -c 即可


if [ -z "$PROJECT_NAME" ]; then
CONFUSE_DIR="."
else
CONFUSE_DIR="${SRCROOT}/${PROJECT_NAME}"
fi

# ⚠️自己配置自己的前綴
CONFUSE_PREFIX="hunxiao_"

BACKUP_FILE=".backup.log"
SYMBOL_FILE=".symbol.log"
CONFUSE_FILE=".confuse.log"
CONFUSE_FLAG=".confuseFlag"

SOURCE_ARRAY=( "*.swift"
"*.m"
"*.h"
"*.c"
"*.cpp")
BACKUP_EXTENSION=".bak"


# 格式:echo -e "\033[背景色;前景色m 打印的字符串 \033[0m"
# 顏色:重置=0,黑色=30,紅色=31,綠色=32,黃色=33,藍色=34,洋紅=35,青色=36,白色=37。
# 示例:echo -e “\033[30m 我是黑色字 \033[0m”
# 參考:https://www.cnblogs.com/xiansong1005/p/7221316.html
#      https://www.cnblogs.com/lr-ting/archive/2013/02/28/2936792.html
info() {
local green="\033[1;32m"
local normal="\033[0m"
echo -e "[${green}info${normal}] $1"
}

error() {
local red="\033[1;31m"
local normal="\033[0m"
echo -e "[${red}error${normal}] $1"
}

# 生成隨機字符串 16字
randomString() {
openssl rand -base64 64 | tr -cd 'a-zA-Z' | head -c 16
}

# 獲取符號的隨機字符串  $1是符號名
randomStringWithSymbol() {
grep -w $1 $SYMBOL_FILE -h | cut -d \  -f 2
}

removeIfExist() {
if [ -f $1 ]; then
rm $1
fi
}

# 備份文件 $1:file full path
backupFile() {
file=$1
# 在原文件名前加個.(點符合)用作備份名
fileName=${file##*/}
backupPath=${file/$fileName/.$fileName$BACKUP_EXTENSION}
echo "backup $file to $backupPath"

if [ ! -f $backupPath ]; then
cp $file $backupPath
echo $backupPath >>$BACKUP_FILE
fi
}

# 方案1. 精確備份:用關鍵字遍歷會修改到的source文件,再將其備份 -- 消耗性能
# 方案2. 整體備份:備份所有source文件 -- 消耗存儲空間
# 根據需要,為簡單起見,這里選用方案2
backupAllSource() {
info "backup all swift files"
NAMES="-name \"${SOURCE_ARRAY[0]}\""
i=1
while [ $i -lt ${#SOURCE_ARRAY[@]} ]; do
NAMES+=" -or -name \"${SOURCE_ARRAY[$i]}\""
let i++
done
# echo $NAMES

removeIfExist $BACKUP_FILE
touch $BACKUP_FILE

eval "find $CONFUSE_DIR $NAMES" | while read file; do
backupFile $file
done
}

# 混淆工作, ⚠️該函數不會自動備份,要備份請調用safeConfuse函數
confuseOnly() {
info "confuse start..."

# 獲取要混淆的函數名和變量名
INCLUDES="--include=\"${SOURCE_ARRAY[0]}\""
i=1
while [ $i -lt ${#SOURCE_ARRAY[@]} ]; do
INCLUDES+=" --include=\"${SOURCE_ARRAY[$i]}\""
let i++
done
eval "grep $CONFUSE_PREFIX -r $CONFUSE_DIR $INCLUDES -n" >$CONFUSE_FILE

# cat $CONFUSE_FILE
# 綁定隨機字符串
removeIfExist $SYMBOL_FILE
touch $SYMBOL_FILE

cat $CONFUSE_FILE | egrep -w $CONFUSE_PREFIX"[0-9a-zA-Z_]*" -o | sort | uniq | while read line; do
echo $line" `randomString`" >>$SYMBOL_FILE
done

# cat $SYMBOL_FILE

# 讀取備份文件記錄
# 在這里沒使用遍歷批量替換,怕文件太多的時候影響性能
cat $CONFUSE_FILE | while read line; do
#        echo "> $line"
# 截取行號
lineNum=`echo $line | sed 's/.*:\([0-9]*\):.*/\1/g'`
# 截取文件路徑
path=${line%%:*}

# 一行可能有多個要替換的子串,要循環遍歷完
# 這里之所以要用`sort -r`倒序是因為有個bug:如有字符串"jjyy abc hello abcde", 現在要替換"abc""123"(abcde保持不變),也就是傳說中的‘全匹配替換’,
# 但不知為何在macOS下單詞邊界表達式不起作用:\<abc\> 或者 \babc\b都不起作用,Linux下這個正則表達式是沒問題的。
# 倒序之后有長串優先替換長串,防止短串把長串部分替換掉。但依然存在bug:若是長串不需要替換,則短串替換是依然會將長串部分替換😂
# 因此依然還需要尋找macOS下單詞邊界/全匹配 的正則表達式
echo $line | egrep -w $CONFUSE_PREFIX"[0-9a-zA-Z_]*" -o | sort -r | while read -ra symbol; do
# 根據名稱獲取綁定的隨機字符串
random=`randomStringWithSymbol $symbol`
#            echo "$path $lineNum $symbol $random"
# 隨機字符串替換
# -i:表示直接在原文件替換,"":表示不要備份
sed -i "" "${lineNum}s/$symbol/$random/g" $path

echo "  $symbol => $random"
done
done

info "confuse done"
}

# 編譯工作,生成通用framework
buildAll() {
info "build start..."

if [ -z "$PROJECT_NAME" ]; then
echo -e "\033[1;31mERROR:當前版本未配置完整Xcode環境變量,僅支持混淆功能,不支持framework編譯,若需編譯請用Xcode運行該腳本\033[0m"
return
fi

# 要build的target名
TARGET_NAME=${PROJECT_NAME}
UNIVERSAL_OUTPUT_DIR="${SRCROOT}/Framework/"

# 創建輸出目錄,並刪除之前的framework文件
mkdir -p "${UNIVERSAL_OUTPUT_DIR}"
rm -rf "${UNIVERSAL_OUTPUT_DIR}/${TARGET_NAME}.framework"

#分別編譯模擬器和真機的Framework
xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} ARCHS="armv7 armv7s arm64" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} ARCHS="i386 x86_64" -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

#拷貝framework到univer目錄
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework" "${UNIVERSAL_OUTPUT_DIR}"

# 合並swiftmodule到univer目錄
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/" "${UNIVERSAL_OUTPUT_DIR}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule"

#合並framework,輸出最終的framework到build目錄
lipo -create -output "${UNIVERSAL_OUTPUT_DIR}/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}"

#刪除編譯之后生成的無關的配置文件
dir_path="${UNIVERSAL_OUTPUT_DIR}/${TARGET_NAME}.framework/"
for file in ls $dir_path; do
if [[ ${file} =~ ".xcconfig" ]]; then
rm -f "${dir_path}/${file}"
fi
done

#判斷build文件夾是否存在,存在則刪除
if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

#rm -rf "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator" "${BUILD_DIR}/${CONFIGURATION}-iphoneos"

#打開合並后的文件夾
open "${UNIVERSAL_OUTPUT_DIR}"

info "build done"
}

# 清理工作,去混淆
unconfuse() {
info "clean start..."
if [ -f $CONFUSE_FLAG ]; then
# 恢復混淆的函數名所在source文件的bak內容
cat $BACKUP_FILE | while read backup; do
backupName=${backup##*/}
fileName=`echo $backupName | cut -d "." -f2,3`
filePath=${backup/$backupName/$fileName}

echo "recover $backup to $filePath"

cp $backup $filePath
rm $backup
done
# 刪除修改記錄
removeIfExist $SYMBOL_FILE
removeIfExist $CONFUSE_FILE
removeIfExist $BACKUP_FILE
removeIfExist $CONFUSE_FLAG
else
echo "Not confuse yet!"
fi
info "clean done"
}

# 檢查是否上次未完成
precheck() {
# 創建一個隱藏文件,僅標記混淆編譯的狀態
# 由於編譯過程有可能被中斷,因此混淆后的代碼可能未恢復,在開始備份前先做判斷
unconfuse
touch $CONFUSE_FLAG
}

# 去混淆->備份->混淆
safeConfuse() {
precheck
backupAllSource
confuseOnly
}

# 去混淆->備份->混淆
# 編譯
# 去混淆
safeConfuseAndBuild() {
info "preparing confuse and build..."

safeConfuse
buildAll
unconfuse

info "all done"
}

usage() {
echo -e "\033[1;31musage: ./confuseAndBuild.sh [-u|c|b|a]"
echo -e "  -u"
echo -e "      unconfuse: 清理工作,去混淆"
echo -e "  -c"
echo -e "      safeConfuse: 去混淆->備份->混淆"
echo -e "  -b"
echo -e "      buildAll: 編譯生成通用framework"
echo -e "  -a"
echo -e "      safeConfuseAndBuild: 去混淆->備份->混淆->編譯->去混淆"
echo -e "EXAMPLE:"
echo -e "  ./confuseAndBuild.sh -u\033[0m"
}

main() {
echo "參數個數:$#  參數值:$1"
case $1 in
"-u" )
unconfuse
;;
"-c" )
safeConfuse
;;
"-b" )
buildAll
;;
"-a" )
safeConfuseAndBuild
;;
* )
usage
;;
esac
}

main $@
View Code

3、在項目里,把你認為的一些類名、方法名等添加前綴

4、打開終端,cd到confuseAndBuild.sh上一層目錄,然后運行./confuseAndBuild.sh -c 即可

 

執行完上述4步后,查看項目,會發現有前綴的方法、類等,都已變成混淆后的字符,然后直接打包發布即可。

 

這里注意一點:執行完腳本之后,項目里的函數方法等就會變成混淆后的內容,會大大影響閱讀醒,因此建議在發布時,執行一下腳本,先別提交,待打包好后,撤回混淆就行了

  

參考文章:

iOS Framework混淆/編譯打包腳本(支持swift/oc/c++)

iOS代碼混淆教程

iOS代碼混淆----自動

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM