1. 程式人生 > >iOS編譯器LLVM + Clang架構分析以及三種混淆方案實踐分析

iOS編譯器LLVM + Clang架構分析以及三種混淆方案實踐分析

Xcode Command + R編譯原理全過程介紹

前言

之前由於啟動優化相關的需求,分析了Xcode編譯的全過程,針對優化點做了記錄和學習。最近被人問到詳述下LLVM架構原理。當時只是略知一二,看過而已,沒理解的那麼深入,這次根據LLVM + Clang的整個編譯流程簡單做個記錄,而且順便在每個不同階段做程式碼混淆做一下Demo介紹。這裡需要安裝很多很多東西,個人認為Mac電腦都會安裝個Homebrew,安裝東西就方便多了,不多說了,下面開始介紹。

LLVM

還是說說 LLVM 到底是什麼吧,LLVM的專案是一個模組化和可重複使用的編譯器和工具技術的集合.LLVM 曾經是一個縮寫詞,現在不是,它就是這個專案的名稱。
Clang 是 LLVM 的子專案,是 C,C++ 和 Objective-C 編譯器。

再來一個更容易理解的說法,iOS 開發中 Objective-C 是 Clang / LLVM 來編譯的。(swift 是 Swift / LLVM)


傳統的編譯器最流行的設計是分三段,分別是前端(Frontend),優化器(Optimizer)和後端(Backend).

前端(Frontend)負責解析原始碼,檢查語法錯誤,並將其翻譯為抽象的語法樹(Abstract Syntax Tree).也就是詞法分析,語法分析,語義分析和生成中間程式碼。

優化器(Optimizer)負責進行各種轉換嘗試改進程式碼的執行時間.release 包比 debug 包體積小執行快,其中的一個原因就是優化器起作用。比如重複計算的消除。

後端(Backend)用來生成實際的機器碼.

這種設計有很多優點,但實際這一結構卻從來沒有被完美實現過。GCC 做的比較好,實現了很多前端和後端,支援了很多語言。但是有個缺陷,那就是他們是一個完整的可執行檔案,沒有把前端和後端分的太開,所以GCC 為了支援一門新的語言,或者支援一種新的平臺,就變得比較困難。

LLVM 就解決了上面的問題,因為它被設計為一組庫,而不是一個編譯器,如下圖

從上圖中我們發現LLVM與GCC在三段式架構上並沒有本質區別,也是分為前端、優化器和後端。但是,其設計最重要的方面是不同的前端、後端使用同一的中間程式碼 LLVM Intermediate Representation (LLVM IR) . 也就是圖中的 LLVM Optimizer

這種設計的好處就是,如果需要支援一種新的程式語言,那麼只需要實現一個新的前端。
如果需要支援一種新的硬體裝置,那麼只需要實現一個新的後端。優化階段是一個通用的階段,它針對的是同一的LLVM IR,不論是支援新的程式語言,還是支援新的硬體裝置,都不需要對優化階段做修改。

Clang 就是基於LLVM架構的C/C++/Objective-C編譯器前端,如下圖

Clang 主要處理一些和具體機器無關的針對語言的分析操作.編譯器的優化器部分和後端部分是LLVM後端,也可以直接叫 LLVM(狹義的LLVM),廣義上LLVM 就是整個LLVM架構。

看上面的圖,左邊是程式語言,最終是機器碼,在我們Xcode 中編寫的程式碼首先會經過 clang 這個編譯器前端,他會生成中間程式碼(IR),這個中間程式碼又經過一系列的優化,這些優化就是 Pass,如果咱要編寫中間程式碼優化程式碼的話,那就是編寫Pass,最後就是生成機器碼.
通過圖也可以看出,Pass 是 LLVM 系統轉化和優化的工作的一個節點,每個節點做一些工作,這些工作加起來就構成了 LLVM 整個系統的優化和轉化。

在編譯一個原始檔時,編譯器的處理過程分為幾個階段。
用命令列檢視一下OC原始檔的編譯過程

$ clang -ccc-print-phases main.m
0: input, "main.m", objective-c
1: preprocessor, {0}, objective-c-cpp-output
2: compiler, {1}, ir
3: backend, {2}, assembler
4: assembler, {3}, object
5: linker, {4}, image
6: bind-arch, "x86_64", {5}, image

