写点什么

看漫画 MHGmhgui,Python 爬虫之神奇的 eval,附赠一个压缩模块

作者:梦想橡皮擦
  • 2022 年 8 月 09 日
    河北
  • 本文字数:3225 字

    阅读完需:约 11 分钟

⛳️ 看漫画 MHG mhgui 实战分析

本文所有 MHG 使用 MHG 替代~


无障碍阅读版本请参考:https://www.cnblogs.com/happymeng/p/16441870.html


本次爬虫采集的案例是 MHG,该站点貌似本身就游走在法律的边缘。



站点地址直接检索即可进入,在该目标站点,橡皮擦发现了 eval 加密的双重用法。


页面所有点位都无太大难点,而且漫画超多,但是当点击详情页的时候,发现加密点位了。


https://i.看评论区.com/ps1/u/17287/cmdty/%E7%AC%AC01%E8%AF%9D/3.jpg.webp?e=1654230046&m=T-uqjbcgI-eyVGgsIsnjLw
复制代码


其中比较关键的就是参数 m,其余参数都比较容易猜到其含义。


  • %E7%AC%AC01%E8%AF%9D:第一话;

  • e:时间戳。


通过开发者工具的 DOM 事件绑定器,找到下一页按钮点击事件,然后在下述位置添加断点。



通过该断点调试,发现参数在页面加载时已经生成,继续寻找的意义不大,接下来要更换思路。


全局检索关键字 m=,查看所有搜索结果之后,最终定位到 config.js 文件,即下图代码高亮位置。



截取相应的代码文件,如下所示,这代码一眼看上去就能猜测是 eval 加密,但是其关键信息,例如 window["\x65\x76\x61\x6c"] 还是存在加密,下面我们优先解决该值。


window["\x65\x76\x61\x6c"](function(i, k, a, n, m, an) {    m = function(a) {        return (a < k ? "" : m(window["\x70\x61\x72\x73\x65\x49\x6e\x74"](a / k))) + ((a = a % k) > 35 ? window["\x53\x74\x72\x69\x6e\x67"]["\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65"](a + 29) : a["\x74\x6f\x53\x74\x72\x69\x6e\x67"](36))    }    ;    if (!''["\x72\x65\x70\x6c\x61\x63\x65"](/^/, window["\x53\x74\x72\x69\x6e\x67"])) {        while (a--)            an[m(a)] = n[a] || m(a);        n = [function(m) {            return an[m]        }        ];        m = function() {            return '\\\x77\x2b'        }        ;        a = 1    }    ;while (a--)        if (n[a])            i = i["\x72\x65\x70\x6c\x61\x63\x65"](new window["\x52\x65\x67\x45\x78\x70"]('\\\x62' + m(a) + '\\\x62','\x67'), n[a]);    return i}('\x72 \x41\x3d\x28\x78\x28\x29\x7b\x72 \x6c\x69\x74"]('\x7c'), 0, {}));
复制代码


别看上述代码长,但是当我使用在线工具解密之后,得到了下面一段代码。


function(f){return LZString.decompressFromBase64(this).split(f)}
复制代码


但是这里并没有前文的关键字参数 m=T-uqjbcgI-eyVGgsIsnjLw,接下来我们在源码中查看一下,看是否存在关键性信息。


得到的代码段如下所示


window["\x65\x76\x61\x6c"](  (function (p, a, c, k, e, d) {    e = function (c) {      return (        (c < a ? "" : e(parseInt(c / a))) +        ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36))      );    };    if (!"".replace(/^/, String)) {      while (c--) d[e(c)] = k[c] || e(c);      k = [        function (e) {          return d[e];        },      ];      e = function () {        return "\\w+";      };      c = 1;    }    while (c--)      if (k[c]) p = p.replace(new RegExp("\\b" + e(c) + "\\b", "g"), k[c]);    return p;  })(    'U.k({"F":i,"E":"D","C":"i.a","B":A,"z":"f","y":["1.a.b","2.a.b","3.a.b","4.a.b","5.a.b","6.a.b","7.a.b","8.a.b","9.a.b","%x%w%v%c%t%G%d%g%h%r.4.1%q.a.b","%p%j%o%c%j%n%c%l%I%d%H%P%d%g%h.a.b"],"J":W,"Y":11,"Z":"/12/u/X/V/f/","10":1,"S":"","R":Q,"O":0,"N":{"e":M,"m":"T-L-K"}}).s();',    62,    65,    "D41hWAODmwO4FMBGlgFECs6CcJA03gAwCMgu9HACCRwAQlgMzbYBMVAHNcAJYC20AIgEMALgOCtWIbADFg2DmgBswJriasWwSACcEASQB2nIbLqSAwjT7oALMABmnADYIAzsADG+gdwTAMGVgB2YI9OABNgFE53YEBIm0ANvMAQt0BavUBbtUivH0jwsTYsViUHQxcACwQIhABPADUAcWgXXRd9cAAZOGAAVwBHcCR3aF1gIgUMayY6AgJrJRdHTR0AN10I1it/IMCJfQQADyEVyMcAe3cAawB9dxjgAGUAWQAJD24woUr7AUcXXyJAtUCwGc+k0whKwBcIiEnTcmhcRCAA="[      "\x73\x70\x6c\x69\x63"    ]("\x7c"),    0,    {}  ));
复制代码


