一、Frida RPC介绍
Frida提供了一种基于JavaScript的RPC(远程过程调用)方案,使得开发者可以通过JavaScript代码远程调用目标应用程序中的函数或方法。
Frida RPC方案的核心思想是在目标应用程序中注入Frida Agent,并与Frida Server建立通信管道。通过这个通信管道,开发者可以使用Frida提供的JavaScript API来在目标应用程序中执行代码,远程调用函数或方法,并获取返回值。
二、Frida RPC优势
在面对复杂的加密逻辑、以及so层加密时,分析算法往往需要大量的时间,以及深厚的逆行功底。而通过Frida RPC远程调用,可以无需分析加密算法,直接调用APP本身的算法,实现加解密。
三、自动加解密方案
由于Frida提供了RPC远程调用的功能,因此,只需要使用Frida去Hook加解密函数,再通过RPC去远程调用,即可实现自动加解密的功能。
本文将通过以下2种方案,来介绍利用Frida RPC联动BurpSuite实现自动加解密。
-
Flask框架+Burpy插件
-
Brida插件
四、APP样本加密代码
定位到APP加密代码后,通过hook该加密类,主动调用该类下面的加、解密方法即可实现自动加解密。
|
五、Flask框架+Burpy插件
简介
Flask框架:
Flask是一个基于Python的轻量Web应用框架,它使用简单灵活,适合快速开发小型Web应用。
Burpy插件:
Burpy是一款BurpSuite插件,能在BurpSuite中调用Python脚本,并将处理结果返回给BurpSuite。
下载
Flask框架安装:
python -m pip install Flask==1.1.2
*左右滑动查看更多
Burpy插件下载:
https://github.com/mr-m0nst3r/Burpy
*左右滑动查看更多
在项目Releases中下载编译好的jar包导入BurpSuite中激活即可。
|
流程图
解析
主要文件:
├─Demo
│ burpy.py //Burpy脚本
│ Flask.py //Flask、Frida启动脚本
│ hook.js //Frida hook逻辑
将上述文件放置在同一文件夹内
*左右滑动查看更多
Burp.py文件
该文件是Burpy插件配置文件,当用户在BurpSuite中点击decrypt/encrypt按钮时,会自动调用对应函数,并将数据包body部分作为请求参数,以POST请求访问Flask服务路径。
import requests
class Burpy:
def __init__(self):
pass
def encrypt(self, header, body):
# 向http://127.0.0.1:8899/encrypt发送一个post请求,请求体为body形参
body = requests.post("http://127.0.0.1:8899/encrypt",data=body).text
return header, body
def decrypt(self, header, body):
# 向http://127.0.0.1:8899/decrypt发送一个post请求,请求体为body形参
body = requests.post("http://127.0.0.1:8899/decrypt",data=body).text
return header, body
def processor(self, payload):
pass
*左右滑动查看更多
Burp插件模板解析
import requests
class Burpy:
def __init__(self):
'''
该函数主要用于初始化,当点击burpy插件的“start server”按钮时会自动调用该函数
'''
pass
def encrypt(self, header, body):
'''
该函数用于处理加密逻辑,当用户点击burpy插件的“burpy encrypt”按钮时会调用该函数对数据包进行加密处理,
数据包的请求头会被传给该函数的header形参,请求体会被传给该函数的body形参。
header形参为dict类型,可直接使用ditc的方式获取请求头中某个字段值,例如header['Host']即可获得数据包请求头中的Host地址
body形参为string类型
'''
# 这里返回时,一定要将header、body都返回,这样才能拼接为一个正常的数据包,否则会报错
return header, body
def decrypt(self, header, body):
'''
该函数用于处理解密逻辑,当用户点击burpy插件的“burpy decrypt”按钮时会调用该函数对数据包进行解密处理
其余与encrypt()函数一致
'''
return header, body
def processor(self, payload):
'''
该函数用于在BurpSuite使用爆破模块时对payload进行处理
payload形参为BurpSuite中设置的payload
例:将下方pass替换为return payload+"123" 即可实现将BurpSuite中设置的payload再拼接上123,
该功能需要在Burpy插件中勾选“Enable Processor (require processor function)“,同时在BurpSuite中intruder模块的paylaod处理规则中选择Burpy插件
'''
pass
*左右滑动查看更多
Flask.py
该脚本主要是启动一个Web服务,接收来自BurpSuite传入的密文/明文,并将密文/明文通过Frida RPC传递给Frida。
当Burpy.py中请求了/decrypt路径,Flask服务会获取请求数据,传入frida_decrypt函数中,frida_decrypt函数使用script.exports.apidecode(data),也就是RPC导出函数将数据传给Frida。
from flask import Flask, request, jsonify
import frida
import sys
app = Flask(__name__)
# Flask请求处理逻辑
def encrypt_data():
data = request.data.decode('utf-8');
encrypted_data = frida_encrypt(data) # 使用Frida进行加密
return encrypted_data
def decrypt_data():
data = request.data.decode('utf-8');
decrypted_data = frida_decrypt(data) # 使用Frida进行解密
return decrypted_data
# 启动frida
def frida_hook():
jscode = open("hook.js", "r", encoding="utf-8").read() # 注入hook.js
process = frida.get_remote_device().attach('com.xxx.xxx.xxx') # hook对应包名app
script = process.create_script(jscode)
script.on("message", message)
script.load()
return script
# RPC远程调用
def frida_encrypt(data):
script = frida_hook()
encrypt_data = script.exports.apiencode(data)
return encrypt_data
def frida_decrypt(data):
script = frida_hook()
decrypt_data = script.exports.apidecode(data)
return decrypt_data
def message(message, data):
if message["type"] == 'send':
print("send message is:",message['payload'])
else:
print(message)
if __name__ == '__main__':
# 启动Flask服务
app.run(host='127.0.0.1', port=8899)
*左右滑动查看更多
文件解析
该部分代码为Falsk框架代码,主要是启动一个web服务。
app = Flask(__name__)
# Flask请求处理逻辑
def encrypt_data():
'''
该函数用于处理/encrypt的请求,获取到请求体赋值给data参数,随后将data传入frida_encrypt()函数
'''
data = request.data.decode('utf-8');
encrypted_data = frida_encrypt(data) # 使用Frida进行加密
return encrypted_data
def decrypt_data():
'''
该函数用于处理/decrypt的请求,获取到请求体赋值给data参数,随后将data传入frida_decrypt()函数
'''
data = request.data.decode('utf-8');
decrypted_data = frida_decrypt(data) # 使用Frida进行解密
return decrypted_data
if __name__ == '__main__':
# 启动Flask服务
app.run(host='127.0.0.1', port=8899)
*左右滑动查看更多
该部分代码为frida启动代码和Frida RPC代码。
# 启动frida
def frida_hook():
# 从文件中读取JavaScript代码,也就是hook逻辑代码
jscode = open("hook.js", "r", encoding="utf-8").read()
# 连接到远程设备并附加到目标应用程序(使用对应的包名)
process = frida.get_remote_device().attach('com.xxx.xxx.xxx')
# 创建Frida脚本并加载JavaScript代码
script = process.create_script(jscode)
script.on("message", message)
script.load()
return script
# RPC远程调用
def frida_encrypt(data):
# 获取hook进程
script = frida_hook()
# 调用JavaScript脚本中的apiencode函数进行加密,script.exports.xxx()表示通过frida rpc调用某个导出函数
encrypt_data = script.exports.apiencode(data)
return encrypt_data
def frida_decrypt(data):
# 获取hook进程
script = frida_hook()
# 调用JavaScript脚本中的apidecode函数进行解密
decrypt_data = script.exports.apidecode(data)
return decrypt_data
def message(message, data):
# 处理Frida脚本发送的消息
if message["type"] == 'send':
print("send message is:", message['payload'])
else:
print(message)
*左右滑动查看更多
hook.js
hook.js主要是Frida的Hook逻辑,通过RCP接收Flask传入的明文/密文。
RPC将数据传递给对应的Hook逻辑,通过类对象主动调用app中的encode/decode函数,进行加解密,最后将密/明文返回,至此,加解密完成。
// 定义变量
var Classz;
var Classobj;
var en_result;
var de_result;
// 动态加载DEX文件
Java.perform(function() {
Java.enumerateClassLoaders({
onMatch: function(loader) {
try {
// 加载指定类
if (loader.loadClass("com.xxx.xxx.xxx.xxx.xxx")) {
// 获取类的引用
Classz = Java.use("com.xxx.xxx.xxx.xxx.xxx");
// 创建实例对象
Classobj = Classz.$new();
console.log("[*] Found class");
}
} catch (error) {
// 异常处理,防止因为类加载失败导致脚本中断
}
},
onComplete: function() {
// 类加载完成后执行的回调函数
}
});
});
// 定义加密函数
function _encode(str_data) {
Java.perform(function(){
// 调用类对象的encode函数,使用utf-8编码进行加密
en_result = Classobj.encode(str_data, 'utf-8');
});
return en_result;
};
// 定义解密函数
function _decode(str_data) {
Java.perform(function(){
// 通过类对象主动调用decode函数,将传入的密文进行解密,使用utf-8编码
de_result = Classobj.decode(str_data, 'utf-8');
});
return de_result;
};
// RPC导出函数
rpc.exports = {
// 将该js文件内部的_encode()函数导出到外部的apiencode()函数
// 也就是说在Flask.py文件中的script.exports.apiencode(data),调用的是该js文件的_encode()函数
// 该js文件的_encode()函数调用的是Classobj对象的encode()函数,即APP应用本身的加密函数。
apiencode: _encode,
apidecode: _decode
};
*左右滑动查看更多
操作演示
1.启动frida-server。
2.启动APP。
3.运行Flask.py。
4.启动Burpy插件。
|
5.实现解密。
|
六、Brida插件
简介
Brida是一个Burp Suite扩展,它作为BurpSuite和Frida之间的桥梁,允许您使用和操作应用程序自己的方法,同时篡改应用程序与其后端服务/服务器之间交换的流量。它支持Frida支持的所有平台(Windows、macOS、Linux、iOS、Android和QNX)。
Brida下载:
https://github.com/federicodotta/Brida
*左右滑动查看更多
流程图
操作演示
本机环境:
frida(14.2.18)
frida-compile(建议10.2.5版本)
BurpSuite Pro V2023.6.1
Brida v0.6pre
1.配置Brida环境:
|
2.启动frida-server:
3.启动APP。
4.启动Brida插件。
|
5.编写Brida脚本。
|
brida.js大致可分为4个区域。最上方区域定义了许多Brida需要用到的常量,同时我们也可以在此区域定义变量。
|
rpc.exports区域用于放置frida rpc的逻辑代码,我们自己编写的frida rpc代码放置在 //Put here the exported functions called by your custom plugins 注解处。
|
// Put here you Frida hooks! 注解处用于放置其他hook逻辑,可用于放置hook类的代码。
|
剩余的部分主要是Brida插件用于对数据做编码处理的,无需操作。
|
在const下面定义4个变量。
|
在 // Put here you Frida hooks! 注解处,放置上述hook.js中hook类、创建类对象的代码。
|
rpc.exports处放置RPC函数逻辑,保存后,重新加载、编译。
|
6.测试RPC是否能正常调用。
|
7.实现自动加解密
|
|
8.测试。
|
七、加固建议
-
代码混淆: -
使用代码混淆工具,例如ProGuard(对于Android)或Obfuscator(对于iOS),来混淆代码。这会使代码更难以理解和分析。 -
反调试技术: -
实施反调试技术,以防止恶意用户使用调试器来分析应用程序。 -
通过检查调试标志或在关键代码路径中添加反调试检查来实现此目标。 -
反Hook技术: -
使用反Hook库和技术,如Anti-Frida、Anti-Xposed等,来检测Hook工具的存在并采取相应的措施。 -
加固文件和资源: -
加固应用程序的资源文件,如图片、声音或视频,以防止它们被轻松提取或替换。 -
检测Rooted或Jailbroken设备: -
在应用程序启动时检查设备是否被Rooted(Android)或Jailbroken(iOS),并采取适当的措施,如拒绝运行或限制功能。 -
加密敏感数据: -
对于敏感数据,使用强加密算法来存储和传输数据,以确保数据的保密性。 -
运行时保护: -
使用运行时保护工具,如DexGuard或iOS的加固框架,来保护应用程序免受运行时攻击。 -
更新和漏洞管理: -
及时更新应用程序以修复已知漏洞,并监视应用程序以检测新的漏洞。 -
监控和日志记录: -
实施监控和日志记录,以检测异常行为或攻击,并记录相关信息以进行分析。 -
网络安全: -
使用HTTPS来保护数据在传输过程中的安全性。 -
验证服务器证书,以防止中间人攻击。
其他参考及推荐阅读:
frida相关学习可参考:
https://zyzling.gitee.io/2020/05/12/Frida学习笔记/
https://github.com/r0ysue/AndroidSecurityStudy
*左右滑动查看更多
往期回顾
原文始发于微信公众号(安恒信息安全服务):九维团队-绿队(改进)| APP安全-Frida联动BurpSuite实现自动加解密
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论