第一篇:[轉(zhuǎn)]Android逆向之動(dòng)態(tài)調(diào)試總結(jié) 神乎
[轉(zhuǎn)]Android逆向之動(dòng)態(tài)調(diào)試總結(jié)
神乎
一、在SO中關(guān)鍵函數(shù)上下斷點(diǎn)
剛學(xué)逆向調(diào)試時(shí)。大多都滿足于在SO中某關(guān)鍵函數(shù)上下斷點(diǎn)。然后通過(guò)操作應(yīng)用程序,去觸發(fā)這個(gè)斷點(diǎn),然后進(jìn)行調(diào)試
詳細(xì)的步驟可以參見(jiàn)非蟲(chóng)大大的《Android軟件安全與逆向分析》
簡(jiǎn)單說(shuō):在libsyclover.so文件中有一個(gè)函數(shù)jnicall1。每次單擊按鈕的時(shí)候,便會(huì)調(diào)用此函數(shù)。
1.靜態(tài)載入此so文件,找到函數(shù)的偏移地址為:0x132C2.執(zhí)行android_server3.端口轉(zhuǎn)發(fā) adb forward tcp:23946 tcp:23946 4.運(yùn)行程序 5.IDA附加
然后會(huì)彈出
點(diǎn)擊OK之后,在彈出的列表框中選擇需要附加的進(jìn)程即可 6.下斷點(diǎn)
附加完成之后,會(huì)停在libc.so這個(gè)模塊中。此時(shí)按下Ctrl + S,彈出模塊列表框,搜索so文件名。
記錄下基地址:0×76072000(RX權(quán)限)
和靜態(tài)分析時(shí)得到的偏移地址0x132C相加得到0x7607332C
G跳轉(zhuǎn)到此位置
F2下好斷點(diǎn)!7.觸發(fā)斷點(diǎn)
下好斷點(diǎn),便F9執(zhí)行,此時(shí)狀態(tài)是runing
此時(shí),去應(yīng)用中單擊按鈕,程序便會(huì)斷在剛剛下好的斷點(diǎn)處~
ok~ 這種調(diào)試方法局限性很大,適合于比較初級(jí)的調(diào)試。這種調(diào)試手法在現(xiàn)在已經(jīng)滿足不了需求了。
二、在JNI_OnLoad函數(shù)上下斷點(diǎn)
JNI_OnLoad函數(shù)大概功能就是在程序加載so的時(shí)候,會(huì)執(zhí)行JNI_OnLoad函數(shù),做一系列的準(zhǔn)備工作。
很多時(shí)候,程序猿們會(huì)將一些重要信息放在此函數(shù)中,而不是通過(guò)某種事件來(lái)重復(fù)觸發(fā)。包括說(shuō)將反調(diào)試函數(shù)放置在此函數(shù)中。因此,調(diào)試手段發(fā)生了改變,上述調(diào)試方法基本上被淘汰。
1.靜態(tài)分析,找到JNI_OnLoad函數(shù)的偏移:0×1504
2.執(zhí)行android_server3.端口轉(zhuǎn)發(fā) adb forward tcp:23946 tcp:23946 4.以調(diào)試模式啟動(dòng)程序 adb shell am start-D-n com.example.mytestcm/.MainActivity
此時(shí),手機(jī)界面會(huì)出現(xiàn)Waiting For Debugger頁(yè)面 5.打開(kāi)ddms或者Eclipse(必要,為了使用jdb命令)6.IDA附加 7.設(shè)置調(diào)試選項(xiàng)
Debugger — Debugger Options
8.F9運(yùn)行程序
IDA中,F(xiàn)9運(yùn)行程序,此時(shí)是runing狀態(tài)。
在命令行中執(zhí)行:jdb-connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700其中port=8700是從ddms中看到的。
此時(shí)程序會(huì)斷下來(lái) 9.下斷點(diǎn)
Ctrl + S 然后搜索到so文件名
記錄下基地址是:0×76118000
加上JNI_OnLoad函數(shù)的偏移地址0×1504為0×76119504
G跳轉(zhuǎn)到0×76119504,下斷點(diǎn)
A.觸發(fā)斷點(diǎn)
下好斷點(diǎn)之后,直接F9運(yùn)行吧,就能斷在JNI_OnLoad函數(shù)處~
當(dāng)這種調(diào)試手法出現(xiàn)之后,將特殊函數(shù),或者反調(diào)試函數(shù)放在JNI_OnLoad中也不是那么的安全了。此時(shí),程序猿們通過(guò)分析系統(tǒng)對(duì)SO文件的加載鏈接過(guò)程發(fā)現(xiàn),JNI_OnLoad函數(shù)并不是最開(kāi)始執(zhí)行的。在JNI_OnLoad函數(shù)執(zhí)行之前,還會(huì)執(zhí)行init段和init_array中的一系列函數(shù)。
因此,現(xiàn)在的調(diào)試方法,都是將斷點(diǎn)下在init_array中~
至于下斷點(diǎn)的方法,可以類比于在JNI_OnLoad中下斷點(diǎn)的方法,在init_array的函數(shù)中下斷點(diǎn)。還有一種方法便是通過(guò)在linker模塊中,通過(guò)對(duì)其中函數(shù)下斷點(diǎn),然后也能單步到init_array中下面便詳細(xì)介紹下如何給任意系統(tǒng)函數(shù)下斷點(diǎn)
三、給任意系統(tǒng)函數(shù)下斷點(diǎn) 1.需要準(zhǔn)備的有:
與你調(diào)試環(huán)境一致的系統(tǒng)源碼,這個(gè)也可以在http://androidxref.com/網(wǎng)站上在線查閱。
root之后的手機(jī),方便將系統(tǒng)的一些so文件dump至本地,靜態(tài)獲取到系統(tǒng)函數(shù)的偏移地址 2.流程
執(zhí)行android_server
端口轉(zhuǎn)發(fā) adb forward tcp:23946 tcp:23946 調(diào)試模式啟動(dòng)程序 adb shell am start-D-n 包名/類名
IDA附加
靜態(tài)找到目標(biāo)函數(shù)對(duì)應(yīng)所在模塊的偏移地址
Ctrl+S找到對(duì)應(yīng)模塊的基地址,兩個(gè)地址相加得到最終地址
G跳轉(zhuǎn)至地址,然后下斷
F9運(yùn)行
執(zhí)行jdb-connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
斷下,進(jìn)行調(diào)試
四、在dvmDexFileOpenPartial函數(shù)下斷點(diǎn),dump出明文dex 發(fā)展至今,從去年到現(xiàn)在,apk的加解密發(fā)展非常迅速。國(guó)內(nèi)出現(xiàn)了很多針對(duì)apk的加殼保護(hù)方案。主要也體現(xiàn)在對(duì)dex的保護(hù)和對(duì)so的保護(hù)!針對(duì)dex的保護(hù),很長(zhǎng)一段時(shí)間,都能通過(guò)對(duì)dvmDexFileOpenPartial函數(shù)下斷點(diǎn),從而dump出明文dex文件。
以這次alictf的第三題為例子,展示下如何對(duì)dvmDexFileOpenPartial函數(shù)下斷點(diǎn)!
其他步驟都是一樣的,這兒主要說(shuō)下如何找到dvmDexFileOpenPartial函數(shù)位置
1.查看源碼
dvmDexFileOpenPartial函數(shù)在rewriteDex這個(gè)函數(shù)中被調(diào)用。
可以看到關(guān)鍵字符串信息是:Unable to create DexFile
此時(shí),從手機(jī)的/system/lib目錄下得到libdvm.so 2.載入IDA,搜索字符串:Unable to create DexFile
得到偏移地址是:0x0005AE8A 3.下斷點(diǎn)
搜索模塊libdvm.so
基地址是0×41492000
加上偏移地址為0x414ECE8A
G跳轉(zhuǎn)至此位置,下好斷點(diǎn),即可 4.dump明文dex文件
下好斷點(diǎn)之后,F(xiàn)9運(yùn)行,執(zhí)行jdb-connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
程序斷下
此時(shí),看到寄存器窗口中的值為:
R0保存dex的起始地址,R1便是dex的長(zhǎng)度
直接dump即可!5.后續(xù)
dump出來(lái)的dex就可以進(jìn)行反編。
效果如下:
五、寫在最后
隨著現(xiàn)在技術(shù)的發(fā)展,對(duì)apk的保護(hù)是越來(lái)越好!大大增加了逆向分析人員的分析難度。同時(shí),在整個(gè)攻防的過(guò)程中,對(duì)攻防兩端的人都帶來(lái)了非常棒體驗(yàn)。雙方都取得了長(zhǎng)足的進(jìn)步!
也促使了整個(gè)加固方向水平的提升!
其中,動(dòng)態(tài)調(diào)試手法在整個(gè)過(guò)程中是必不可少的。
第二篇:Android之a(chǎn)ctivity總結(jié)——轉(zhuǎn)自論壇
Android之a(chǎn)ctivity總結(jié)——轉(zhuǎn)自論壇
一、什么是activity Activity 是用戶接口程序,原則上它會(huì)提供給用戶一個(gè)交互式的接口功能。它是 android 應(yīng)用程序的基本功能單元。Activity 本身是沒(méi)有界面的。所以activity類創(chuàng)建了一個(gè)窗口,開(kāi)發(fā)人員可以通過(guò)setContentView(View)接口把UI放到activity創(chuàng)建的窗口上,當(dāng)activity指向全屏窗口時(shí),也可以用其他方式實(shí)現(xiàn):作為漂浮窗口(通過(guò)windowIsFloating的主題集合),或者嵌入到其他的activity(使用ActivityGroup)。activity是單獨(dú)的,用于處理用戶操作。幾乎所有的activity都要和用戶打交道,二、activity生命周期
2011-11-20 20:23:32 上傳 下載附件(64.6 KB)由圖可知:
在一個(gè)Activity正常啟動(dòng)過(guò)程中,這些方法調(diào)用的順序是onCreate-> onStart-> onResume;在Activity被kill掉的時(shí)候方法順序是onPause-> onStop-> onDestroy,此為一個(gè)完整的Lifecycle。那么對(duì)于中斷處理(比如電話來(lái)了),則是onPause-> onStop,恢復(fù)時(shí)onStart-> onResume;如果當(dāng)前應(yīng)用程序的是一個(gè)Theme為Translucent(半透明)或者Dialog 的Activity那么中斷就是onPause ,恢復(fù)的時(shí)候onResume。
那么對(duì)于”O(jiān)ther app need memory”,就是我們手機(jī)在運(yùn)行一個(gè)應(yīng)用程序的時(shí)候,有可能打進(jìn)來(lái)電話發(fā)進(jìn)來(lái)短信,或者沒(méi)有電了,這時(shí)候程序都會(huì)被中斷,優(yōu)先去服務(wù)電話的基本功能,另外系統(tǒng)也不允許你占用太多資源,至少要保證一些功能(比如電話),所以資源不足的時(shí)候也就有可能被kill掉。方法在系統(tǒng)中的作用及我們應(yīng)該做什么:
onCreate:在這里創(chuàng)建界面,做一些數(shù)據(jù)的初始化工作;
onStart: 到這一步變成“用戶可見(jiàn)不可交互”的狀態(tài);
onResume:變成和用戶可交互的,(在Activity棧系統(tǒng)通過(guò)棧的方式管理這些Activity,即當(dāng)前Activity在棧的最上端,運(yùn)行完彈出棧,則回到上一個(gè)Activity);
onPause:到這一步是可見(jiàn)但不可交互的,系統(tǒng)會(huì)停止動(dòng)畫等消耗CPU的事情。從上文的描述已經(jīng)知道,應(yīng)該在這里保存你的一些數(shù)據(jù),因?yàn)檫@個(gè)時(shí)候你的程序的優(yōu)先級(jí)降
低,有可能被系統(tǒng)收回。在這里保存的數(shù)據(jù),應(yīng)該在onResume里讀出來(lái)。
onStop:變得不可見(jiàn),被下一個(gè)activity覆蓋了
onDestroy:這是Activity被kill前最后一個(gè)被調(diào)用方法了,可能是其他類調(diào)用finish方法或者是系統(tǒng)為了節(jié)省空間將它暫時(shí)性的干掉,可以用isFinishing()來(lái)判斷它,如果你有
一個(gè)Progress Dialog在線程中運(yùn)行,請(qǐng)?jiān)趏nDestroy里把他cancel掉,不然等線程結(jié)束的時(shí)候,調(diào)用Dialog的cancel方法會(huì)拋異常。
onPause,onstop,onDestroy,三種狀態(tài)下 activity都有可能被系統(tǒng)kill 掉。
三、Activity之間的通信
在 Android 中,不同的 Activity 實(shí)例可能運(yùn)行在一個(gè)進(jìn)程中,也可能運(yùn)行在不同的進(jìn)程中。因此我們需要一種特別的機(jī)制幫助我們?cè)?Activity 之間傳遞消息。Android 中通過(guò) Intent 對(duì)象來(lái)表示一條消息,一個(gè) Intent 對(duì)象不僅包含有這個(gè)消息的目的地,還可以包含消息的內(nèi)容,這好比一封 Email,其中不僅應(yīng)該包含收件地址,還可以包含具體的內(nèi)容。對(duì)于一個(gè) Intent 對(duì)象,消息“目的地”是必須的,而內(nèi)容則是可選項(xiàng)。
Intent負(fù)責(zé)對(duì)操作的動(dòng)作、動(dòng)作涉及數(shù)據(jù)、附加數(shù)據(jù)進(jìn)行描述,Android則根據(jù)此Intent的描述,負(fù)責(zé)找到對(duì)應(yīng)的組件,將 Intent傳遞給調(diào)用的組件,并完成組件的調(diào)用。因此,Intent在這里起著一個(gè)媒體中介的作用,專門提供組件互相調(diào)用的相關(guān)信息,實(shí)現(xiàn)調(diào)用者與被調(diào)用者之間的解耦。
在應(yīng)用中,我們可以以兩種形式來(lái)使用Intent:
直接Intent:指定了component屬性的Intent(調(diào)用setComponent(ComponentName)或者setClass(Context, Class)來(lái)指定)。通過(guò)指定具體的組件類,通知應(yīng)用啟動(dòng)對(duì)應(yīng)的組件。
間接Intent:沒(méi)有指定comonent屬性的Intent。這些Intent需要包含足夠的信息,這樣系統(tǒng)才能根據(jù)這些信息,在在所有的可用組件中,確定滿足此Intent的組件。對(duì)于直接Intent,Android不需要去做解析,因?yàn)槟繕?biāo)組件已經(jīng)很明確。
Android需要解析的是那些間接Intent,通過(guò)解析,將 Intent映射給可以處理此Intent的Activity、IntentReceiver或Service。Intent解析機(jī)制主要是通過(guò)查找已注冊(cè)在AndroidManifest.xml中的所有IntentFilter及其中定義的Intent,最終找到匹配的Intent。
四、Activity 的 Intent Filter
Intent Filter 描述了一個(gè)組件愿意接收什么樣的 Intent 對(duì)象,Android 將其抽象為 android.content.IntentFilter 類。在 Android 的 AndroidManifest.xml 配置文件中可以通過(guò)
當(dāng)使用 startActivity(intent)來(lái)啟動(dòng)另外一個(gè) Activity 時(shí),如果直接指定 intent 對(duì)象的 Component 屬性,那么 Activity Manager 將試圖啟動(dòng)其 Component 屬性指定的 Activity。否則 Android 將通過(guò) Intent 的其它屬性從安裝在系統(tǒng)中的所有 Activity 中查找與之最匹配的一個(gè)啟動(dòng),如果沒(méi)有找到合適的 Activity,應(yīng)用程序會(huì)得到一個(gè)系統(tǒng)拋出的異常。這個(gè)匹配的過(guò)程如下:
2011-11-20 20:23:59 上傳 下載附件(16.72 KB)
五、Activity的棧式管理
Android針對(duì)Activity的管理使用的是棧,就是說(shuō)某一個(gè)時(shí)刻只有一個(gè)Activity處在棧頂,當(dāng)這個(gè)Activity被銷毀后,下面的Activity才有可能浮到棧頂,或者有一個(gè)新的Activity被創(chuàng)建出來(lái),則舊的Activity就被壓棧沉下去了。Activity是Android程序的表現(xiàn)層。程序的每一個(gè)顯示屏幕就是一個(gè)Activity。正在運(yùn)行的Activity處在棧的最頂端,它是運(yùn)行狀態(tài)的。
2011-11-20 20:26:09 上傳 下載附件(23.43 KB)
當(dāng)在程序中調(diào)用 Activity.finish()方法時(shí),結(jié)果和用戶按下 BACK 鍵一樣:它告訴
Activity Manager該Activity實(shí)例可以被“回收”。隨后 Activity Manager 激活處于棧第二層的 Activity,把原 Activity 壓入到棧的第二層,從 Running 狀態(tài)轉(zhuǎn)到 Paused 狀態(tài)。
六、Activity的加載模式standard、singleTop、singleTask、singleInstance(其中前兩個(gè)是一組、后兩個(gè)是一組),默認(rèn)為standard standard:就是intent將發(fā)送給新的實(shí)例,所以每次跳轉(zhuǎn)都會(huì)生成新的activity。singleTop:也是發(fā)送新的實(shí)例,但不同standard的一點(diǎn)是,在請(qǐng)求的Activity正好位于棧頂時(shí)(配置成singleTop的Activity),不會(huì)構(gòu)造新的實(shí)例singleTask:和后面的singleInstance都只創(chuàng)建一個(gè)實(shí)例,當(dāng)intent到來(lái),需要?jiǎng)?chuàng)建設(shè)置為singleTask的Activity的時(shí)候,系統(tǒng)會(huì)檢查棧里面是否已經(jīng)有該Activity的實(shí)例。如果有直接將intent發(fā)送給它。singleInstance:首先說(shuō)明一下task這個(gè)概念,Task可以認(rèn)為是一個(gè)棧,可放入多個(gè)Activity。比如啟動(dòng)一個(gè)應(yīng)用,那么Android就創(chuàng)建了一個(gè)Task,然后啟動(dòng)這個(gè)應(yīng)用的入口Activity,那在它的界面上調(diào)用其他的Activity也只是在這個(gè)task里面。那如果在多個(gè)task中共享一個(gè)Activity的話怎么辦呢。舉個(gè)例來(lái)說(shuō),如果開(kāi)啟一個(gè)導(dǎo)游服務(wù)類的應(yīng)用程序,里面有個(gè)Activity是開(kāi)啟GOOGLE地圖的,當(dāng)按下home鍵退回到主菜單又啟動(dòng)GOOGLE地圖的應(yīng)用時(shí),顯示的就是剛才的地圖,實(shí)際上是同一個(gè)Activity,實(shí)際上這就引入了singleInstance。singleInstance模式就是將該Activity單獨(dú)放入一個(gè)棧中,這樣這個(gè)棧中只有這一個(gè)Activity,不同應(yīng)用的intent都由這個(gè)Activity接收和展示,這樣就做到了共享。當(dāng)然前提是這些應(yīng)用都沒(méi)有被銷毀,所以剛才是按下的HOME鍵,如果按下了返回鍵,則無(wú)效。
七、Activity的跳轉(zhuǎn)Activity跳轉(zhuǎn),無(wú)返回結(jié)果 這是最簡(jiǎn)單的Activity跳轉(zhuǎn)方式。從一個(gè)Activity啟動(dòng)另一個(gè)Activity,直接startActivity(new Intent(當(dāng)前Activity.this, 下一Activity.class))。
Activity跳轉(zhuǎn),返回?cái)?shù)據(jù)/結(jié)果 需要返回?cái)?shù)據(jù)或結(jié)果的,則使用startActivityForResult(Intent intent, int requestCode),requestCode的值是自定義的,用于識(shí)別跳轉(zhuǎn)的目標(biāo)Activity。跳轉(zhuǎn)的目標(biāo)Activity所要做的就是返回?cái)?shù)據(jù)/結(jié)果,setResult(int resultCode)只返回結(jié)果不帶數(shù)據(jù),或者setResult(int resultCode, Intent data)兩者都返回!而接收返回的數(shù)據(jù)/結(jié)果的處理函數(shù)是onActivityResult(int requestCode, int resultCode, Intent data),這里的requestCode就是startActivityForResult的requestCode,resultCode就是setResult里面的resultCode,返回的數(shù)據(jù)在data里面。
** 注意,在setResult后,要調(diào)用finish()銷毀當(dāng)前的Activity,否則無(wú)法返回到原來(lái)的Activity,就無(wú)法執(zhí)行原來(lái)Activity的onActivityResult函數(shù),看到當(dāng)前的Activity沒(méi)反應(yīng)。