帶你開發(fā)一款給Apk中自動注入代碼工具icodetools(開鑿篇)

一、前言
從這篇開始咋們開始一個全新的靜態(tài)方式逆向工具icodetools的實現(xiàn)過程,這個也是我自己第一次寫的個人覺得比較有用的小工具,特別是在靜態(tài)方式逆向apk找關(guān)鍵點的時候,后續(xù)會分為三篇來詳細(xì)介紹這個工具實現(xiàn):
第一篇:開鑿篇,簡單介紹實現(xiàn)原理以及簡單的初次方案實現(xiàn)簡單的apk注入代碼功能
第二篇:填坑篇,這一篇是在前一篇的基礎(chǔ)上對工具的優(yōu)化,可以應(yīng)對市面上大部分的apk代碼注入功能實現(xiàn)
第三篇:生產(chǎn)篇,這一篇是在前兩篇的基礎(chǔ)上利用這個工具來實際操刀如何進(jìn)行快速定位應(yīng)用的關(guān)鍵方法功能
還記得那一年咋們 靜態(tài)方式破解應(yīng)用,為了更好的追蹤代碼位置,手動反編譯成smali文件,然后添加smali日志代碼,在回編譯,查看日志信息來定位關(guān)鍵點。那種操作現(xiàn)在回想是苦不堪言,操作非常復(fù)雜。那么就嘗試想想如果有一個工具可以在自動為每個方法注入日志代碼,這樣就可以很快速的定位到我們想要的方法,所以本文就來介紹一下這個工具的實現(xiàn)原理,我將其命名為icodetools

二、實現(xiàn)方案
首先咋們來看一下具體實現(xiàn)原理吧,這個工具最終的形態(tài)應(yīng)該是這樣的,就是輸入一個apk,然后在為apk中每個類的每個方法添加一段打印此方法的堆棧信息日志,然后在重新簽名打包成新的apk。所以這個過程中我們最關(guān)鍵的地方就是如何把日志代碼插入到已經(jīng)編譯好的apk中。我們可能想到的有兩個方案:
第一個方案:首先利用apktool進(jìn)行反編譯成smali文件,然后解析smali文件找到每個方法的位置,添加指定smali日志代碼。那么這里有一個很大的問題,就是如何分析smali文件,如何定位到每個方法?這個過程工作量就比較大了,所以這個方案就廢棄了。
第二個方案:利用dex2jar獲取到apk中的dex轉(zhuǎn)化之后的jar文件,然后在解析jar文件獲取到每個class文件,解析class文件進(jìn)行方法的信息獲取。這里會發(fā)現(xiàn)這個方案很靠譜,因為我們解析class文件比解析smali文件方便多了。而且在這個過程中會發(fā)現(xiàn)有一個更大的驚喜,就是dex2jar這個工具是開源的,其實內(nèi)部實現(xiàn)原理就是解析dex文件格式,然后借助asm工具將其變成class文件的,這里又出現(xiàn)了一個非常重要的工具asm,這個工具下面會詳細(xì)介紹。
說明:
1》這里非常感謝dex2jar的作者Claud大神的開源精神,這個工具的地址:https://github.com/pxb1988/dex2jar,是純java代碼,所以大家一定要先解讀這個工具源碼,內(nèi)部實現(xiàn)原理自己研讀,本文不會詳細(xì)介紹的。
2》這里有的同學(xué)會想到,能不能直接解析dex文件格式,然后在找到每個類的每個方法添加日志信息,雖然我們在前面有詳細(xì)介紹dex文件格式:Dex文件格式詳解,但是如果想在每個類每個方法中添加日志代碼這個工作量感覺比操作smali還要復(fù)雜,所以直接將其轉(zhuǎn)化成class文件進(jìn)行操作就非常方便了,因為我們有asm工具。
三、方案實現(xiàn)
上面已經(jīng)探討了方案了,在上面提到了很多次一個非常重要的工具就是asm,那么這個工具到底是干嘛的呢?這個工具非常有用,他的表現(xiàn)之處在JavaWeb開發(fā)中的Spring框架就有用到,可以動態(tài)的解析class文件,然后可以操作這個類,比如添加類成員,方法等等操作。所以下面不多解釋了,直接用一個簡單的案例來看看他的強(qiáng)大之處,我們實現(xiàn)給一個類添加一個成員字段,方法,給每個方法調(diào)用前添加一行代碼。
第一、asm庫基本使用


這里借助ClassReader來讀取一個類,使用ClassVisitor來進(jìn)行類信息操作,ClassWriter將操作完之后的類寫入文件中
第二、添加類成員字段
上面看到了一個主要的類ClassVistor,他主要就是用來操作一個類:

這里看到的是繼承了ClassAdapter,然后在構(gòu)造方法中可以添加類成員信息包括字段,方法等,這里我們添加一個字段mJW,類型是String的??纯慈绾翁砑拥模?br>

