iOS 代码混淆 && 垃圾代码

2字数 1360阅读 12234

app风靡的时代,总有一些奇葩的需求。
为了刷量,刷排名,制作壳包,为了通过苹果爸爸审核,想到代码混淆,垃圾代码等策略。
作为一名程序员,怎么办?

爬了一些文章博客。总的来说有一下几方面:

  • 字符串加密:
  • 类名方法名混淆
  • 程序代码混淆
  • 加入安全SDK

除了这些外,还有很多方面可以做加固保护的,以上这些只是范范一谈。制作壳包为了通过审核,还有注入垃圾代码来解决和主包代码重复率的问题。本文主要讲解类名方法名混淆及垃圾代码的问题。如有问题,还请大神指点!

Objective-C的方法名混淆

混淆的方法
方法名混淆其实就是字符串替换,有2个方法可以,一个是#define,一个是利用tops。
利用#define的方法有一个好处,就是可以把混淆结果合并在一个.h中,在工程Prefix.pch的最前面#import这个.h。不导入也可以编译、导入则实现混淆。

单段的selector,如func: ,可以通过#define func 来实现字符串替换。
多段的selector,如a:b:c: ,可以通过分别#define a 、b、c 来实现字符串替换。

第一步 创建如下文件

1、工程中建立pch文件 加入以下内容

#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>  
//添加混淆作用的头文件(这个文件名是脚本confuse.sh中定义的)  
//#import "codeObfuscation.h"
#endif

2、在工程目录下创建confuse.sh文件


#!/usr/bin/env bash

TABLENAME=symbols
SYMBOL_DB_FILE="symbols"
STRING_SYMBOL_FILE="func.list"
HEAD_FILE="$PROJECT_DIR/$PROJECT_NAME/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 Demo_codeObfuscation_h
#define Demo_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 

3、在工程目录下创建fun.list文件,文件中存放需要混淆的方法名,类名,文件等等

didReceiveMemoryWarning

4、配置项目$PROJECT_DIR/confuse.sh

image.png

5、编译查看结果
直接build,混淆脚本会在编译前运行,进行字符随机替换,并且每次build的随机字符不同,如图:

image.png

类名方法名混淆

此方法是参考下开源项目:ios-class-guard

操作步骤如下:

1、 安装工具

brew install ios-class-guard 
brew install --HEAD ios-class-guard   # install bleeding edge version:
image.png
ios-class-guard --v #查看版本

2、下载obfuscate_project到工程根目录下

curl -o obfuscate_project https://raw.githubusercontent.com/Polidea/ios-class-guard/master/contrib/obfuscate_project && chmod +x obfuscate_project

效果如果:


image.png

注意点:提交的commit信息它脚本中会移除掉,包括obfuscate_project也会被移除

image.png

WARNING: This will wipe all your not commited changes in your repository
警告:这将会移除你未提交的更改在你的仓库中。

问题点:


image.png

需要修改脚本中的工程名,scheme,sdk等:


image.png

3、然后继续执行:
当你每次想混淆你的项目。都应该执行此操作。存储包含符号映射的json文件,以便在发生崩溃时获取原始符号名称。

bash obfuscate_project

打开工程,发现已经生成了.hjson文件

image.png

4、添加.pch文件

  • Create PCH file in your project's root directory. In Xcode go to File -> New -> File -> iOS -> Other -> PCH File. To ensure backward compatibility iOS-Class-Guard will be looking for a file matching the *-Prefix.pch mask, as an example MyProject-Prefix.pch
  • At the target's Build Settings, in Apple LLVM - Language section, set Prefix Header to your PCH file name.
  • At the target's Build Settings, in Apple LLVM - Language section, set Precompile Prefix Header to YES.
    image.png

$(SRCROOT)/MyProject/MyProject-Prefxi.pch

image.png

容易犯的错误:


image.png

注意是:MyProject-Prefix.pch
因为脚本中pch的名字有Prefix

image.png

每次混淆之后都会删除脚本,清理工程。可以直接修改脚本代码


image.png

ios-class-guard使用命令等

ios-class-guard 0.8 (64 bit)
Usage: ios-class-guard [options] <mach-o-file>

  where options are:
        -F <class>     specify class filter for symbols obfuscator (also protocol))
        -i <symbol>    ignore obfuscation of specific symbol)
        --arch <arch>  choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64, armv6, armv7, armv7s, arm64)
        --list-arches  list the arches in the file, then exit
        --sdk-ios      specify iOS SDK version (will look for /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS<version>.sdk
                       or /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS<version>.sdk)
        --sdk-mac      specify Mac OS X version (will look for /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX<version>.sdk
                       or /Developer/SDKs/MacOSX<version>.sdk)
        --sdk-root     specify the full SDK root path (or use --sdk-ios/--sdk-mac for a shortcut)
        -X <directory> base directory for XIB, storyboards (will be searched recursively)
        -P <path>      path to project.pbxproj of Pods project (located inside Pods.xcodeproj)
        -O <path>      path to file where obfuscated symbols are written
        -m <path>      path to symbol file map (default value symbols.json)
        -c <path>      path to symbolicated crash dump

还有一些单独对xib,storyboard,pods等单独操作进行混淆的。点击这里

脚本源码:有兴趣可以研究下脚本源码,这才是核心根源。

#!/bin/bash

set -e

# General build options
# WORKSPACE=YourWorkspace.xcworkspace
PROJECT=test.xcodeproj
SCHEME=test
CONFIGURATION=Release
SDK=11.3

# Additional build options
XCODEBUILD_OPTS=""
CLASS_GUARD_OPTS="-i IgnoredSymbol -F !ExcludedClass"

