FRIDA-API使用篇:rpc严就、Process总寻、Module、Memory使用方法及示例

摘抄自安全客

前言

大家好梢为,窩又來寫文章了渐行,咱們現(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 代碼示例

圖1-1 終端執(zhí)行

可以到終點(diǎn)已經(jīng)成功注入了腳本并且打印了hello初厚,但是顏色不同,這是log的級(jí)別的原因孙技,在FRIDAconsole中有三個(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履因、headeransi盹愚。

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-2 Int64 API

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-3 執(zhí)行python腳本

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屬性匈辱,nameso模塊的名稱振湾。見下圖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-5112A地址,其實(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ì)象咱們拭目以待吧~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末列吼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子苦始,更是在濱河造成了極大的恐慌寞钥,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陌选,死亡現(xiàn)場(chǎng)離奇詭異理郑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)咨油,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門您炉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人役电,你說我怎么就攤上這事赚爵。” “怎么了法瑟?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵冀膝,是天一觀的道長。 經(jīng)常有香客問我霎挟,道長窝剖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任氓扛,我火速辦了婚禮枯芬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘采郎。我一直安慰自己千所,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布蒜埋。 她就那樣靜靜地躺著淫痰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪整份。 梳的紋絲不亂的頭發(fā)上待错,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天籽孙,我揣著相機(jī)與錄音,去河邊找鬼火俄。 笑死犯建,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瓜客。 我是一名探鬼主播适瓦,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼谱仪!你這毒婦竟也來了玻熙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤疯攒,失蹤者是張志新(化名)和其女友劉穎嗦随,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敬尺,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡枚尼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筷转。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姑原。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡悬而,死狀恐怖呜舒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情笨奠,我是刑警寧澤袭蝗,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站般婆,受9級(jí)特大地震影響到腥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔚袍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一乡范、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧啤咽,春花似錦晋辆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鳞青,卻和暖如春霸饲,著一層夾襖步出監(jiān)牢的瞬間为朋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國打工厚脉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留习寸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓傻工,卻偏偏與公主長得像融涣,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子精钮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容