• Cloudflare分析第二天:解密返回数据


    前言

    Cloudflare分析第一天:简单的算法反混淆

    由上篇for (j = "10|8|5|9|1|4|0|2|3|6|7"["split"]('|')

    可以看到循环的循序

    1. case '6':
    2. o = (n = {},
    3. n["msg"] = f,
    4. n.cc = g,
    5. hF["VNwzz"](JSON["stringify"](n))["replace"]('+', "%2b"));
    6. continue;
    7. case '7':
    8. m["send"](i["TglBA"](i["iEKkH"]('v_', fy["_cf_chl_opt"]["cRay"]) + '=', o));
    9. continue;

    提交之前先把数据转为字符串,再进行加密之后send

    为了防止代码进入错误分支(第一天的分析中,只是为了定位加密的位置,调试出来的数据肯定是错误的),之后hook json来输出加密前的JSON数据

    Hook代码:

    1. JSON_=JSON.stringify;
    2. JSON.stringify=function(data) {
    3. console.log(JSON_(data));
    4. return JSON_(data);
    5. }

    输出如图:

     加密算法应该就是hF["VNwzz"]

    算法暂且不提,提交之后返还如图:

    明显也是加密过的,既然返回,既然有后续,那么可以断定肯定可以解密的,找一下解密函数的位置.

     从send往下跟(下面JS代码非第一篇中的JS代码了,是实时调试的代码,因为每次刷新JS内容都不一样,所以你们显示的代码跟我贴出来的不会相同,但是会类似)

    1. i[jj(473)] = function(jm, l, m, n, o, s, u, v, w) {
    2. if (jm = jj,
    3. l = {},
    4. l["VWkdu"] = "unspun",
    5. m = l,
    6. n = "600010",
    7. i["readyState"] != 4)
    8. return;
    9. (o = this["getResponseHeader"]("content-type"),
    10. f["MMxvO"](o, f["SFsFE"])) && (s = JSON["parse"](i["responseText"]),
    11. s["err"] && (n = s["err"]));
    12. if (u = f["fzhiJ"](hj, n),
    13. u && f["fzhiJ"](hk, u),
    14. i["status"] === 400) {
    15. if ("QwWqw" === "QwWqw")
    16. return void fy["fUJhKx5"]();
    17. else
    18. e(f, function(B, jn) {
    19. jn = jm,
    20. B[jn(274)][jn(448)] = jn(502),
    21. B[jn(274)][jn(1191)] = jn(496)
    22. })
    23. }
    24. if (f["mycqq"](i["status"], 200) && f["mycqq"](i["status"], 304)) {
    25. if (f["ZYzcT"]("Vjfpl", "Vjfpl"))
    26. return void f["AQGEw"](h);
    27. else
    28. e("spinner-icon", function(C, jo) {
    29. jo = jm,
    30. C[jo(1878)][jo(397)](m[jo(1372)])
    31. }),
    32. f(f["YBWCH"])
    33. }
    34. (v = gc(i["responseText"]),
    35. v["startsWith"]("window._")) ? new fy[("Function")](v)(d) : (w = g2(v),
    36. f["jKZSc"](typeof w, "function") && w(d))
    37. }

    可以看到得到i["responseText"],会经过函数gc,然后根据gc内容进入两个分支,应该是不同版本的Cloudflare的原因,也可以是跟请求次数的原因,这个留着后面再看!

    这里返回的V内容如图:

     明显跟分支一的判断条件v["startsWith"]("window._"))不相关,那就是走第二个分支(w = g2(v),
        f["jKZSc"](typeof w, "function") && w(d))

    先把v经过函数g2复制给w,判断w是不是一个function,是的话用运行函数w 传入的参数是d,

    记录一下d的值是:

    {"KhMOxC9":"interactive","bndrvD9":"6653","MYYj1":"2","ikkssZ0":0,"kbcqog7":0,"VQtOX1":1,"BtZG4":{"ru":"aHR0cHM6Ly9yZXNlcnZlLmNvdGFpdGlja2V0aW5nLmNvbS92ZW5ldGlhbi9ib29raW5nL3RlYW1sYWIyMDIwYT9sYW5nPXpoX2Nu","ra":"TW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV2luNjQ7IHg2NCkgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzExNS4wLjAuMCBTYWZhcmkvNTM3LjM2","rm":"R0VU","d":"GLaiWK7+Aynp53e83DlICIPs5kPXyow7ZJCuyNtNUjK0jVYAnt+TbytmxWrcP+62RSFFXIPuPmb/3fbHixQTprOyAwChBbvM1MrAvfjlmXW6qkuXmRFOKuykwiPuP3DMHmmaC63qr/9BJ+yhj2PzrjTA952Vb9Su06wVTdu7kEqdvr8OieyHZCkOpa+lGKgP/c6gQgEFq6S8VyKgGecCBuxJ56f14LFIYU2oNONruHPciGevRsu5QOgcMsbuwvMHB9JeIQK59eMH9M4J7rru11sjzPYBJLctT93PUSVKYS4dmYcFsb0dj/6RX7y3ODNkmURLa3vso3UJByrBLVZ5IuVymXA87PlT+VLbdfBMyJbXP7xStKwqEmxlbnp9VLzvtAnTkVFY8DSIuvnUSjqQWnNnQvAr3RPIDxrQbSNgVzdV+g3bHulxk6UCVIV1PN7SMvsZ+NAFFzVvhBjXOJEKEOpgEvhjL+0KYUSx9h0/yQBzAsPL/0GC8O7wwAyttYwfGhRNud5X+76dmcm9xKMV92iQrREz3f/6EMIgpNbnhzs=","t":"MTY5NTczNTI1My4zNDQwMDA=","cT":1695735254,"m":"2nCYUb/c8IGLtnA7v0cShWvIPXJfl/OTJmP5UNxF+1w=","i1":"X+hEwD3IazR/zARQ0f6Vsg==","i2":"2zPnYa8F0C5i9HwWO/A93A==","zh":"nokJ+kv3PhcFpycs7wM5nNWc180K5fDj0ICCUUtH6GA=","uh":"49m45payZ+JaK1qP7bVg0G3ztg3QEguIG+n0xYKxzGA=","hh":"2lEEhm+aTIz86a+3BVsMSx+TmoW9esNsNWiuxMPl5I4="},"JTJoTA3":{"bxAwfI6":0,"EMltvi8":0,"byQaTk7":0,"OBLzip2":0,"QZKLG1":0,"NAzoXH1":0,"OUeDDN9":0,"Ybbkg4":0},"LkMnc9":false}

    貌似跟刚hook JSON输出的内容一样.

    w的函数内容是:

    1. function fI(i, j, l, n, o, s, u, v, w, ig, x, B, C, D) {
    2. return ig = ia,
    3. x = {},
    4. x["VLuHS"] = "QTvFm",
    5. x["UFwjI"] = function(E, F) {
    6. return F * E
    7. }
    8. ,
    9. x["eQQaR"] = function(E, F) {
    10. return E < F
    11. }
    12. ,
    13. x["DMIyJ"] = function(E, F) {
    14. return E ^ F
    15. }
    16. ,
    17. x["kBIZP"] = function(E, F) {
    18. return E ^ F
    19. }
    20. ,
    21. x["hRCDz"] = function(E, F) {
    22. return F ^ E
    23. }
    24. ,
    25. x["uPoTE"] = function(E, F) {
    26. return F ^ E
    27. }
    28. ,
    29. x["CGyfQ"] = function(E, F) {
    30. return E ^ F
    31. }
    32. ,
    33. x["bKlIO"] = function(E, F) {
    34. return E ^ F
    35. }
    36. ,
    37. x["ckUij"] = function(E, F) {
    38. return E ^ F
    39. }
    40. ,
    41. x["EfMnC"] = function(E, F) {
    42. return F ^ E
    43. }
    44. ,
    45. B = x,
    46. C = this,
    47. D = this.h[133 ^ this.g],
    48. this.h[B["uPoTE"](9, this.g)]["push"]([NaN, '', '', 0], this.h[B["bKlIO"](97, this.g)]["length"], 20),
    49. this.h[B["uPoTE"](68, this.g)] = j,
    50. this.h[this.g ^ 139] = l,
    51. this.h[this.g ^ 149.42] = n,
    52. this.h[126 ^ this.g] = o,
    53. this.h[72 ^ this.g] = s,
    54. this.h[254.22 ^ this.g] = u,
    55. this.h[this.g ^ 26] = v,
    56. this.h[135 ^ this.g] = w,
    57. this.h[this.g ^ 133.86] = i["slice"](),
    58. function(ih, E, F) {
    59. for (ih = ig,
    60. E = {
    61. 'YBIKS': ih(1687),
    62. 'HjGch': B[ih(167)],
    63. 'BmmCx': function(G, H, ii) {
    64. return ii = ih,
    65. B["UFwjI"](G, H)
    66. },
    67. 'Tkrye': ih(1527),
    68. 'SSwvN': function(G, H, ij) {
    69. return ij = ih,
    70. B[ij(1303)](G, H)
    71. }
    72. },
    73. F = {}; !isNaN(C.h[B[ih(376)](133, C.g)][0]); F = {
    74. 'j': F.j
    75. },
    76. F.j = C.h[B[ih(1187)](133, C.g)][3] ^ 87 + C.h[B[ih(1861)](133, C.g)][1][ih(433)](C.h[B[ih(954)](133, C.g)][0]++) & 255.69,
    77. function(G, ik, H) {
    78. return ik = ih,
    79. H = {
    80. 'Ljnku': E["YBIKS"],
    81. 'AjvvY': E["HjGch"],
    82. 'IPsXd': function(I, J) {
    83. return I + J
    84. },
    85. 'BkFWt': function(I, J, il) {
    86. return il = ik,
    87. E[il(194)](I, J)
    88. },
    89. 'zbNLn': function(I, J) {
    90. return J !== I
    91. },
    92. 'gBDEx': E["Tkrye"],
    93. 'aYteo': function(I, J) {
    94. return I ^ J
    95. },
    96. 'GRFey': function(I, J, im) {
    97. return im = ik,
    98. E[im(1664)](I, J)
    99. },
    100. 'LoecI': function(I, J) {
    101. return I ^ J
    102. }
    103. },
    104. function(io, I, J, N, K) {
    105. if (io = ik,
    106. I = {
    107. 'ApVtT': H["Ljnku"],
    108. 'ALfoN': function(L, M) {
    109. return L(M)
    110. },
    111. 'BbJsM': function(L, M, N, O) {
    112. return L(M, N, O)
    113. }
    114. },
    115. "UbZvD" === H["AjvvY"])
    116. return !s(I["ApVtT"]) && I["ALfoN"](C, "cookies_missing"),
    117. ![];
    118. else {
    119. J = (J = C.h[133.64 ^ C.g],
    120. J[3] = H["IPsXd"](H["BkFWt"](28083, J[3] + G.j), 13090) & 255,
    121. C.h[G.j ^ C.g]);
    122. try {
    123. H["zbNLn"]("tCuMr", H["gBDEx"]) ? (G = "symbol" !== typeof o ? s + '' : u,
    124. N = {},
    125. N["enumerable"] = !0,
    126. N["configurable"] = !0,
    127. N["writable"] = !0,
    128. N["value"] = void 0,
    129. v in w ? I["BbJsM"](x, B, C, N) : D[E] = void 0) : J["bind"](C)(G.j)
    130. } catch (N) {
    131. if (J = C.h[H["aYteo"](97, C.g)],
    132. H["GRFey"](0, J["length"]))
    133. C.h[H["aYteo"](155, C.g)] = N,
    134. K = J["pop"](),
    135. C.h[133 ^ C.g] = J["pop"](),
    136. C.h[H["LoecI"](9, C.g)]["splice"](K);
    137. else
    138. throw N
    139. }
    140. }
    141. }
    142. }(F)())
    143. ;
    144. return C.h[B[ih(1446)](135, C.g)]
    145. }(),
    146. this.h[B["ckUij"](133, this.g)] = D,
    147. this.h[B["EfMnC"](20, this.g)]
    148. }

    给自己留个备注:  暂时没看到解密出来的明文数据,需要进一步分析

  • 相关阅读:
    向量数据库Milvus Cloud 2.3 Attu 界面升级,用户体验更友好
    程序员亲试,人体工学椅真的有用吗?
    Docker全解
    多种工具软件实现宿主机与Ubuntu虚拟机之间文件传输
    Spring学习笔记
    杰理之在所有模式下打开喊话增加 mic 自动 mute【篇】
    如何用mindspore高阶API实现互学习
    gRPC 拦截器 & 自定义命名解析
    开发工程师必备————【Day17】q前端HTML基础知识点
    C#进阶——反射(Reflection)
  • 原文地址:https://blog.csdn.net/qq_29340905/article/details/133324226