此时关键信息逐渐出现,我们重点解密该代码段即可。


直接使用 eval 函数解析上述代码,发现出现如下错误。



但是 \x65\x76\x61\x6c 可以解码为 eval


console.log('\x65\x76\x61\x6c')16:42:45.372 VM251:1 eval
复制代码


但是下述这段代码出现了问题。



在结合刚才我们得到的一个莫名的加密函数。


function(f){return LZString.decompressFromBase64(this).split(f)}
复制代码


可以试着用 Python 解密一下上述代码段,而且 Python 中恰好有同名第三方模块。


pip install lzstring
复制代码


直接解密加密字符串即可。


import lzstring
x = lzstring.LZString()
decompressed = x.decompressFromBase64( 'D41hWAODmwO4FMBGlgF加密字符串AA=')print(decompressed)
复制代码


得到的信息如下所示,变得越来越清楚了。


||||||||||jpg|webp|E5|E9||第01话|A1|B5|39921|8B|imgData|88||9F|9B|E6|29|2821|preInit|93||9C|BD|E4|files|cname|558777|cid|bpic|沉默的庭园|bname|bid|81|85|86|finished|eyVGgsIsnjLw|uqjbcgI|1654230046|sl|prevId|8D|558778|nextId|block_cc||SMH|cmdty|false|17287|len|path|status||ps1
复制代码


此时还是无法得到最终的答案,然后可以看到代码结构发现下述规律,即代码出现了相似的部分,并且都是 eval。



细心环节,将代码一点点翻译成可逆向的


lzstring 解密字符串,然后手动使用 split 函数进行分隔,因为上述代码 \x73\x70\x6c\x69\x63 解析出来竟然是 splic 函数。


谷歌开发者工具的控制台中运行下述代码即可。


"||||||||||jpg|webp|E5|E9||第01话|A1|B5|39921|8B|imgData|88||9F|9B|E6|29|2821|preInit|93||9C|BD|E4|files|cname|558777|cid|bpic|沉默的庭园|bname|bid|81|85|86|finished|eyVGgsIsnjLw|uqjbcgI|1654230046|sl|prevId|8D|558778|nextId|block_cc||SMH|cmdty|false|17287|len|path|status||ps1".split(  "|");
复制代码


得到的信息如下所示。


[  "",  "",  "",  "",  "",  "",  "",  "",  "",  "",  "jpg",  "webp",  "E5",  "E9",  "",  "第01话",  "A1",  "B5",  "39921",  "8B",  "imgData",  "88",  "",  "9F",  "9B",  "E6",  "29",  "2821",  "preInit",  "93",  "",  "9C",  "BD",  "E4",  "files",  "cname",  "558777",  "cid",  "bpic",  "沉默的庭园",  "bname",  "bid",  "81",  "85",  "86",  "finished",  "eyVGgsIsnjLw",  "uqjbcgI",  "1654230046",  "sl",  "prevId",  "8D",  "558778",  "nextId",  "block_cc",  "",  "SMH",  "cmdty",  "false",  "17287",  "len",  "path",  "status",  "",  "ps1",];
复制代码


然后将其替换到上述 JS 中,使用解密工具直接在线解析。


SMH.imgData({  bid: 39921,  bname: "沉默的庭园",  bpic: "39921.jpg",  cid: 558777,  cname: "第01话",  files: [    "1.jpg.webp",    "2.jpg.webp",    "3.jpg.webp",    "4.jpg.webp",    "5.jpg.webp",    "6.jpg.webp",    "7.jpg.webp",    "8.jpg.webp",    "9.jpg.webp",    "%E4%BD%9C%E5%93%81%E9%A1%B5%2821.4.1%29.jpg.webp",    "%E6%8B%9B%E5%8B%9F%E5%88%86%E9%85%8D%E9%A1%B5.jpg.webp",  ],  finished: false,  len: 11,  path: "/ps1/u/17287/cmdty/第01话/",  status: 1,  block_cc: "",  nextId: 558778,  prevId: 0,  sl: { e: 1654230046, m: "T-uqjbcgI-eyVGgsIsnjLw" },}).preInit();
复制代码


此时,一些关键参数都已经得到了,例如 e 的值,m 的值。


接下来的 Python 编码就变的索然无味 了,大家加油~


📢📢📢📢📢📢💗 你正在阅读 【梦想橡皮擦】 的博客👍 阅读完毕,可以点点小手赞一下🌻 发现错误,直接评论区中指正吧📆 橡皮擦的第 <font color=red>687</font> 篇原创博客


发布于: 刚刚阅读数: 3
用户头像

爬虫 100 例作者,蓝桥签约作者,博客专家 2021.02.06 加入

6 年产品经理+教学经验,3 年互联网项目管理经验; 互联网资深爱好者; 沉迷各种技术无法自拔,导致年龄被困在 25 岁; CSDN 爬虫 100 例作者。 个人公众号“梦想橡皮擦”。

评论

发布
暂无评论
看漫画MHGmhgui,Python爬虫之神奇的eval,附赠一个压缩模块_Python_梦想橡皮擦_InfoQ写作社区