乐趣区

关于大数据:抖音数据采集Frida教程rpcProcessModuleMemory使用方法及示例

抖音数据采集 Frida 教程,rpc、Process、Module、Memory 应用办法及示例

前言

大家好,窝又来写文章了,咱们当初在这篇文章中,咱们来对其官网的一些十分罕用的 API 进行学习。所谓工欲善其事,必先利其器。想要好好学习 FRIDA 咱们就必须对 FRIDA API 深刻的学习以对其有更深的理解和应用,通常大部分外围原理也在官网 API 中写着,咱们学会来应用一些案例来联合 API 的应用。
留神,运行以下任何代码时都须要提前启动手机中的 frida-server 文件。

 

1.1 FRIDA 输入打印

1.1.1 console 输入

不论是什么语言都好,第一个要学习总是如何输入和打印,那咱们就来学习在 FRIDA 打印值。在官网 API 有两种打印的形式,别离是 consolesend,咱们先来学习十分的简略的console,这里我创立一个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);

当文件创建好之后,咱们须要运行在手机中装置的 frida-server 文件,在上一章咱们学过了如何装置在 android 手机装置 frida-server,当初来应用它,咱们在ubuntu 中开启一个终端,运行以下代码,启动咱们装置好的 frida-server 文件。

roysue@ubuntu:~$ adb shell
sailfish:/ $ su
sailfish:/ $ ./data/local/tmp/frida-server

而后执行以下代码,对指标利用 app 的过程 com.roysue.roysueapplication 应用 -l 命令注入 Chap03.js 中的代码 1-1 以及执行脚本之后的效果图 1-1
frida -U com.roysue.roysueapplication -l Chap03.js
代码 1 -1 代码示例


图 1 -1 终端执行
能够到起点曾经胜利注入了脚本并且打印了 hello,然而色彩不同,这是log 的级别的起因,在 FRIDAconsole中有三个级别别离是log、warn、error

级别 含意
log 失常
warn 正告
error 谬误

1.1.2 console 之 hexdump

error级别最为重大其 次 warn,然而个别在应用中咱们只会应用 log 来输入想看的值;而后咱们持续学习 console 的好兄弟,hexdump,其含意: 打印内存中的地址,target参数能够是 ArrayBuffer 或者 NativePointer, 而options 参数则是自定义输入格局能够填这几个参数 offset、lengt、header、ansi
hexdump 代码示例以及执行成果如下。

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 回调函数,jscode内所有的信息都被监控 script.on('message', on_message),当输入信息的时候on_message 函数会拿到其数据再通过 format 转换,其最重要的性能也是最外围的是可能间接将数据以 json 格局输入,当然数据是二进制的时候也仍然是能够应用 send,非常不便,咱们来看代码1-2 示例以及执行成果。

# -*- 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()
运行脚本成果如下:roysue@ubuntu:~/Desktop/Chap09$ python Chap03.py 
[object Object]
[*] {'handle': '0xdf4f8000', 'vm': {}}

能够看出这里两种形式输入的不同的成果,console间接输入了 [object Object],无奈输入其失常的内容,因为jni_env 实际上是一个对象,然而应用 send 的时候会主动将对象转 json 格局输入。通过比照,咱们就晓得 send 的益处啦~
 

1.2 FRIDA 变量类型

学完输入之后咱们来学习如何申明变量类型。

API 含意
new Int64(v) 定义一个有符号 Int64 类型的变量值为 v,参数 v 能够是字符串或者以 0x 结尾的的十六进制值
new UInt64(v) 定义一个无符号 Int64 类型的变量值为 v,参数 v 能够是字符串或者以 0x 结尾的的十六进制值
new NativePointer(s) 定义一个指针,指针地址为 s
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) 提供了一些相干的 API:

API 含意
add(rhs)、sub(rhs)、and(rhs)、or(rhs)、xor(rhs) 加、减、逻辑运算
shr(N)、shl(n) 向右 / 向左移位 n 位生成新的 Int64
Compare(Rhs) 返回整数比拟后果
toNumber() 转换为数字
toString([radix=10]) 转换为可选基数的字符串(默认为 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));
        // 转 string
        console.log("8888 toString:"+new Int64("8888").toString());
    });
}

