AST实战|某CloudFlare 5秒盾第一层混淆代码一键还原思路分享

举报
悦来客栈的老板 发表于 2022/08/02 23:28:23 2022/08/02
【摘要】 关注它,不迷路。 本文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,否则后果自负,如有侵权,请联系作者立即删除! 一.实战地址 https://www.e-food.gr/ 加载的混淆js地址,但是是动态的哈: https://www.e-food.gr/cdn-cgi/challenge-platform/...

关注它,不迷路。

  • 本文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,否则后果自负,如有侵权,请联系作者立即删除!

一.实战地址

https://www.e-food.gr/
  

加载的混淆js地址,但是是动态的哈:

https://www.e-food.gr/cdn-cgi/challenge-platform/h/g/orchestrate/jsch/v1?ray=7334095989227e52
  

混淆代码如图所示:

cedf569deaf8e87bdcd2b4f24f770788.png

这种一看就是变种的ob混淆,一个大数组 + 移位函数 + 解密函数。

二.还原分析

还原第一步:

实参为字面量的函数调用,能还原,先还原:

c('0x1b7')     ===>   'document'

还原后的结果如下:

cfe71096ad4f57a18427b0259d4507ed.png

还原第二步:

代码结够能调整的,先调整:

一般调整的是逗号表达式,但是在处理逗号表达式之前,我们需要先处理一些block,好多都没有{},这是不规范的,得先给它补上:


   
  1. if (0 == J && (J = Math.pow(2, L),
  2. L++),
  3. I[V])
  4. V = I[V];
  5. else {
  6. if (V === K)
  7. V = B["VwayE"](N, N["charAt"](0));
  8. else
  9. return null;
  10. }

===>


   
  1. if (0 == J && (J = Math.pow(2, L),
  2. L++),
  3. I[V]) {
  4. V = I[V];
  5. } else {
  6. if (V === K) {
  7. V = B["VwayE"](N, N["charAt"](0));
  8. } else {
  9. return null;
  10. }
  11. }

还原第三步:

逗号表达式的还原:


   
  1. if (A = {}, A["wzYNQ"] = function (K, L) {
  2. return K * L;
  3. }, A["qobwJ"] = function (K, L) {
  4. return K == L;
  5. }, A["jCUes"] = function (K, L, M, N) {
  6. return K(L, M, N);
  7. }, A["MUwqS"] = function (K, L) {
  8. return K !== L;
  9. }, A["vhpCJ"] = function (K, L) {
  10. return K + L;
  11. }, A["PfjYi"] = function (K, L) {
  12. return K === L;
  13. }, A["JusLJ"] = "McOvX", A["WdCju"] = "lbAdP", A["DBACO"] = "请启用Cookie并重新加载页面。", A["HBUlA"] = function (K, L) {
  14. return K(L);
  15. }, A["UxpOE"] = "cf_chl_", A["IhiBw"] = function (K, L) {
  16. return K + L;
  17. }, A["xOnNk"] = function (K, L) {
  18. return K + L;
  19. }, B = A, B["MUwqS"](d["_cf_chl_opt"]["cLt"], 'd')) {
  20. d["_cf_chl_opt"]["cLt"] = 'd';
  21. } else {
  22. return void 0;
  23. }if (A = {}, A["wzYNQ"] = function (K, L) {
  24. return K * L;
  25. }, A["qobwJ"] = function (K, L) {
  26. return K == L;
  27. }, A["jCUes"] = function (K, L, M, N) {
  28. return K(L, M, N);
  29. }, A["MUwqS"] = function (K, L) {
  30. return K !== L;
  31. }, A["vhpCJ"] = function (K, L) {
  32. return K + L;
  33. }, A["PfjYi"] = function (K, L) {
  34. return K === L;
  35. }, A["JusLJ"] = "McOvX", A["WdCju"] = "lbAdP", A["DBACO"] = "请启用Cookie并重新加载页面。", A["HBUlA"] = function (K, L) {
  36. return K(L);
  37. }, A["UxpOE"] = "cf_chl_", A["IhiBw"] = function (K, L) {
  38. return K + L;
  39. }, A["xOnNk"] = function (K, L) {
  40. return K + L;
  41. }, B = A, B["MUwqS"](d["_cf_chl_opt"]["cLt"], 'd')) {
  42. d["_cf_chl_opt"]["cLt"] = 'd';
  43. } else {
  44. return void 0;
  45. }

