小红书x-s新版分析(2023-05-30失效)

近期又更新了,先是改了x-s生成,然后又加上了a1校验。

后面可能会全参校验,比如再加上gid、deviceId、profileData、x-s-common、smidV2之类。

估计以后不能写xhs了,大家且看且珍惜吧。


X-s

还是先找x-s。全局搜关键词"X-s"

file

c = (a || void 0 !== window._webmsxyw ? window._webmsxyw : sign)(u, i) || {};

if a:
    return a
elif "window._webmsxyw" in globals() and window._webmsxyw is not None:
    return window._webmsxyw
else:
    return sign

file

可发现feed接口没走sign,走的方法是在 window._webmsxyw = _garp_dc33b

file

可以测试下把 window._webmsxyw置为null是否能正常返回。

file


window._webmsxyw

跳转过去能发现代码混淆过了,并且自执行了,不便阅读。

Shanks

先看外部Shanks。

(function() {
    function Shanks() {
        var _garp_d6c76 = 2147483647
          , _garp_a0c6d = 1
          , _garp_33d28 = 0
          , _garp_cb56b = !!_garp_a0c6d
          , _garp_35e13 = !!_garp_33d28;
        return function(_garp_d3e7c, _garp_d0ad1, _garp_8d381){}
        ;
    }
    ;Shanks()(window, {});
}
)();

这段代码定义了Shanks函数,定义了一个闭包,返回一个匿名函数,并使用立即执行函数将其调用。
在调用Shanks函数时,它接受两个参数,分别是window和对象{}。


decode

不难看出 decode 是一段实现了 Base64 解码的方法,包括了将 Base64 编码的字符串解码为正常字符串的逻辑,以及处理 Unicode 字符的逻辑。

