1 安裝python環(huán)境
mac 自帶不需要安裝
2 安裝pip
easy_install pip
3 安裝frida 安裝frida-tools
pip install frida
pip install frida-tools
//檢測(cè)是否安裝成功
frida-ps
//能看到系統(tǒng)進(jìn)程,表示安裝成功
4 下載frida-server
官網(wǎng)下載:https://github.com/frida/frida/releases 對(duì)應(yīng)的版本,
注意:Frida-server的版本必須跟你宿主機(jī)的Frida版本一致,比如我宿主機(jī)Frida的版本是12.2.28攀例,
getprop ro.product.cpu.abi
armeabi-v7a
Android手機(jī)是arm的它浅,那么應(yīng)該下載:rida-server-12.2.28-android-arm.xz 文件。
5 推送frida-server到root過(guò)的手機(jī)
#下載后解壓文件铭拧,并將文件重命名為: frida-server,然后推送到手機(jī)
adb push frida-server /data/local/tmp/
#修改權(quán)限并運(yùn)行frida-server
adb shell
su
cd /data/local/tmp/
chmod 777 frida-server
./frida-server
#如果要啟動(dòng)frida-server作為后臺(tái)進(jìn)程、可以使用這個(gè)命令./frida-server &
6 開(kāi)一個(gè)終端嫉父,使用frida-ps -U命令檢查Frida是否正常運(yùn)行沛硅,如果正常運(yùn)行則會(huì)列出Android設(shè)備上當(dāng)前正在運(yùn)行的進(jìn)程
7 開(kāi)始Hook
利用命令行工具h(yuǎn)ook libc.so的open()函數(shù)
frida這個(gè)命令行工具,可以通過(guò)frida -help 查看
"-U" 參數(shù)代表我們連接的是遠(yuǎn)程USB server绕辖,同理你也可以使用其他參數(shù)來(lái)連接稽鞭,
"-f "參數(shù)則表示在手機(jī)端啟動(dòng)一個(gè)你指定的android程序,那個(gè)FILE則表示應(yīng)用的包名引镊,
通常"-f"這個(gè)參數(shù)配合"--no-pause"參數(shù)來(lái)使用朦蕴,因?yàn)榭赡懿蛔屵M(jìn)程恢復(fù)的話可能會(huì)有奇怪的問(wèn)題,
"-p" 與"-n"命令分別表示attach到進(jìn)程的名字或者pid弟头,
"-l"參數(shù)則是代表需要注入的javascript腳本吩抓,而這個(gè)javascript的腳本就是我們所寫的hook代碼,完成函數(shù)的hook赴恨,內(nèi)存的dump等一系列功能疹娶,
當(dāng)我們使用frida這個(gè)命令行工具成功attach到目標(biāo)進(jìn)程的時(shí)候,frida會(huì)給我們返回一個(gè)Frida CLI伦连,說(shuō)明白點(diǎn)就是一個(gè)交互窗口雨饺,下面我們就能看到
test.js
setImmediate(function() {
Interceptor.attach(Module.findExportByName("libc.so" , "open"), {
onEnter: function(args) {
log("open() called!")
},
onLeave:function(retval){
}
});
});
bogon:~ ljp$ frida -U -f com.android.chrome --no-pause
____
/ _ | Frida 12.2.28 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at http://www.frida.re/docs/home/
[LGE Nexus 5::com.android.chrome]-> %load /Users/ljp/Documents/frida/test.js
首先我們知道frida是python的一個(gè)模塊,那么這樣我們當(dāng)然可以通過(guò)寫python腳本import frida來(lái)實(shí)現(xiàn)對(duì)frida的利用惑淳,此外frida同時(shí)會(huì)提供幾個(gè)命令行工具(工具存放在python/Scripts目錄下面额港,所以你可以添加到系統(tǒng)環(huán)境變量方便使用),
# hook chrome進(jìn)程的libc.so中的函數(shù)open
import frida
import sys
device = frida.get_usb_device()
pid = device.spawn(["com.android.chrome"])
session = device.attach(pid)
device.resume(pid)
src = """
Interceptor.attach(Module.findExportByName("libc.so" , "open"), {
onEnter: function(args) {
send("open called!");
},
onLeave:function(retval){
}
});
"""
def on_message(message ,data):
print(message['payload'])
script = session.create_script(src)
script.on("message" , on_message)
script.load()
sys.stdin.read()
這個(gè)args其實(shí)就包括我們想要的東西歧焦,
onEnter 表示在函數(shù)調(diào)用之前執(zhí)行的代碼移斩,
onLeave 表示在函數(shù)執(zhí)行后需要執(zhí)行的代碼,所以這個(gè)retval也就包括了返回值绢馍,關(guān)于我們用的Interceptor API向瓷,frida官方的JavaScript API 文檔是這么寫的:
Interceptor.attach()第一個(gè)參數(shù)是一個(gè)NativePointer指針,
在之前我們用的Module.findExportByName("libc.so" , "open")的返回值舰涌,關(guān)于Moudle同樣在文檔中可以找到猖任,
第二個(gè)參數(shù)則就是我們的js代碼塊,我們所要的打印參數(shù)與返回值也就是在這里完成瓷耙。
我們完善一下代碼朱躺,關(guān)于libc.so的open函數(shù)參數(shù)是這樣定義的,int open( const char * pathname, int flags);
//hook chrome進(jìn)程的libc.so中的函數(shù)open
import frida
import sys
import io
device = frida.get_usb_device()
pid = device.spawn(["com.android.chrome"])
session = device.attach(pid)
scr = """
setImmediate(function() {
Interceptor.attach(Module.findExportByName("libc.so" , "open"), {
onEnter: function(args) {
send("open called! args[0]:",Memory.readByteArray(args[0],256));
},
onLeave:function(retval){
}
});
});
"""
def on_message(message ,data):
file_object=open("/Users/ljp/Documents/frida/log.txt",'ab+')
file_object.write(message['payload'].encode())
file_object.write(data.split(b'\x00')[0])
file_object.write('\n'.encode())
file_object.close()
script = session.create_script(scr)
script.on("message" , on_message)
script.load()
sys.stdin.read()
細(xì)心的同學(xué)可能會(huì)發(fā)現(xiàn)哺徊,我這次沒(méi)有用spawn()函數(shù)來(lái)啟動(dòng)chrome應(yīng)用室琢,因?yàn)槿绻阆雋ook的動(dòng)作如果不是在程序開(kāi)始就進(jìn)行的話,而是可控的動(dòng)作落追,那么你直接attach到其相應(yīng)的進(jìn)程上就好了盈滴,這樣可以避免我從程序一開(kāi)始就大量hook open,
此次我們啟動(dòng)的方式為python open.py
send("open called! args[0]:",Memory.readByteArray(args[0],256));
可以看到args[0]表示open的第一個(gè)參數(shù),由于我并不知道第一個(gè)參數(shù)的長(zhǎng)度有多長(zhǎng)巢钓,所以我用Memory.readByteArray(args[0],256)來(lái)讀取256個(gè)字節(jié)(文件名一般不會(huì)長(zhǎng)過(guò)256個(gè)字節(jié)吧)
然后傳遞給send(message[, data])的第二個(gè)參數(shù)data病苗,
關(guān)于send(message[, data])的介紹也在官網(wǎng)的JS的API中,如下截圖:
可見(jiàn)第二個(gè)參數(shù)是需要ArrayBuffer類型的症汹,而Memory.readByteArray(args[0],256)的返回值剛好是ArrayBuffer類型的硫朦,所以直接傳值就可以。
那么有的同學(xué)會(huì)問(wèn)背镇,如果不是ArrayBuffer類型的怎么辦咬展,比如說(shuō)文檔中的hexdump(target[, options])函數(shù),它的返回值不是ArrayBuffer類型的瞒斩,那么我們就需要利用下面的函數(shù)來(lái)轉(zhuǎn)換:
function str2ab(str) {
var buf = new ArrayBuffer(str.length); // 1 bytes for each char
var bufView = new Uint8Array(buf);
for (var i=0, strLen=str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
將上面這段代碼放入hook代碼中破婆,然后調(diào)用它便可以解決問(wèn)題。
數(shù)據(jù)通過(guò)send(message[, data])傳遞給python的on_message(message,data)函數(shù)胸囱。
第一個(gè)參數(shù)message是一個(gè)python字典類型祷舀,message['payload']存放的是send(message[, data])參數(shù)1的內(nèi)容
第二個(gè)參數(shù)data是send(message[, data])的第二個(gè)參數(shù),不過(guò)是以bytes的類型傳遞給python data參數(shù)烹笔。
所以我們寫入文件的話裳扯,如果文件打開(kāi)方式為"ab+"那么直接可以寫進(jìn)去,否則如果是"a+"來(lái)打開(kāi)文件的話谤职,那么需要data.decode()轉(zhuǎn)換為str類型來(lái)寫入饰豺。
那細(xì)心的同學(xué)可能問(wèn)了,你為啥寫的data.split(b'\x00')[0]柬帕,首先我打開(kāi)方式是"ab+"哟忍,所以不需要轉(zhuǎn)換類型,其次由于我之前不知道args[0]有多長(zhǎng)陷寝,所以我讀取了256個(gè)字節(jié),那這256個(gè)字節(jié)肯定不是我全想要的其馏,我們知道文件名中肯定不能存在0x00字節(jié)凤跑,而且C語(yǔ)言中字符串是要以0x00'\0'作為截?cái)嗟模晕矣?strong>split(b'\x00')[0]分割字符串并且取列表中的第一項(xiàng)輸出到文件叛复。
到此我們的open函數(shù)就算是hook完了;
作者:SimonKoh
鏈接:http://www.reibang.com/p/b833fba1bffe
來(lái)源:簡(jiǎn)書
著作權(quán)歸作者所有仔引。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處褐奥。