借助ClassVisitor的visitField方法就可以進(jìn)行字段的添加了。然后我們運(yùn)行程序之后,使用JD-GUI工具查看保存本地的class文件信息:

看到了吧,這里成功的定義了一個字段mJW。

第三、為類的所有方法前添加代碼
這里我們需要借助另外一個類了MethodVisitor了,他是用來操作方法信息的:


在ClassAdapter的visitMethod回調(diào)方法中可以獲取方法信息,然后進(jìn)行操作:

在visitCode回調(diào)方法中利用MethodVisitor開始添加代碼:

這里看到可以利用visitFieldInsn方法方法System類的靜態(tài)變量out,然后在使用visitLdcInsn從常量池中獲取值,最后在利用visitMethodInsn方法來調(diào)用PrintStream類的成員方法println來打印信息,運(yùn)行程序之后繼續(xù)借助JD-GUI來查看class文件:

看到了,類中所有的方法前面都被加了一行打印代碼。
注意:有的同學(xué)發(fā)現(xiàn)了,上面那個添加代碼怎么得到呢?難道真的要記住那么多api去添加嗎?其實不用那么復(fù)雜,Eclipse有一個插件Bytecode,可以把Java代碼自動生成類似于上面的代碼,咋們之后手動拷貝一下就好了!工具后面會說。

第四、為類添加成員方法
下面在來看最后一個操作吧,就是給類中添加一個成員方法,有了上面的操作之后我們應(yīng)該知道,如果要操作類就要借助ClassVisitor類,要是操作方法就需要借助MethodVisitor類,那么這里為類添加成員方法,借助ClassVistor類來進(jìn)行操作了,但是在操作之前咋們得先搞好一個工具Bytecode,這個是Eclipse插件,安裝很簡單:



安裝完成之后,可以打開視圖欄:



然后選擇Java中的bytecode視圖就可以了:

下面咋們首先在一個類中編寫好我們想要添加的方法代碼,然后點擊Bytecode視圖卡片就可以看到對應(yīng)的asm代碼:

看到了吧,這樣操作是不是如此簡單,我們可以把這段asm代碼直接拷貝到AsmUtils中:



然后在ClassVisitor的構(gòu)造方法中直接調(diào)用這個方法就可以了:

再次運(yùn)行程序之后,使用JD-GUI查看類信息:

成功的添加了printStackTrace方法了。就是如此簡單。借助Eclipse的強(qiáng)大工具Bytecode就可以了,以后都不要在自己去調(diào)用asm庫的api去手動編寫了。這個工具太好了得記住它!

四、工具案例實踐
上面就介紹完了如何操作一個類和方法,給類添加字段,方法,在每個方法之前添加一行代碼。下面就得進(jìn)入本文的主題了,如何給apk應(yīng)用中每個類中的每個方法添加一行打印日志信息。在開始的時候我們有了方法,就是借助工具dex2jar源碼,他內(nèi)部也是解析dex格式,然后利用asm將其信息變成一個class文件的,那么我們只要在這個過程中得到ClassVisitor和MethodVisitor這兩個對象,就可以盡情的干很多事了。所以第一步你一定要先看懂dex2jar的源碼。這里我不會對源碼進(jìn)行詳細(xì)分析了,用過dex2jar工具的都知道,找入口很簡單,直接看他的一個d2j-dex2jar.bat腳本信息:


Dex2jarCmd就是工具的入口類:

然后分析代碼,會發(fā)現(xiàn)處理的核心類是Dex2jar類:

這里會看到可以拿到ClassVisitor類對象的,那么我就可以添加打印堆棧信息的方法了:

這里需要注意的是打印消息用了Android的Log.d方法。然后在每個方法調(diào)用之前在調(diào)用這個打印方法:

這里過濾依然過濾了構(gòu)造方法和靜態(tài)代碼塊方法。

其實我們就需要這么做就可以了,下面咋們就用一個簡單的Apk來做一下實驗,咋們把a(bǔ)pk中的classes.dex文件解壓出來,為了簡單直接跑這個dex2jar工具,可以在Dex2jarCmd開始處構(gòu)造一個簡單的命令:


輸入的dex文件為指定目錄的,輸出的jar文件也是指定目錄的:

然后咋們就可以運(yùn)行程序了。運(yùn)行結(jié)束之后我們得到了一個classes.jar文件,可以使用JD-GUI進(jìn)行查看:

到這里我們就成功的,把a(bǔ)pk中的classes.dex中的每個類每個方法添加了我們自己的打印消息的代碼了,已經(jīng)成功一大半了,下面為了驗證效果,咋們還得把classes.jar轉(zhuǎn)成dex,在弄到apk中運(yùn)行看效果。這個過程就簡單了,利用系統(tǒng)的dx命令,把classes.jar在變成classes.dex文件:

