安卓的逆向題目在ctf中已經比較常見了。自從上次網鼎杯用了frida框架做過bang之後,感覺這個框架功能很是強大,因此打算學習一下這個框架,並記錄一下學習過程以免以後忘了
frida安裝
pip install frida
pip install frida-tools
我是在Windows系統上安裝的,用的是python3,因爲python2會報錯
pyhton2安裝失敗結果:
frida-server啓動流程
首先需要去下載一個frida-server,網址:server下載地址
因爲我用的是雷電模擬器調試,因此下載的是x86的(模擬器好像一般都是x86)
adb shell連接上去
使用adb push 把frida-server文件放到/data/local/tmp目錄下
chmod 755,賦予執行權限,然後啓動server:
最後還需要設置一下轉發:
adb forward tcp:27043 tcp:27043
adb forward tcp:27042 tcp:27042
frida-server交互
在完成上面的操作之後,我們就可以通過python腳本與frida-server進行交互了
比如在之前的bang中,我們直接運行exp脫殼
接下來我們以一道seccon的題目講解一下如何寫交互腳本
該題目flag生成邏輯如下:
calc()是在so文件中,當然我們可以直接去逆向so文件,思路就和逆向c語言寫的程序差不多,不過這裏我們主要講一下frida的使用,這個方法就不多講了
如果我們能直接調用calc()函數,不就不需要去逆向它了嗎?
下面是官網提供的exp:
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
jscode = """
Java.perform(function () {
// Function to hook is defined here
var MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');
// Whenever button is clicked
var onClick = MainActivity.onClick;
onClick.implementation = function (v) {
// Show a message to know that the function got called
send('onClick');
// Call the original onClick handler
onClick.call(this, v);
// Set our values after running the original onClick handler
this.m.value = 0;
this.n.value = 1;
this.cnt.value = 999;
// Log to the console that it's done, and we should have the flag!
console.log('Done:' + JSON.stringify(this.cnt));
};
});
"""
process = frida.get_usb_device().attach('com.example.seccon2015.rock_paper_scissors')
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read()
首先是get_usb_device()
函數,可以得到當前連接的設備,它是一個Device()對象
之後使用attach方法可以根據pid連接上對應的進程
create_script
可以返回一個Script類的實例化
在on方法中可以設置自定義回調函數。
def on(self, signal, callback):
if signal == 'message':
self._on_message_callbacks.append(callback)
else:
self._impl.on(signal, callback)
下面對js代碼進行分析
//通過perform執行js代碼
Java.perform(function () {
// Function to hook is defined here
var MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');
// Whenever button is clicked
//這裏可以把onClick函數hook
var onClick = MainActivity.onClick;
onClick.implementation = function (v) {
// Show a message to know that the function got called
//與用戶腳本交互
send('onClick');
// Call the original onClick handler
//call原有的onClick()函數
onClick.call(this, v);
// Set our values after running the original onClick handler
//重新設置MainActivity中變量的值,這裏看一下apk源代碼就能理解
//對於爲什麼能在調用了原有的onClick()之後再進行賦值,這是因爲onClick()中
//對showMessageTask的調用使用的是handler.postDelayed(this.showMessageTask, 1000)
//這個函數會延遲一秒之後再調用showMessageTask
this.m.value = 0;
this.n.value = 1;
this.cnt.value = 999;
// Log to the console that it's done, and we should have the flag!
console.log('Done:' + JSON.stringify(this.cnt));
};
});
當然可以還有一種思路,就是直接把MainActivity的onCreate()函數給hook了,在裏面直接調用calc()函數並計算出flag發送回來即可,代碼如下:
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
jscode = """
Java.perform(function () {
var MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');
MainActivity.onCreate.implementation = function () {
send("Hook Start...");
var returnValue = this.calc();
send("Return:"+returnValue);
var result = (1000+returnValue)*107;
send("Flag:"+"SECCON{"+result.toString()+"}");
}
});
"""
process = frida.get_usb_device().attach('com.example.seccon2015.rock_paper_scissors')
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()
運行結果: