刚刚开始学Android逆向,发现Frida是个好东西,于是赶紧下载研究一番。 下载源码编译,切换到最新版16.0.11, 编译之前注意先更新nodejs
然后执行
就可以成功生成frida-server以及frida相关tools,于是push到手机上执行
报错了...额,继续往下试试
把手机上的名为com.example.myapplication的demo app放到前台,然后注入一个helloword级别的js
然后执行
咳,出师不利,不过反正我也是做c++开发的,虽然不懂javascript, 连蒙带猜也能看个差不多,那就研究研究报错原因吧。
从现有信息来看,第一怀疑对象应该是那个报错"Error: Java API not available", 也指明了报错位置at _checkAvailable (frida/nodemodules/frida-java-bridge/index.js:298:1) at .perform (frida/node_modules/frida-java-bridge/index.js:203:1)\n ,那就在源码里搜索下。 发现这个index.js位于build/tmp-android-arm64/frida-gum/bindings/gumjs/node_modules/frida-java-bridge目录, 然后看下perform实现
这个函数第一行就是_checkAvailable,跟进去看看
果然报错就是在这里,那么关键的判断就是available了,再跳过去看看
那么只有一种可能,就是getApi()返回为null,再跟进去看看,这个getApi的有几层跳转如下
看代码的意思是进程内没找到加载的libart.so或者libdvm.so,真奇怪了,你可是android进程,没有虚拟机咋跑的?
那就看下这个进程加载了什么,首先找到进程id
然后检查下maps
果然没有,见鬼了,我把maps的输出保存下来,在编辑器里查看才发现了端倪,原来进程加载的so里有一个libartd.so,因为这个手机是pixel5,系统是我自己下载AOSP编译的,选择的是eng版,这样编出来的系统so都是debug版,也就意味着后缀都有一个d,难怪frida找不到。
知道了原因,那解决方案就简单了,把那段查找libart.so的代码改成查找libartd.so即可。不过还有一个问题,这个frida-java-bridge是编译的时候从网上下载的,我们本地修改会被覆盖,那么就得研究下frida的编译系统了,让它使用我们本地的frida-java-bridge。
首先在源码里搜索frida-java-bridge,果不其然,是在一个generate-runtime.py里面,代码如下
看来是编译的时候,用npm install -E把frida-java-bridge下载下来了,那么接下来就是要把这个依赖项改成我们本地的。 首先下载一个到本地
然后全局查找libart.so,改成libartd.so
这时候需要用到npm link把我们本地的frida-java-bridge注册到系统中
然后要让frida中的编译脚本指向我们这个,也就是不要用npm install了,需要改成npm link, 修改generate-runtime.py代码如下
然后再重新编译, 生成后推到手机执行
果然没有报错了,非常完美!
wget
-
qO
-
https:
/
/
deb.nodesource.com
/
setup_16.x | sudo
-
E bash
-
sudo apt
-
get install
-
y nodejs
wget
-
qO
-
https:
/
/
deb.nodesource.com
/
setup_16.x | sudo
-
E bash
-
sudo apt
-
get install
-
y nodejs
make core
-
android
-
arm64
make tools
-
linux
-
x86_64 PYTHON
=
$HOME
/
miniconda3
/
bin
/
python
make core
-
android
-
arm64
make tools
-
linux
-
x86_64 PYTHON
=
$HOME
/
miniconda3
/
bin
/
python
redfin:
/
data
/
local
/
tmp
{
"type"
:
"error"
,
"description"
:
"Error: Java API not available"
,
"stack"
:
"Error: Java API not available\n at _checkAvailable (frida/node_modules/frida-java-bridge/index.js:298:1)\n at _.perform (frida/node_modules/frida-java-bridge/index.js:203:1)\n at /internal-agent.js:490:6"
,
"fileName"
:
"frida/node_modules/frida-java-bridge/index.js"
,
"lineNumber"
:
298
,
"columnNumber"
:
1
}
redfin:
/
data
/
local
/
tmp
{
"type"
:
"error"
,
"description"
:
"Error: Java API not available"
,
"stack"
:
"Error: Java API not available\n at _checkAvailable (frida/node_modules/frida-java-bridge/index.js:298:1)\n at _.perform (frida/node_modules/frida-java-bridge/index.js:203:1)\n at /internal-agent.js:490:6"
,
"fileName"
:
"frida/node_modules/frida-java-bridge/index.js"
,
"lineNumber"
:
298
,
"columnNumber"
:
1
}
setTimeout(
function() {
Java.perform(function() {
console.log(
"Hello frida!"
)
})
}
)
/
/
test.js
setTimeout(
function() {
Java.perform(function() {
console.log(
"Hello frida!"
)
})
}
)
/
/
test.js
(base)
/
data
/
code
/
OpenSource
/
crack
/
frida
/
build
/
frida
-
linux
-
x86_64
/
bin
(
16.0
.
11
✔) .
/
frida
-
U
-
l ..
/
..
/
..
/
..
/
frida_script
/
test.js com.example.myapplication
____
/
_ | Frida
16.0
.
11
-
A world
-
class
dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/
_
/
|_|
help
-
> Displays the
help
system
. . . .
object
?
-
> Display information about
'object'
. . . . exit
/
quit
-
> Exit
. . . .
. . . . More info at https:
/
/
frida.re
/
docs
/
home
/
. . . .
. . . . Connected to AOSP on redfin (
id
=
0A051FDD4003BW
)
Failed to spawn: cannot read properties of undefined (reading
'getRunningAppProcesses'
)
(base)
/
data
/
code
/
OpenSource
/
crack
/
frida
/
build
/
frida
-
linux
-
x86_64
/
bin
(
16.0
.
11
✔) .
/
frida
-
U
-
l ..
/
..
/
..
/
..
/
frida_script
/
test.js com.example.myapplication
____
/
_ | Frida
16.0
.
11
-
A world
-
class
dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/
_
/
|_|
help
-
> Displays the
help
system
. . . .
object
?
-
> Display information about
'object'
. . . . exit
/
quit
-
> Exit
. . . .
. . . . More info at https:
/
/
frida.re
/
docs
/
home
/
. . . .
. . . . Connected to AOSP on redfin (
id
=
0A051FDD4003BW
)
Failed to spawn: cannot read properties of undefined (reading
'getRunningAppProcesses'
)
perform (fn) {
this._checkAvailable();
if
(!this._isAppProcess() || this.classFactory.loader !
=
=
null) {
try
{
this.vm.perform(fn);
} catch (e) {
Script.nextTick(()
=
> { throw e; });
}
}
else
{
this._pendingVmOps.push(fn);
if
(this._pendingVmOps.length
=
=
=
1
) {
this._performPendingVmOpsWhenReady();
}
}
}
perform (fn) {
this._checkAvailable();
if
(!this._isAppProcess() || this.classFactory.loader !
=
=
null) {
try
{
this.vm.perform(fn);
} catch (e) {
Script.nextTick(()
=
> { throw e; });
}
}
else
{
this._pendingVmOps.push(fn);
if
(this._pendingVmOps.length
=
=
=
1
) {
this._performPendingVmOpsWhenReady();
}
}
}
_checkAvailable () {
if
(!this.available) {
throw new Error(
'Java API not available'
);
}
}
_checkAvailable () {
if
(!this.available) {
throw new Error(
'Java API not available'
);
}
}
get available () {
return
this._tryInitialize();
}
_tryInitialize () {
if
(this._initialized) {
return
true;
}
if
(this._apiError !
=
=
null) {
throw this._apiError;
}
let api;
try
{
api
=
getApi();
this.api
=
api;
} catch (e) {
this._apiError
=
e;
throw e;
}
if
(api
=
=
=
null) {
return
false;
/
/
只有这里返回为false
}
const vm
=
new VM(api);
this.vm
=
vm;
Types.initialize(vm);
ClassFactory._initialize(vm, api);
this.classFactory
=
new ClassFactory();
this._initialized
=
true;
return
true;
}
get available () {
return
this._tryInitialize();
}
_tryInitialize () {
if
(this._initialized) {
return
true;
}
if
(this._apiError !
=
=
null) {
throw this._apiError;
}
let api;
try
{
api
=
getApi();
this.api
=
api;
} catch (e) {
this._apiError
=
e;
throw e;
}
if
(api
=
=
=
null) {
return
false;
/
/
只有这里返回为false
}
const vm
=
new VM(api);
this.vm
=
vm;
Types.initialize(vm);
ClassFactory._initialize(vm, api);
this.classFactory
=
new ClassFactory();
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!