代码执行成果如图 1 -2。

图 1 -2 Int64 API
 

1.3 RPC 近程调用

能够替换或插入的空对象,以向应用程序公开 RPC 款式的 API。该键指定办法名称,该值是导出的函数。此函数能够返回一个纯值以立刻返回给调用方,或者承诺异步返回。也就是说能够通过 rpc 的导出的性能应用在python 层,使 python 层与 js 交互,官网示例代码有 Node.js 版本与 python 版本,咱们在这里应用 python 版本,代码如下。

1.3.1 近程调用代码示例

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 近程调用代码示例详解

官网源码示例是附加在指标过程为 iTunes,再通过将rpc./agent.js文件读取到 source,进行应用。我这里批改了附加的指标的过程以及间接将rpc 的代码定义在 source 中。咱们来看看这段是咋运行的,依然先对指标过程附加,而后在写 js 中代码,也是 source 变量,通过 rpc.exports 关键字定义须要导出的两个函数,下面定义了 add 函数和 sub 函数,两个的函数写作形式不一样,大家当前写依照 add 办法写就好了,sub略微有点简单。申明完函数之后创立了一个脚本并且注入过程,加载了脚本之后能够到 print(script.exports.add(2, 3)) 以及 print(script.exports.sub(5, 3)),python层间接调用。add的返回的后果为 5sub 则是 2,下见下图1-3

图 1 -3 执行 python 脚本
 

1.4 Process 对象

咱们当初来介绍以及应用一些 Process 对象中比拟罕用的api~

1.4.1 Process.id

Process.id:返回附加指标过程的PID

1.4.2 Process.isDebuggerAttached()

Process.isDebuggerAttached():检测以后是否对目标程序曾经附加

1.4.3 Process.enumerateModules()

枚举以后加载的模块,返回模块对象的数组。
Process.enumerateModules()会枚举以后所有已加载的 so 模块,并且返回了数组 Module 对象,Module对象下一节咱们来具体说,在这里咱们临时只应用 Module 对象的 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 对象的所有 api,调用了Process.enumerateModules() 办法之后会返回一个数组,数组中存储 N 个叫 Module 的对象,既然曾经晓得返回了的是一个数组,很简略咱们就来 for 循环它便是,这里我应用下标的形式调用了 Module 对象的 name 属性,nameso 模块的名称。见下图 1-4

图 1 -4 终端输入了所有已加载的 so

1.4.4 Process.enumerateThreads()

Process.enumerateThreads():枚举以后所有的线程,返回蕴含以下属性的对象数组:

属性 含意
id 线程 id
state 以后运行状态有 running, stopped, waiting, uninterruptible or halted
context 带有键 pc 和 sp 的对象,它们是别离为 ia32/x64/arm 指定 EIP/RIP/PC 和 ESP/RSP/SP 的 NativePointer 对象。也能够应用其余处理器特定的密钥,例如 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);

获取以后是所有线程之后返回了一个数组,而后循环输入它的值,如下图 1-5

图 1 -4 终端执行

1.4.5 Process.getCurrentThreadId()

Process.getCurrentThreadId():获取此线程的操作系统特定 ID 作为数字
 

1.5 Module 对象

3.4 章节中 Process.EnumererateModules() 办法返回了就是一个 Module 对象,咱们这里来具体说说 Module 对象,先来瞧瞧它都有哪些属性。

1.5.1 Module 对象的属性

属性 含意
name 模块名称
base 模块地址,其变量类型为 NativePointer
size 大小
path 残缺文件系统门路

除了属性咱们再来看看它有什么办法。

1.5.2 Module 对象的 API