# In case of using Xcode >= 6 and SDK >= 8
CLASS_GUARD_OPTS_SDK="--sdk-root /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$SDK.sdk"

####################################################
# BUILD SCRIPT STARTS HERE
####################################################

# Just in case
echo "WARNING: This will wipe all your not commited changes in your repository"
echo "Press Ctrl-C to Cancel or Enter to proceed."
read

function echo_and_run() {
    echo "$@"
    "$@"
}

# Jump to directory where obfuscate script is located
pushd $(dirname $0)

# Symbols file path
SYMBOLS_FILE="$PWD/symbols.h"

# Clean current workspace
echo_and_run git reset --hard
echo_and_run git clean -fdx

# Just in case: wipe build/
rm -rf build/

# Automatically detect PODS
[[ -f Podfile ]] && [[ ! -f Pods/Manifest.lock ]] && pod install
[[ -f Pods/Pods.xcodeproj/project.pbxproj ]] && CLASS_GUARD_OPTS="$CLASS_GUARD_OPTS -P Pods/Pods.xcodeproj/project.pbxproj"

# Build project to fetch symbols
[[ -n "$WORKSPACE" ]] && XCODEBUILD_OPTS="$XCODEBUILD_OPTS -workspace $WORKSPACE"
[[ -n "$PROJECT" ]] && XCODEBUILD_OPTS="$XCODEBUILD_OPTS -project $PROJECT"
[[ -n "$SCHEME" ]] && XCODEBUILD_OPTS="$XCODEBUILD_OPTS -scheme $SCHEME"
[[ -n "$CONFIGURATION" ]] && XCODEBUILD_OPTS="$XCODEBUILD_OPTS -configuration $CONFIGURATION"

xcodeversion=`xcodebuild -version | grep -oE '^Xcode\s+\d+' | grep -oE '\d+'`
if ((xcodeversion > 5)) || ((SDK >= 8.0))
then
    [[ -n "$SDK" ]] && XCODEBUILD_OPTS="$XCODEBUILD_OPTS -sdk iphonesimulator$SDK"
else
    [[ -n "$SDK" ]] && XCODEBUILD_OPTS="$XCODEBUILD_OPTS -sdk iphoneos$SDK"
    [[ -n "$SDK" ]] && CLASS_GUARD_OPTS_SDK="--sdk-ios $SDK"
fi

echo_and_run xcodebuild $XCODEBUILD_OPTS \
    clean build \
    -derivedDataPath build
    OBJROOT=build/ \
    SYMROOT=build/

# Insert SYMBOLS_FILE to all .pch found in project
echo_and_run find . -name '*-Prefix.pch' -exec sed -i .bak '1i\
'"#import \"$SYMBOLS_FILE\"
" "{}" \;

# Obfuscate project
appsNumber=0;
while read app
do
    if ((appsNumber > 0))
    then
        echo ""
        echo ""
        echo "You cannot use this tool when there is more than one .app file in products. Otherwise, only the first one will be used for obfuscation."
        echo ""
        echo ""
        exit 1
    fi
    ((appsNumber+=1))

    TARGET=$(basename "$app" .app)
    echo "Obfuscating $TARGET in $app..."
    echo_and_run ios-class-guard \
        $CLASS_GUARD_OPTS_SDK \
        $CLASS_GUARD_OPTS \
        -O "$SYMBOLS_FILE" \
        "$app/$TARGET"
done < <(find build/ -name '*.app')

echo ""
echo ""
echo "Congratulations! Obfuscation completed. You can now build, test and archive Your project using Xcode, Xctool or Xcodebuid..."
echo ""
echo ""

工具混淆

垃圾代码

用于应对苹果对重复应用的审核(Guideline 4.3 Design Spam),避免苹果机审检测概率。

主要功能

  1. 修改工程名
  2. 修改类名前缀
  3. 扫描工程中的代码,生成同等数量的 Category 文件,文件中及是同等方法数量的垃圾代码。
  4. 修改 xxx.xcassets 文件夹中的 png 资源文件名。
  5. 删除代码中的所有注释和空行。
使用步骤如下

1、下载源码。
2、用 Xcode 打开工程并配置参数。如图

image.png

3、运行
使用二进制文件,在终端中执行 GenerateSpamCode

  • spamCodeOut 生成垃圾代码
./GenerateSpamCode \
/Users/wangzelong/Desktop/TeamCode/cardloan \
-spamCodeOut /Users/wangzelong/Desktop/appLog AppLog

注明:appLog是一个文件夹,垃圾代码生成到的文件夹目录。 后面的AppLog是将要生成的垃圾代码分类参数等可以再测试代码中尝试。

  • deleteComments 删除工程目录下 .h .m .swift 文件中的注释和空行。
    ./GenerateSpamCode
    /Users/wangzelong/Desktop/appium
    -deleteComments

参数介绍

坑:
1、Podfile被修改后需要手动pod install
2、如果工程项目很大。则建议导入一部分工程代码去生成垃圾代码,因为项目中很多文件包括依赖的三方库等,可能是 .m 文件中实现的私有类,编译垃圾代码可能会报错,删除该垃圾代码 .h .m 文件及可。

此外提供一个压缩图片的轻量工具:

使用 ImageMagick 对 png 图片做轻量压缩,及不损失图片质量,又可改变图片文件 hash 值。方法:
  1. 安装 ImageMagick
    brew install imagemagick
  2. 压缩工程目录下所有 png 文件
    find . -iname "*.png" -exec echo {} \; -exec convert {} {} \;

推荐阅读更多精彩内容