← 返回文章列表

某夕夕anti_content算法分析

  • 代码中大量报错 , 按照顺序处理

403错误 , 未授权

  • 调整至fiddler工具中
  • 采集真实小程序中产生的token信息 , 并中转拦截处理

  • 拦截授权请求后 , 业务接口可以正常访问

  • 余下报错为初始化过程中 , wss初始化链接数过多 , 堆栈定位一下

  • 寻找r.MaxWebsocketConnect 参数初始化时引用的对象 , 并修改
  • app.js中修改调试器的全局参数__devtoolsConfig.setting.MaxWebsocketConnect = 5

  • 此时已成功没有错误 , 429状态码为风控引起的返回状态码 , 忽略即可

anti_content算法

  • 随便定位一条带有anti_content的请求
  • https://xcxapp.pinduoduo.com/backend/conf/startup_v2

  • 放眼望去 , 只有这么几条参数值得关注
  • 两条token大概率由授权请求返回的 , 不是我们关注的重心
  • xcx_hash看上去大概率为签名 , 最后一步看即可 , 接下来分析anti_content
  • 查看堆栈

  • 直接忽略asdebug与waservice的堆栈 , 这是工具自身的引用栈 , 与业务代码无关 , 直接从41.js分析即可

  • 确认引用了anti_content后 , 往上追溯至没有异步的地方或生成的地方

  • 业务代码并没有严重的混淆 , 所以很轻松定位到了生成的位置 , 不过参数传入为boolean , 难道不应该为对象吗
  • 进入此函数 , 并打印传入参数

  • 调试信息都不是想像中的亚子 , 那是不是找错链接了呢 , 尝试寻找其他较长的anti_content
  • 尝试调试了其他链接的anti_content后 ,长度不一致 , 问题不在外部函数 , 那么就需要深入anticontent函数了
function g(t) {
    for (var e = t || {}, n = e.systemInfoAsync, a = e.fingerprintAsync, r = n || function() {
        try {
            return wx && wx.getSystemInfoSync ? wx.getSystemInfoSync() : {};
        } catch (t) {
            return {};
        }
    }(), i = a || function() {
        try {
            if (!wx || !wx.getStorageSync) return "";
            var t = wx.getStorageSync("e488cb9fe650282");
            if (!t || !t.data) return "";
            var e = JSON.parse(t.data);
            return e && e.a || "";
        } catch (t) {
            return "";
        }
    }() || l, h = r.model, u = r.pixelRatio, f = r.version, c = r.system, d = r.platform, _ = r.fontSizeSetting, p = r.SDKVersion, g = [].concat(v.packN(), A.packN(h), b.packN(), y.packN(), O.packN(), w.packN(), k.packN(), S.packN(), m.packN(), x.packN(), C.packN(u), z.packN(f), H.packN(c), E.packN(d), T.packN(_), D.packN(p), N.packN(i)), I = g.length.toString(2).split(""), M = 0; I.length < 16; M += 1) I.unshift("0");
    I = I.join("");
    var B = [];
    0 === g.length ? B.push(0, 0) : g.length > 0 && g.length <= 255 ? B.push(0, g.length) : g.length > 255 && B.push(parseInt(I.substring(0, 8), 2), parseInt(I.substring(8, 16), 2)),
    g = [].concat([ 3 ], [ 3, 0, 0 ], B, g);
    var R = o.default.deflate(g), j = [].map.call(R, function(t) {
        return String.fromCharCode(t);
    });
    return "3ak" + s.default.encode(j.join(""), s.default.budget);
}
  • 稍微深入后 , 即可发现anti_content的生成位置

  • 最后一句encode的函数 , 粗略看上去像是类似base64的编码算法 , 直接调用即可
  • 看看encode前调用了哪些参数
[
    {"data": 0},
    {"data": "iPhone 5"},
    {"data": ["pages/index/index"]},
    {"data": 13},
    {"data": [83, 251, 218, 43]},
    {"data": "1451015129656341-1661093800919"},
    {"data": "1001"},
    {"data": ""},
    {"data": 1661093800858},
    {"data": 325444},
    {"data": 2},
    {"data": "8.0.5"},
    {"data": "iOS 10.0.1"},
    {"data": "devtools"},
    {"data": 16},
    {"data": "2.24.7"},
    {"data": "uybW3WN48WL3SblRjUYCZeT4q0lDWdkx"}
]
  • 到此为止 , 调用了哪些环境信息就可以知道了
  • 关于wss中请求的内容 , 有时间再讲一期 , 难度都不高

侵权说明

此分析仅供学习参考 , 并不提供源码以及代码指导 , 如有侵权 , 联系邮箱admin@tisoz.com删除