micro850通讯协议msg_某右协议分析(三)

本文详细介绍了分析某右5.5.10版本通讯协议的过程,涉及请求参数的AES加密和签名。通过Frida的RPC调用,实现了AES加解密及签名函数的交互。在解决类型转换问题后,成功获取了热门数据。总结强调了Frida RPC调用中处理参数类型的重要性,同时提到Frida的不稳定性,建议线上环境使用Xposed。文章旨在分享逆向工程技术,并警告读者非法使用技术的法律后果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、目标

分析某右的通讯协议,实现段子爬虫

  • 某右版本 5.5.10

Note:
  • frida rpc调用

二、分析

我们上篇文章分析完了,某右的通讯协议流程是 请求参数→AES加密→密文做sign签名 ,所以我们需要通过frida的rpc调用Aes加解密函数和密文签名函数。

用jeb打开之前分析的 com.izuiyou.network.NetCrypto 类,可以找到目标函数

 public static native byte[] decodeAES(byte[] arg0, boolean arg1) {
}

public static native byte[] encodeAES(byte[] arg0) {
}

public static native String getProtocolKey() {
}

public static native void setProtocolKey(String arg0) {
}

public static native String sign(String arg0, byte[] arg1) {
}

我们以调用encodeAES为例,encodeAES函数的参数和返回值都是byte数组,但是encodeAES的参数实际是个字符串,所以我们在python调用时传入字符串,然后在js代码中来转成byte[]类型。

返回值的处理比较麻烦,因为python和js对byte[]类型的处理可能不一样,所以我们在js代码中把byte数组转成对应hex字符串,然后再返回给python。

run.py
@app.route('/aesenc', methods=['POST']) # 数据加密
def zy_aesenc():
global gScript

data = request.get_data()
print(data.decode("utf-8"))

res = gScript.exports.callencaes(data.decode("utf-8"))
return res
hook.js
function callEncodeAes(strData){
var result = 'null';

Java.perform(function() {
var ZYNetCrypto = Java.use("com.izuiyou.network.NetCrypto");

var strIn = Java.use('java.lang.String');
var byteIn = strIn.$new(strData).getBytes();

var res = ZYNetCrypto.encodeAES(byteIn);

result = Bytes2HexString(res);

});

return result;
}

某右请求的返回值也是加密数据,解密函数由decodeAES完成,调用decodeAES的时候遇到一个问题,decodeAES函数的返回值是byte[]类型,但是实际上是String类型的明文。所以一开始我们用

	var result = this.decodeAES(arg1,arg2);
var strIn = Java.use('java.lang.String');
var outStr = strIn.$new(result);

这种方式把类型转换成String,然后直接返回给python代码,结果总是异常报错,百思不得其解。 最后还是用encodeAES一样的方式来转成hex字符串来输出:

run.py
@app.route('/aesdec', methods=['POST']) # 数据解密
def zy_aesdec():
global gScript

data = request.get_data()
res = gScript.exports.calldecaes(data.decode("utf-8"))
return res
hook.js
// 解密
function callDecodeAes(dataBuf){
var rc = 'null';

var arr = HexString2Bytes(dataBuf);

Java.perform(function() {
var ZYNetCrypto = Java.use("com.izuiyou.network.NetCrypto");
var res = ZYNetCrypto.decodeAES(arr,true);
rc = Bytes2HexString(res);
});

return rc;
}

最后我们用一个python来组装获取某右热门数据的请求

# 获取数据
def get_data(uri, msg):
postData = dataAesEnc(msg)
# print(postData)
sign = dataSign(postData)
# print(sign)
protocolKey = dataGetKey()
# print(protocolKey)

url = uri + str(sign)
headers = { 'ZYP': 'mid=239631186',
'X-Xc-Agent' : 'av=5.5.11,dt=0',
'User-Agent': 'okhttp/3.12.2 Zuiyou/5.5.11 (Android/27)',
'X-Xc-Proto-Req' : protocolKey,
'Request-Type' : 'text/json',
'Content-Type' : 'application/xcp',
}
byte_data = bytes.fromhex(postData)

# proxies = {'http': '127.0.0.1:8888',
# 'https': '127.0.0.1:8888'
# }

try:
# ,proxies=proxies
r = requests.post(url, headers=headers, data=byte_data, verify=False,stream=True,timeout=15)

# print(r.headers['X-Xc-Proto-Res'])
# key是 cat开头的就需要把返回包里面的duck key设置进去,
if protocolKey.find('cat') == 0:
print(protocolKey)
print(r.headers['X-Xc-Proto-Res'])
dataSetKey(r.headers['X-Xc-Proto-Res'])
# 这里要做一些错误处理
bufRc = r.raw.read();
rcStr = dataAesDec(bufRc.hex())
rc = bytes.fromhex(rcStr).decode("utf-8")
return rc

except RequestException as e:
print(e)

def main():
# 手机端首页推荐地址
uri = 'http://api.izuiyou.com/index/recommend?sign='
msg = '{"filter":"all","auto":0,"tab":"推荐","direction":"down","c_types":[1,2,11,15,16,51,17,52,53,40,50,41,22,25,27],"sdk_ver":{"tt":"3.1.0.3","tx":"4.211.1081","bd":"5.86","mimo":"5.0.3","tt_aid":"5004095","tx_aid":"1106701465","bd_aid":"c8655095","mimo_aid":"2882303761518470184"},"ad_wakeup":1,"h_ua":"Mozilla\/5.0 (Linux; Android 8.1.0; Redmi 6A Build\/O11019; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/62.0.3202.84 Mobile Safari\/537.36","manufacturer":"Xiaomi","h_av":"5.5.11","h_dt":0,"h_os":27,"h_app":"zuiyou","h_model":"Redmi 6A","h_did":"866655030396869","h_nt":1,"h_m":239631186,"h_ch":"xiaomi","h_ts":1603179121590,"token":"T7K4Nnqg98_aFV9JwkfuiZtvPrRJ02EXxbnm7TXr3qiIWWaT1vjNNNCpcUu112TDw_VXu","android_id":"57b9b8465c2e440b","h_ids":{"imei2":"878739042239784","meid":"98001184062989","imei1":"878739042239776","imei":"98001184062989"},"h_os_type":"miui"}'

items = get_data(uri, msg)
print(items)

结果如下,可以成功获取到数据:

4f8eff2a202f74bfac53265b3b5f6009.png
1:bashrc

三、总结

frida rpc调用主要就是处理好参数类型,python和js的互相调用。实际运行过程中 frida不是很稳定,偶尔会崩溃退出,所以线上环境还是建议用Xposed来做rpc。

Tip:

本文的目的只有一个就是学习更多的逆向技巧和思路,如果有人利用本文技术去进行非法商业获取利益带来的法律责任都是操作者自己承担,和本文以及作者没关系,本文涉及到的代码项目可以去 奋飞的朋友们 知识星球自取,欢迎加入知识星球一起学习探讨技术。有问题可以加我wx: fenfei331 讨论下。

a878f6f2b0555c92d2373bc065930097.png

关注微信公众号,最新技术干货实时推送

4a5703a3f73ef6b9adf4b14299589c0c.png

手机查看不方便,可以网页看

http://91fans.com.cn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值