===>


   
  1. A = {};
  2. A["uVDHf"] = "gncnt";
  3. A["Ehaxm"] = "7|1|2|6|8|3|0|5|4";
  4. A["iIBCc"] = "data-translate";
  5. A.NwOfM = "error code: 1020";
  6. A["FQgtt"] = function (H, I) {
  7. return H < I;
  8. };
  9. A["dpEeO"] = "none";
  10. B = A;
  11. C = e.getElementById("challenge-form");
  12. if (C) {
  13. if ("JwQCM" !== B["uVDHf"]) {
  14. D = B["Ehaxm"]["split"]('|');
  15. for (E = 0; !![];) {
  16. switch (D[E++]) {
  17. case '0':
  18. F["setAttribute"](B["iIBCc"], "error");
  19. continue;
  20. case '1':
  21. G["style"]["display"] = "none";
  22. continue;
  23. case '2':
  24. C["appendChild"](G);
  25. continue;
  26. case '3':
  27. F["className"] = 'text-gray-600';
  28. continue;
  29. case '4':
  30. G["appendChild"](F);
  31. continue;
  32. case '5':
  33. F["innerText"] = B["NwOfM"];
  34. continue;
  35. case '6':
  36. F = e["createElement"]("span");
  37. continue;
  38. case '7':
  39. G = e["createElement"]("span");
  40. continue;
  41. case '8':
  42. B["FQgtt"](Math["random"](), .25) && (F.style["display"] = B["dpEeO"]);
  43. continue;
  44. }
  45. break;
  46. }
  47. } else {
  48. function H() {
  49. return void 0;
  50. }
  51. }
  52. }

还原第四步:

object对象的还原。

从上面的代码就知道下一步应该还原object了。

===>


   
  1. if (C) {
  2. if ("JwQCM" !== "gncnt") {
  3. D = "7|1|2|6|8|3|0|5|4"["split"]('|');
  4. for (E = 0; true;) {
  5. switch (D[E++]) {
  6. case '0':
  7. F["setAttribute"]("data-translate", "error");
  8. continue;
  9. case '1':
  10. G["style"]["display"] = "none";
  11. continue;
  12. case '2':
  13. C["appendChild"](G);
  14. continue;
  15. case '3':
  16. F["className"] = 'text-gray-600';
  17. continue;
  18. case '4':
  19. G["appendChild"](F);
  20. continue;
  21. case '5':
  22. F["innerText"] = "error code: 1020";
  23. continue;
  24. case '6':
  25. F = e["createElement"]("span");
  26. continue;
  27. case '7':
  28. G = e["createElement"]("span");
  29. continue;
  30. case '8':
  31. Math["random"]() < .25 && (F["style"]["display"] = "none");
  32. continue;
  33. }
  34. break;
  35. }
  36. } else {
  37. function H() {
  38. return void 0;
  39. }
  40. }
  41. }

如果直接用星球里的插件,会发现还有一个object没有还原:    

25064988103da8f09b1b3c903a7fbb5a.png

分析后发现,它是这样的:


   
  1. (function (B, H, I, J, K, L, M, R, Q, P, O, N, C) {
  2. B["hgTsd"] = "0|13|5|7|8|10|1|11|2|6|14|9|12|4|15|16|3";
  3. ......
  4.  })({}, /^[\],:{}\s]*$//\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g/(?:^|:|,)(?:\s*\[)+/g/[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g);