一共是7個階段,
第0個階段找到原始碼,讀入檔案。
第1個階段 preprocessor,前處理器,就是把頭匯入,巨集定義給展開,包括 #define、 #include、 #import、 #indef、 #pragma
第2階段就是 compiler,編譯器編譯成 ir 中間程式碼。
第3階段就是交給後端,來生成彙編程式碼(assembler)。
第4階段是將彙編程式碼轉換為目標物件檔案
第5階段是連結器,將多個目標物件檔案合併為一個可執行檔案 (或者一個動態庫) 。
最後一階段 生成可執行檔案 :Mach-O

這裡後續的展開具體流程Xcode裡面可以看到,之前的文章也介紹了,這裡就不記錄了。

如何在實際中應用這些特性

很明顯,流程很清晰,知道就是知道了,但是為什麼要了解這個?因為可以自己寫外掛

之所以 clang 很酷:是因為它是一個開源的專案、並且它是一個非常好的工程:幾乎可以說全身是寶。使用者可以建立自己的 clang 版本,針對自己的需求對其進行改造。比如說,可以改變 clang 生成程式碼的方式,增加更強的型別檢查,或者按照自己的定義進行程式碼的檢查分析等等。要想達成以上的目標,有很多種方法,其中最簡單的就是使用一個名為 libclang 的C類庫。libclang 提供的 API 非常簡單,可以對 C 和 clang 做橋接,並可以用它對所有的原始碼做分析處理。不過,根據我的經驗,如果使用者的需求更高,那麼 libclang 就不怎麼行了。針對這種情況,推薦使用 Clangkit,這個庫有點久了,但是可以學習下思路,它是基於 clang 提供的功能,用 Objective-C 進行封裝的一個庫。

最後,clang 還提供了一個直接使用 LibTooling 的 C++ 類庫。這裡要做的事兒比較多,而且涉及到 C++,但是它能夠發揮 clang 的強大功能。用它你可以對原始碼做任意型別的分析,甚至重寫程式。如果你想要給 clang 新增一些自定義的分析、建立自己的重構器 (refactorer)、或者需要基於現有程式碼做出大量修改,甚至想要基於工程生成相關圖形或者文件,那麼 LibTooling 是很好的選擇。

Libclang和Libtooling這兩個庫到底有什麼不同?

在開始動手之前,我們應該先大致瞭解一下LibTooling。Clang的LibTooling是一個獨立的庫,它允許使用者很方便地搭建屬於你自己的編譯器前端工具。libclang是另外一個不錯的選擇,它提供給使用者基於C的穩定的程式設計介面,隔離了編譯器底層的複雜設計,擁有更強的Clang版本相容性,以及更好的多語言支援能力,對於大多數分析AST的場景來說,libclang是一個很好入手的選擇。libTooling的優點與缺點一樣明顯,它基於C++介面,讀起來晦澀難懂,但是提供給使用者遠比libclang強大全面的AST解析和控制能力,同時由於它與Clang的核心過於接近導致它的版本相容能力比libclang差得多,Clang的變動很容易影響到LibTooling。一般來說,如果你只需要語法分析或者做程式碼補全這類功能,libclang將是你避免掉坑的最佳的選擇。我們之所以選擇libTooling還有一個重要的原因是它提供了完整的引數解析方案,可以很方便的構建一個獨立的命令列工具。這是libclang所不具備的能力。

官方對於如何進行選擇的解釋請看這裡。有興趣瞭解更多關於libclang,可以看官方doxygen文件以及這篇文章libclang: Thinking Beyond the Compiler

上面說了那麼說,來總結一下:

1.LLVM編譯一個原始檔的過程:

預處理 -> 詞法分析 -> Token -> 語法分析 -> AST -> 程式碼生成 -> LLVM IR -> 優化 -> 生成彙編程式碼 -> Link -> 目標檔案

2.基於LLVM,我們可以做什麼?

  1. libclang、libTooling做語法樹分析,實現語言轉換OC轉Swift、JS or 其它語言,字串加密。
  2. 編寫ClangPlugin,命名規範,程式碼規範,擴充套件功能。
  3. 編寫Pass,程式碼混淆優化

