RPC概念和实例

本章来看一下RPC相关的问题
RPC远程过程调用,是一种计算机通信协议,用于在计算机网络中的程序之间进行通信。它允许程序调用另一个地址空间(通常是远程机器上的程序)的过程,就像调用本地过程一样,而无需显式地处理网络细节。
在RPC中,客户端程序调用远程服务器上的过程,就像调用本地过程一样。RPC框架负责将参数传递给远程过程并返回结果。这使得分布式计算变得更加容易,因为开发人员可以将远程调用抽象为本地调用,而不必去关心底层网络通信的实现细节。

- 在进行RPC之前,要先把问题在hook和主动调用阶段解决,然后再去进行RPC的互联
远程调用
这里拿lesson4 编写的apk来进行RPC调用测试
调用secret()

先执行这个脚本看是否起作用了

- 起作用了我们开始进行下一步的RPC调用
RPC注入的脚本:
PS:Amazon CodeWhisperer的代码智能提示挺好用的,支持中文还免费
lesson7_lesson4.js
function invoke(){
Java.perform(function(){
Java.choose("com.xiaoeryu.lesson4_4.MainActivity",{
onMatch:function(instance){
console.log("found instance: ", instance)
console.log("found instance: ", instance.secret())
},onComplete:function(){}
})
})
}
// setTimeout(invoke, 3000);
rpc.exports = {
invokefunc:invoke
}
lesson7_loader.py
import time
import frida
def my_message_handler(message, payload):
# 处理Frida脚本发送的消息
print(message)
print(payload)
# 获取连接到计算机的USB设备,通常是Android设备
device = frida.get_usb_device()
# ==============================
# 选择一种注入方式(方式1或方式2),注释掉另一种方式
# Way 1: 通过spawn方式创建进程并附加
# pid = device.spawn(["com.xiaoeryu.lesson4_4"])
# device.resume(pid)
# time.sleep(1)
# session = device.attach(pid)
# Way 2: 直接绑定到指定的进程
session = device.attach("com.xiaoeryu.lesson4_4") # 绑定指定进程
# ==============================
# 打开名为lesson7_lesson4.js的Frida脚本文件
with open("lesson7_lesson4.js") as f:
# 创建Frida脚本对象并加载脚本内容
script = session.create_script(f.read())
# 将my_message_handler函数注册为脚本的消息处理程序
script.on("message", my_message_handler)
# 加载脚本到目标应用程序中,使其开始执行
script.load()
command = ""
while True:
# 等待用户输入命令,提示符为>>>
command = input(">>>")
if command == "1":
# 如果用户输入为"1",跳出循环,结束程序
break
elif command == "2":
# 如果用户输入为"2",调用Frida脚本中导出的invokefunc函数
script.exports.invokefunc()
执行效果

多主机多手机多端口混连
先把手机的wifi adb
打开

打开frida-server绑定9999端口

- 现在我们局域网下面的设备就都可以使用adb命令连接192.168.1.7这台设备了
修改一下我们的python脚本为远程连接

打印设备的信息也是可以的

互联互通、动态修改、上传到PC打印
下面先写一下用来测试的登陆界面 ,然后截取登陆界面的用户名和密码并修改
PS:使用下载的代码的时候最好把IDE的代理挂上,不然有些包下载不下来各种报错

- 在这里我们设置一下不允许使用admin用户名登陆,后面hook后强制修改
- 然后把输入的用户名和密码
base64
后传给服务端 - 可以通过HOOK
message_tv.setText()
来拿到base64后的用户名和密码
编写hook脚本
setText()
是一个通用函数肯定有多个重载,可以先确定这里使用的是哪个重载
使用objection来确定一下使用了哪个重载
- 这里frida-server不小心断开了,重连了一遍,所以端口改为了8888
Called android.widget.TextView.setText(java.lang.CharSequence)
function main(){
Java.perform(function(){
Java.use("android.widget.TextView").setText.overload('java.lang.CharSequence').implementation = function(x){
console.log("TextView.setText: " + x)
return this.setText(x)
}
})
}
setImmediate(main)
在使用RPC之前先试一下本地调用是否ok
- 测试ok,开始修改脚本去跟服务端联动
修改脚本:添加发送和接收进行RPC联动
修改后的lesson7sec.js
Java.perform(function(){
Java.use("android.widget.TextView").setText.overload('java.lang.CharSequence').implementation = function(x){
var string_to_send_x = x.toString()
var string_to_recv
send(string_to_send_x)
recv(function(recv_json_objection){
string_to_recv = recv_json_objection.my_data
// x = string_to_recv.toString()
console.log("string_to_recv: " + string_to_recv)
}).wait()
var javaStringToSend = Java.use("java.lang.String").$new(string_to_recv)
var result = this.setText(javaStringToSend)
// console.log("TextView.setText: " + x)
return result
}
})
lesson7secLoader.py
import time
import frida
import base64
# 定义消息处理函数
def my_message_handler(message, payload):
# 打印接收到的消息和负载
print(message)
print(payload)
# 检查消息类型是否为 "send"
if message["type"] == "send":
# 打印接收到的负载数据
print(message["payload"])
# 解码 base64 编码的数据,并转换为字符串
data = message["payload"].split(":")[1].strip()
data = str(base64.b64decode(data), encoding="utf-8")
print("解码后的数据: ", data)
# 将解码后的数据拆分成用户名和密码
usr, pw = data.split(":")
print("密码: ", pw)
# 将用户名替换为 "admin",然后重新编码为 base64
data = str(base64.b64encode(("admin" + ":" + pw).encode()))
print("编码后的数据: ", data)
# 向脚本发送修改后的数据
script.post({"my_data": data})
print("修改后的数据已发送!")
# 连接到远程设备
device = frida.get_device_manager().add_remote_device("192.168.1.7:8888")
# 附加到目标应用进程
session = device.attach("com.example.lesson7sec")
# 从文件中读取 JavaScript 脚本
with open("lesson7sec.js") as f:
script = session.create_script(f.read())
# 设置消息处理回调函数
script.on("message", my_message_handler)
# 加载并执行 JavaScript 脚本
script.load()
# 等待输入,保持脚本运行
input()
运行结果
- 标题: RPC概念和实例
- 作者: xiaoeryu
- 创建于 : 2023-11-24 16:15:00
- 更新于 : 2023-11-24 21:30:36
- 链接: https://github.com/xiaoeryu/2023/11/24/RPC概念和实例/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论