某CSDN文字点选算法分析

javascript 复制代码
url = aHR0cHM6Ly93d3cuY3Nkbi5uZXQv

来到这个网站,选择登入操作,点击发送xx验证码,就会出现这个验证码 这里就详细来分析一下这个验证过程,首先是有两个这样的接口

其中第一个接口返回了需要验证的提示,第二个接口返回了验证码的图片地址和一个key,但是它们都是被加密后的,所以需要解密,然后就是验证接口 验证成功,返回一个yd_captcha_token,这里我们对这个进行base64解码 观察到这个值被加入到了cookie中,所以这个应该是一个凭证一样的东西,验证通过,cookie中有这个值,可以进行后面的请求。

开始分析第一个接口,这里有好几个参数需要分析

python 复制代码
params = {
    "callback": "callback_1769924628084",
    "fpv": "H4sIAAAAAAAAAwXBgREAIAgDsZnkHpnHa8v+I5jgDl3P21ZSUMO5DhLLfPltmfogAAAA",
    "level": "H4sIAAAAAAAAA0tJTUsszSkBAN8AXuMHAAAA",
    "type": "H4sIAAAAAAAAAytJzS3ISSxJBQCDH2CXCAAAAA==",
    "wlocation": "H4sIAAAAAAAAA2WNTWsCMRCG/8qQk4Ld7JdZVEoRDwpWLxU8x93ZTTCbhCTSYul/7yz0VuY0z/v1zZSLia2ZlzF6F1LWxs5mFhNbMBWwJ0ml5OOa838Wbtyg7VvrOnyV3htMkVKPiGE7oJ1aT+6pjZF8meUwu2rbuc8I5wsUeZZvgICoN/Al6jlsp/wVb0ed+LJqskrA7Hi4nN4XYPQdYY/t3c1hp4IbkRfkyKeDD9nLoP8itO6NTL0LI41TfVUSMtIODzkgoad62Z0JJT3SWzRitSprUTZNXf78At9XvQgLAQAA",
    "captcha_protect": "H4sIAAAAAAAAAw3SNRajUAAAwANRYMGKLXAJn0Bwmn248%2FEAp9%2Bt5gJTf6j1wyKIpzjYD3QeXl7qAa0fS48yU5FYiI9Yw4u%2BeTiKkM2CRAOX8MT1VYBkvW2LY1ZK6zPwpUIof3yLPM0bPu3CvZnRQpk2PkvXXMLsaAzsauZlHIIYXEIKVVpnanvmXRnuXJb6NBkeByOQ4lg%2FXyP8TGPglvfdbKG2ITlnVPKfPJ33vEn%2Fzivcy3yvdrEMku0BKalz%2BfiEDr2kv9MYvglVLV8kosKT45beefmO8VKkUXxNRVEJdJuU3%2FckLW7kRzO%2BaIDvu%2FAsAoIxtNd49v628lcVoFZXGhfFfaYodueVvaBS%2FjZB8j3mJjQbYkaL3w4vlPLn43ov9lSV%2BNfeTz7S6AwossIXd1%2BOrysrsocC47%2Fhy7T1wSEzEQMZ4SKQI2G4EtemUgvyaAyxHCg9kVzEH56JRR1p9e%2B0ONug0Q8kOFiUnc63i8gDYobdmVDC9eVlC8vM1uiW4r60VT6dF3D5iPgymI1LoGhJjbHJ9GHHTPWCKLjkuM%2BLU0gkomCl8ujpmCpolTDFVKj3EsuZRUcb3XTQ0zl00YKPAexq1%2BO3omNkrg2dbmORKmv6bjbDj0ymUJNVGTATdR4nsZ2L94b4rGR0LXdtgvvd9fVLPUINeEgMjvIVwvtAwsSCoZ0EB7XHdvaQxfAtuMkqhtHt%2Bkvx4a%2FYaJK4vBb8RHDJJhpGntXUwjP63SESaKm7EAMXCECNS6mmgTkrATIM26yhqiTRDxavguio7w1By0tJQTqxSp350s1djcWEH6Zr5fiy6twklQPje3tiS3S%2FIep0Y%2Fj%2FI0RyGKk5BmccJeTMmBMnTMsN5O%2FEGGAVfWOsbMXPt3RZJjq9jRSsc%2FZti3JctSJwqxkH1f6ZyYMM5M3bj%2BhhDf4EudVvTLFhCHtrBuwRqw9G5Qdln63wnuL0yjEk91X%2FWi3fGGxPnhrjx8loO1bcMG2Cl71y5nQrdb39A8WlfVC7AwAA",
    "originalImage": "H4sIAAAAAAAAAyspKk0FAI1M/P0EAAAA",
    "_": "1769924627695"
}