大廠的一些實踐:

滴滴的動態化方案 DynamicCocoa 就是使用了一個將 OC 原始碼轉 JS 的外掛來進行程式碼的轉換.
鵝廠的動態化方案 OCS 是直接在端內寫了個編譯器.
可以搜尋 《DynamicCocoa:滴滴 iOS 動態化方案的誕生與起航》 和 《OCS——史上最瘋狂的iOS動態化方案》檢視介紹。

以下三個方案Demo都來源於網上,自己可以根據自己專案來選擇,我就不把自己專案的實現貼出來了,大家看看Demo自己根據需要來實現即可,這裡幫大家蒐集了三種不同階段的混淆方案,正常LLVM有三個階段 前端  LLVM優化 後端三個階段,以下三個方案分別是在LLVM編譯之前,LLVM IR優化和前段(Clang外掛)三個階段分別做了簡單的Demo實踐

混淆方案一(程式碼階段)

該方案也是非常容易理解和上手的,我們一般在程式碼層面會寫一個比較敏感的字串,我們就可以在程式碼階段通過指令碼語言例如Python進行混淆(暫時就叫iOS字串硬編碼混淆方案)

混淆原理:因為硬編碼的字串是在可執行檔案 Mach-O 全域性的資料區,在符號表中很容易被搜尋到,而字串陣列則不會。

Demo地址

下載完Demo可以看到如下目錄結構

開啟Xcode檔案,這裡有個confusion檔案,這裡是python3編寫的指令碼,一般系統自帶Python2.7,需要安裝Python3我推薦用HomeBrew來安裝,同一管理即可。首先開啟專案,先不管,直接跑,然後用Hopper Disassembler來看下反彙編是否有我們寫的明文

可以看到hello world就能通過反彙編出來,那麼就需要混淆了。這裡用Python指令碼來直接修改專案中的字串,Demo裡面用巨集來標記,然後指令碼來修改標記的字串進行混淆,然後再跑Demo,再看下反彙編程式碼

可以看到已經沒有了,這是最上層最容易理解的混淆方案,具體操作可以看下Demo,下面錄了一個操作步驟演示,Python指令碼混淆前後對比

這裡採用的是直接修改原始碼的方式做混淆。首先對需要混淆的字串用巨集打上標記,然後使用指令碼過濾所有原始碼,生成混淆過的程式碼。因為混淆過的程式碼可讀性極差,不利於維護,所以就需要解混淆程式碼,用於把混淆過的程式碼做還原。

 

混淆方案二(LLVM IR階段)

iOS混淆--OLLVM在iOS中的實踐

OLLVM的混淆操作就是在中間表示IR層,通過編寫Pass來混淆IR,然後後端依據IR來生成的目的碼也就被混淆了。得益於LLVM的設計,OLLVM適用LLVM支援的所有語言(C,C++,Objective-C,Ada,Fortran)和目標平臺(x86,x86-64,PowerPC,PowerPC-64, ARM, Thumb, SPARC, Alpha, CellSPU, MIPS, MSP430, SystemZ, 和 XCore)

可以看看這個文章,早幾年,這個方案就可以用,但是貌似不維護了,Xcode9和Xcode10之後反正不能用了,後續就出現了這個,專門針對這個做了高版本的適配。

首先Xcode的BuildSetting裡面的對應的compiler選項對應的外掛路徑是在

mikejingdeMacBook-Pro:~ MKJ$ cd /Applications/Xcode.app/Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/
mikejingdeMacBook-Pro:Plug-ins MKJ$ ls
Clang LLVM 1.0.xcplugin		Obfuscator.xcplugin
Core Data.xcplugin		SceneKit.xcplugin
CoreBuildTasks.xcplugin		SpriteKit.xcplugin
IBCompilerPlugin.xcplugin	XCLanguageSupport.xcplugin
Intents.xcplugin		XCWatchKit1Support.xcplugin
MLKit.xcplugin			XCWatchOSSupport.xcplugin
Metal.xcplugin			assetvalidation.xcplugin

可以看到,這裡有個Obfuscator就是我們要自己新增的外掛。

