百度翻译JS逆向

872 阅读7分钟

百度翻译JS逆向

百度翻译 sign 加密参数逆向过程分析

需求分析

实现一个我们自己的百度翻译,暂定 英译中

抓包

首先在翻译栏中输入内容点翻译按钮,F12抓包一下

image-20220614202200834

发现每一次点击翻译都会请求两个地址

langdetect请求,从请求参数,以及返回值 很明显的能发现是一个检查当前输入内容是什么语种的请求。

v2transapi这个请求就是真正的翻译请求,翻译一下名字也许是v2 trans apiv2版本的翻译 api

将抓到的参数用python requests 库请求一下看看

image-20220614202837657

试了很多次发现请求头里面需要携带cookie,这个cookie是我在无痕模式下copy过来的,应该是没有携带上个人信息的。

这个时候我们发现,把参数原封不动的复制过来是可以直接请求成功的。既然这样,我们换点翻译内容多试几次看看请求参数有什么不同。

  • 测试用例:hello

image-20220614203509690

  • 测试用例:word

image-20220614203536964

  • 测试用例:baidu

image-20220614203611109

经过多个样例可以发现请求参数的大致一些规律

formto这个很好理解是从什么语种翻译到什么语种

query 是我们的查询参数

transtypesimple_means_flagtokendomain 是固定参数,没有变化。

唯一有变化的是 sign 参数,看样子是需要解决这个参数的加密方式了

并且发现,在query参数一样的时候,请求的sign参数也是一样的。先合理猜测一下。sign是根据query参数加密得来的。

逆向

全局搜索

全局搜索 v2transapi

image-20220615094954061

image-20220615095048642

发现在 index.js 文件里面定义了两处,点进index.js文件中,先是格式化一下,然后在这个文件内 ctrl + f 搜索一下v2transapi

直接在两处打上断点,然后点翻译按钮看一下js的执行过程。

image-20220615095425842

我就这里就直接的断在了url的地方,点翻译按钮js执行到了这里了。然后我们点一下下一步。发现进入到了这个done里面了。

image-20220615095905079

这个时候如果会一点js就很快能懂这里的执行逻辑了,是用的 jQuery$ 发起一个ajax请求。那我们重点关注一下这个ajax请求的data参数是怎么来的。

往上找一点就很容易发现,这个请求是在 langIsDeteced这个方法里面定义的,在请求的上面就定义了一些参数。

image-20220615100059809

y参数构造

我们分析一下这个 y 参数的构造,在结合上面抓包的分析,我们重点是要看一下 sign这个参数是怎么来的,

这个时候我们吧所有的断点取消掉,只在这个sign这个地方加一个断点,方便调试。

image-20220615100438051

大致看一下 sign 是通过调用 I 函数传了一个 e 过去,再看一下query参数对应的值很容易猜出来这个e就是我们的查询参数。

I函数分析

这个时候断底一下进入到这个 I函数 看一下内部是怎么实现的。点这个按钮就能进入这个函数内部了。

image-20220615100656324

不过进入之后我们发现我们进入到了一个 e 函数内部,刚刚明明调用的是 I函数怎么进入到了e函数内部呢。不过仔细的看一下参数r 也确实是我们的查询参数。了解一点js的能好理解一点,这个文件导出了一个函数,在另外一个文件内引入了这个函数并且重命名了。(题外话,这个重命名估计是代码打包过程做的js混淆)

image-20220615100808320

现在进入到了这个e 函数内部也好棘手啊,右边作用域内一大堆的参数头都要晕掉。

这个时候不要慌,我们发现这个函数一共才30几行。我们直接复制到一个 index.html文件中。执行一下这段脚本看看什么情况。

image-20220615101414649

执行一下看一下控制台

image-20220615101450688

什么?报错了,23行 i is not defined

不要慌,30行的代码,缺什么我们补什么,要有信心,看一下源代码里面这个i是个什么东东

image-20220615101620194

这里是给这个u赋值,看i是不是null,是null就取 window[l] 不是就取 i

这里又出来了一个 window[l],不要怕,我们的代码里面肯定是看不出来这个是啥的,我们去刚刚断点调试的环境里面看一下这个是什么东东。

image-20220615102015177

看我圈起来的地方定义了l,好像是一个固定值,gtk

那现在就是取 window['gtk']

这个时候就比较迷惑了,这个值哪来的。刚刚分析 u 的值就是

window['gtk'],然后在右边的参数栏里面就能发现 u = window['gtk'] = 320305.131321201

我们现在全局的搜索一下320305.131321201

image-20220615102449209

点进去看一下

image-20220615102532542

然后我们就发现了,在这个script里面就找到了定义的地方,注意我圈起来的地方定义了token。我们请求的参数里面也有一个token

这个时候,你应该问我,你怎么知道这个token就是我们请求时候的token

其实是我之前在分析的时候先分析的token参数,全局搜索搜索到这里的。而且回过头看一下y参数构造里面的token,直接就是取的 window.common.token

补环境

现在我们知道了window['gtk'] 是一个固定值,那我们就在我们的代码里面给他补上

image-20220615103235865

这个时候我们在到浏览器里面看一下这个函数的调用有没有符合我们的预期结果。

image-20220615103244040

TNND,你怎么还不出结果,你给我出啊!

吐槽一番,又报错了,36行的n is not defined

我们再去源代码中找一下n函数的调用,断点调试进去看看。

image-20220615103614862

如图,这个时候断点要打在n函数上,在行号上打断点的时候会出现两个向右的点头,n函数前面的箭头要断点上

image-20220615103755543

发现n函数就在 e函数前面定义着,而且也就8行,直接复制到我们的环境中。

image-20220615103850903

这个时候在看一下控制台的执行结果。

image-20220615103924473

我擦,感动,结果已经出来了。这个时候在对比一下我们copy来的代码输出结果和请求时候携带的sign是否一致。发现是一致的,那么至此我们的sign参数就逆向完成了。

Spider启动

现在这个sign的加密过程我们就拿到了,不过是js代码,我们的spider是用Python写的。

现在就有两个思路

  1. 我们模仿js的逻辑写一个Python的函数出来。因为代码一共也就40来行。
  2. 我们用Python去调用这个js代码

我们这里采用 PyExecJS 这个Python库采用第二种思路来实现 sign的加密函数。

signFun.js 内容,改变了第一行,先吧window定义成了一个对象,因为PyExecJS运行环境默认是node环境,在node环境中没有window全局对象

image-20220615133636808

运行成功

image-20220615133858337

总结

至此基本的百度翻译逆向工作就做完了,要做成一个爬虫的话后面还有一下工作要处理,比如cookietokenwindow['gtk'],还有就是toformquery参数的处理,逻辑也比较简单就不写啦。


写这个文章用了一天左右的时间,主要是下班了写了一半没写完,第二题天继续开干,不过也证实了一点,cookie,token这些参数是死的,过了一天继续用都没问题。

image-20220614203611109

image-20220614203611109