当前位置: 首页 > 后端技术 > Python

百度索引Cipher-Text,百度翻译Acs-Token逆向分析

时间:2023-03-25 21:37:15 Python

K哥写了一篇关于百度翻译逆向的文章,还在bilibili上发布了相应的视频。有网友建议百度翻译增加了一个请求头参数Acs-Token。如果不带这个参数,直接按照前面的方法处理,会出现1022错误,而如果直接把Acs-Token写成固定值,前几次可能会成功,同样的错误多次查询后报告。现在逆向分析重构之前的代码。同时,K哥发现百度索引的部分接口有一个Cipher-Text参数,类似于百度翻译的Acs-Token加密方式,我们一起来分析一下。声明本文所有内容仅供学习交流,不作任何其他用途,不提供完整代码,抓包内容、敏感URL、数据接口等内容均已脱敏处理,并严禁用于商业及非法用途,否则由此产生的一切后果与作者无关!本文未经许可禁止转载,修改后禁止二次传播。对于因未经授权使用本文所解释的技术而导致的任何事故,作者概不负责。如有侵权,请第一时间联系作者公众号【K爬虫哥】删除!反向目标target:百度翻译最新请求头参数Acs-Token,百度索引请求头Cipher-Text主页:https://fanyi.baidu.com/接口:https://fanyi.baidu.com/v2tra...sign,token参数的reverse方法本文不再赘述。想了解更多可以看K哥之前百度翻译逆向的文章。它出来了。由此可以推断是Ajax加载的。打开开发者工具,选择XHR过滤Ajax请求,找到接口位置,详细分析。推荐看K哥之前的百度翻译逆向文章。如下图,可以看到requestheader中添加了一个Acs-Token参数,前两串数字看起来像是时间戳,具体的加密方式还需要进一步分析:这里我们使用Fiddler插件hook定位到Acs-Token参数,相关hook操作方法可以看K哥往期文章,本文不再赘述:(function(){varorg=window.XMLHttpRequest.prototype.setRequestHeader;window.XMLHttpRequest.prototype.setRequestHeader=function(key,value){console.log(key,':',value)if(key=='Acs-Token'){调试器;}returnorg.apply(this,arguments);};})();清空缓存,点击翻译,可以看到成功hook到Acs-Token参数,去可以找到它的值产生的位置,顺着栈:逆向分析顺着栈分析,Acs的值-Token参数在translate.js文件的第187行生成并通过sign参数传递。第180行定义sign参数,第195行设置断点调试。点击翻译后,在断点处成功破解:跟进getAcsSign()函数,全选,点击进入paris.js文件,可以看到在函数体中创建了一个异步Promise对象,用于异步operation:Promise的构造函数接收一个函数参数,这个函数需要传入两个参数:resolve:异步操作执行成功后的回调函数;reject:异步操作执行失败后的回调函数,所以异步操作成功时返回sign参数的值:这里已经获取到sign了,我们顺栈查找Acs-Tokenparameter的值是在acs-2060.js文件的第805行生成的,明显是拼接的:上图前几天分析的时候坏了,再次分析的时候结构变了今天,如下图提示:这个acs-2060.js是怎么来的?在paris.js中,其实可以看到init初始化了一些配置文件,其中acsUrl是acs-2060.js的地址,2060是频道号,是管理员分配的。根据评论可以看到这个东西叫“玉门关”。继续前面的步骤,分析acs-2060.js,在805行断点调试,分析a8()中各个拼接部分的含义,得到如下结果:b('0x78')or'\x31\x36\x36\x30\x35\x34\x36\x38\x30\x39\x35\x30\x35\x5f':固定字符串1660287615129_或1660546809505_,每隔一段时间就变一次。具体的变化周期需要不断观察才能知道。ae:当前时间戳'\x5f':underscore_eg(a2,a0,a1):一大串加密字符串,在控制台输出a0可以知道a2,a0,a1各自的含义,a1是固定值,分析a2字典中各个参数值??的含义:ua:浏览器类型url:翻译链接,比如输入一个蜘蛛,url为https://fanyi.baidu.com/#zh/e...platform:platformoperatingsystemversionclientTs:Currenttimestampversion:versionnumber选择eg,跟进eg函数定义的位置,在acs-2060.js文件第537行:具体内容如下:functioneg(a2,a8,a9){returna2=b('0x4d')==typeofa2?JSON[b('0xc')](a2):void0x0===a2?'':''+a2,dD[b('0x37')](a2,ad[b('0x29')](a8),{'\x69\x76':ad[b('0x29')](a9),'\x6d\x6f\x64\x65':cc,'\x70\x61\x64\x64\x69\x6e\x67':cz})[b('0x27')][b('0xa')](ag);}可以在538行调试,或者直接在控制台打印混淆部分,会发现三个经典的加密参数:'\x69\x76':iv,offset'\x6d\x6f\x64\x65':mode,encryptionmethod'\x70\x61\x64\x64\x69\x6e\x67':padding,paddingmethodandassigntowindow.aes_encryptintheline548,很明显AES加密了,你可以选择直接引用库,或者直接扣代码,这里不继续研究:百度索引密文百度索引的密文和百度翻译的Acs-Token在结构上是一样的。根据百度翻译的经验,我们知道核心加密密码应该在“玉门关”,不同的站分配的频道号是不一样的。我们直接全局搜索acsUrl,或者直接找acs开头的JS,会发现有acs-2057.js:照例停在a8()刷新界面即可。分解:百度索引和百度翻译的区别就是开头的时间戳不一样,变量a0不一样,其他逻辑都是一样的。我们注意到开始的时间戳会在一段时间后发生变化。在项目代码中手动更改肯定是不合理的。这里的处理思路可以是先在本地固定一套算法,然后每次请求获取acs开头的JS。拿到内容后,通过正则匹配得到时间戳,然后传给本地算法生成最终的值,然后就可以灵活的去做了。Cipher-Text和Acs-Token的分析就结束了。这个反向加密算法其实并不难,但是要想找到被加密的位置就需要一定的技巧了。另外,在写这篇文章的时候,发现百度翻译可以在不添加Acs-Token的情况下进行请求。现在的情况是有时候不加acs-token可以请求,有时候不加就不能请求。如果请求发现错误{"errno":1022,"errmsg":"访问异常,请刷新重试!","error":1022,"errShowMsg":"访问异常,请刷新重试!""},那么你可以尝试添加这个参数。完整代码bilibili关注K哥爬虫,小助手动手视频教学:https://space.bilibili.com/16...GitHub关注K哥爬虫,持续分享爬虫相关代码!欢迎加星!https://github.com/kgepachong/下面只是演示了部分关键代码,不能直接运行!baidufanyi_encrypt.jsvarwindow=global;//后面部分太长,此处略去//完整代码关注github:https://github.com/kgepachong/crawler(function(){...})()functionascToken(translate_url){//有些参数直接写死,不同网站参数值不同,如果在项目中使用,请灵活处理vara0='uyaqcsmsseqyosiy';vara1='1234567887654321';varae=(新日期)。获取时间();vara2='{"ua":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/103.0.0.0Safari/537.36","url":'+translate_url+'","platform":"Win32","clientTs":'+ae+',"version":"2.2.0"}';//这个开头的时间戳是硬编码的,如果请求失败请更新这个值return'1660546809505_'+ae+'_'+window.aes_encrypt(a2,a0,a1);}//console.log(ascToken("https://fanyi.baidu.com/#zh/en/%E6%B5%8B%E8%AF%95"))baidufanyi.py#==================================#--*--编码:utf-8--*--#@Time:2021-08-12#@Author:微信公众号:K哥笨虫#@FileName:baidufanyi.py#@Software:PyCharm#==================================importreimportexecjsimportrequestsfromurllibimportparsession=requests.session()index_url='https://fanyi.baidu.com/'lang_url='https://fanyi.baidu.com/langdetect'translate_api='https://fanyi.baidu.com/v2transapi'headers={'User-Agent':'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/103.0.0.0Safari/537.36',}#cookies={#"BAIDUID":"624363427DBD2BFCDF0C3D6E129F5C65:FG=1"#}defget_params(query):#获取令牌和gtksession.get(url=index_url,headers=headers)#print(session.cookies.get_dict())response_index=session.get(url=index_url,headers=headers)token=re.findall(r"token:'([0-9a-z]+)'",response_index.text)[0]gtk=re.findall(r'gtk="(.*?)"',response_index.text)[0]#自动检测语言response_lang=session.post(url=lang_url,headers=headers,data={'query':query})lang=response_lang.json()['lan']returntoken,gtk,langdefget_sign_and_token(query,gtk,lang):withopen('baidufanyi_encrypt.js','r',encoding='utf-8')asf:baidu_js=f.read()sign=execjs.compile(baidu_js).call('e',query,gtk)translate_url='https://fanyi.baidu.com/#%s/en/%s'%(lang,parse.quote(查询))acs_token=execjs.compile(baidu_js).call('ascToken',translate_url)returnsign,acs_tokendefget_result(query,lang,sign,token,acs_token):data={'from':lang,'to':'en','query':query,'transtype':'realtime','simple_means_flag':'3','sign':sign,'token':token,}headers["Acs-Token"]=acs_tokenresponse=session.post(url=translate_api,headers=headers,data=data)结果=response.json()['trans_result']['data'][0]['dst']returnresultdefmain():query=input('请输入要翻译的文本:')token,gtk,lang=get_params(query)sign,acs_token=get_sign_and_token(query,gtk,lang)result=get_result(query,lang,sign,token,acs_token)print('翻译成英文的结果是:',result)if__name__=='__main__':主要的()