上面的這個文章介紹的是早起版本LLVM版本對應的混淆外掛,反正現在是不能用了,但是思路是一樣的,那麼現在都升級了X9和X10,怎麼辦,可以看看這個OLLVM庫裡面的issues 問題所在

可以看到,有人專門fork針對高版本做了適配-----> Hikari

其實他是基於 obfuscator 進行了Xcode9的適配

macOS Quick Install

This script assumes current working directory is not the user's home directory(aka ~/). cd to some where else if this is the case. This script also assumes you have cmake and ninja installed, if not, use Homebrew and similar package managers to install them

翻譯如下,執行指令碼需要自己在弄個檔案,而且需要安裝cmake和ninja,如果沒有,直接下載Homebrew來安裝這個兩個,然後執行如下指令碼

git clone -b release_70 https://github.com/HikariObfuscator/Hikari.git Hikari && mkdir Build && cd Build && cmake -G "Ninja" -DLLDB_CODESIGN_IDENTITY='' -DCMAKE_BUILD_TYPE=MinSizeRel -DLLVM_APPEND_VC_REV=on -DLLVM_CREATE_XCODE_TOOLCHAIN=on -DCMAKE_INSTALL_PREFIX=~/Library/Developer/ ../Hikari && ninja &&ninja install-xcode-toolchain && git clone https://github.com/HikariObfuscator/Resources.git ~/Hikari && rsync -a --ignore-existing /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/ ~/Library/Developer/Toolchains/Hikari.xctoolchain/ && rm ~/Library/Developer/Toolchains/Hikari.xctoolchain/ToolchainInfo.plist

OK,只要一切OK,你能安裝好了toolchain(後面你需要在Xcode中選擇自己的編譯工具)而且Hikari也編譯好了。本來這個作者有些中文文件,但是不知道什麼原因,全部被刪掉了,可能開源作者有點生氣,那麼這裡有個英文文件,這裡先看了Compiler和Usage,看下基本面。

一下有兩個文章介紹怎麼給Xcode新增外掛的筆記

掘金混淆筆記

iOS馬甲包混淆方案 Harika

首先執行根據介紹執行上面那坨指令碼,主要是在Xcode上能選擇這個toolchain

然後如果和OLLVM一樣,可以自己在外掛選擇區域,複製一份Apple Default Clang外掛,然後把對應的Info.Plist裡面的文案改成我們自己配置的文案即可。最後在Xcode中選擇配置即可。

步驟如下(以下步驟和OLLVM一樣,無非編譯的包版本不同而已,而且不那麼做的話,執行上面的指令碼生成toolchain也行)

準備

下載 Hikari


mkdir build

cd build

cmake -DCMAKE_BUILD_TYPE=Release ../Hikari/

make -j7

1.copy

$ cd /Applications/Xcode.app/Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/
$ sudo cp -r Clang\ LLVM\ 1.0.xcplugin/ Obfuscator.xcplugin
$ cd Obfuscator.xcplugin/Contents/
$ sudo plutil -convert xml1 Info.plist
$ sudo vim Info.plist

2.change


<string>com.apple.compilers.clang</string> -> <string>com.apple.compilers.obfuscator</string>
<string>Clang LLVM 1.0 Compiler Xcode Plug-in</string> -> <string>Obfuscator Xcode Plug-in</string>

3.xcspec移動

$ sudo plutil -convert binary1 Info.plist
$ cd Resources/
$ sudo mv Clang\ LLVM\ 1.0.xcspec Obfuscator.xcspec
$ sudo vim Obfuscator.xcspec

4.xcsprc修改

<key>Description</key>
<string>Apple LLVM 9.0 compiler</string> -> <string>Obfuscator 4.0 compiler</string>
<key>ExecPath</key>
<string>clang</string> -> <string>//Users/MKJ/Desktop/MK/build/bin/clang(這一坨就是我們編譯的LLVM Clang)</string>
<key>Identifier</key>
<string>com.apple.compilers.llvm.clang.1_0</string> -> <string>com.apple.compilers.llvm.obfuscator.4_0</string>
<key>Name</key>
<string>Apple LLVM 9.0</string> -> <string>Obfuscator 4.0</string>
<key>Vendor</key>
<string>Apple</string> -> <string>HEIG-VD</string>
<key>Version</key>
<string>9.0</string> -> <string>4.0</string>