API 含意
Module.load() 加载指定 so 文件,返回一个 Module 对象
enumerateImports() 枚举所有 Import 库函数,返回 Module 数组对象
enumerateExports() 枚举所有 Export 库函数,返回 Module 数组对象
enumerateSymbols() 枚举所有 Symbol 库函数,返回 Module 数组对象
Module.findExportByName(exportName)、Module.getExportByName(exportName) 寻找指定 so 中 export 库中的函数地址
Module.findBaseAddress(name)、Module.getBaseAddress(name) 返回 so 的基地址

1.5.3 Module.load()

frida-12-5 版本中更新了该 API,次要用于加载指定so 文件,返回一个 Module 对象。
应用代码示例如下:

function frida_Module() {Java.perform(function () {
         // 参数为 so 的名称 返回一个 Module 对象
         const hooks = Module.load('libhello.so');
         // 输入
         console.log("模块名称:",hooks.name);
         console.log("模块地址:",hooks.base);
         console.log("大小:",hooks.size);
         console.log("文件系统门路",hooks.path);
    });
}
setImmediate(frida_Module,0);
输入如下:模块名称: libhello.so
模块地址: 0xdf2d3000
大小: 24576
文件系统门路 /data/app/com.roysue.roysueapplication-7adQZoYIyp5t3G5Ef5wevQ==/lib/arm/libhello.so

1.5.4 Process.EnumererateModules()

咱们这一小章节就来应用 Module 对象,把上章的 Process.EnumererateModules() 对象输入给它补全了,代码如下。

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("文件系统门路",process_Obj_Module_Arr[i].path);
            }
         }
    });
}
setImmediate(frida_Module,0);
输入如下:模块名称: libhello.so
模块地址: 0xdf2d3000
大小: 24576
文件系统门路 /data/app/com.roysue.roysueapplication-7adQZoYIyp5t3G5Ef5wevQ==/lib/arm/libhello.so

这边如果去除判断的话会打印所有加载的 so 的信息,这里咱们就晓得了哪些办法返回了 Module 对象了,而后咱们再持续深刻学习 Module 对象自带的API

1.5.5 enumerateImports()

该 API 会枚举模块中所有中的所有 Import 函数,示例代码如下。

