本帖最后由 公过水蚊 于 2020-11-23 11:11 编辑
1、前言 逆向萌新,闲来无事,找了个app练习一下,这次案例是某猫免费小说,特开一贴用来记录一下分析过程。(ps:本篇分析的APP版本为4.0.0)
2、APP抓包分析用Fiddler对目标app进行抓包,抓包结果如下:
主要找sign的生成过程,打开jadx搜索代码"sign",把可能会生成sign的方法都给hook,再发送一次请求看生成sign的方法在哪。一些包名有huawei,meizu这些的可以直接过滤掉。
代码如下:
[Asm] 纯文本查看 复制代码 function main(){
Java.perform(
function(){
/*
var e = Java.use('anet.channel.strategy.dispatch.e');
e.a.overload('java.util.Map').implementation = function(v1,v2){
console.log('dispatch')
return this.a(v1,v2);
}
var p = Java.use('com.bytedance.sdk.openadsdk.core.p');
p.a.overload('java.lang.String', 'java.lang.String').implementation = function(v1,v2){
console.log('openadsdk');
return this.a(v1,v2);
}
var c = Java.use('com.km.repository.net.a.a.c');
c.intercept.implementation = function(v1){
console.log('repository');
return this.intercept(v1);
}
var c = Java.use('com.kmxs.reader.download.a');
c.c.overload('java.lang.String').implementation = function(v1){
console.log('reader...');
console.log('v1:', v1);
var sig = this.c(v1);
console.log('sig:', sig);
return sig;
}*/
// 生成sig方法
var a = Java.use('com.km.core.b.a');
a.a.overload('java.lang.String').implementation = function(v1){
console.log('core.....');
console.log('v1:', v1);
var sig = this.a(v1);
console.log('sig:', sig);
return sig;
}
/*
var a = Java.use('com.km.repository.net.b.a');
a.d.overload().implementation = function(){
console.log('repository.....');
var sig = this.d();
console.log('sig:', sig);
return sig;
}*/
}
)
}
setImmediate(main)
运行脚本查看
多次请求对比可以看到,headers里面的sign是固定的,生成sign的参数都是头部信息里的。url的sign主要由page页数决定。知道这些就可以用frIDA rpc进行调用。
3、frida rpc进行调用并尝试请求找到刚才hook到的方法。
跳到a方法的声明查看下
再深入看刚才sign()方法,可以看到加密过程是在so文件里,这里就不去分析加密过程了,直接rpc调用就可以了。
构建参数使用rpc调用sign生成后使用python请求进行验证,代码如下:
[Python] 纯文本查看 复制代码 import frida
import sys
import uuid
import requests
rpc_sig_js = """
rpc.exports = {
getsig: function(str){
var sig = '';
Java.perform(
function(){
var a = Java.use('com.km.core.b.a');
sig = a.a(str);
}
)
return sig;
}
}
"""
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
def process_script(parse):
"""启动frida rpc"""
process = frida.get_remote_device().attach('com.kmxs.reader')
script = process.create_script(rpc_sig_js)
script.on('message', on_message)
script.load()
sig = script.exports.getsig(parse)
return sig
def get_headers():
"""生成headers参数sign,返回组装好的headers"""
u = str(uuid.uuid4())
# header请求sign生成参数
h_sign = 'AUTHORIZATION=\
app-version=40000\
application-id=com.kmxs.reader\
brand=google\
channel=qm-xiaomi_lf\
client-id=79b101a4c922edfa\
device-id=2020112023043231b16f0157e713801955886211dbcfdb017201340dee7bb7\
hardware-id=ffffffff-eff3-95ad-0000-0000010e8b41\
imei=867686020207104\
is-white=0\
mac=A0:8D:16:F3:87:76\
model=Nexus 6P\
oaid=\
platform=android\
reg=\
sys-ver=6.0.1\
trusted-id=DuIeA8U6wmfOJw7D2Rqs/JpyGmn4sYtvJiZs/BOd1VR15C+Efah4kyPwraT1RZuQBXU7RSTen/1Z2auWSGAqi9kQ\
uuid={}\
wlb-imei=867686020207104\
wlb-uid=867686020207104'.format(u)
# print(h_sign)
head_sig = process_script(h_sign)
headers = {
"wlb-imei": "867686020207104",
"hardware-id": "ffffffff-eff3-95ad-0000-0000010e8b41",
"mac": "A0:8D:16:F3:87:76",
"uuid": u,
"client-id": "79b101a4c922edfa",
"oaid": "",
"app-version": "40000",
"platform": "android",
"trusted-id": "DuIeA8U6wmfOJw7D2Rqs/JpyGmn4sYtvJiZs/BOd1VR15C+Efah4kyPwraT1RZuQBXU7RSTen/1Z2auWSGAqi9kQ",
"reg": "",
"device-id": "2020112023043231b16f0157e713801955886211dbcfdb017201340dee7bb7",
"AUTHORIZATION": "",
"imei": "867686020207104",
"is-white": "0",
"brand": "google",
"application-id": "com.kmxs.reader",
"wlb-uid": "867686020207104",
"sys-ver": "6.0.1",
"channel": "qm-xiaomi_lf",
"model": "Nexus 6P",
"sign": head_sig,
"QM-it": "1605888000",
"QM-ii": "2018866918",
"User-Agent": "webviewversion/40000",
"Host": "api-bc.wtzw.com",
"Connection": "Keep-Alive",
"Accept-Encoding": "gzip"
}
return headers
def get_page():
"""翻页"""
headers = get_headers()
p_sign = 'gender=1&page_no=3'
sig = process_script(p_sign.replace('&', ''))
page_url = 'https://api-bc.wtzw.com/api/v3/recommend/high-score?{}&sign={}'.format(p_sign, sig)
response = requests.get(page_url, headers=headers)
if response.status_code == 200:
print(response.text)
if __name__ == "__main__":
get_page()
运行查看结果:
4.结论可以看到请求成功,这app的sign分析还是挺简单的,其中的sign加密算法在so文件里,等后续研究研究。 |