5.

$ cd English.lproj/
$ sudo mv Apple\ LLVM\ 9.0.strings "Obfuscator 3.4.strings"
$ sudo plutil -convert xml1 Obfuscator\ 3.4.strings
$ sudo vim Obfuscator\ 3.4.strings

6.

<key>Description</key>
<string>Apple LLVM 9.0 compiler</string> -> <string>Obfuscator 4.0 compiler</string>
<key>Name</key>
<string>Apple LLVM 9.0</string> -> <string>Obfuscator 4.0</string>
<key>Vendor</key>
<string>Apple</string> -> <string>HEIG-VD</string>
<key>Version</key>
<string>7.0</string> -> <string>4.0</string>

7.

sudo plutil -convert binary1 Obfuscator\ 4.0.strings

以上都是準備工作,操作完之後Xcode啟動Demo

1.選擇Xcode -> Toolchains -> Hikari將混淆工具和專案關聯。

2.將所有與要執行的target相關的target(包括pod進來的庫)Enable Index-While-Building 的值改為NO。

3.Optimization Level 的值設定為 None[-O0]

3.如果是全域性混淆,則在需要混淆的target中直接將Other C Flags的值加上所需的混淆標記

Other C Flags

* 每個flag前加需要上-mllvm

常用組合

-mllvm -enable-fco

-mllvm -enable-funcwra

-mllvm -enable-strcry

-mllvm -enable-acdobf

-mllvm -enable-bcfobf 啟用偽控制流

-mllvm -enable-cffobf 啟用控制流平坦化

-mllvm -enable-splitobf 啟用基本塊分割

-mllvm -enable-subobf 啟用指令替換

-mllvm -enable-acdobf 啟用反class-dump

-mllvm -enable-indibran 啟用基於暫存器的相對跳轉,配合其他加固可以徹底破壞IDA/Hopper的虛擬碼(俗稱F5)

-mllvm -enable-strcry 啟用字串加密

-mllvm -enable-funcwra 啟用函式封裝

-mllvm -enable-allobf 依次性啟用上述所有標記

以下是操作步驟,Xcode 10測試,混淆前就不測試了,用Hopper Disassemble開啟的話是可以搜尋到明文的,下面看看混淆操作啟動,而且不一個個測試了,我這裡直接啟用-mllvm -enable-allobf這個選項,全部進行標記

可以看到,混淆之後的反編譯程式碼中沒有了mikejing這些個關鍵字,其他測試可以自行測試下結果。

 

混淆方案三(LLVM Clang外掛  Xcode10我沒成功)

注意:X9可以,X10編譯不過了已經,但是思路如下,可以參考參考

參考文章 B站大神泰戈爾

首先讓我們來看下 LLVM 子專案都有哪些:

1)LLVM Core
提供了一個現代的原始碼和目標獨立優化器, 以及許多流行的 CPU (甚至是一些不太常見的處理器) 的彙編程式碼生成支援。
2)Clang
一個 C/C++/Objective-C 編譯器,致力於提供令人驚訝的快速編譯,極其有用的錯誤和警告資訊,提供一個可用於構建很棒的原始碼級別的工具。
3)dragonegg
GCC 外掛,可將 GCC 的優化和程式碼生成器替換為 LLVM 的相應工具。
4)LLDB
基於LLVM提供的庫和Clang構建的優秀的本地偵錯程式。
5)libc++、libc++ ABI
符合標準的,高效能的C++標準庫實現,以及對 C++11 的完整支援。
6)compiler-rt
針對 __fixunsdfdi 和其他目標機器上沒有一個核心 IR(intermediate representation) 對應的短原生指令序列時,提供高度調優過的底層程式碼生成支援。
7)OpenMP
Clang 中對多平臺並行程式設計的runtime支援。
8)vmkit
基於 LLVM 的 Java 和 .NET 虛擬機器實現
9)polly
支援高級別的迴圈和資料本地化優化支援的 LLVM 框架。
10)libclc
OpenCL 標準庫的實現
11)klee
基於 LLVM 編譯基礎設施的符號化虛擬機器
12)SAFECode
記憶體安全的C/C++編譯器
13)lld
Clang/LLVM 內建的連結器

