如何提升代码的安全性 —— 代码混淆
目錄
- 一、背景
- 1.1 Android應(yīng)用安全存在多重隱患
- 二、代碼混淆
- 2.1 代碼混淆的原理
- 2.2 代碼混淆的方法
- 2.3 常見的代碼混淆方式
- 三、 C/C++ 代碼混淆
- 3.1 Obfuscator-LLVM實現(xiàn)C/C++混淆
- 3.1.1 常見的混淆方法
- 3.1.2其他常見的C/C++混淆手段:
- 四、代碼混淆可能帶來的問題
一、背景
1.1 Android應(yīng)用安全存在多重隱患
-
代碼可逆向:客戶端App的邏輯能夠被輕易獲取和逆向,得到代碼和程序中的敏感數(shù)據(jù);
-
功能泄漏:客戶端App中高權(quán)限行為和功能被其他未授權(quán)的應(yīng)用程序調(diào)用訪問;
-
可調(diào)試:客戶端App能夠被調(diào)試,動態(tài)地提取、修改運(yùn)行時的程序數(shù)據(jù)和邏輯;
-
日志信息泄漏:客戶端App將開發(fā)時輔助調(diào)試信息打印泄露,包含敏感參數(shù)等信息;
-
可二次打包:客戶端App可能被修改代碼,重新打包發(fā)布在市場上供用戶下載;
-
密碼學(xué)誤用:客戶端App代碼中使用了不安全的密碼學(xué)實現(xiàn),例如固定硬編碼的對稱加密,ECB模式的對稱加密,CBC模式中IV固定等;
-
敏感信息泄漏:客戶端App代碼中泄漏敏感數(shù)據(jù),如認(rèn)證使用的共享密鑰、不應(yīng)被暴露的后臺服務(wù)器管理地址等;
-
通信數(shù)據(jù)明文傳輸:客戶端App與服務(wù)器端交互的數(shù)據(jù)通過明文的通信信道傳輸,或者加密傳輸,但數(shù)據(jù)依然可以被解密;
移動應(yīng)用代碼安全非常重要,代碼逆向會導(dǎo)致代碼邏輯被獲取,進(jìn)一步導(dǎo)致控制流被hook,安全防線被破,給APP安全帶來巨大風(fēng)險,因此開發(fā)者一般都會進(jìn)行代碼混淆保護(hù)。本文主要介紹了代碼混淆的原理、方法、以及常見代碼混淆的方式和工具。
二、代碼混淆
2.1 代碼混淆的原理
代碼混淆是將計算機(jī)程序的代碼,轉(zhuǎn)換成功能上等價,但是難于閱讀和理解形式的行為。混淆就是對發(fā)布出去的程序進(jìn)行重新組織和處理,使得處理后的代碼與處理前代碼完成相同的功能,而混淆后的代碼很難被反編譯,即使反編譯成功也很難得出程序的真正語義,通過進(jìn)行代碼混淆可以有效提升應(yīng)用被逆向破解的難度。
2.2 代碼混淆的方法
字符串加密:對應(yīng)用程序中使用到的字符串進(jìn)行加密,防止通過IDA等工具獲取關(guān)鍵詞定位核心業(yè)務(wù)代碼;
類名、方法名混淆:將代碼中類名、方法名、屬性名替換為無意義符號,增加代碼逆向難度;將有意義的類,字段、方法名稱更改為無意義的字符串。生成的新名稱越短,字節(jié)代碼越小。在名稱混淆的字節(jié)代碼中,包,類,字段和方法名稱已重命名,并且永遠(yuǎn)不能恢復(fù)原始名稱。不過這種方法混淆后,控制流程仍然清晰可見
程序結(jié)構(gòu)混淆加密:對應(yīng)用程序邏輯結(jié)構(gòu)進(jìn)行打亂混排,保證源碼可讀性降到最低。用于if, switch, while,for等關(guān)鍵字,對字節(jié)碼進(jìn)行細(xì)微的修改,模糊控制流,而不改變代碼在運(yùn)行時的行為。通常情況下,選擇和循環(huán)等邏輯構(gòu)造會被更改。流模糊的字節(jié)碼通常強(qiáng)制反編譯器將一系列標(biāo)簽和非法的goto語句插入到它們生成的源代碼中。源代碼有時會因為反編譯錯誤而變得更加模糊。
2.3 常見的代碼混淆方式
常見的代碼混淆方式包括Java代碼混淆、C/C++代碼混淆以及h5 腳本混淆等。
三、 C/C++ 代碼混淆
下圖為C++代碼的混淆,保護(hù)之后控制流大幅度偽造,逆向難度非常高。當(dāng)然控制流偽造也會影響運(yùn)營效率,所以一般也只是對核心的一些功能做保護(hù)。
混淆的過程中添加的一些字串的保護(hù)如下圖:
介紹一個c/c++代碼混淆工具,逆向?qū)估鳌狶LVM。LLVM不僅僅提供混淆實現(xiàn),通過多重Optimize(優(yōu)化器),實現(xiàn)多種效果,例如代碼控制流扁平化、虛假控制流、字符串加密、符號混淆、指令替換等。
代碼混淆是將計算機(jī)程序的代碼,轉(zhuǎn)換成功能上等價,但是難于閱讀和理解形式的行為。代碼混淆可以有效提升反編譯的難度。
3.1 Obfuscator-LLVM實現(xiàn)C/C++混淆
3.1.1 常見的混淆方法
利用Obfuscator-LLVM工具實現(xiàn)C/C++混淆方法:
-
控制流平坦化:在不改變源代碼功能的前提下,將C、C++等語言中的if、while、for、do等控制語句轉(zhuǎn)化為switch分支選擇語句。控制流平坦化有點(diǎn)像虛擬機(jī)保護(hù),case塊相當(dāng)于vm的handle,case值相當(dāng)于vm的opcode。
-
指令替換:生成條件跳轉(zhuǎn)指令有兩種方法,一種稱為opaque predicate,另一種稱為bogus control flow。
假設(shè)基本塊 偽代碼如下:
block0;opaque predicate指令替換后:
/* opaque predicate 指令替換 */ if (恒等式) {block0; } else {垃圾代碼 } /* 或者另一種方式 */ if (恒不等式) {垃圾代碼 } else {block0; }bogus control flow指令替換后:
if (隨機(jī)條件) {block0; } else {block1; /* 基本塊block1復(fù)制于block0 */ }- 控制流偽造
3.1.2其他常見的C/C++混淆手段:
-
多重分支
-
基本塊分割:把基本塊分成多個基本塊。有兩種方法:一種是根據(jù)概率對基本塊的當(dāng)前指令進(jìn)行分割;另一種是計算基本塊的總指令數(shù),標(biāo)記為a,隨機(jī)生成小于a的數(shù),標(biāo)記為b,基本塊b條指令后進(jìn)行分割,a減掉b,進(jìn)行多次迭代直至a等于1。
-
字符串加密
-
常量隱藏
-
常量展開
-
常量數(shù)組隨機(jī)化:讓常量在數(shù)組中的索引隨機(jī)化。假設(shè)常量數(shù)組a[],索引值i,隨機(jī)生成索引數(shù)組b[]、c[]、d[](可生成更多),循環(huán)用z[b[c[d[i]]]] = a[i]生成隨機(jī)后的常量數(shù)組z[],然后用z[b[c[d[i]]]]替換a[i]。
-
表達(dá)式變換:對邏輯操作not、and、or、xor,可以先把操作數(shù)抽取分成多個更小的數(shù)進(jìn)行操作,最后用or連接起來,當(dāng)然這四個操作可以用與非門或是或非門來完成。還有其它常見的運(yùn)算可以把操作數(shù)看成大數(shù)然后進(jìn)行大數(shù)運(yùn)算,還有一些運(yùn)算可以轉(zhuǎn)變?yōu)镾IMD指令進(jìn)行運(yùn)算。至于浮點(diǎn)數(shù),有很多浮點(diǎn)數(shù)的軟件實現(xiàn)可供參考。
四、代碼混淆可能帶來的問題
被混淆的代碼難于理解,因此調(diào)試以及除錯也變得困難起來。開發(fā)人員通常需要保留原始的未混淆的代碼用于調(diào)試。對于支持反射的語言,代碼混淆有可能與反射發(fā)生沖突。代碼混淆并不能真正阻止反向工程,只能增大其難度。因此,對于對安全性要求很高的場合,僅僅使用代碼混淆并不能保證源代碼的安全。
總結(jié)
以上是生活随笔為你收集整理的如何提升代码的安全性 —— 代码混淆的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Confluence 6 手动备份站点
- 下一篇: 如何进入指定文件目录_Python如何遍