爬虫第八式:破解百度翻译案例(特别详细) - JS逆向

温馨提示:

爬虫玩得好,监狱进得早。数据玩得溜,牢饭吃个够。

《刑法》第 285 条,非法获取计算机信息系统数据罪。
       违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金;情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。

正文:

之前我们 破解了有道翻译 的案例,现在我们应该有这样一种意识,如果我们当时分析的JS代码很复杂怎么办,没关系,本文将介绍更高级的一种手段—— JS逆向,我们将通过 破解百度翻译 这一案例,来学习JS逆向工程

介绍

1】应用场景
	当JS加密的代码过于复杂,没有办法破解时,考虑使用JS逆向思想
【2】模块
	2.1》模块名:execjs
	2.2》安装: sudo pip3 install pyexecjs
	2.3》使用流程
		import execjs
		with open('xxx.js', 'r') as f:
			js_code = f.read()
            
		js_obj = execjs.compile(js_code)
		# 把一个字符串当成一个表达式来执行
        js_obj.eval('函数名("参数")')

接下来我们还是像之前的有道翻译的那样,翻译一个单词,直接抓包:
在这里插入图片描述
我们看到抓包,文件中有一个v2transapi开头的文件,点开它就是我们抓包抓到的数据,在General中我们看到了,url请求地址,以及重要的post请求方式,然后我们看Form Data里面,我们其他的不用看我们看两个:token、sign,其中,token是不变的,而sign是变化的,翻译一个单词他就会变化一次,我们需要对他处理

接着,我们还是搜索在JS里面搜索sign
在这里插入图片描述
我们看这个跟我们之前的不一样啊,好多包含sign的js文件啊,我们只能一个一个看,但是在这我就直接点了啊,就点第一个包含sign的js文件,因为我们看到sign:他后面还有一个token,大概就是了

点进去,跳转到Sources选项卡中,格式化一下,在这个文件里面再搜索sign:
在这里插入图片描述
打上断点后,我们接着,在翻译一个单词:
在这里插入图片描述
把鼠标放到y上,我们进入到上面显示的 f e® 函数里面去:
在这里插入图片描述
这个就是我们所说的生成sign加密的函数,然后把这段代码复制出来,我们在调试,复制从最上面复制,就是下面划横线的那个函数里面的代码,就是 红框框起来的所有代码
在这里插入图片描述
创建一个JS文件先给他存进去,这是三个函数,其中1、2不用管,我们看第3个函数,这个函数就是真正生成sign的函数,我们看这个函数的参数是 r,对于这个r是什么,我们再翻译一个单词就知道了在这里插入图片描述
如果刚刚没有停止断点的话,我们点击这个,就可以往下走就会显示出了:
在这里插入图片描述
(如果停止上一次断点了,就接着在那个函数下面打断点,在翻译一个单词就看到了)
好了,我们看到这个r, 就是我翻译的单词,所以我们要调用e这个函数:
在这里插入图片描述
到这里我们分析的就这样了,但是我们还是没有分析完,因为一般来说不会这样顺利的,找出代码,一执行就完了,这是不可能的,所以接下来我们用Python代码测试一下:

# 调试js代码的库
import execjs

# 只读打开文件
with open('translate.js', 'r') as f:
    js_code = f.read()

# 创建编译对象
js_obj = execjs.compile(js_code)
# 把一个字符串当成一个表达式来执行
sign = js_obj.eval('e("dragon")')
print(sign)

运行代码:
在这里插入图片描述
直接报错,我们看报错最后一行,t is not defined ,这个是我们刚才复制的js代码,最后一行,那我们就先把他注释上,再次运行:
在这里插入图片描述
还是报错,这次的错误是window is not defined,那我们在js代码里找window
在这里插入图片描述
这里大概在32行左右,这里的window[l],中的l,对应着上一行的l,它又对应着 后面一大串代码,这个是,字符串的Ascii码,接着复制 l 后面段代码,接着Console一下:
在这里插入图片描述
这个打印出来的是gtk,应该是代码上面分别对应的:
左边103的是g
中间116的是t
右边107的是k

那我们明白了,window[l],中的l,就是gtk,那我们去源代码中搜索一下gtk是个什么鬼?
在这里插入图片描述
就一处,显示的是window.gtk,那我们这样,直接把他后面的字符串复制到js代码中的window[l]这里,试一下看能不能翻译,因为它获取的就是这段字符串,索性我们就直接给到他:
在这里插入图片描述
再运行我们写的Python代码:
在这里插入图片描述
这就行了?那我们去在翻译一下,在抓包找一下
sign
对一下不就知道了吗,我们走着:
在这里插入图片描述
没问题,这就粗略的搞定了,那万一有一天百度翻译把这个字符串改了,我们还得去找它,所以我们直接在JS代码里加一个参数,代替他,这样就不怕它会变了,等到我们在页面里面用正则提取出来,作为参数,这样传过去也是没问题的:
在这里插入图片描述
这样就OK了,再看token,这个东西是不变的,我们不必在分析它,这个在它的源代码里也是有的,我们就不用管它了:

在这里插入图片描述

我们再处理一下 headers和data,headers去抓首页的,data只能是先翻译一个单词再抓加上General 里的 url,处理成这样:
在这里插入图片描述

保存一下,这三个一会儿会用到,现在开始写代码:
导入模块

import requests
import execjs 
import re

实例化变量

class BaiduTranslateSpider:
    def __init__(self):
    	# 这个是获取到gtk和token后的url,写到逻辑函数时用到
        self.url = 'https://fanyi.baidu.com/v2transapi?from=zh&to=en'
        # 这个是我们要得获取gtk和token得用到的url
        self.index_url = 'https://fanyi.baidu.com/'
        # headers写自己浏览器的
        self.headers = {
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
            "accept-encoding": "gzip, deflate, br",
            "accept-language": "zh-CN,zh;q=0.9",
            "cookie": "PSTM=1605584756; BAIDUID=621509D1EDB1556EC71CC68C1A5E304C:FG=1; BIDUPSID=1AEB19AD6C78D3C7A1EFF1AEF6482602; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; __yjs_duid=1_cab112ddffaa4af33775ae7d7dfa029c1608807397345; BAIDUID_BFESS=621509D1EDB1556EC71CC68C1A5E304C:FG=1; delPer=0; PSINO=1; H_PS_PSSID=1443_33223_33306_31660_32971_33350_33313_33312_33169_33311_33310_33339_33309_26350_33308_33307_33145_33389_33370; BCLID=8765896679250944447; BDSFRCVID=L9-OJexroG3SwVJrTfwCjurRFtc7jnQTDYLEqQKg3tugmU4VJeC6EG0Ptj35efA-EHtdogKK0gOTH6KF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; H_BDCLCKID_SF=tR3h3RrX26rDHJTg5DTjhPrM2HrJWMT-MTryKKORQnrjqxbSqqo85JDwQRnfKx-fKHnRhlRNtqTjHtJ4bM4b3jkZyxomtfQxtNRJQKDE5p5hKq5S5-OobUPUDMJ9LUkqW2cdot5yBbc8eIna5hjkbfJBQttjQn3hfIkj2CKLtCvHjtOm5tOEhICV-frb-C62aKDs2IIEBhcqJ-ovQTb65pKpKROh-MJBb6rNKtbJJbc_VfbeWfvpKq_UbNbJ-4bLQRnpaJ5nJq5nhMJmM6-hbtKFqto7-P3y523ion3vQpP-OpQ3DRoWXPIqbN7P-p5Z5mAqKl0MLPbtbb0xXj_0-nDSHH-fqT_q3D; BCLID_BFESS=8765896679250944447; BDRCVFR[S4-dAuiWMmn]=I67x6TjHwwYf0; BA_HECTOR=a084852k2k0l00ah2s1fubldu0r; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1608855621,1608855625,1608858163,1608897985; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1608899822; ab_sr=1.0.0_ZDYxNDU1MTNjNDBjOTkwOGMwYzc4Zjk0MDc5NmRjOGU1MDU2YTBjNjkyYWU5ZTIwNTg5Yzc2YjMyZDRhNDJiZDA3ZTdlNGNmNjljODNlYjk5MmE2ZGM4OGJhMzk4ODM1; __yjsv5_shitong=1.0_7_36bddc638f8abe26b68d5c474b5aa7d1bf8b_300_1608899822168_43.254.90.134_bed0d9ad; yjs_js_security_passport=52a6024d37461c03b90ffc37c07f84492340e8cd_1608899823_js",
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "none",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1",
            "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36", }

获取gtk和token

def get_gtk_token(self):
    """获取gtk和token"""
    html = requests.get(url=self.index_url,
                        headers=self.headers).text
    # 正则获取我们之前分析的gtk参数和token参数,因为token数不变的,所以我们不必分析
    gtk = re.findall("window.gtk = '(.*?)'", html, re.S)[0]
    token = re.findall("token: '(.*?)'", html, re.S)[0]

    return gtk, token

接下来就是功能函数:生成sign

def get_sign(self, word):
	# word 是要翻译的单词
    """功能函数:生成sign"""
    # 先获取到gtk和token
    gtk, token = self.get_gtk_token()
    # 打开我们之前的JS代码
    with open('translate.js', 'r') as f:
        js_code = f.read()

    js_obj = execjs.compile(js_code)
    # eval把一个字符串当成一个表达式来执行
    sign = js_obj.eval('e("{}","{}")'.format(word, gtk))
    return sign

爬虫逻辑函数

