抓包分析
- copy CURL 转 requests代码
def app1():
import requests
headers = {
"Accept-Language": "zh-CN,zh;q=0.8",
"User-Agent": "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; Nexus 6P Build/OPM1.171019.011) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
"Host": "www.python-spider.com",
"Cache-Control": "no-cache"
}
url = "https://www.python-spider.com/api/app1"
data = {
"page": "1", # 页码
"sign": "538f6c31cc41a5154d549b1026b6c7cf",
"t": "1670468702882" # 时间戳
}
response = requests.post(url, headers=headers, data=data)
print(response.text)
print(response)
响应
{"status": "1", "state": "success", "data": [{"value": "8080\r"}, {"value": "4988\r"}, {"value": "3842\r"}, {"value": "3520\r"}, {"value": "1500\r"}, {"value": "1237\r"}, {"value": "9936\r"}, {"value": "6209\r"}, {"value": "4303\r"}, {"value": "5807\r"}]}
- 逆向目标:sign生成
jadx搜索
搜索代码:"sign
搜到类似代码片段,有参数page,t,sign应该就是我们要找的
右键跳转声明位置(代码位置是一个接口)
sign= new C5334Oooo000().OooO(sb.toString().getBytes(StandardCharsets.UTF_8));
完整加密代码:
public String OooO(byte[] bArr) {
ArrayList<Integer> OooO0oO2 = OooO0oO(bArr);
int i = 1732584193;
int i2 = -271733879;
int i3 = -1732584194;
int i4 = 271733878;
for (int i5 = 0; i5 < OooO0oO2.size() / 64; i5++) {
int[] iArr = new int[16];
for (int i6 = 0; i6 < 16; i6++) {
int i7 = (i5 * 64) + (i6 * 4);
iArr[i6] = (OooO0oO2.get(i7 + 3).intValue() << 24) | OooO0oO2.get(i7).intValue() | (OooO0oO2.get(i7 + 1).intValue() << 8) | (OooO0oO2.get(i7 + 2).intValue() << 16);
}
int[] iArr2 = {0, 4, 8, 12};
int i8 = i;
int i9 = i2;
int i10 = i3;
int i11 = i4;
int i12 = 0;
while (i12 < 4) {
int i13 = iArr2[i12];
i8 = OooO0O0(i8, i9, i10, i11, iArr[i13], 3);
int OooO0O02 = OooO0O0(i11, i8, i9, i10, iArr[i13 + 1], 7);
i10 = OooO0O0(i10, OooO0O02, i8, i9, iArr[i13 + 2], 11);
i9 = OooO0O0(i9, i10, OooO0O02, i8, iArr[i13 + 3], 19);
i12++;
i11 = OooO0O02;
}
int[] iArr3 = {0, 1, 2, 3};
int i14 = i8;
int i15 = i11;
for (int i16 = 0; i16 < 4; i16++) {
int i17 = iArr3[i16];
i14 = OooO0Oo(i14, i9, i10, i15, iArr[i17], 3);
i15 = OooO0Oo(i15, i14, i9, i10, iArr[i17 + 4], 5);
i10 = OooO0Oo(i10, i15, i14, i9, iArr[i17 + 8], 9);
i9 = OooO0Oo(i9, i10, i15, i14, iArr[i17 + 12], 13);
}
int[] iArr4 = {0, 2, 1, 3};
int i18 = i14;
int i19 = 0;
while (i19 < 4) {
int i20 = iArr4[i19];
int OooO0o2 = OooO0o(i18, i9, i10, i15, iArr[i20], 3);
i15 = OooO0o(i15, OooO0o2, i9, i10, iArr[i20 + 8], 9);
i10 = OooO0o(i10, i15, OooO0o2, i9, iArr[i20 + 4], 11);
i9 = OooO0o(i9, i10, i15, OooO0o2, iArr[i20 + 12], 15);
i19++;
i18 = OooO0o2;
}
i += i18;
i2 += i9;
i3 += i10;
i4 += i15;
}
return String.format("%02x%02x%02x%02x", Integer.valueOf(i), Integer.valueOf(i2), Integer.valueOf(i3), Integer.valueOf(i4));
}
- 加密逻辑不长,感兴趣的也可直接翻译成python代码
- 我就不翻译了,直接上frida Hook测试一下
FridaHook
Java.perform(function () {
console.log('perform seccuss')
let Oooo000 = Java.use("o00oO00o.Oooo000");
Oooo000.OooO.implementation = function(s){
let arr = Java.use("java.util.Arrays")
let JavaString = Java.use("java.lang.String")
console.log("args Bytes:",arr.toString(s))
console.log("args String:", JavaString.$new(s))
let res = this.OooO(s)
console.log('res String:',JavaString.$new(res))
return res
}
});
启动app,注入测试
attach seccuss
perform seccuss
load seccuss
args Bytes: [112, 97, 103, 101, 61, 49, 49, 54, 55, 48, 57, 56, 55, 57, 52, 57, 49, 49, 55]
args String: page=11670987949117
res String: 67e0adb2756e899f36f6184316562da6
args Bytes: [112, 97, 103, 101, 61, 50, 49, 54, 55, 48, 57, 56, 55, 57, 53, 52, 52, 54, 48]
args String: page=21670987954460
res String: 9eea998e3017f9e244f700a5cd1a0e62
- 入参为
"page=" + 页码 + 时间戳
Frida主动调用
- 以参数
page=11670987949117
测试 Java.use("o00oO00o.Oooo000").OooO(bArr)
直接调用会报错:Error: OooO: cannot call instance method without an instance
- 用
Java.choose()
的方式从内存中搂个实例用,注入时需要进入指定页面触发指定函数,保证内存中已经加载了我们需要的类。
完整代码
Java.perform(function () {
function stringToBytes(str) {
var ch, st, re = [];
for (var i = 0; i < str.length; i++ ) {
ch = str.charCodeAt(i);
st = [];
do {
st.push( ch & 0xFF );
ch = ch >> 8;
}
while ( ch );
re = re.concat( st.reverse() );
}
return re;
}
console.log('perform seccuss')
let JavaString = Java.use("java.lang.String")
Java.choose("o00oO00o.Oooo000",{
onMatch:function(instance){
console.log('choose seccuss')
let str1 = "page=11670987949117"
let intArr = stringToBytes(str1)
let bArr = Java.array('byte',intArr)
let res = instance.OooO(bArr)
console.log('res String:',JavaString.$new(res))
},
onComplete(){}
});
});
测试结果:
attach seccuss
perform seccuss
choose seccuss
res String: 67e0adb2756e899f36f6184316562da6
load seccuss
- 和我们上面抓包的结果匹配
FridaRPC
- 目标函数接收的参数类型为
bytes[]
- 我们准备的函数为str类型
- 需要将参数进行String to BytesArray 的转换
js代码
function app1_sign_func(page, t) {
var res;
Java.perform(function () {
function stringToBytes(str) {
var ch,
st,
re = [];
for (var i = 0; i < str.length; i++) {
ch = str.charCodeAt(i);
st = [];
do {
st.push(ch & 0xff);
ch = ch >> 8;
} while (ch);
re = re.concat(st.reverse());
}
return re;
}
console.log("perform seccuss");
Java.choose("o00oO00o.Oooo000", {
onMatch: function(instance){
console.log("choose seccuss");
let str1 = "page=" + page + t;
console.log("str1 =>",str1)
let intArr = stringToBytes(str1);
let bArr = Java.array("byte", intArr);
res = instance.OooO(bArr);
console.log('res =>',res)
},
onComplete:function(){},
});
});
return res;
}
rpc.exports = {
getsign: app1_sign_func,
};
注入的python代码:
import frida
import sys
import time
import requests
f = open('./js_code.js','r',encoding='utf-8')
jscode = f.read()
f.close()
process = frida.get_usb_device(-1).attach('猿人学APP')
print('attach seccuss')
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
print('load seccuss')
api = script.exports
# sys.stdin.read()
def app1(page):
headers = {
"Accept-Language": "zh-CN,zh;q=0.8",
"User-Agent": "Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; Nexus 6P Build/OPM1.171019.011) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
"Host": "www.python-spider.com",
"Cache-Control": "no-cache"
}
url = "https://www.python-spider.com/api/app1"
t = str(int(time.time()*1000))
sign = api.getsign(str(page),t)
data = {
"page": page,
"sign": sign,
"t": t
}
print(data)
response = requests.post(url, headers=headers, data=data)
print(response.text)
print(response)
app1(1)
调用结果:
attach seccuss
load seccuss
perform seccuss
choose seccuss
str1 => page=11670997598567
res => 7e8154f39058fa6e585afa2ec48013bf
choose seccuss
str1 => page=11670997598567
res => 7e8154f39058fa6e585afa2ec48013bf
{'page': 1, 'sign': '7e8154f39058fa6e585afa2ec48013bf', 't': '1670997598567'}
{"status": "1", "state": "success", "data": [{"value": "9198\r"}, {"value": "2463\r"}, {"value": "6344\r"}, {"value": "5559\r"}, {"value": "6558\r"}, {"value": "2162\r"}, {"value": "1289\r"}, {"value": "6426\r"}, {"value": "1735\r"}, {"value": "8974\r"}]}
<Response [200]>
结束
- Frida三板斧完事,收工。