难怪没办法还原,B的赋值是在参数里面,因此,需要点小技巧,变成:


   
  1. (function (B, H, I, J, K, L, M, R, Q, P, O, N, C) {
  2. B = {};
  3. B["hgTsd"] = "0|13|5|7|8|10|1|11|2|6|14|9|12|4|15|16|3";
  4. ......
  5. })({}, /^[\],:{}\s]*$/, /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, /(?:^|:|,)(?:\s*\[)+/g, /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g);

这样,就可以一起还原啦。

tips:当你发现你的插件没办法兼容所有的情况,那你可以使用点小技巧,让插件能将其还原,但是不能影响它的执行逻辑。

还原第四步:

控制流的还原。

===>


   
  1. if (C) {
  2. if ("JwQCM" !== "gncnt") {
  3. G = e["createElement"]("span");
  4. G["style"]["display"] = "none";
  5. C["appendChild"](G);
  6. F = e["createElement"]("span");
  7. Math["random"]() < .25 && (F["style"]["display"] = "none");
  8. F["className"] = 'text-gray-600';
  9. F["setAttribute"]("data-translate", "error");
  10. F["innerText"] = "error code: 1020";
  11. G["appendChild"](F);
  12. } else {
  13. function H() {
  14. return void 0;
  15. }
  16. }
  17. }

还原到这里,基本就差不多了,剩下的是一些收尾工作,例如删除deadcode等。

还原第五步:

删除deadcode等收尾工作。


   
  1. function E() {
  2. if ("vXRMB" === "gIBma") {
  3. function S(a5, a4, a3, a2, a1, a0, Z, Y, X, W, V, U, T) {
  4. V = D[0];
  5. a5 = E[1];
  6. a0 = F[2];
  7. a1 = G[3];
  8. a2 = H[4];
  9. a3 = I[5];
  10. W = J[6];
  11. a4 = K[7];
  12. for (a0 = 0; 64 > a0; (a5 = V, (a0 = a5, (a1 = a0, (a2 = a5(a1, X), (a3 = a2, (W = a3, (a4 = W, (Y = a5(a4, V & a5 ^ V & a0 ^ a5 & a0), (a4 = a2(a4, 2) ^ a2(a4, 13) ^ a2(a4, 22), (a4 = V, (X = a5(a5(a5(a5(a4, X), a2 & a3 ^ ~a2 & W), V[a0]), Y[a0]), (X = a2(X, 6) ^ a2(X, 11) ^ a2(X, 25), (X = a2, (Y[X] = Y, (16 > a0 ? Y = a3[a0 + a4] : (Z = a2(Z, 7) ^ a2(Z, 18) ^ Z >>> 3, (Z = Y[a0 - 15], (Y = a5(Y, Y[a0 - 7]), (Y = a2(Y, 17) ^ a2(Y, 19) ^ Y >>> 10, (Y = Y[a0 - 2], Y = a5(a5(Y, Z), Y[a0 - 16])))))), (X = a0, V = a5(X, Y))))))))))))))))), a0++) {
  13. ;
  14. }
  15. N[0] = a5(V, O[0]);
  16. P[1] = a5(a5, Q[1]);
  17. R[2] = a5(a0, S[2]);
  18. T[3] = a5(a1, U[3]);
  19. V[4] = a5(a2, W[4]);
  20. X[5] = a5(a3, Y[5]);
  21. Z[6] = a5(W, a0[6]);
  22. a1[7] = a5(a4, a2[7]);
  23. }
  24. } else {
  25. return this["valueOf"]();
  26. }
  27. }

===>


   
  1. function E() {
  2. return this["valueOf"]();
  3. }

到这里,基本就还原了。

整个还原的完整代码我放星球了,供大家参考学习,地址:

https://t.zsxq.com/04j6a6Qzb
  

三.交流学习

加我好友,拉你进群,现在快开6群了,学习氛围浓,注意,严禁讨论破解相关的话题。

39a9045bb6c902c6d849e2475fea77b4.jpeg

文章来源: blog.csdn.net,作者:悦来客栈的老板,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/qq523176585/article/details/126113251

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。