def attack_bd(self, word):
    """爬虫逻辑函数"""
    gtk, token = self.get_gtk_token()
    sign = self.get_sign(word)
    # 我们之前处理的data数据,这个也是用自己浏览器的
    data = {
        "from": "en",
        "to": "zh",
        "query": word,
        "transtype": "realtime",
        "simple_means_flag": "3",
        "sign": sign,
        "token": token,
        "domain": "common",
    }
    # json():把json格式的字符串转为python数据类型
    html = requests.post(url=self.url,
                         data=data,
                         headers=self.headers).json()
    result = html['trans_result']['data'][0]['dst']

    return result

最后奉上全部代码:

import requests
import execjs
import re


class BaiduTranslateSpider:
    def __init__(self):
        self.url = 'https://fanyi.baidu.com/v2transapi?from=zh&to=en'
        self.index_url = 'https://fanyi.baidu.com/'
        self.headers = {
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
            "accept-encoding": "gzip, deflate, br",
            "accept-language": "zh-CN,zh;q=0.9",
            "cookie": "PSTM=1605584756; BAIDUID=621509D1EDB1556EC71CC68C1A5E304C:FG=1; BIDUPSID=1AEB19AD6C78D3C7A1EFF1AEF6482602; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; __yjs_duid=1_cab112ddffaa4af33775ae7d7dfa029c1608807397345; BAIDUID_BFESS=621509D1EDB1556EC71CC68C1A5E304C:FG=1; delPer=0; PSINO=1; H_PS_PSSID=1443_33223_33306_31660_32971_33350_33313_33312_33169_33311_33310_33339_33309_26350_33308_33307_33145_33389_33370; BCLID=8765896679250944447; BDSFRCVID=L9-OJexroG3SwVJrTfwCjurRFtc7jnQTDYLEqQKg3tugmU4VJeC6EG0Ptj35efA-EHtdogKK0gOTH6KF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; H_BDCLCKID_SF=tR3h3RrX26rDHJTg5DTjhPrM2HrJWMT-MTryKKORQnrjqxbSqqo85JDwQRnfKx-fKHnRhlRNtqTjHtJ4bM4b3jkZyxomtfQxtNRJQKDE5p5hKq5S5-OobUPUDMJ9LUkqW2cdot5yBbc8eIna5hjkbfJBQttjQn3hfIkj2CKLtCvHjtOm5tOEhICV-frb-C62aKDs2IIEBhcqJ-ovQTb65pKpKROh-MJBb6rNKtbJJbc_VfbeWfvpKq_UbNbJ-4bLQRnpaJ5nJq5nhMJmM6-hbtKFqto7-P3y523ion3vQpP-OpQ3DRoWXPIqbN7P-p5Z5mAqKl0MLPbtbb0xXj_0-nDSHH-fqT_q3D; BCLID_BFESS=8765896679250944447; BDRCVFR[S4-dAuiWMmn]=I67x6TjHwwYf0; BA_HECTOR=a084852k2k0l00ah2s1fubldu0r; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1608855621,1608855625,1608858163,1608897985; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1608899822; ab_sr=1.0.0_ZDYxNDU1MTNjNDBjOTkwOGMwYzc4Zjk0MDc5NmRjOGU1MDU2YTBjNjkyYWU5ZTIwNTg5Yzc2YjMyZDRhNDJiZDA3ZTdlNGNmNjljODNlYjk5MmE2ZGM4OGJhMzk4ODM1; __yjsv5_shitong=1.0_7_36bddc638f8abe26b68d5c474b5aa7d1bf8b_300_1608899822168_43.254.90.134_bed0d9ad; yjs_js_security_passport=52a6024d37461c03b90ffc37c07f84492340e8cd_1608899823_js",
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "none",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1",
            "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36", }

    def get_gtk_token(self):
        """获取gtk和token"""
        html = requests.get(url=self.index_url,
                            headers=self.headers).text
        gtk = re.findall("window.gtk = '(.*?)'", html, re.S)[0]
        token = re.findall("token: '(.*?)'", html, re.S)[0]

        return gtk, token

    def get_sign(self, word):
        """功能函数:生成sign"""
        # 先获取到gtk和token
        gtk, token = self.get_gtk_token()
        with open('translate.js', 'r') as f:
            js_code = f.read()

        js_obj = execjs.compile(js_code)
        sign = js_obj.eval('e("{}","{}")'.format(word, gtk))
        return sign

    def attack_bd(self, word):
        """爬虫逻辑函数"""
        gtk, token = self.get_gtk_token()
        sign = self.get_sign(word)
        data = {
            "from": "en",
            "to": "zh",
            "query": word,
            "transtype": "realtime",
            "simple_means_flag": "3",
            "sign": sign,
            "token": token,
            "domain": "common",
        }
        # json():把json格式的字符串转为python数据类型
        html = requests.post(url=self.url,
                             data=data,
                             headers=self.headers).json()
        result = html['trans_result']['data'][0]['dst']

        return result

    def run(self):
        word = input('请输入要翻译的单词:')
        print(self.attack_bd(word))


if __name__ == '__main__':
    spider = BaiduTranslateSpider()
    spider.run()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨旭华 

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值