首先,Clang外掛我在Xcode10上面編寫一直跑不通,權當做做個筆記記錄下流程,網上有個混淆函式相關的,也是通過Clang來做的,如果各位是X10以下,可以試試,我試過X10不行 專案混淆函式

 

Clang 作為 LLVM 提供的編譯器前端,將使用者的原始碼 (C/C++/Objective-C) 編譯成語言/目標裝置無關的IR實現。並且提供良好的外掛支援,容許使用者在編譯時,執行額外的自定義動作。既然能做額外的自定義,那麼我們做字串分析,加密,OS和JS轉換,命名規範,程式碼規範,擴充套件功能都可以實現,這裡就通過Demo簡單實現下第一個Clang外掛步驟,拋磚引玉,各路大神自己寫cpp,實現各種自定義業務邏輯。

1.準備

Clang 需要用 CMake 和 Ninja 來編譯,可以通過 Homebrew 安裝

2.下載LLVM和CLang

Clang 原始碼需要安裝到 llvm/tools 目錄下

mikejingdeMacBook-Pro:~ MKJ$ cd Desktop/
mikejingdeMacBook-Pro:Desktop MKJ$ mkdir 1
mikejingdeMacBook-Pro:Desktop MKJ$ cd 1/
git clone https://git.llvm.org/git/llvm.git/
cd llvm/tools
git clone https://git.llvm.org/git/clang.git/

3.編譯

A。使用Ninja編譯

在 llvm 同級目錄下新建一個 llvm_build 目錄,然後執行以下操作

cd llvm_build
cmake -G Ninja ../llvm -DCMAKE_INSTALL_PREFIX=../llvm_release 

# -DCMAKE_INSTALL_PREFIX 指定 LLVM 的安裝路徑

接著執行 

ninja

ninja install

目錄下llvm_build和llvm_release就是Ninja編譯出來的LLVM Clang

 

B。使用Xcode編譯

在 llvm 同級目錄下新建一個 llvm_Xcode 目錄,然後執行以下操作

cd llvm_xcode 
cmake -G Xcode ../llvm

生成檔案LLVM.xcodeproj,開啟

然後吃飯去吧,吃完飯可能還在編譯。。。。。。

 

4.外掛編寫

這個外掛實現的功能就是,檢測 ObjC 中的類宣告,按照一般的類宣告規範,類名需要駝峰式的拼寫方法,並且類名第一個字母需要大寫,不能有 "_",如果不符合這個規範則需要在編譯過程中提示警告資訊。

1)在 llvm/tools/clang/tools 原始碼目錄下新建一個外掛目錄,假設叫做 MyPlugin,如下圖所示標記 2。

 

2)修改下圖中標記1 CMakeLists.txt 檔案的內容,在最後一行新增如下內容:

3)在 MyPlugin 目錄中新增檔案 MyPlugin.cpp,用於編寫外掛程式碼。

4)在 MyPlugin 目錄中新增檔案 CMakeLists.txt 如圖示記3,並新增如下內容

add_llvm_loadable_module(MyPlugin MyPlugin.cpp)

5)在 MyPlugin.cpp 中編寫如下程式碼:

連結

6)編寫完程式碼後,重新輸入以下命令

# 注意cd到llvm_xcode
cmake -G Xcode ../llvm

7)然後選擇 MyPlugin 這個Target 進行編譯,編譯完後會生成一個動態庫檔案 MyPlugin.dylib(可以在 Products 中找到),為了方便可以把這個檔案放到桌面。

5.使用外掛

1)命令列使用

首先用命令列對單檔案測試一下剛剛生成的 Clang 外掛是否正確,新建一個測試用檔案 test.m 放在桌面,test.m 如下:

@interface ViewController : UIViewController
@end
@implementation ViewController
- (instancetype)init
{
    if(self = [super init]){

    }
    return self;
}
@end

然後把 test.m 檔案和 MyPlugin.dylib 放到桌面的同一個目錄下,

接著命令列 cd 到該目錄,然後執行以下命令:

