摘抄自安全客
前言
大家好梢为,窩又來寫文章了渐行,咱們現(xiàn)在在這篇文章中,我們來對(duì)其官方的一些非常常用的API
進(jìn)行學(xué)習(xí)铸董。所謂工欲善其事祟印,必先利其器。想要好好學(xué)習(xí)FRIDA
我們就必須對(duì)FRIDA API
深入的學(xué)習(xí)以對(duì)其有更深的了解和使用粟害,通常大部分核心原理也在官方API
中寫著蕴忆,我們學(xué)會(huì)來使用一些案例來結(jié)合API
的使用。
注意悲幅,運(yùn)行以下任何代碼時(shí)都需要提前啟動(dòng)手機(jī)中的frida-server
文件套鹅。
系列文章目錄搬新“家”了,地址:https://github.com/r0ysue/AndroidSecurityStudy 汰具,接下來窩會(huì)努力寫更多喔 ~
1.1 FRIDA輸出打印
1.1.1 console輸出
不論是什么語言都好卓鹿,第一個(gè)要學(xué)習(xí)總是如何輸出和打印,那我們就來學(xué)習(xí)在FRIDA
打印值郁副。在官方API
有兩種打印的方式减牺,分別是console
豌习、send
存谎,我們先來學(xué)習(xí)非常的簡單的console
拔疚,這里我創(chuàng)建一個(gè)js
文件,代碼示例如下既荚。
function hello_printf() {
Java.perform(function () {
console.log("");
console.log("hello-log");
console.warn("hello-warn");
console.error("hello-error");
});
}
setImmediate(hello_printf,0);
當(dāng)文件創(chuàng)建好之后稚失,我們需要運(yùn)行在手機(jī)中安裝的frida-server
文件,在上一章我們學(xué)過了如何安裝在android
手機(jī)安裝frida-server
恰聘,現(xiàn)在來使用它句各,我們?cè)?code>ubuntu中開啟一個(gè)終端,運(yùn)行以下代碼晴叨,啟動(dòng)我們安裝好的frida-server
文件凿宾。
roysue@ubuntu:~$ adb shell
sailfish:/ $ su
sailfish:/ $ ./data/local/tmp/frida-server
然后執(zhí)行以下代碼,對(duì)目標(biāo)應(yīng)用app
的進(jìn)程com.roysue.roysueapplication
使用-l
命令注入Chap03.js
中的代碼1-1
以及執(zhí)行腳本之后的效果圖1-1
兼蕊!
frida -U com.roysue.roysueapplication -l Chap03.js
代碼1-1 代碼示例
可以到終點(diǎn)已經(jīng)成功注入了腳本并且打印了hello
初厚,但是顏色不同,這是log
的級(jí)別的原因孙技,在FRIDA
的console
中有三個(gè)級(jí)別分別是log产禾、warn、error
牵啦。
級(jí)別 | 含義 |
---|---|
log | 正常 |
warn | 警告 |
error | 錯(cuò)誤 |
1.1.2 console之hexdump
error
級(jí)別最為嚴(yán)重其次warn
亚情,但是一般在使用中我們只會(huì)使用log
來輸出想看的值;然后我們繼續(xù)學(xué)習(xí)console
的好兄弟哈雏,hexdump
楞件,其含義:打印內(nèi)存中的地址,target
參數(shù)可以是ArrayBuffer
或者NativePointer
,而options
參數(shù)則是自定義輸出格式可以填這幾個(gè)參數(shù)offset
裳瘪、lengt
履因、header
、ansi
盹愚。
hexdump
代碼示例以及執(zhí)行效果如下栅迄。
var libc = Module.findBaseAddress('libc.so');
console.log(hexdump(libc, {
offset: 0,
length: 64,
header: true,
ansi: true
}));
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
00000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 .ELF............
00000010 03 00 28 00 01 00 00 00 00 00 00 00 34 00 00 00 ..(.........4...
00000020 34 a8 04 00 00 00 00 05 34 00 20 00 08 00 28 00 4.......4. ...(.
00000030 1e 00 1d 00 06 00 00 00 34 00 00 00 34 00 00 00 ........4...4...
1.1.3 send
send
是在python
層定義的on_message
回調(diào)函數(shù),jscode
內(nèi)所有的信息都被監(jiān)控script.on('message', on_message)
皆怕,當(dāng)輸出信息的時(shí)候on_message
函數(shù)會(huì)拿到其數(shù)據(jù)再通過format
轉(zhuǎn)換毅舆, 其最重要的功能也是最核心的是能夠直接將數(shù)據(jù)以json
格式輸出,當(dāng)然數(shù)據(jù)是二進(jìn)制的時(shí)候也依然是可以使用send
愈腾,十分方便憋活,我們來看代碼1-2
示例以及執(zhí)行效果。
# -*- coding: utf-8 -*-
import frida
import sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
jscode = """
Java.perform(function ()
{
var jni_env = Java.vm.getEnv();
console.log(jni_env);
send(jni_env);
});
"""
process = frida.get_usb_device().attach('com.roysue.roysueapplication')
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()
運(yùn)行腳本效果如下:
roysue@ubuntu:~/Desktop/Chap09$ python Chap03.py
[object Object]
[*] {'handle': '0xdf4f8000', 'vm': {}}
可以看出這里兩種方式輸出的不同的效果虱黄,console
直接輸出了[object Object]
悦即,無法輸出其正常的內(nèi)容,因?yàn)?code>jni_env實(shí)際上是一個(gè)對(duì)象,但是使用send
的時(shí)候會(huì)自動(dòng)將對(duì)象轉(zhuǎn)json
格式輸出辜梳。通過對(duì)比粱甫,我們就知道send
的好處啦~
1.2 FRIDA變量類型
學(xué)完輸出之后我們來學(xué)習(xí)如何聲明變量類型。
索引 API | 含義 |
---|---|
1 new Int64(v) | 定義一個(gè)有符號(hào)Int64類型的變量值為v作瞄,參數(shù)v可以是字符串或者以0x開頭的的十六進(jìn)制值 |
2 new UInt64(v) | 定義一個(gè)無符號(hào)Int64類型的變量值為v茶宵,參數(shù)v可以是字符串或者以0x開頭的的十六進(jìn)制值 |
3 new NativePointer(s) | 定義一個(gè)指針,指針地址為s |
4 ptr(“0”) | 同上 |
代碼示例以及效果
Java.perform(function () {
console.log("");
console.log("new Int64(1):"+new Int64(1));
console.log("new UInt64(1):"+new UInt64(1));
console.log("new NativePointer(0xEC644071):"+new NativePointer(0xEC644071));
console.log("new ptr('0xEC644071'):"+new ptr(0xEC644071));
});
輸出效果如下:
new Int64(1):1
new UInt64(1):1
new NativePointer(0xEC644071):0xec644071
new ptr('0xEC644071'):0xec644071
frida
也為Int64(v)
提供了一些相關(guān)的API
:
索引 API | 含義 |
---|---|
1 add(rhs)宗挥、sub(rhs)乌庶、and(rhs)、or(rhs)契耿、xor(rhs) | 加瞒大、減、邏輯運(yùn)算 |
2 shr(N)搪桂、shl(n) | 向右/向左移位n位生成新的Int64 |
3 Compare(Rhs) | 返回整數(shù)比較結(jié)果 |
4 toNumber() | 轉(zhuǎn)換為數(shù)字 |
5 toString([radix=10]) | 轉(zhuǎn)換為可選基數(shù)的字符串(默認(rèn)為10) |
我也寫了一些使用案例糠赦,代碼如下。
function hello_type() {
Java.perform(function () {
console.log("");
//8888 + 1 = 8889
console.log("8888 + 1:"+new Int64("8888").add(1));
//8888 - 1 = 8887
console.log("8888 - 1:"+new Int64("8888").sub(1));
//8888 << 1 = 4444
console.log("8888 << 1:"+new Int64("8888").shr(1));
//8888 == 22 = 1 1是false
console.log("8888 == 22:"+new Int64("8888").compare(22));
//轉(zhuǎn)string
console.log("8888 toString:"+new Int64("8888").toString());
});
}
代碼執(zhí)行效果如圖1-2锅棕。
1.3 RPC遠(yuǎn)程調(diào)用
可以替換或插入的空對(duì)象拙泽,以向應(yīng)用程序公開RPC
樣式的API
。該鍵指定方法名稱裸燎,該值是導(dǎo)出的函數(shù)顾瞻。此函數(shù)可以返回一個(gè)純值以立即返回給調(diào)用方,或者承諾異步返回德绿。也就是說可以通過rpc
的導(dǎo)出的功能使用在python
層荷荤,使python
層與js
交互,官方示例代碼有Node.js
版本與python
版本移稳,我們?cè)谶@里使用python
版本蕴纳,代碼如下。
1.3.1 遠(yuǎn)程調(diào)用代碼示例
import frida
def on_message(message, data):
if message['type'] == 'send':
print(message['payload'])
elif message['type'] == 'error':
print(message['stack'])
session = frida.get_usb_device().attach('com.roysue.roysueapplication')
source = """
rpc.exports = {
add: function (a, b) {
return a + b;
},
sub: function (a, b) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(a - b);
}, 100);
});
}
};
"""
script = session.create_script(source)
script.on('message', on_message)
script.load()
print(script.exports.add(2, 3))
print(script.exports.sub(5, 3))
session.detach()
1.3.2 遠(yuǎn)程調(diào)用代碼示例詳解
官方源碼示例是附加在目標(biāo)進(jìn)程為iTunes
个粱,再通過將rpc
的./agent.js
文件讀取到source
古毛,進(jìn)行使用。我這里修改了附加的目標(biāo)的進(jìn)程以及直接將rpc
的代碼定義在source
中都许。我們來看看這段是咋運(yùn)行的稻薇,仍然先對(duì)目標(biāo)進(jìn)程附加,然后在寫js中代碼胶征,也是source
變量塞椎,通過rpc.exports
關(guān)鍵字定義需要導(dǎo)出的兩個(gè)函數(shù),上面定義了add
函數(shù)和sub
函數(shù)睛低,兩個(gè)的函數(shù)寫作方式不一樣案狠,大家以后寫按照add
方法寫就好了服傍,sub
稍微有點(diǎn)復(fù)雜。聲明完函數(shù)之后創(chuàng)建了一個(gè)腳本并且注入進(jìn)程骂铁,加載了腳本之后可以到print(script.exports.add(2, 3))
以及print(script.exports.sub(5, 3))
吹零,在python
層直接調(diào)用。add
的返回的結(jié)果為5
从铲,sub
則是2
瘪校,下見下圖1-3
澄暮。
1.4 Process對(duì)象
我們現(xiàn)在來介紹以及使用一些Process
對(duì)象中比較常用的api
~
1.4.1 Process.id
Process.id
:返回附加目標(biāo)進(jìn)程的PID
1.4.2 Process.isDebuggerAttached()
Process.isDebuggerAttached()
:檢測(cè)當(dāng)前是否對(duì)目標(biāo)程序已經(jīng)附加
1.4.3 Process.enumerateModules()
枚舉當(dāng)前加載的模塊名段,返回模塊對(duì)象的數(shù)組。
Process.enumerateModules()
會(huì)枚舉當(dāng)前所有已加載的so
模塊泣懊,并且返回了數(shù)組Module
對(duì)象伸辟,Module
對(duì)象下一節(jié)我們來詳細(xì)說,在這里我們暫時(shí)只使用Module
對(duì)象的name
屬性馍刮。
function frida_Process() {
Java.perform(function () {
var process_Obj_Module_Arr = Process.enumerateModules();
for(var i = 0; i < process_Obj_Module_Arr.length; i++) {
console.log("",process_Obj_Module_Arr[i].name);
}
});
}
setImmediate(frida_Process,0);
我來們開看看這段js
代碼寫了啥:在js
中能夠直接使用Process
對(duì)象的所有api
信夫,調(diào)用了Process.enumerateModules()
方法之后會(huì)返回一個(gè)數(shù)組,數(shù)組中存儲(chǔ)N個(gè)叫Module的對(duì)象卡啰,既然已經(jīng)知道返回了的是一個(gè)數(shù)組静稻,很簡單我們就來for
循環(huán)它便是,這里我使用下標(biāo)的方式調(diào)用了Module
對(duì)象的name
屬性匈辱,name
是so
模塊的名稱振湾。見下圖1-4
。
1.4.4 Process.enumerateThreads()
Process.enumerateThreads()
:枚舉當(dāng)前所有的線程亡脸,返回包含以下屬性的對(duì)象數(shù)組:
索引 | 屬性 | 含義 |
---|---|---|
1 | id | 線程id |
2 | state | 當(dāng)前運(yùn)行狀態(tài)有running, stopped, waiting, uninterruptible or halted |
3 | context | 帶有鍵pc和sp的對(duì)象押搪,它們是分別為ia32/x64/arm指定EIP/RIP/PC和ESP/RSP/SP的NativePointer對(duì)象。也可以使用其他處理器特定的密鑰浅碾,例如eax大州、rax、r0垂谢、x0等厦画。 |
使用代碼示例如下:
function frida_Process() {
Java.perform(function () {
var enumerateThreads = Process.enumerateThreads();
for(var i = 0; i < enumerateThreads.length; i++) {
console.log("");
console.log("id:",enumerateThreads[i].id);
console.log("state:",enumerateThreads[i].state);
console.log("context:",JSON.stringify(enumerateThreads[i].context));
}
});
}
setImmediate(frida_Process,0);
獲取當(dāng)前是所有線程之后返回了一個(gè)數(shù)組,然后循環(huán)輸出它的值滥朱,如下圖1-4
苛白。
1.4.5 Process.getCurrentThreadId()
Process.getCurrentThreadId()
:獲取此線程的操作系統(tǒng)特定 ID
作為數(shù)字
1.5 Module對(duì)象
3.4章節(jié)中Process.EnumererateModules()
方法返回了就是一個(gè)Module
對(duì)象,咱們這里來詳細(xì)說說Module
對(duì)象焚虱,先來瞧瞧它都有哪些屬性购裙。
1.5.1 Module對(duì)象的屬性
索引 | 屬性 | 含義 |
---|---|---|
1 | name | 模塊名稱 |
2 | base | 模塊地址,其變量類型為NativePointer |
3 | size | 大小 |
4 | path | 完整文件系統(tǒng)路徑 |
除了屬性我們?cè)賮砜纯此惺裁捶椒ā?/p>
1.5.2 Module對(duì)象的API
索引 | API | 含義 |
---|---|---|
1 | Module.load() | 加載指定so文件鹃栽,返回一個(gè)Module對(duì)象 |
2 | enumerateImports() | 枚舉所有Import庫函數(shù)躏率,返回Module數(shù)組對(duì)象 |
3 | enumerateExports() | 枚舉所有Export庫函數(shù)躯畴,返回Module數(shù)組對(duì)象 |
4 | enumerateSymbols() | 枚舉所有Symbol庫函數(shù),返回Module數(shù)組對(duì)象 |
5 | Module.findExportByName(exportName)薇芝、Module.getExportByName(exportName) | 尋找指定so中export庫中的函數(shù)地址 |
6 | Module.findBaseAddress(name)蓬抄、Module.getBaseAddress(name) | 返回so的基地址 |
1.5.3 Module.load()
在frida-12-5
版本中更新了該API
,主要用于加載指定so
文件夯到,返回一個(gè)Module
對(duì)象嚷缭。
使用代碼示例如下:
function frida_Module() {
Java.perform(function () {
//參數(shù)為so的名稱 返回一個(gè)Module對(duì)象
const hooks = Module.load('libhello.so');
//輸出
console.log("模塊名稱:",hooks.name);
console.log("模塊地址:",hooks.base);
console.log("大小:",hooks.size);
console.log("文件系統(tǒng)路徑",hooks.path);
});
}
setImmediate(frida_Module,0);
輸出如下:
模塊名稱: libhello.so
模塊地址: 0xdf2d3000
大小: 24576
文件系統(tǒng)路徑 /data/app/com.roysue.roysueapplication-7adQZoYIyp5t3G5Ef5wevQ==/lib/arm/libhello.so
1.5.4 Process.EnumererateModules()
咱們這一小章節(jié)就來使用Module
對(duì)象,把上章的Process.EnumererateModules()
對(duì)象輸出給它補(bǔ)全了耍贾,代碼如下阅爽。
function frida_Module() {
Java.perform(function () {
var process_Obj_Module_Arr = Process.enumerateModules();
for(var i = 0; i < process_Obj_Module_Arr.length; i++) {
if(process_Obj_Module_Arr[i].path.indexOf("hello")!=-1)
{
console.log("模塊名稱:",process_Obj_Module_Arr[i].name);
console.log("模塊地址:",process_Obj_Module_Arr[i].base);
console.log("大小:",process_Obj_Module_Arr[i].size);
console.log("文件系統(tǒng)路徑",process_Obj_Module_Arr[i].path);
}
}
});
}
setImmediate(frida_Module,0);
輸出如下:
模塊名稱: libhello.so
模塊地址: 0xdf2d3000
大小: 24576
文件系統(tǒng)路徑 /data/app/com.roysue.roysueapplication-7adQZoYIyp5t3G5Ef5wevQ==/lib/arm/libhello.so
這邊如果去除判斷的話會(huì)打印所有加載的so
的信息,這里我們就知道了哪些方法返回了Module
對(duì)象了荐开,然后我們?cè)倮^續(xù)深入學(xué)習(xí)Module
對(duì)象自帶的API
付翁。
1.5.5 enumerateImports()
該API會(huì)枚舉模塊中所有中的所有Import函數(shù),示例代碼如下晃听。
function frida_Module() {
Java.perform(function () {
const hooks = Module.load('libhello.so');
var Imports = hooks.enumerateImports();
for(var i = 0; i < Imports.length; i++) {
//函數(shù)類型
console.log("type:",Imports[i].type);
//函數(shù)名稱
console.log("name:",Imports[i].name);
//屬于的模塊
console.log("module:",Imports[i].module);
//函數(shù)地址
console.log("address:",Imports[i].address);
}
});
}
setImmediate(frida_Module,0);
輸出如下:
[Google Pixel::com.roysue.roysueapplication]-> type: function
name: __cxa_atexit
module: /system/lib/libc.so
address: 0xf58f4521
type: function
name: __cxa_finalize
module: /system/lib/libc.so
address: 0xf58f462d
type: function
name: __stack_chk_fail
module: /system/lib/libc.so
address: 0xf58e2681
...
1.5.6 enumerateExports()
該API會(huì)枚舉模塊中所有中的所有Export
函數(shù)百侧,示例代碼如下。
function frida_Module() {
Java.perform(function () {
const hooks = Module.load('libhello.so');
var Exports = hooks.enumerateExports();
for(var i = 0; i < Exports.length; i++) {
//函數(shù)類型
console.log("type:",Exports[i].type);
//函數(shù)名稱
console.log("name:",Exports[i].name);
//函數(shù)地址
console.log("address:",Exports[i].address);
}
});
}
setImmediate(frida_Module,0);
輸出如下:
[Google Pixel::com.roysue.roysueapplication]-> type: function
name: Java_com_roysue_roysueapplication_hellojni_getSum
address: 0xdf2d411b
type: function
name: unw_save_vfp_as_X
address: 0xdf2d4c43
type: function
address: 0xdf2d4209
type: function
...
1.5.7 enumerateSymbols()
代碼示例如下能扒。
function frida_Module() {
Java.perform(function () {
const hooks = Module.load('libc.so');
var Symbol = hooks.enumerateSymbols();
for(var i = 0; i < Symbol.length; i++) {
console.log("isGlobal:",Symbol[i].isGlobal);
console.log("type:",Symbol[i].type);
console.log("section:",JSON.stringify(Symbol[i].section));
console.log("name:",Symbol[i].name);
console.log("address:",Symbol[i].address);
}
});
}
setImmediate(frida_Module,0);
輸出如下:
isGlobal: true
type: function
section: {"id":"13.text","protection":"r-x"}
name: _Unwind_GetRegionStart
address: 0xf591c798
isGlobal: true
type: function
section: {"id":"13.text","protection":"r-x"}
name: _Unwind_GetTextRelBase
address: 0xf591c7cc
...
1.5.8 Module.findExportByName(exportName), Module.getExportByName(exportName)
返回so
文件中Export
函數(shù)庫中函數(shù)名稱為exportName
函數(shù)的絕對(duì)地址佣渴。
代碼示例如下。
function frida_Module() {
Java.perform(function () {
Module.getExportByName('libhello.so', 'c_getStr')
console.log("Java_com_roysue_roysueapplication_hellojni_getStr address:",Module.findExportByName('libhello.so', 'Java_com_roysue_roysueapplication_hellojni_getStr'));
console.log("Java_com_roysue_roysueapplication_hellojni_getStr address:",Module.getExportByName('libhello.so', 'Java_com_roysue_roysueapplication_hellojni_getStr'));
});
}
setImmediate(frida_Module,0);
輸出如下:
Java_com_roysue_roysueapplication_hellojni_getStr address: 0xdf2d413d
Java_com_roysue_roysueapplication_hellojni_getStr address: 0xdf2d413d
1.5.9 Module.findBaseAddress(name)初斑、Module.getBaseAddress(name)
返回name
模塊的基地址辛润。
代碼示例如下。
function frida_Module() {
Java.perform(function () {
var name = "libhello.so";
console.log("so address:",Module.findBaseAddress(name));
console.log("so address:",Module.getBaseAddress(name));
});
}
setImmediate(frida_Module,0);
輸出如下:
so address: 0xdf2d3000
so address: 0xdf2d3000
1.6 Memory對(duì)象
Memory
的一些API
通常是對(duì)內(nèi)存處理越平,譬如Memory.copy()
復(fù)制內(nèi)存频蛔,又如writeByteArray
寫入字節(jié)到指定內(nèi)存中,那我們這章中就是學(xué)習(xí)使用Memory API
向內(nèi)存中寫入數(shù)據(jù)秦叛、讀取數(shù)據(jù)晦溪。
1.6.1 Memory.scan搜索內(nèi)存數(shù)據(jù)
其主要功能是搜索內(nèi)存中以address
地址開始,搜索長度為size
挣跋,需要搜是條件是pattern三圆,callbacks
搜索之后的回調(diào)函數(shù);此函數(shù)相當(dāng)于搜索內(nèi)存的功能避咆。
我們來直接看例子舟肉,然后結(jié)合例子講解,如下圖1-5
查库。
如果我想搜索在內(nèi)存中112A
地址的起始數(shù)據(jù)要怎么做路媚,代碼示例如下。
function frida_Memory() {
Java.perform(function () {
//先獲取so的module對(duì)象
var module = Process.findModuleByName("libhello.so");
//??是通配符
var pattern = "03 49 ?? 50 20 44";
//基址
console.log("base:"+module.base)
//從so的基址開始搜索樊销,搜索大小為so文件的大小整慎,搜指定條件03 49 ?? 50 20 44的數(shù)據(jù)
var res = Memory.scan(module.base, module.size, pattern, {
onMatch: function(address, size){
//搜索成功
console.log('搜索到 ' +pattern +" 地址是:"+ address.toString());
},
onError: function(reason){
//搜索失敗
console.log('搜索失敗');
},
onComplete: function()
{
//搜索完畢
console.log("搜索完畢")
}
});
});
}
setImmediate(frida_Memory,0);
先來看看回調(diào)函數(shù)的含義脏款,onMatch:function(address,size)
:使用包含作為NativePointer
的實(shí)例地址的address
和指定大小為數(shù)字的size
調(diào)用裤园,此函數(shù)可能會(huì)返回字符串STOP
以提前取消內(nèi)存掃描撤师。onError:Function(Reason)
:當(dāng)掃描時(shí)出現(xiàn)內(nèi)存訪問錯(cuò)誤時(shí)使用原因調(diào)用。onComplete:function()
:當(dāng)內(nèi)存范圍已完全掃描時(shí)調(diào)用拧揽。
我們來來說上面這段代碼做了什么事情:搜索libhello.so
文件在內(nèi)存中的數(shù)據(jù)剃盾,搜索以pattern
條件的在內(nèi)存中能匹配的數(shù)據(jù)。搜索到之后根據(jù)回調(diào)函數(shù)返回?cái)?shù)據(jù)淤袜。
我們來看看執(zhí)行之后的效果圖1-6
痒谴。
我們要如何驗(yàn)證搜索到底是不是圖1-5
中112A
地址,其實(shí)很簡單饮怯。so
的基址是0xdf2d3000
闰歪,而搜到的地址是0xdf2d412a
嚎研,我們只要df2d412a-df2d3000=112A
蓖墅。就是說我們已經(jīng)搜索到了!
1.6.2 搜索內(nèi)存數(shù)據(jù)Memory.scanSync
功能與Memory.scan
一樣临扮,只不過它是返回多個(gè)匹配到條件的數(shù)據(jù)论矾。
代碼示例如下。
function frida_Memory() {
Java.perform(function () {
var module = Process.findModuleByName("libhello.so");
var pattern = "03 49 ?? 50 20 44";
var scanSync = Memory.scanSync(module.base, module.size, pattern);
console.log("scanSync:"+JSON.stringify(scanSync));
});
}
setImmediate(frida_Memory,0);
輸出如下杆勇,可以看到地址搜索出來是一樣的
scanSync:[{"address":"0xdf2d412a","size":6}]
1.6.3 內(nèi)存分配Memory.alloc
在目標(biāo)進(jìn)程中的堆上申請(qǐng)size
大小的內(nèi)存贪壳,并且會(huì)按照Process.pageSize
對(duì)齊齐邦,返回一個(gè)NativePointer
贡歧,并且申請(qǐng)的內(nèi)存如果在JavaScript
里面沒有對(duì)這個(gè)內(nèi)存的使用的時(shí)候會(huì)自動(dòng)釋放的。也就是說捧灰,如果你不想要這個(gè)內(nèi)存被釋放钻注,你需要自己保存一份對(duì)這個(gè)內(nèi)存塊的引用蚂且。
使用案例如下
function frida_Memory() {
Java.perform(function () {
const r = Memory.alloc(10);
console.log(hexdump(r, {
offset: 0,
length: 10,
header: true,
ansi: false
}));
});
}
setImmediate(frida_Memory,0);
以上代碼在目標(biāo)進(jìn)程中申請(qǐng)了10
字節(jié)的空間~我們來看執(zhí)行腳本的效果圖1-7
。
可以看到在0xdfe4cd40
處申請(qǐng)了10
個(gè)字節(jié)內(nèi)存空間~
也可以使用:
Memory.allocUtf8String(str)
分配utf字符串
Memory.allocUtf16String
分配utf16字符串
Memory.allocAnsiString
分配ansi字符串
1.6.4 內(nèi)存復(fù)制Memory.copy
如同c api memcp
一樣調(diào)用幅恋,使用案例如下杏死。
function frida_Memory() {
Java.perform(function () {
//獲取so模塊的Module對(duì)象
var module = Process.findModuleByName("libhello.so");
//條件
var pattern = "03 49 ?? 50 20 44";
//搜字符串 只是為了將so的內(nèi)存數(shù)據(jù)復(fù)制出來 方便演示~
var scanSync = Memory.scanSync(module.base, module.size, pattern);
//申請(qǐng)一個(gè)內(nèi)存空間大小為10個(gè)字節(jié)
const r = Memory.alloc(10);
//復(fù)制以module.base地址開始的10個(gè)字節(jié) 那肯定會(huì)是7F 45 4C 46...因?yàn)橐粋€(gè)ELF文件的Magic屬性如此。
Memory.copy(r,module.base,10);
console.log(hexdump(r, {
offset: 0,
length: 10,
header: true,
ansi: false
}));
});
}
setImmediate(frida_Memory,0);
輸出如下捆交。
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
e8142070 7f 45 4c 46 01 01 01 00 00 00 .ELF......
從module.base
中復(fù)制10
個(gè)字節(jié)的內(nèi)存到新年申請(qǐng)的r
內(nèi)
1.6.6 寫入內(nèi)存Memory.writeByteArray
將字節(jié)數(shù)組寫入一個(gè)指定內(nèi)存淑翼,代碼示例如下:
function frida_Memory() {
Java.perform(function () {
//定義需要寫入的字節(jié)數(shù)組 這個(gè)字節(jié)數(shù)組是字符串"roysue"的十六進(jìn)制
var arr = [ 0x72, 0x6F, 0x79, 0x73, 0x75, 0x65];
//申請(qǐng)一個(gè)新的內(nèi)存空間 返回指針 大小是arr.length
const r = Memory.alloc(arr.length);
//將arr數(shù)組寫入R地址中
Memory.writeByteArray(r,arr);
//輸出
console.log(hexdump(r, {
offset: 0,
length: arr.length,
header: true,
ansi: false
}));
});
}
setImmediate(frida_Memory,0);
輸出如下。
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
00000000 72 6f 79 73 75 65 roysue
1.6.7 讀取內(nèi)存Memory.readByteArray
將一個(gè)指定地址的數(shù)據(jù)品追,代碼示例如下:
function frida_Memory() {
Java.perform(function () {
//定義需要寫入的字節(jié)數(shù)組 這個(gè)字節(jié)數(shù)組是字符串"roysue"的十六進(jìn)制
var arr = [ 0x72, 0x6F, 0x79, 0x73, 0x75, 0x65];
//申請(qǐng)一個(gè)新的內(nèi)存空間 返回指針 大小是arr.length
const r = Memory.alloc(arr.length);
//將arr數(shù)組寫入R地址中
Memory.writeByteArray(r,arr);
//讀取r指針玄括,長度是arr.length 也就是會(huì)打印上面一樣的值
var buffer = Memory.readByteArray(r, arr.length);
//輸出
console.log("Memory.readByteArray:");
console.log(hexdump(buffer, {
offset: 0,
length: arr.length,
header: true,
ansi: false
}));
});
});
}
setImmediate(frida_Memory,0);
輸出如下。
[Google Pixel::com.roysue.roysueapplication]-> Memory.readByteArray:
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
00000000 72 6f 79 73 75 65 roysue
結(jié)語
在這篇中我們學(xué)會(huì)了在FRIDACLI中如何輸出想要輸出格式肉瓦,也學(xué)會(huì)如何聲明變量遭京,一步步的學(xué)習(xí)银还。在逐步的學(xué)習(xí)的過程,總是會(huì)遇到不同的問題洁墙。歌曲<奇跡再現(xiàn)>我相信你一定聽過吧~蛹疯,新的風(fēng)暴已經(jīng)出現(xiàn),怎么能夠停止不前..遇到問題不要怕,總會(huì)解決的热监。
咱們會(huì)在下一篇中來學(xué)會(huì)如何使用FRIDA中的Java對(duì)象捺弦、Interceptor對(duì)象、NativePointer對(duì)象NativeFunction對(duì)象孝扛、NativeCallback對(duì)象咱們拭目以待吧~