function frida_Module() {Java.perform(function () {const hooks = Module.load('libhello.so');
        var Imports = hooks.enumerateImports();
        for(var i = 0; i < Imports.length; i++) {
            // 函数类型
            console.log("type:",Imports[i].type);
            // 函数名称
            console.log("name:",Imports[i].name);
            // 属于的模块
            console.log("module:",Imports[i].module);
            // 函数地址
            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 会枚举模块中所有中的所有 Export 函数,示例代码如下。

function frida_Module() {Java.perform(function () {const hooks = Module.load('libhello.so');
        var Exports = hooks.enumerateExports();
        for(var i = 0; i < Exports.length; i++) {
            // 函数类型
            console.log("type:",Exports[i].type);
            // 函数名称
            console.log("name:",Exports[i].name);
            // 函数地址
            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 函数库中函数名称为 exportName 函数的相对地址。
代码示例如下。

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 对象

Memory的一些 API 通常是对内存解决,譬如 Memory.copy() 复制内存,又如 writeByteArray 写入字节到指定内存中,那咱们这章中就是学习应用 Memory API 向内存中写入数据、读取数据。

1.6.1 Memory.scan 搜寻内存数据

其次要性能是搜寻内存中以 address 地址开始,搜寻长度为 size,须要搜是条件是pattern,callbacks 搜寻之后的回调函数;此函数相当于搜寻内存的性能。
咱们来间接看例子,而后联合例子解说,如下图 1-5

图 1 -5 IDA 中 so 文件某处数据
如果我想搜寻在内存中 112A 地址的起始数据要怎么做,代码示例如下。

function frida_Memory() {Java.perform(function () {
        // 先获取 so 的 module 对象
        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 的数据
        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);

先来看看回调函数的含意,onMatch:function(address,size):应用蕴含作为 NativePointer 的实例地址的 address 和指定大小为数字的 size 调用,此函数可能会返回字符串 STOP 以提前勾销内存扫描。onError:Function(Reason):当扫描时呈现内存拜访谬误时应用起因调用。onComplete:function():当内存范畴已齐全扫描时调用。
咱们来来说下面这段代码做了什么事件:搜寻 libhello.so 文件在内存中的数据,搜寻以 pattern 条件的在内存中能匹配的数据。搜寻到之后依据回调函数返回数据。
咱们来看看执行之后的效果图 1-6

图 1 -6 终端执行
咱们要如何验证搜寻到底是不是图 1-5112A地址,其实很简略。so的基址是0xdf2d3000,而搜到的地址是0xdf2d412a,咱们只有df2d412a-df2d3000=112A。就是说咱们曾经搜寻到了!

1.6.2 搜寻内存数据 Memory.scanSync

性能与 Memory.scan 一样,只不过它是返回多个匹配到条件的数据。
代码示例如下。

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 内存调配 Memory.alloc

在指标过程中的堆上申请 size 大小的内存,并且会依照 Process.pageSize 对齐,返回一个 NativePointer,并且申请的内存如果在JavaScript 外面没有对这个内存的应用的时候会主动开释的。也就是说,如果你不想要这个内存被开释,你须要本人保留一份对这个内存块的援用。
应用案例如下

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);

以上代码在指标过程中申请了 10 字节的空间~
能够看到在 0xdfe4cd40 处申请了 10 个字节内存空间~
也能够应用:
Memory.allocUtf8String(str) 调配 utf 字符串
Memory.allocUtf16String 调配 utf16 字符串
Memory.allocAnsiString 调配 ansi 字符串

1.6.4 内存复制 Memory.copy

如同 c api memcp 一样调用,应用案例如下。

function frida_Memory() {Java.perform(function () {
        // 获取 so 模块的 Module 对象
        var module = Process.findModuleByName("libhello.so"); 
        // 条件
        var pattern = "03 49 ?? 50 20 44";
        // 搜字符串 只是为了将 so 的内存数据复制进去 不便演示~
        var scanSync = Memory.scanSync(module.base, module.size, pattern);
        // 申请一个内存空间大小为 10 个字节
        const r = Memory.alloc(10);
        // 复制以 module.base 地址开始的 10 个字节 那必定会是 7F 45 4C 46... 因为一个 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 中复制 10 个字节的内存到新年申请的 r

1.6.6 写入内存 Memory.writeByteArray

将字节数组写入一个指定内存,代码示例如下:

function frida_Memory() {Java.perform(function () {
        // 定义须要写入的字节数组 这个字节数组是字符串 "roysue" 的十六进制
        var arr = [0x72, 0x6F, 0x79, 0x73, 0x75, 0x65];
        // 申请一个新的内存空间 返回指针 大小是 arr.length
        const r = Memory.alloc(arr.length);
        // 将 arr 数组写入 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 读取内存 Memory.readByteArray

将一个指定地址的数据,代码示例如下:

function frida_Memory() {Java.perform(function () {
        // 定义须要写入的字节数组 这个字节数组是字符串 "roysue" 的十六进制
        var arr = [0x72, 0x6F, 0x79, 0x73, 0x75, 0x65];
        // 申请一个新的内存空间 返回指针 大小是 arr.length
        const r = Memory.alloc(arr.length);
        // 将 arr 数组写入 R 地址中
        Memory.writeByteArray(r,arr);
        // 读取 r 指针,长度是 arr.length 也就是会打印下面一样的值
        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

 

结语

在这篇中咱们学会了在 FRIDACLI 中如何输入想要输入格局,也学会如何申明变量,一步步的学习。在逐渐的学习的过程,总是会遇到不同的问题。歌曲 < 奇观再现 > 我置信你肯定听过吧~,新的风暴曾经呈现, 怎么可能停止不前.. 遇到问题不要怕,总会解决的。

短视频、直播数据实时采集接口,请查看文档:TiToData

免责申明:本文档仅供学习与参考,请勿用于非法用处!否则所有后果自负。

退出移动版