断点来到这个文件,这里发现代码被混淆了,直接解混淆就可以了,这里我是用的这个工具:https://github.com/dummyvx/decodeObfuscator,非常的方便就可以解开这种类ob混淆

javascript 复制代码
 _0x2e1f8e = {
      'fpv': _0x43706c["gzip"](_0x43706c["_bsc_cv"]["fpv"]),
      'level': _0x43706c["gzip"](_0x1c18ff),
      'type': _0x43706c["gzip"]("template"),
      'wlocation': _0x43706c["gzip"](JSON["stringify"](_0x43706c["_bsc_cv"]["wlocation"])),
      'captcha_protect': _0x43706c["captcha_protect"](),
      'originalImage': _0x43706c["gzip"](_0x43706c["originalImage"] + '')
    };

第一个参数是fpv,观察到是这个_0x43706c["gzip"]加密了_0x43706c["_bsc_cv"]["fpv"],这个_0x43706c["_bsc_cv"]["fpv"]是通过_0x43706c["_bsc_cv"]["fpv"] = _0x43706c["_bsc_cv"]["guid2"]()生成的,简单来说就是这个方法

javascript 复制代码
 function _0x28c256() {
      return ((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1);
    }
_0x43706c["_bsc_cv"]["guid2"] = function () {
    function _0x28c256() {
      return ((1 + Math["random"]()) * 65536 | 0)["toString"](16)["substring"](1);
    }

    return _0x28c256() + _0x28c256() + _0x28c256() + _0x28c256() + _0x28c256() + _0x28c256() + _0x28c256() + _0x28c256();
  };

这个是gzip就是一个压缩然后经过base64,不知道的,直接问一下ai就可以了

javascript 复制代码
_0x43706c["gzip"] = function (_0x1911db) {
    var _0x1048d6 = pako["gzip"](_0x1911db);

    return Base64_Uint8["fromByteArray"](_0x1048d6);
  };

这里让ai给我写了一个函数

javascript 复制代码
function compressAndEncodeWithPako(data) {
    // 压缩数据
    const compressed = pako.gzip(data);

    // 将Uint8Array转换为Buffer,然后转为Base64
    const buffer = Buffer.from(compressed);
    return buffer.toString('base64');
}

然后第二个参数是level,加密了_0x1c18ff,这个就是"default",默认值,同样的经过了gzip压缩,base64编码。

第三个参数是type,加密值非常清楚了,这里不再说明 第四个参数是wlocation,这里就是加密了一堆游览器的环境信息,也没什么好说的。 第五个参数是captcha_protect,这里是_0x43706c["captcha_protect"](),进入方法内部看到

javascript 复制代码
window["captcha_protect"] = function () {
    _0x478615["end_time"] = new Date()["getTime"]();
    _0x478615["guid"] = window["_bsc_cv"]["guid"]();

    var _0x29e761 = CryptoJS["MD5"](_0x478615["name"] + '_' + _0x478615["fpv"])["toString"]();

    var _0x36ae83 = window["rsaEncrypt"](_0x29e761);

    var _0x6c0312 = window["aesEncryptKey"](_0x29e761, JSON["stringify"](_0x478615));

    return encodeU

这里也是对游览器的环境进行了加密,_0x478615里面就是游览器的环境信息,检测了一些常见的环境,然后下面是一个标准的RSA加密,上面套了一个MD5加密,最后进行AES加密,由于代码是解过混淆的,所以这些逻辑都非常的清楚,这些都是标准的算法,直接套库就可以实现了。 观察到请求头里面还有一个"X-Req-Token",这个也是直接在解混淆后的代码里面搜索就可以找到了。

javascript 复制代码
_0x43706c["_bsc_cv"]["signature"] = function () {
    var _0x1b0b44 = _0x43706c["_bsc_cv"]["guid2"]()["substring"](0, 16),
        _0xfbc344 = CryptoJS["MD5"](_0x1b0b44 + "shyundun")["toString"]()["substring"](0, 16);

    return _0x1b0b44 + _0xfbc344;
  };

同时这个接口的响应是这种,这里可以猜测就是这个gizp压缩的逆过程,因为这里的响应代码中有这种"H4sIAAAAAAAAA"什么的和我们加密和的值格式上差不多。

javascript 复制代码
callback_1769924770126({"ret":0,"time":1769925885000,"body":"H4sIAAAAAAAAAM1VzWvUQBQ\/J3\/FNApJYJNdFaR0kwWtPQiCRYrgqUwnb3dHJ5k4M8l2bRfcg\/hBBU89FbyJCLbevPjvbGlP\/gvOJFmr\/aAXkZ7mff7mvd97mUQL9x4urz1ZXUFDlbKeHZkDMZwNYufFMCCZY2yAE32koLAOU3kAzwtaxs4yzxRkKlgb5+AgUmuxo2BTtQ1OF5EhFhJUXKh+sOjMMTKcQuyUFEY5F+qPzBFN1DBOoKQEgkpp0YwqilkgCWYQ32il2pAW6YmON\/\/SCwmiUvCG1jNuLlVUMegRRsmz9fJm1K51O2o3jW3wZNyz7SihJSIMSxk7BOeK8iwYCZxrCOscnzGfZ19fr\/AdRBPNRSX2jg6+z\/Z3Dt98mO2\/nb36fPxl5+hgGrV18oUghIsGY16405tnNGdz2JEkguYKKT2Hhv6nuMS11ZRZYlHNtMADQDEa0SzhozDDJR1gxUX427e9fda5IfhIk\/qgienatkX7yFugcnlIM5DgzdN9H23pdsxtVd\/6qoSTItWzDQegVhgY8e74fuI1xPg6vJJCU3WzTzrNXWWAJejNSHMGClAJgvYpwYYbt2tbE9uyr3vutTk3rh\/mnGZKPjaBY0\/XkfIElpDbp5uQuC3bEnrYY7SE+kVGDIxXVTvRHlkQAlKe8f1j3qxLeLMYHoMIUznwXE3FQGBVsKpj6bbQlhxi01AnvNVSNNXS7U5n4ndPEgnjEu4w5rm5BnVrF+17TWVUCmAcJ3GsRAF+daOlP841DcYL5TlNHOM1zWEd7vldp7XY6dRwmndrgoDp2Zwu+XD6dba79\/PHTr3dZtnffbxahdfjFqCEXoQrM+tHpp5TRKFTTF3A+fHey6NP0+PX7w93v9W0X4ZTUwBCcHGV9v1\/c2Dblayf0PqVNI9p\/RuIql9X7xdylM2WGQcAAA==","level":"click_v2"})

直接让ai写一个解密的函数,这里不做强调,自己去测试一下就可以了。

javascript 复制代码
function decodeAndDecompress(base64Data) {
    // 1. 将Base64字符串解码为Buffer
    const buffer = Buffer.from(base64Data, 'base64');

    // 2. 将Buffer转换为Uint8Array
    const uint8Array = new Uint8Array(buffer);

    // 3. 使用pako进行gunzip解压
    const decompressed = pako.ungzip(uint8Array, {to: 'string'});

    return JSON.parse(decompressed);
}

然后看下第二个接口

javascript 复制代码
params = {
    "callback": "callback_1769926110428",
    "captcha_protect": "H4sIAAAAAAAAAw3SudpzWgBA4QtSmIniFDHPxBQ05zFmI%2Ba9BVf%2Ff%2B1q3mZZYW1P6%2FN3vFFiWf2En2R1XyfFEMPZBmSMhUaw0qjBCXRQ8j7zln53D%2FVMXuLkvv2ZvVT95ozIw%2FfxaZIh8P2QIOhd0DxomYzKDJf18M%2FbsH55R1u1udOI6H19P%2Fx5y3iit2vP0JCH1XveFQ0%2FYHgkMLf9qLnJmq%2FmsqnEIESCVV7%2FVcUCK1D8v2wzbCqYk9KJ0bCqpbraNo1bS01xGfb3%2BOitYeUo%2FtVldAQadmfxsgTfvcq%2BFCHjVfsWQgc0c7wvirndadmNMPKZoRc9wgUkfxz2AM79L9Mb4cbuuHlbIisjOWe2sGngFWvQimPEFHbTjQArPREayZeoXap%2FtxKSWDsT68WCzuN7KwowgXHeEW0zbjJuljLtLDNNBSVykdPNe%2FRceBTrtvYtqc%2BScuDs3I2iLZ0ga8CU3VzINg%2Fgd4Vq%2F%2FLPFrXmu1%2BczqckPPYGhhASTwgHPgJPKCC4cpiQ0BdLGlgQbMomjvP78yZ577ExbD0YqV1F6Z4nwTAYR2wEPD5Lxf70duso1VNmq9Jv5fqbU89XeDS7Vs0c5nZt2q4tFPX0STqJIECrTGNVrG67pmGjXuLKn7sZnaOEhBc9sq9xJLZVcORTbe%2FuhzKCx6qs3l1TALdAUaGV%2B58mGkNmw86aexxoAxrzBKNQIBD%2BLZc0gppqu4jwq6uI5E5oHzi3Ew7BYPhNsE%2BFBlNbce7y5OoOlviS%2BIT5%2Bmip2RN5Ekcf0tHJHuR%2BnzVJiW36SrdVnGN1ETVTu5Qmv2itU6KmTkokR3Rc0MrFHX2bOYupCP2p2N9TAzINeizwEKeQv7dlgbhXmGHI2yxb5E6a5uInLrN0Zda7n%2F3q8WfOacndGpTGFGY%2FGefQ%2FOYO7jeKLhveuO%2BUuIrzV1mnUnwRoalvQqy2x%2FoU2GJtKT0OpCDb%2Bo6YnhxfKt8BdHBis%2B%2Fnk%2Ff8L8XxvUSGX7mjUvwD%2BrKSh7sDAAA%3D",
    "fpv": "H4sIAAAAAAAAAzM3MjC2MDYyMbBMTDU3TjK1MLMwTzZISbQ0SLFMTTVJBADLJUPgIAAAAA==",
    "isUpgrade": "false",
    "type": "H4sIAAAAAAAAAyvIz8wriS/ITAYA19P4mAkAAAA=",
    "wlocation": "H4sIAAAAAAAAA2WNTYvCMBCG/8qQk4KbtLbWVRERDy64elnBc7adNsE0CUnExWX/u1PwtgwMzDPvxy9TLia2ZF7G6F1IvI6N5RYTmzAVsKWXSsnHpRD/JMK4TttN7RpcS+8NpkiuW8Sw7dAOqUf30MZIMeMZjC7aNu4e4XSGPOPZCghU5Qp+qnIM28F/we+DTmJWzHlRwejwcT5+TsDoK8Ie66sbw04F16PISZENA1+ylUG/LNTujUytCz2VU3wxJWSk7W6yQ0IP9bY7EUq6pzOfV4vFtKT9XhZ/TwuBE8sLAQAA",
    "_": "1769924769836"
}

这个接口和我们分析的第一个接口的加密方式都是一样的,只不过是加密的字符串值不一样,自己去分析一下就知道了,这里不再分析,同时这个接口的响应里面也有我们的需要的验证码图片地址和一个key。 最后就是验证接口了

javascript 复制代码
{
    "captcha_protect": "H4sIAAAAAAAAAw2QN7KrSAAAD0QgPCLYACe88DbZYjAanHCDEaf%2FL%2Bikk67qEk82jQ3N%2BHVRHx%2Fu0iLnD878uVfBGrlrnWxI68uEEZT8a3QjQKXkafzkJS8fVh7Xs%2BsHFQxyqqnPd%2FqHArrQrdl9fkBt%2FkwjwNmH5NSy0veXRfcORRlsnbBDy6gaj%2Ft2xrv6Btyzo9la69Zc4Ao3OM2NDBlpoz0C65pU2tIIheH5X1nMqITF%2F%2FM6obpEOSFdGIXKSqrKdVXZBajKm2bO50drdDPfo7MC4eGr2J1F8%2BwPW5kNJC4%2FyibhAxvWU7TNirHeKWhHFLp034kO%2FoYEdxxWD6%2FtT1Mr%2Fo7e4%2BqssayMxJRZ%2FKpCL1KRGUU7XVh1O0IMOCLS4wGv3mSXNNIuMVYmVrOJ7OdwKwo0oH7dIWXR73hcTeW7MfT3W5AiG9rttIXCzO2RZqkDID9zysKrfa8kZWo4UUEatFMhWxxEw4Jenedezd4YSTfbrUtKj8jpaZyPHT7ouRAKiN%2FRwmJ8TP0YQsd8f1VWcZyST0JwznOlmarXU6sM0y2P%2Fb7Xj0j3ucckFZvgbOYBXpfMlMBt5GrIScELjnpTy4nF3m2TNkuDRC0VCDvmeWSCNHqJ5W1VFKpfP3Hhrs0Ir1HaeY8aGW8c8XXhbfl6NXd77hnOYWVWbW%2BDhzdPkoGZu586HAN6xa6KfR77ClVagCNf7DAIdD%2Bu%2BVeqbuL%2B%2BLUlHt8x5UL7toPe73W39rdvoaLUUuwbXGzVIvCYYxc3vI%2BaGh2ex1H4IWyN6GDudlkdA2zVFqopoxyrirD%2BNjMwuFltbLDXVQx2OaSiglJ%2B7NE1mT0bCt9dijVcKpQp2GG%2Bs7MKcSamCaNOofs%2Bb7JsllvpOxWnOE%2FSLzOTbnLL519zSgF7q0gaU5Sd8oPdp%2BSPw4k1d4uU4Cw6ATMLZu%2Bbv6uaSIGHlwhD9VwK4WuMGuW1JKr0kxLAuEbbuY%2BCEeHqNxckZue%2BwGOGgmiH1DjYf5pSm2m7AwAA",
    "body": "aHN3VqomfyS20SY5l/f9OFBrmXvpvmQ9XU7UBfnqniRXJgdF5s7RrAmrb298897xQs1OT/o15/HVZqxDp9zcUMU/igtO22PjHiYkC8iAXOwt2fULkLHQe7av4FM6H8GeqwMS6ORygvZemuOCT0tSP28MyPJypjDO1rYdvKU2YNpwfB4hDEV5WKjyhRlHMlJFsk/Mm5euhxNsUG4T/62jwdjWMdZ87IdXq4jaI8CWqA/48qrTuZhAVTd3gaOJULvHkHjTXYXLMoT9EGWPAibqzCO7VJlWEYqN94I9b5+IcVF6mL2xE6on3vhUit1ooacQeIs8erO1dhSqdS7j1A1kBg1DHKiHNjNPEYjyqyYejnZBekOH3zGrp6j9I1vX6HDtCWw+8HSdton7RElqUAwY4ow6CjlANpIQGKvuKdFhAQNyXu661aE2ergw5u4CFIIvkKdxaSUTEjCOh2Ji1YnBSGZdC1MhU7T/+Kta3VU5T2TQJbbJAN+TrJxFZto6BY3Ela3yOWFJ0xYogam8DrJi51nDKb6vLJppGpNlF1BnVLdmcnuLtjdQ/FrsQzfkc1VxIUw+MNsTSYku+jPYGyYyXwdRt2w/dFhSHIktaIyvFC4aACGVG8II6p5mwx5OUKEIRf1LQ7td224fAzt3hA4kYBq4pD2co9WPpQbaFUvmRkgS/HOECOqWMz8Q4bn4V+Iq8Vu2Jju27grznx8K58xfLj/sP+kzimk90e1lL3Yew8z3hLX+hEWs7mOv1sp/FfChXcMFnFYgfj/CZJXaSKAjCvbj6SgZieGs84O0dL31WDufXAsrT3M1wHf55oTLBJtR/B7coRFq+XRWVU7B8oMd/fWpRExHSURc6/NJlhDUlSY8weeJ+nj7Xa6X9QStR4zFVzYvdZmfgNFKpxW9UzVIPM6bBvtRSIKrkuh6IWtFv3cq+GAv3Ge+jYazjvHOfysRmUwanJJFAVeyMyBZqpG7bI0AcT0ZV4cW/JTBYiXo7t7ScHeTDIzdRFqTAzONcd6YikpjeaKai8evYGzN58BRuHm+M2BPNIfqIKp3wgvd7n2VtfLW+5IKwCyJeLjO2idPQs6wtKpLQ6ORB4QUBXeexTTeytIHEe4fhD0s1uan1Rzlq7afazvsOf9kM9kRJVbG3JIu6ogfX4Vbjs2mMpmyrWc7D22EVKvPZ44p7MJqzskqvxEZOrILBK2T7NXUsvfHh2N7kiA4rWSemIzYssnZYDSLSQMgitgigKAuzJ+E0X23FKTJzeV2kxr71Zq4R/DELIhY3YN2ckN48G1nOzM9qqNcEggEqS55OwbOq6UTC28kKpLkF+0oY/uev1boPxwuypXu2xyAZ7f4J/cqBbrRw1hswf2k+a1ZCRs59vFz5BnEOR7aWO4Vy7DKvhcne1c7YUPxDoWZJzbxX0Os0SPWFLZxP4iFDxBSvp8unPxs34E=",
    "fpv": "C7xXBK0SpE8JYLIBIzZYb/3rZSTLBXHs8twkVn9P5mXCy1BIp1qy7RqSrLPssD4CFBtTg/O458LGZj9rY13e0AJwmkeNP0ZUcPTBeVkaKVP5+k8vJmtcoLEq2kYxk/q9bD59mkhapRt+E4lWZMwtM8SyYoZD9Ypl1HV5MxlRYU0=",
    "isUpgrade": "false",
    "refreshTimes": "0",
    "type": "points",
    "wlocation": "H4sIAAAAAAAAA2WNTYvCMBCG/8qQk4KbtLbWVRERDy64elnBc7adNsE0CUnExWX/u1PwtgwMzDPvxy9TLia2ZF7G6F1IvI6N5RYTmzAVsKWXSsnHpRD/JMK4TttN7RpcS+8NpkiuW8Sw7dAOqUf30MZIMeMZjC7aNu4e4XSGPOPZCghU5Qp+qnIM28F/we+DTmJWzHlRwejwcT5+TsDoK8Ie66sbw04F16PISZENA1+ylUG/LNTujUytCz2VU3wxJWSk7W6yQ0IP9bY7EUq6pzOfV4vFtKT9XhZ/TwuBE8sLAQAA"
}

可以看到加密参数差不多,多了一个body,然后这个fpv从gzip压缩变成了RSA加密,这里分析一下这个body。 加密的值里面randomKey就是前面我们那个接口解密后的key,checkPosArr就是点击的坐标,tracks就是鼠标轨迹信息。

加密的方式这里已经非常清楚了,gzip压缩后进行AES加密。

javascript 复制代码
_0x4fb42a["aesEncrypt"](_0x4fb42a["gzip"](JSON["stringify"](_0x69117a)))

最后写完,也就200行js代码,看一下验证结果 如有侵权,联系删除!!!

如有侵权,联系删除!!!

相关推荐
心.c7 小时前
Vue3+Node.js实现文件上传分片上传和断点续传【详细教程】
前端·javascript·vue.js·算法·node.js·哈希算法
独自破碎E21 小时前
【前缀和+哈希】LCR_011_连续数组
算法·哈希算法
2501_940315261 天前
leetcode统计一致字符串的数目(哈希表)
算法·哈希算法·散列表
历程里程碑1 天前
滑动窗口----滑动窗口最大值
javascript·数据结构·python·算法·排序算法·哈希算法·散列表
历程里程碑2 天前
子串----和为K的子数组
大数据·python·算法·leetcode·elasticsearch·搜索引擎·哈希算法
只是懒得想了2 天前
C++实现密码破解工具:从MD5暴力破解到现代哈希安全实践
c++·算法·安全·哈希算法
拼好饭和她皆失2 天前
字符串题型练习
算法·字符串·哈希算法
独自破碎E2 天前
【前缀和+哈希】LCR 010. 和为 K 的子数组
算法·哈希算法·散列表
Maỿbe3 天前
Java的基础知识
算法·哈希算法