本文我将重点分析下PerimeterX SDK的逆向分析
我在抓包的时候发现PerimeterX在我抓包初始化之前就已经完成了现在我来固定下SSL以便更好的抓包分析
直接搜索 perimeterx.net 这个关键词
PerimeterX是okhttp3里的CertificatePinner里的add方法
Java.perform(function() {
let okhttp3Pin = Java.use("okhttp3.CertificatePinner$Builder")
okhttp3Pin["add"].implementation = function(pattern, pins) {
return this
}
})现在我们已经破解了 SSL pinning,可以开始研究反机器人了。首先,确保强制关闭应用并清除缓存和存储空间。我在对任何应用进行逆向工程时都会确保这样做,因为大多数应用都会将某些内容放入缓存/存储空间,而反机器人通常会将之前会话的信息放入存储空间。
毫无疑问这个就是我们要分析的目标payload
如果细心你会发现这个是个base64的一个编码

好的现在我们分析下这个解码后的参数 PX1214这个参数,如果你仔细的去在SDK中寻找的话这个其实就是x-px-device-fp是个常数 为了节省大家的时间,我会告诉大家接下来的几个值也可以这样做,如下所示:
const crypto = require('crypto');
function a(input) {
const hash = crypto.createHash('sha1').update(input, 'utf8');
return hash.digest('hex').toUpperCase();
}
datas="Pixel 5"+"00000199-f656-5976-0000-000000000001"+"00000199"
console.log(a(datas));这个就是PX328的运算流程
PX256,PX259是在第一次请求中ob的参数
{
"do": ["sid|a075a46c-abf8-11f0-8555-6c17dbda30bb", "appc|1|1760774493089|7d723aa87b31da59679ebd76ebf591d4bf0679f8240f1cee26faee2598ed163c|a0772f90-abf8-11f0-a025-27390821ff19", "appc|2|1760774493089|7d14acde7faecc20563deadb8c4d56c27001cc2829dc19e06b76172f0ed1890b,7d14acde7faecc20563deadb8c4d56c27001cc2829dc19e06b76172f0ed1890b|483|1601|1122|2659|2160|3882", "ipd|true"]
}
PX259是前面三个的工作量证明
/**
* 简化版 AppcInstruction 函数:只关注计算 PX257
* @param {string} appc APPC 2 指令字符串。
* @param {Uint8Array} px320_bArr Px320 的基准字节数组
* @returns {{PX256: string, PX259: number, PX257: string} | null} 计算结果对象,或 null (失败时)。
*/
function calculateAppcPX257(appc, px320_bArr = PX320_BYTES) {
const parts = appc.split("|");
// 1. 格式验证
if (parts[1] !== "2" || parts.length !== 10) {
return null;
}
const output = {
PX256: parts[3],
PX259: 0,
PX257: ""
};
// 2. 提取 PX259 (时间戳)
const date = parseInt(parts[2], 10);
if (isNaN(date)) {
return null;
}
output.PX259 = date;
// 3. 提取并转换 6 个数字
const numbers = [];
for (let i = 4; i < 10; i++) {
const num = parseInt(parts[i], 10);
if (isNaN(num)) {
return null;
}
numbers.push(num | 0);
}
// 4. 计算 mathOut (混淆值)
// numbers: [374, 3542, 3311, 1478, 3717, 352]
// 内部: pow(3311, 1478, 374, 352)
const innerResult = pow(numbers[2], numbers[3], numbers[0], numbers[5]);
// 外部: pow(innerResult, 3717, 3542, 352)
const mathOut = pow(innerResult, numbers[4], numbers[1], numbers[5]);
// 5. 提取 Px320 的前 4 字节整数 (res)
let res = 0;
if (px320_bArr.length >= 4) {
// 读取大端序 32 位整数
const dataView = new DataView(px320_bArr.buffer, px320_bArr.byteOffset, px320_bArr.byteLength);
res = dataView.getInt32(0, false);
}
// 6. 计算最终的 PX257 (res ^ mathOut)
const finalResult = (res ^ mathOut) | 0;
// 7. 转换为字符串并赋值
output.PX257 = String(finalResult);
return output;
}

