🛫 系列文章导航
- 【Frida】【Android】01_手把手教你环境搭建 https://blog.csdn.net/kinghzking/article/details/136986950
- 【Frida】【Android】02_JAVA层HOOK https://blog.csdn.net/kinghzking/article/details/137008446
- 【Frida】【Android】03_RPC https://blog.csdn.net/kinghzking/article/details/137050967
▒ 目录 ▒
🛫 导读
开发环境
版本号 | 描述 | |
---|---|---|
文章日期 | 2024-03-24 | |
操作系统 | Win11 - 22H2 | 22621.2715 |
node -v | v20.10.0 | |
npm -v | 10.2.3 | |
夜神模拟器 | 7.0.5.8 | |
Android | 9 | |
python | 3.9.9 | |
frida | 16.2.1 | |
frida-tools | 12.3.0 | |
objection | 1.11.0 | |
1️⃣ Android App解释
过Frida存在两种操作模式,其中第一种
命令行模式
在之前的章节中一直使用,在这一节中,将介绍一些关于RPC模式
以及使用RPC完成自动化的相关知识。在Frida中,可以使用Python完成JavaScript脚本对进程的注入以及相应的Hook。
Java示例代码
参考《【Frida】【Android】02_JAVA层HOOK https://blog.csdn.net/kinghzking/article/details/137008446》,我们需要通过python代码完成下面两个任务:
- 每次调用
secret()
函数对字符串进行扩展。- 获取
total
这个实例
变量的值。
2️⃣ 注入的js代码
注意事项:
- 整体逻辑,不用通过
Java.perform(rpc测试)
执行,该函数是通过对rpc.exports
赋值,实现rpc的功能导出。- 由于目标不是静态变量,我们需要对实例进行操作,所以,需要使用
Java.choose
动态获取。- 导出的对象中,必须使用全小写作为key,否则python访问不到。
js
function rpc测试() {
function CallSecretFunc(){
Java.perform(function(){
// 动态函数主动调用
Java.choose('com.yemao.demo.MainActivity',{
onMatch: function(instance){
instance.secret()
},
onComplete: function(){
}
})
})
}
function getTotalValue(){
Java.perform(function(){
// var MainAcitivity = Java.use('com.yemao.demo.MainActivity')
// 动态函数主动调用
Java.choose('com.yemao.demo.MainActivity',{
onMatch: function(instance){
// console.log('instance found',instance)
// instance.secret()
console.log('total value = ',instance.total.value)
// console.log('secret func exec success')
},
onComplete: function(){
console.log('search Complete')
}
})
})
}
rpc.exports = {
gettotalvalue: getTotalValue,
callfunc: CallSecretFunc,
CallSecretFunc: CallSecretFunc
}
}
rpc测试()
3️⃣ python控制端
- 由于我们使用的是模拟器,需要使用
frida.get_remote_device()
获取设备对象device
。对于真机,使用frida.get_usb_device()
。- 附加目标进程,使用的是
device.attach
,传参需要注意,一开始使用的是com.yemao.demo
,没有效果。
通过执行device.enumerate_processes()
,打印所有进程,看到名称为demo,传递给device.attach
才正常运行。
- 读取js时,需要指定编码
encoding='utf-8'
,否则会报错的。
python
import frida
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
def main():
# device = frida.get_usb_device()
# device = frida.get_device_manager().add_remote_device('127.0.0.1:62025')
device = frida.get_remote_device()
print(device, device.enumerate_processes())
# return
# process = device.attach('com.yemao.demo')
process = device.attach('demo')
# process = device.attach('com.android.settings.intelligence')
with open('./build/02.js', encoding='utf-8') as f:
jscode = f.read()
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
while True:
command = input ("\nEnter command:\nl: Exit\n2: Call secret function\n3: Get Total Value\nchoice:")
if command == "1":
print('script.exports_sync = ', dir(script.exports_sync))
break
elif command== "2":#在这里调用
script.exports_sync.callfunc()
elif command == "3":
script.exports_sync.gettotalvalue()
elif command == "4":
script.exports_sync.CallSecretFunc()
main()
4️⃣ 效果
测试流程:
- 执行一次
3: Get Total Value
,获取修改前的total
- 执行一次
Call secret function
,修改total
- 再执行一次
3: Get Total Value
,获取修改后的total
从图中可以看到,满足我们的预期,测试通过!!!
🛬 文章小结
- 通过
dir(script.exports_sync)
可以打印所有的exports_sync内容['CallSecretFunc', 'callfunc', 'gettotalvalue']
,这里面就是我们导出的三个函数。
我们可以看到,其中是有区分大小写的方法CallSecretFunc
的,但是如果通过rpc进行调用,又会报如下错误:
所以,命名上,我们只可以写小写的rpc函数
。
📖 参考资料
- 《安卓Frida逆向与抓包实战》
- 【Frida】 00_简单介绍和使用 https://blog.csdn.net/kinghzking/article/details/123225580
- 本节源码地址 https://gitcode.com/android8/AndroidFridaBeginnersBook
ps: 文章中内容仅用于技术交流,请勿用于违规违法行为。