【Web】记一次破解 JS 加密

一直在寻找一个可用的搜题接口

之前刷网课搜题一直用的 “帅搜”,写了个 py 的脚本,平常用起来很方便。
后来也不知道什么原因,人家把接口给关闭了。

import win32clipboard as win
import win32con
from requests_html import HTMLSession,sys
from urllib import parse
import time

def getText():
    win.OpenClipboard()
    text = win.GetClipboardData(win32con.CF_TEXT)
    win.CloseClipboard()
    return text

last = ''
while True:
    try:
        temp = str(getText(), 'gbk')
        pre = temp
        if last != pre:
            print('问题:' + pre)
            html = HTMLSession().get('http://chati.xuanxiu365.com/index.php?q=' + parse.quote(pre)).html
            print('\n' + '未查询到您需要的答案...' + '\n' + '\n' if '未查询到' in html.html or '禁止' in html.html else '\n' + html.find('body > form > div.weui-panel > div.weui-panel__bd > div > div', first=True).text + '\n' + '\n')
            last = pre
    except:
        last = ''
    time.sleep(1)

后来就只能去微信公众号上搜题,但总感觉效率慢很多。
当时还把上面的代码基于 wxpy 改了一下:

import win32clipboard as win
import win32con
# from requests_html import HTMLSession,sys
# from urllib import parse
from wxpy import *
import time


def gettext():
    win.OpenClipboard()
    text = win.GetClipboardData(win32con.CF_TEXT)
    win.CloseClipboard()
    return text

def initial(bot, chat_obj ,timeout):
    msg_received = False
    msg = ''
    @bot.register(chat_obj)
    def getMsg(in_msg):
        nonlocal msg, msg_received
        msg = in_msg
        msg_received = True

    def main_fun(question):
        nonlocal msg, msg_received
        local_time = time.time()
        msg = ''
        chat_obj.send_msg(question)
        while msg_received != True:
            time.sleep(0.5)
            if time.time() - local_time > timeout:
                return '超时未返回'
        msg_received = False

        return  msg.text
    return main_fun

def getbot():
    bot = Bot(cache_path=True)
    char_obj = bot.mps(update=True)# .search('呆小呆搜题')
    return bot,char_obj

bot, chat_obj = getbot()
getan = initial(bot, chat_obj, 10)
last = ''
while True:
    try:
        temp = str(gettext(), 'gbk')
        pre = temp
        if last != pre:
            print('问题:' + pre)
            # html = HTMLSession().get('http://chati.xuanxiu365.com/index.php?q=' + parse.quote(pre)).html
            # print('\n' + '未查询到您需要的答案...' + '\n' + '\n' if '未查询到' in html.html or '禁止' in html.html else '\n' + html.find('body > form > div.weui-panel > div.weui-panel__bd > div > div', first=True).text + '\n' + '\n')
            print(getan(pre))

            last = pre
    except:
        last = ''
    time.sleep(1)

但是我的微信号不提供 web wx 服务,每次搜题还得找同学,也不方便。

偶然发现了一个可以搜题的网站

进入正题:
有一个同学,他可能网课比我多,就总是抱怨搜题的效率低下,很难受。
今天中午跟他在外边恰饭,期间他在知乎上找到了一个搜题的网站。
当即抓了下包看了看。
在这里插入图片描述
有一个 token字段,感觉有些不妙。

回家之后开始分析:

刚打开就来了个反调试,疯狂断点。
在这里插入图片描述
通过Blackbox script (脚本黑箱化) 解决:
在这里插入图片描述
现在可以调试了,先抓个包:
在这里插入图片描述
除 token 外的两个字段都好说。
type 是前端一个选项决定的。question 就是问题关键字,莫得问题。
现在主要就是这个 token 字段了。

获取 token 字段

这里不要混淆了,此 token 非彼 token,这里的 token 仅仅用于它后端的验证。
首先看一下查询按钮的回调:
在这里插入图片描述
点进去:
发现是直接注册在 Dom 结构上的
在这里插入图片描述
全局搜一下:
发现是请求页面里的函数
在这里插入图片描述
看一下函数体:
在这里插入图片描述
可以看到 token 是通过挂载在 window 下的 jjm 得到的。
接下来就是找这个 jjm。
在这里插入图片描述
全局搜一下,结果没搜到。于是关一下黑箱,下断点单步跟跟一下调用看看:
在这里插入图片描述
跟进去就来到了一个叫 jm.js 的 js 文件:
可以看到,这个文件的代码被混淆过。
框起来的就是被挂载在 window 下的方法,jjm 这个方法名应该是通过 _0x58fb('0x57','rl4#') 返回的。

在这里插入图片描述
通过 chrom 自带的 pretty code 可以格式化代码:
在这里插入图片描述
所有代码复制一下放在 vscode 中,提取这个主加密算法 jjm 在单独文件中,并导入先前的代码。
在这里插入图片描述
观察到仅红框位置涉及外部调用。
绿框处的 md5 加密算法需要额外导入。
接下来我们什么也不调,直接运行一下。
在这里插入图片描述迟迟没有反应,而我本不富裕的内存也雪上加霜,过了一会,堆崩了。
这时猜测 jm.js 中被调用的混淆算法检测了环境,然后通过不断地 new 或者循环的方式把堆给搞崩掉了。
我们下断点单步跟一下看看。
在这里插入图片描述
发现代码永远死在了这个 for 里面。
不过没关系,我发现这个函数没有名字,是自调用的,而且与其他函数完全没有耦合,可以放心删掉。
不过在我删掉后,发现接下来又来了一波看不懂的判断,直接就给我抛了异常。
中间也有着耦合的函数调用,于是我决定放弃这条路,直接渐进式地从主加密算法向外添加函数。
在这里插入图片描述
我们把导入 jm.js 语句删掉,然后抽出唯一的外部调用进来。
这个函数贼长,但是我发现他与外部关联的调用仅此一个,于是我们把它从外边复制进来。
在这里插入图片描述
导入 md5 ,然后直接调这个 jjm 来试一下:
离胜利不远了。
在这里插入图片描述
然后代码又死在了这个 for 里。
在这里插入图片描述
还是太麻烦了,我们回头分析一下主加密算法:
md5 调用的参数使用到了这个高亮的 JSON 对象。可以看到这个对象有两个成员,一个是 iWtcL,另一个是iTvRA,分别对应两个方法。
而这个外部的调用可以看出来是高亮对象的一个字段。那么这个位置不是iWtcL,就是iTvRA。我们直接替换为iTvRA试一下
在这里插入图片描述
直接输出了类似 token 的值,我们用 postman 试一下
在这里插入图片描述
结果人家后端说 token 错误。

在这里插入图片描述
检察一下参数。
刷新一下页面,发现这里的常量变了,看来这个页面是后端渲染的。
在这里插入图片描述
这下我们用这个字符串加密试一下。
在这里插入图片描述
在这里插入图片描述
然后直接拿到了结果:
Unicode 字符,JSON.parse()即可。
在这里插入图片描述

至此就结束了

后面就是,先封装一下加密算法。然后为了解决跨域的问题,自己写个后端包装一下,让别人调。
在这里插入图片描述
我是完成之后来写博客的,所以后端已经完成了。
据说挺 6 --> 带佬的博客
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_16181837/article/details/107265383