Android中实现「类方法指令抽取方式」加固方案原理解析
一、前言
Android中加固方案一直在進(jìn)步,因?yàn)樾碌募庸谭桨赋鰜砭蜁?huì)被人無情的破解脫殼了,從第一代加固方案落地加密dex文件,第二代加固方案不落地加密dex文件,在到第三代加固方案類方法抽取,以后后面的更多加固方案來說都是安全的進(jìn)步,關(guān)于脫殼方案網(wǎng)上有很多資料,但是加固方案卻沒多少資料,因?yàn)橛行┘庸谭桨甘且恍┘庸坦镜纳虡I(yè)機(jī)密不可泄露的,所以我們現(xiàn)在看到的網(wǎng)上加固方案還是以前的加固方案,不了解以前的加固方案同學(xué),可以看我寫的逆向大黃書「Android應(yīng)用安全防護(hù)和逆向分析」,而本文就來介紹如何實(shí)現(xiàn)類方法抽取方案來實(shí)現(xiàn)應(yīng)用加固。
二、指令抽取方案
首先不多說,這種方案依賴的技術(shù)就是攔截系統(tǒng)的加載類函數(shù),然后進(jìn)行類方法指令還原。所以這個(gè)技術(shù)必須了解,好在我們?cè)谥耙黄恼轮幸呀?jīng)詳細(xì)介紹了如何在native層攔截系統(tǒng)函數(shù)實(shí)現(xiàn)應(yīng)用方法指令篡改,不了解的同學(xué)可以看這篇文章:Android中Hook系統(tǒng)函數(shù)實(shí)現(xiàn)運(yùn)行時(shí)態(tài)篡改方法執(zhí)行邏輯;本文的技術(shù)是依賴于這篇文章,如果這篇文章沒看明白,那么本文將很難看懂。一定要先看這篇文章。不多說了,我們?cè)诮榻B加固方案主要從兩方面入手,一方面是如何進(jìn)行指令抽取,一方面是如何進(jìn)行指令還原,所以下面先來介紹如何進(jìn)行類方法的指令抽取功能。
我們還是先用之前的工程作為案例:
在這個(gè)類中,我們定義了一個(gè)獲取密碼的方法:
現(xiàn)在為了安全,我們將這個(gè)方法信息置空,可以先用010Editor工具查看這個(gè)方法的指令信息:
看到這個(gè)方法包含了3個(gè)指令,那么我們?nèi)绾螌⑵湓O(shè)置成0呢?這里就需要自己寫個(gè)工具了,因?yàn)槲覀儾荒芤蕾囉谶@個(gè)工具手動(dòng)去置空,那就太不智能了。這個(gè)就需要借助之前介紹dex文件格式解析的時(shí)候那個(gè)源碼了。我們需要做一下改動(dòng)就可以實(shí)現(xiàn)這個(gè)功能。dex文件格式解析源碼下載地址:https://github.com/fourbrother/parse_androiddex;是個(gè)java工程,下載之后直接導(dǎo)入Eclipse即可。代碼邏輯不做分析了,不了解的同學(xué)看之前的一篇文章:Android逆向之旅---解析編譯之后的Dex文件格式;我們的目的就是想置空指定方法的的指令數(shù)據(jù),那么直接去解析方法指令的那塊邏輯即可:
這里在解析代碼結(jié)構(gòu)的時(shí)候,對(duì)類方法和對(duì)象方法的代碼結(jié)構(gòu)體信息,進(jìn)行保存,用到的是map結(jié)構(gòu),而key值就必須用方法的唯一簽名信息,這樣后面會(huì)通過具體的方法簽名信息獲取到該方法對(duì)應(yīng)的代碼結(jié)構(gòu)體信息,然后進(jìn)行操作:
這里通過解析完dex文件格式之后:在通過指定類的指定方法檢索到其代碼結(jié)構(gòu)體信息,然后拿到指令個(gè)數(shù)和指令的偏移地址,構(gòu)造一個(gè)空指令集,覆蓋原始指令。最后重新計(jì)算文件的checksum和signature值,回寫回去。這里最后一步非常重要,如果dex文件的checksum和signature值不正確,dex文件就是失效的。沒任何意義了加載也是失敗。下面在來詳細(xì)看一下這兩個(gè)值的計(jì)算方法:
這兩個(gè)值的計(jì)算方法很簡單,我們可以從系統(tǒng)源碼查看[Android源碼目錄/dalvik/libdex/DexFile.cpp]中,首先看看checksum的計(jì)算方法:
整個(gè)dex文件去除頭部中的magic和checksum共12個(gè)字節(jié),余下的內(nèi)容計(jì)算crc即可。而signature的計(jì)算方法:
對(duì)整個(gè)dex文件,去除頭部信息中的magic,checksum,signature共32個(gè)字節(jié),余下的內(nèi)容做sha1計(jì)算即可。最終都要回寫到文件中的頭部信息,我們可以利用010Editor查看:
這樣我們就一氣呵成,利用自己寫的工具對(duì)指定方法進(jìn)行指令置空:先解析原始dex文件格式,保存所有類的所有方法的代碼結(jié)構(gòu)體信息,然后通過傳入的方法簽名信息檢索到其代碼結(jié)構(gòu)體信息,在獲取其指令個(gè)數(shù)和指令偏移地址,構(gòu)造出同數(shù)量的空指令集,覆蓋原始指令實(shí)現(xiàn)置空。最后一步非常關(guān)鍵,就是需要重新計(jì)算dex文件的checksum和signature信息回寫到頭部信息中。
下面我們就用上面的CoreDex工程編譯出來的dex文件作為案例,借助這個(gè)工具,將CoreUtils.getPwd方法指令置空,然后用IDA工具進(jìn)行查看:
不相信的話,我們?cè)诶^續(xù)用Jadx工具進(jìn)行查看:
這個(gè)方法就是個(gè)空方法了,到這里我們抽空方法指令的功能就完成了,下面繼續(xù)來看如何進(jìn)行還原指令。
三、指令還原
還原指令就簡單了,直接借助之前那個(gè)篡改內(nèi)存指令的代碼即可,在native層hook系統(tǒng)函數(shù)dexFindClass,然后進(jìn)行類的方法名過濾,獲取指定方法的代碼結(jié)構(gòu)體,修改指令內(nèi)存塊為可讀屬性,然后把指令還原即可:
這里為了簡單,就把原始指令保存在native中,然后直接還原了。到這里我們還原指令的邏輯也完成了,下面就運(yùn)行項(xiàng)目看看日志和效果,先把之前抽取指令的dex文件拷貝到SD卡中,然后用這個(gè)工程進(jìn)行動(dòng)態(tài)加載運(yùn)行看看效果:
這里看到了,dex中的指令的確被抽取置空了,然后我們也還原成功了,方法執(zhí)行也有結(jié)果了:
四、流程總結(jié)
到這里我們就介紹完了本文內(nèi)容,下面來總結(jié)一下流程:
第一、抽取指令流程
1、解析原始dex文件格式,保存所有方法的代碼結(jié)構(gòu)體信息。
2、通過傳入需要置空指令的方法和類名,檢索到其代碼結(jié)構(gòu)體信息。
3、通過方法的代碼結(jié)構(gòu)體信息獲取指令個(gè)數(shù)和偏移地址,構(gòu)造空指令集,然后覆蓋原始指令。
4、重新計(jì)算dex文件的checksum和signature信息,回寫到頭部信息中。
第二、指令還原流程
1、native層hook系統(tǒng)函數(shù)dexFindClass,獲取類結(jié)構(gòu)體信息。
2、獲取類中所有的方法信息,通過指定方法名進(jìn)行過濾,獲取該方法的代碼結(jié)構(gòu)體信息。
3、獲取該方法被抽取的指令集,修改方法對(duì)應(yīng)的內(nèi)存地址為可讀屬性,直接進(jìn)行指令還原。
在這個(gè)過程中,抽取指令需要借助編寫的工具,當(dāng)然工具可以進(jìn)行深入優(yōu)化。可以留給你們進(jìn)行完善。對(duì)于還原指令中,如何保存抽取指令并沒有介紹,這部分內(nèi)容可以后續(xù)完善優(yōu)化,比如我們可以將抽取的指令再做一次加密保存到程序中的某個(gè)地方,在指令還原的時(shí)候去這個(gè)文件進(jìn)行讀取解密即可。下面來看看整個(gè)流程圖:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
本文涉及到的代碼項(xiàng)目可以去編碼美麗小密圈自取,歡迎加入小密圈一起學(xué)習(xí)探討技術(shù)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
五、總結(jié)
在之前的兩代加固方案中,我們都可以攔截系統(tǒng)解析dex的函數(shù)或者IDA動(dòng)態(tài)調(diào)試來dump出解密后的dex文件,那個(gè)依賴的核心就是不管dex文件怎么加密,最終都是需要解密加載到內(nèi)存中運(yùn)行的。但是這種類方法信息抽取加固方案就可以解決dump出內(nèi)存的dex文件的問題。因?yàn)槲覀兪窃诜椒ǔ绦蜻\(yùn)行的時(shí)候進(jìn)行指令還原,所以在此之前dump出的dex文件都是被抽取指令的,其實(shí)沒什么意義了。所以后面結(jié)合native層對(duì)抽取指令加密等更強(qiáng)的安全防護(hù),這種加固方案還是可取的。
不過遺憾的是,這種加固方案并不是完美的,畢竟沒有絕對(duì)的安全可言,我們可以看到在還原指令的時(shí)候是攔截系統(tǒng)函數(shù)做到的,那么破解的人也可以攔截這個(gè)系統(tǒng)函數(shù),他在你已經(jīng)還原成功之后在獲取類信息,然后重組dex文件,這樣就可以完美的還原原始dex文件了。不過這個(gè)破解難度就會(huì)增大了。
?
總結(jié)
以上是生活随笔為你收集整理的Android中实现「类方法指令抽取方式」加固方案原理解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Studio中进行单元测
- 下一篇: android如何创建进度条,Andro