然后在把這個classes.dex文件塞到apk中,不過這時候得重新簽名了,可以借助jarsigner工具:
jarsigner -verbose -keystore cyy_game.keystore -storepass cyy1888 -signedjar signed.apk unsigned.apk cyy_game.keystore -digestalg SHA1 -sigalg MD5withRSA
然后咋們就可以安裝apk,然后開始運(yùn)行效果:

看到效果了吧,表示成功的不要不要的。有點小興奮,通過棧信息加上我們出發(fā)一個事件之后就可以定位這個事件的方法了。對于我們在使用hook的時候?qū)ふ襤ook點非常重要。

五、技術(shù)總結(jié)
到這里我們本文的知識點就算結(jié)束了,但是整個工具開發(fā)并沒有結(jié)束,下面就來總結(jié)一下本文涉及到的知識點:
1、學(xué)會了利用asm庫來操作類,實現(xiàn)添加字段,方法等操作。
2、了解到了Eclipse的一個強(qiáng)大插件Bytecode,可以快速得到j(luò)ava代碼對應(yīng)的asm代碼
3、了解了dex2jar的實現(xiàn)原理,內(nèi)部也是借助于asm來進(jìn)行操作的
其實本文的這個自動注入代碼工具絕大部分是借助了dex2jar這個工具的,我們只是在適當(dāng)?shù)牡胤教砑恿宋覀兿胍男畔⒋a。在操作類的時候只要有ClassVisitor對象就可以操作類,MethodVisitor對象就可以操作方法了。而在dex2jar中正好有這兩個對象,所以我們實際要操作的內(nèi)容并不復(fù)雜。當(dāng)我們使用通過修改之后的dex2jar得到了classes.jar之后,在用dx工具將其還原成classes.dex文件,在放到apk中進(jìn)行重簽名驗證。

六、遺留的問題
如果到這里有的同學(xué)覺得這個是挺簡單的,那其實就錯了,因為開始的時候我已經(jīng)說了后面還有一個填坑篇文章,在那篇文章會詳細(xì)說明在實際操作其他企業(yè)app會遇到哪些問題,我們需要繼續(xù)優(yōu)化這個工具,同時對這個工具最好能夠做到一鍵化工作,所以我們需要解決這幾個問題:
1、上面看到我們是為每個類添加了一個打印棧信息的方法,那么就有一個很大的問題,如果一個dex文件過大,包含的類很多,那么就是增加了很多方法,對于dx進(jìn)行轉(zhuǎn)化的時候會發(fā)現(xiàn)方法數(shù)超了。
2、在實際的apk操作過程中會發(fā)現(xiàn)在每個方法中插入日志之后,當(dāng)你啟動app的時候那日志幾乎會被霸屏的,而且一個龐大的app內(nèi)部調(diào)用的方法非常多,導(dǎo)致應(yīng)用會出現(xiàn)無響應(yīng)狀態(tài),所以咋們得弄個開關(guān)以及想在哪些方法中添加。
3、上面在看到在整個過程中,先把dex轉(zhuǎn)成jar,然后再把jar轉(zhuǎn)成dex,在放到apk中,在簽名,整個過程我們都是手動操作的,顯得非常的費(fèi)勁,所以我們還得優(yōu)化這個工作,做到真正意義上的一鍵化,輸入一個apk,輸入就是已經(jīng)添加日志信息的apk就可以了。

所以后面一個填坑篇文章會有很多工作要做的,當(dāng)坑都填完了,咋們就得實際生產(chǎn)拿一些app進(jìn)行實戰(zhàn)操刀了。最后在來看一下我總結(jié)的一張原理圖吧(可以點擊查看高清大圖):

嚴(yán)重說明:
===》本文介紹的是基礎(chǔ)篇,可以看到我們是大致走通了整個流程,但是這個和最終的工具實現(xiàn)差的很多,后續(xù)還有很多問題需要解決,所以重點其實在下一篇中,那里會去解決在實際使用過程中遇到的各個問題。以及最重要的就是如何把所有的步驟連貫起來,一鍵化開發(fā)完善。一定要記得看下一篇內(nèi)容,那里才是主戰(zhàn)場!
===》一定要自己去github上下載dex2jar的源碼,自己先調(diào)試走通程序,不然一切都是枉然,因為這個工具是純Java編寫的,代碼不是很多,所以難度不大。

七、總結(jié)
對于這個自動插入代碼的工具我個人覺得有需求采取這么干的,因為以前遭受過那種手動注入代碼的痛苦,但是從本文的工具可以看到,對于一些加固app是無能無力的。而工具的理念來源是美團(tuán)的一個熱修復(fù)框架Robust的。關(guān)于源碼的話等后面都介紹完了,我把我寫的部分公開,但是你還是得先去看看dex2jar的源碼。又開始了寫這種文章,每次寫完感覺自己身體被掏空了一樣,多多點贊。打賞就在好不過了。

更多內(nèi)容:點擊這里

關(guān)注微信公眾號,最新技術(shù)干貨實時推送


掃一掃加小編微信添加時注明:“編碼美麗”否則不予通過!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,536評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內(nèi)容