var decode = function(j) {
    if (!j) {
        return ""
    }
    var n = function(e) {
        var f = []
          , t = e.length;
        var u = 0;
        for (var u = 0; u < t; u++) {
            var w = e.charCodeAt(u);
            if (((w >> 7) & 255) == 0) {
                f.push(e.charAt(u))
            } else {
                if (((w >> 5) & 255) == 6) {
                    var b = e.charCodeAt(++u);
                    var a = (w & 31) << 6;
                    var c = b & 63;
                    var v = a | c;
                    f.push(String.fromCharCode(v))
                } else {
                    if (((w >> 4) & 255) == 14) {
                        var b = e.charCodeAt(++u);
                        var d = e.charCodeAt(++u);
                        var a = (w << 4) | ((b >> 2) & 15);
                        var c = ((b & 3) << 6) | (d & 63);
                        var v = ((a & 255) << 8) | c;
                        f.push(String.fromCharCode(v))
                    }
                }
            }
        }
        return f.join("")
    };
    var k = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
    var p = j.length;
    var l = 0;
    var m = [];
    while (l < p) {
        var s = k.indexOf(j.charAt(l++));
        var r = k.indexOf(j.charAt(l++));
        var q = k.indexOf(j.charAt(l++));
        var o = k.indexOf(j.charAt(l++));
        var i = (s << 2) | (r >> 4);
        var h = ((r & 15) << 4) | (q >> 2);
        var g = ((q & 3) << 6) | o;
        m.push(String.fromCharCode(i));
        if (q != 64) {
            m.push(String.fromCharCode(h))
        }
        if (o != 64) {
            m.push(String.fromCharCode(g))
        }
    }
    return n(m.join(""))

_garp_dc33b

简单调了一下,大面积的自增运算,让人看不下去。
file

file

file


补环境

直接把上面代码copy到本地先补环境看看,看日志要补的东西挺多,具体怎么用的没细看。(后面没用的我会删掉)

RegExp、Math、indexedDB、eval、localStorage、isNaN、unescape、Array、Function、setInterval、encodeURIComponent、decodeURIComponent、CanvasRenderingContext2D、HTMLCanvasElement、navigator、location、String、Date、Object、screen、document、

还有追加的 openDatabase、devicePixelRatio、AudioContext、webkitAudioContext、setInterval、getAttribute、xhsFingerprintV3

主要都是window对象的方法和属性,有两处报错的地方,补好后try-catch一下。

file

另外输出中还看到了process,先不管这个。

等到报错:

file

补到这里就快了。

file

还是catch下,把_webmsxyw给到window上。

file

这里补好就可以生成了。

file

但是发现本地生成的和浏览器的差了很多位数,调试发现是由于cookie中没有xsecappid和a1参数。

把cookie加上后发现还是少了24位,再检查下发现本地生成的x-s中没有加 "signVersion":"1" 。

signVersion追加在localStorage中,默认是1。

file

简单一点,可以做类型判断然后给上值,注意signVersion的值是string类型。

 if (_garp_a3d40 && typeof _garp_a3d40==="object" && _garp_a3d40.hasOwnProperty('signVersion')){
     _garp_a3d40["signVersion"] = "1"
 }

现在生成的位数就一致了,但是测了下还是不可用。


X-s生成流程

继续调试分析,看流程是先去生成X1,然后构建payload。
payload由x1、x2、x3、x4组成。x1是api+formdata md5生成的,x2固定,x3是a1,x4是时间戳。

file

拼接为:x1=72ff6a81a0474a774ad1db6681c9614a;x2=0|0|0|1|0|0|1|0|0|1|1|0|0|0|0;x3=188392ccdbbk41ajfrbba1ngli7wcccg88o04w12v50000303000;x4=1684603371781;

然后做一些编码和加密生成密文payload,payload生成后再跟几个参数拼起来。

file

拼接完进行base64编码,然后和XYW_拼起来生成了最终的X-s。

file

流程并不复杂,现在需要找到本地生成不可用的原因,排除了请求报文和生成环境的可能后,需要从payload加密的位置入手。

前面已经看了x2固定,x3是a1,x4是时间戳。大概率问题在x1上面。确定下md5结果是否和浏览器一样。

file

控制台覆盖JS文件,然后查看输出。

file

一看不太对,feed接口在本地的x1是7开头的,控制台x1是1开头的。

本地 Nodejs 和浏览器的 MD5 算法结果是相同的,那说明本地md5前的参数不对。

本地x1一直是72ff6a81a0474a774ad1db6681c96,浏览器是会根据不同作品ID变化的。

调试发现,本地x1参数生成时没有加formdata。

file

确认原因发现是我在调用的时候传了string类型的formdata,修改为对象就能解决问题。

window._webmsxyw("/api/sns/web/v1/feed",{"source_note_id":"62d4e8a800000000120019dd"})

file

改完发现还是不能用。。。继续调试,重新检查,结果发现本地x2和浏览器不一样,应该是有环境没补上,省时间就直接写死吧。

file

判断后赋值。

   if (_garp_a3d40 && Array.isArray(_garp_a3d40)){
         const lastElement = _garp_a3d40[_garp_a3d40.length - 3];
            if (typeof lastElement === "object" &&  lastElement.hasOwnProperty("key")&& lastElement.key === "x2") {
               _garp_a3d40[_garp_a3d40.length - 3].value = '0|0|0|1|0|0|1|0|0|0|1|0|0|0|0'
            }
  }

然后再将时间戳固定后,生成的x-s和浏览器一致。

file


有插件检测和一些hook检测。注意还有个 crawler-spam ,用的异常点检测,影响调试。

file

如果断到这部分直接跳过,重试吧。

file


备注

注意请求时的a1要和xs生成时的a1一致,然后注意formdata参数格式的问题。

大家加油, 本文内容建立在feed接口上,gid和web_session注册不再说了,其他接口自行修改。

有问题欢迎留言,估计文章过几天又被下架了 。


另外,祝更新签名的你也好,O.o

file


Python请求测试

import requests,json
import execjs

def feed(source_note_id,web_session,a1):
    headers= {
        "accept":"application/json, text/plain, */*",
        "accept-language":"zh-CN,zh;q=0.9",
        "cache-control":"no-cache",
        "content-type":"application/json;charset=UTF-8",
        "cookie":f"a1={a1}; web_session={web_session};",
        "origin":"https://www.xiaohongshu.com",
        "pragma":"no-cache",
        "referer":"https://www.xiaohongshu.com/",
        "sec-ch-ua":"\"Chromium\";v=\"112\", \"Google Chrome\";v=\"112\", \"Not:A-Brand\";v=\"99\"",
        "sec-ch-ua-mobile":"?0",
        "sec-ch-ua-platform":"\"Windows\"",
        "sec-fetch-dest":"empty",
        "sec-fetch-mode":"cors",
        "sec-fetch-site":"same-site",
        "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
        "x-b3-traceid":"a31fffc0ee4f5d8f",
        "x-s-common":"",
    }
    data = {"source_note_id":source_note_id}
    exc = execjs.compile(open('xs.js','r',encoding='utf-8').read())
    xs_xt = exc.call('get_xs','/api/sns/web/v1/feed',data,a1)
    xs_xt['X-t'] = str(xs_xt['X-t'])
    print(xs_xt)
    headers.update(xs_xt)
    feed = 'https://edith.xiaohongshu.com/api/sns/web/v1/feed'
    print(requests.post(url=feed, data=json.dumps(data, separators=(",", ":")), headers=headers).text)

if __name__ == '__main__':
    source_note_id = "646840370000000027028120"
    web_session = "030037a35bebc65742dcfef910234ae23a23fc"
    a1 = "188392ccdbbk41ajfrbba1ngli7wcccg88o04w12v50000303000"
    feed(source_note_id,web_session,a1)

JS代码部分

【温馨提示:此处隐藏内容需要付费订阅后才能查看!】

点赞
  1. nanhe说道:
    Google Chrome Mac OS X 10.15.7
    RegExp怎么补 window补this吗?大佬
  2. 阿道说道:
    Google Chrome Windows 10
    平台又改了 :han:
    1. Lx Lx说道:
      Google Chrome Windows 10
      待我看看
    2. Lx Lx说道:
      Google Chrome Windows 10
      更新好了,看最新的文章
  3. 小马驹说道:
    Google Chrome Windows 10
    {"code":300015,"success":false,"msg":"浏览器异常,请尝试关闭/卸载风险插件或重启试试!","data":{}}
  4. zwq说道:
    Google Chrome Windows 10
    学到了 :kaixin:
  5. 唐朝的宇宙说道:
    Google Chrome Windows 10
    你好,我用支付宝付费订阅了,但还显示没有订阅
    1. Lx Lx说道:
      Google Chrome Windows 10
      不好意思,延迟处理了,目前已开通。
  6. 阿道说道:
    Google Chrome Windows 10
    有的win10读取js文件会出现语法错误,linux读取也是,是什么原因?
    1. Lx Lx说道:
      Google Chrome Windows 10
      一般是编码问题。可以安装下nodejs执行下是否有报错。linux可以用iconv -f转一下编码,如果还不行就是文件内有特殊字符,根据报错信息找一下字符位置。
      1. 阿道说道:
        Google Chrome Windows 10
        谢谢,是新机器,没安装node.js
  7. Nevaeh说道:
    Google Chrome Windows 10
    大佬,求search接口的测试
  8. jerry说道:
    Google Chrome Windows 10
    大佬,search/notes接口报code:-1,是参数search_id错了吗
    1. Lx Lx说道:
      Google Chrome Windows 10
      search我没测,可能是的。一般x-s错了返回非法浏览
    2. Nevaeh说道:
      Google Chrome Windows 10
      搜索关键词中文的话 要uni
      1. Lx Lx说道:
        Google Chrome Windows 10
        :good:
      2. junhan说道:
        Google Chrome Windows 10
        是计算加密uni还是请求时传unicode呢
      3. junhan说道:
        Google Chrome Windows 10
        可以贴一下示例吗,辛苦!

发表回复