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