../1/llvm_build/bin/clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.1.sdk -Xclang -load -Xclang ./MyPlugin.dylib -Xclang -add-plugin -Xclang MyPlugin -c ./test.m

但是Xcode10貌似不如所願,還是隻有這些錯誤,X9做測試就可以

2)Xcode中使用外掛

首先和Harika一樣,需要給外掛系統來個xcplugin(Hack Xcode)下載地址

裡面有 HackedBuildSystem.xcspec 和 HackedClang.xcplugin 兩個檔案,修改一下 HackedClang.xcplugin/Contents/Resources/HackedClang.xcspec 檔案,將 ExecPath 的值修改為你編譯出來的 Clang 的目錄:

BuiltinJambaseRuleName = ProcessC;
ExecPath = "/Users/MKJ/Desktop/1/llvm_build/bin/clang";
UseCPlusPlusCompilerDriverWhenBundlizing = Yes;

然後在解壓的 XcodeHacking 目錄下,執行以下命令將 XcodeHacking 的內容移動到Xcode內:

sudo mv HackedClang.xcplugin/ `xcode-select -print-path`/../PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins


sudo mv HackedBuildSystem.xcspec `xcode-select -print-path`/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Specifications

執行完上述操作後,重啟 Xcode,重啟後修改Xcode的編譯器

點選 Target 的 Build Settings,修改 Compiler for C/C++/Objective-C 項為 Clang LLVM Trunk

然後選擇載入外掛,依舊是Build Settings,搜尋CFLag 新增選項為 如下

-Xclang -load -Xclang /Users/MKJ/Desktop/2/MyPlugin.dylib -Xclang -add-plugin -Xclang MyPlugin

注意,這裡的外掛地址就是我們上面編譯出來移動到的位置地址

X9編譯後就會出現如下報錯資訊,資訊是根據cpp檔案編譯出來dylib所展示,但是X10我試了就炸了,死活過不了

我為了第三個方案的作者 Bilibili 泰戈爾,他說是X9做的,我試過X10編譯不過,本來想請教他一下,可能大神比較忙,沒時間做適配,我自己搞了半天第三個方案死活過不了,希望有空適配下,看下到底思路哪裡有問題。。。

擴充套件閱讀

網上有幾個文章也介紹如何寫Clang外掛,但是為數真的不多,但問題是都是按照X9做的,我估計X10又不行了,但是思路還是在的,就當學習下第三個方案的思路

iOS方法名混淆

基於Clang libTooling外掛編寫自動打點系統方案思路 

 

 

總結下

這方面文章真的不多,我覺得很多我都看了一遍了,按這次介紹的目的混淆來說,其實主要針對馬甲包來說,還有我們自己的主包拿去第三方機構進行安全性評估的時候別人報告上提到的幾個風險漏洞做了深入學習,其中一個就是反編譯明文這個不好的安全漏洞。

1.方案一來講,應該是最容易理解,而且可用性比較高,難度也不大,懂點指令碼,自己寫一下即可,專案中也可以用,Apple也不會為難這種包

2.方案二來講,相對需要LLVM的基礎,不然你完全不知道他在幹什麼,其實就是IR優化pass的編寫,Hirika是OLLVM的進化高階適配版本,多了幾個新功能,具體可以看上面介紹,我們只要整合toolchain,換個預設編譯器名字即可使用,親測X10安全可行,但是issue裡面也有提到,這種包的混淆加固等,現在可能會遭到Apple的拒絕,慎用慎用

3.方案三來講,針對編譯器前段Clang的外掛編寫,Clang前段外掛由於能搞出AST語法數,因此會有很大的操作控制元件,很多外掛也應運而生,但是外掛的注入X9還行,X10我試了幾次一直失敗,希望有大神看到這個,如果能適配X10,希望給個介紹或者Demo交流下,不勝感激

一份小小的學習筆記,算是初步瞭解下LLVM以及一些混淆方案的實踐

 

參考文獻

iOS字串硬編碼混淆

網易LLVM

GCC CLang LLVM對比

LLVM小專欄

objc China

iOS混淆工具對比 

OLLVM在iOS中的實踐

Hikari

2018混淆筆記

馬甲包混淆方案

B戰大神泰戈爾X9的Clang Demo