注意:本篇是一個(gè)以方法論為導(dǎo)向的文章袍睡。
Q1:Smali是什么创泄。
Smali是一種寬松式的Jasmin/dedexer語(yǔ)法.
簡(jiǎn)單來(lái)說(shuō)就是我們用java寫(xiě)的代碼編譯成class打包成dex文件后使用baksmali程序逆向回來(lái)的一種語(yǔ)法艺玲。
Q2:為什么要學(xué)習(xí)Smali。
首先鞠抑,提到smali就不得不說(shuō)逆向板驳。早在還沒(méi)有android之前,各大平臺(tái)和語(yǔ)言上就有對(duì)應(yīng)的逆向一說(shuō)碍拆。那么到目前為止若治,逆向一個(gè)apk通常是安全工程師(逆向工程師)和做破解等惡意分子因?yàn)槟承├嬖谧觯╝pk二次打包插入廣告慨蓝、破解收費(fèi)應(yīng)用、惡意代碼植入端幼、剽竊api等)礼烈。
技術(shù)是一把雙刃劍,怎么用在人婆跑。而不在技術(shù)本身上此熬。那么我們說(shuō)為什么應(yīng)用層開(kāi)發(fā)者也要學(xué)smali呢?我能想到以下幾點(diǎn)供參考滑进。
1.借鑒 當(dāng)我們發(fā)現(xiàn)其他應(yīng)用有一個(gè)很牛逼功能犀忱,而我們想不明白如何實(shí)現(xiàn)的時(shí)候。拿不到源碼可以選擇逆向扶关。
2.安全 我們寫(xiě)的app需要考慮安全性阴汇,但是我們可能只知道混淆和第三方加固,需要明白別人是怎么破解我們的應(yīng)用节槐。
3.適配 當(dāng)我們發(fā)現(xiàn)api在某些手機(jī)上被棄用搀庶,而其他應(yīng)用或系統(tǒng)應(yīng)用又能實(shí)現(xiàn)該功能的時(shí)候。關(guān)于這點(diǎn)我之前寫(xiě)過(guò)一篇逆向小米做適配的文章铜异。
喂哥倔,差不多夠了吧?還不能打動(dòng)你學(xué)嗎揍庄?給你升職加薪怎么樣咆蒿? :)
噗,壞蛋B熳印N植狻!缆镣,我學(xué) 我學(xué)芽突,還不行嗎试浙?
Q3:Smali難不難董瞻?
不難。也許你很早之前看過(guò)一些文章田巴∧坪或者也常用一些工具去打開(kāi)反編譯后的代碼∫疾福看著一團(tuán)麻的指令和一些你從未見(jiàn)過(guò)的關(guān)鍵字抄伍、代碼格式風(fēng)格,賴(lài)不住性子就潦草的關(guān)掉了管宵。但實(shí)際上是你沒(méi)有找對(duì)方法來(lái)學(xué)習(xí)它截珍。
Q4:怎么學(xué)
我一向的風(fēng)格都是不愛(ài)把知識(shí)生拉硬套的往腦子里塞攀甚,我更加習(xí)慣從實(shí)踐中去分析,而后反過(guò)來(lái)做總結(jié)「诤恚現(xiàn)在給大家推薦一款好用的Smali學(xué)習(xí)工具插件秋度。我們打開(kāi)AndroidStudio找到插件安裝的位置。如下圖
打開(kāi) Browse Repositories钱床,輸入java2smali安裝重啟即可荚斯。
github地址在這里:intellij-java2smali
這個(gè)步驟以后,我們就可以愉快的將任何java代碼在androidStudio中直接轉(zhuǎn)換成smali來(lái)學(xué)習(xí)里查牌。步驟如下事期。
1.編寫(xiě)一個(gè)最簡(jiǎn)單的java文件。比如下面這樣的纸颜。
然后我們點(diǎn)擊Build->Compile to smali
稍等幾秒鐘后就會(huì)得到smali文件兽泣。
接下來(lái)我們就可以對(duì)照著java代碼來(lái)逐行分析這個(gè)smali文件。如果是第一次看我們可能會(huì)被一些沒(méi)見(jiàn)過(guò)關(guān)鍵字干擾到懂衩。其實(shí)這里有個(gè)很簡(jiǎn)單的辦法撞叨。注意.line關(guān)鍵字就是用來(lái)描述當(dāng)前代碼在java源文件中的行數(shù)。然后你可以通過(guò)對(duì)照兩組代碼的方法進(jìn)行反推浊洞。這樣就可以很輕松的學(xué)會(huì)看smali文件牵敷。
好下面是一個(gè)示例代碼,供參考法希。
示例代碼:
原java代碼
public AA methodAReturn(AA mAA, AA sAA) {
return mAA;
}
AA aa= new AA();
//調(diào)用
methodAReturn(aa, aa);
Smali代碼
.method public methodAReturn(Lcom/bolex/AA;Lcom/bolex/AA;)Lcom/bolex/AA;
.registers 3
.param p1, "mAA" # Lcom/bolex/AA;
.param p2, "sAA" # Lcom/bolex/AA;
.prologue
.line 34
return-object p1
.end method
.line 21
new-instance v0, Lcom/bolex/AA;
invoke-direct {v0}, Lcom/bolex/AA;-><init>()V
.line 22
invoke-virtual {p0, v0, v0}, Lcom/bolex/seamAct;->methodAReturn(Lcom/bolex/AA;Lcom/bolex/AA;)Lcom/bolex/AA;
.line
.line 34
表示當(dāng)前代碼在源java文件中的行數(shù)枷餐。
method
.method public methodAReturn(Lcom/bolex/AA;Lcom/bolex/AA;)Lcom/bolex/AA;
表示來(lái)自公共方法methodAReturn返回值是一個(gè)對(duì)象com.bolex.AA
registers
.registers 3
表示該函數(shù)上需要使用3個(gè)寄存器
param
.param p1, "mAA" # Lcom/bolex/AA;
.param p2, "sAA" # Lcom/bolex/AA;
表示接收兩個(gè)入?yún)⒍际茿A對(duì)象,并標(biāo)記寄存器p1和p2
.prologue
.prologue
表示函數(shù)內(nèi)執(zhí)行的起始標(biāo)記苫亦。直譯為開(kāi)場(chǎng)白的意思毛肋。
.line
.line 34
表示在源代碼中的第34行。
return-object
return-object p1
表示 返回寄存器上p1對(duì)象
.end method
.end method
表示函數(shù)結(jié)束標(biāo)記
new-instance
new-instance v0, Lcom/bolex/AA;
創(chuàng)建一個(gè)AA對(duì)象
invoke-direct
invoke-direct {v0}, Lcom/bolex/AA;-><init>()V
表示使用無(wú)參構(gòu)造方法直接調(diào)用
invoke-virtual
invoke-virtual {p0, v0, v0}, Lcom/bolex/seamAct;->methodAReturn(Lcom/bolex/AA;Lcom/bolex/AA;)Lcom/bolex/AA;
表示為虛擬方法
就是這個(gè)樣子的屋剑,有沒(méi)有很簡(jiǎn)單呢润匙?
以上只舉例了部分關(guān)鍵字,更多的關(guān)鍵字可以自行依賴(lài)兩組文件反推唉匾。其實(shí)有時(shí)候更加講究的是一個(gè)方法孕讳。我覺(jué)得這個(gè)方法就挺不錯(cuò)的,所以就分享給大家咯巍膘,咱也不需要刻意去背下來(lái)厂财。熟能生巧,玩多了豈能不是老司機(jī)峡懈?
關(guān)于smali的知識(shí)還有很多本文并未詳細(xì)闡述璃饱,如寄存器、類(lèi)型(原始類(lèi)型肪康、對(duì)象類(lèi)型)荚恶、數(shù)組方法的表示形式撩穿。如讀者還需要進(jìn)一步深入挖≮撕常可以參考官方文檔冗锁。里面有詳細(xì)的解釋?zhuān)逊g成中文版了。
https://source.android.com/devices/tech/dalvik/dex-format
如何下次找到我?
- 關(guān)注我的簡(jiǎn)書(shū)
- 本篇同步Github倉(cāng)庫(kù):https://github.com/BolexLiu/DevNote (可以關(guān)注)
本文首發(fā)香脆的大雞排 原創(chuàng)文章轉(zhuǎn)載請(qǐng)先取得聯(lián)系嗤栓。