国家税务总局全国增值税发票查验平台网站js逆向分析及全逆向算法还原

  本文教程针对的是2021年7月2日时国税查验平台的js分析,其中版本号为V2.0.06_009。主要分析内容为key9和flwq39以及fplx这3个参数的算法,其中key9分为获取验证码阶段和查验阶段,算法有所区别,flwq39同理。

  教程开始:

  一、官方网址

  国家税务总局全国增值税发票查验平台

  二、请求分析

  国税查验平台请求共分为2个,第一个请求获取验证码,第二个请求为输入验证码后查验数据并返回发票详细信息。

  第一步:安装证书

  基础:谷歌浏览器

  首先需要安装证书,建议选择自动安装,在某些教程中可能选择手动安装,以便于使用ast工具挂代理找内存数据,但是这里我们采用一种新的方法来解决js逆向问题,因此那种方便用那种。

  

  第二步:抓包

  基础:谷歌浏览器+开发者工具+js基础知识

  我们使用开发者工具或按F12打开谷歌浏览器的开发者工具,请注意尽量在网页加载完成后打开开发者工具,界面如下:

  

  官方很给力,直接debug了,至于如何去掉断点,可以参考百度上的其他教程,这里给出一个办法,上图中点击数据1所处位置,使其颜色为蓝色,点击2或者点击上方的debug恢复按钮。此时,我们成功绕过了debug,但是特别注意尽量关闭其他无用软件或者网页,因为在后面的操作中,会感到特别卡顿。

  我们在发票代码输入框和发票号码中输入合法的数据,并在开发者工具模块,观察所发送的请求包:

  https://fpcy.anhui.chinatax.gov.cn/NWebQuery/yzmQuery?callback=jQuery11020854931324645166_1625223145135&fpdm=034012000211&fphm=12345678&r=0.28901229909781767&v=V2.0.06_009&nowtime=1625223446708&publickey=1625223446708&key9=ec213f1e1aa579511f5d58f09a01a5a2&_=1625223145136&flwq39=LdjaQwXUtzKjxpXQ%2FmD7KCBtBMP7lqfc7uBJNuxAumYpT9mjp90BloLfM4V6KKuD4GWdYCxRLLjJX9a1YrNy7Bs95NmSWQmpc1VAibkeG3HydXc0r9xsRc%2BkIsPWeHrFk3PYAP6k8tAcTJzoIdlhctD8wOUVXOUwczcMJW6WiF0%3D

  在这个请求中,分为url的网址前缀部分和尾部参数,其中尾部参数如下:

  如果你观察过会发现,不同地区的发票,请求的地址不同,如这里是anhui。该请求的前缀部分在一个js文件中,如图:

  

  但是,很不幸,当你打开这个文件时,你会发现混淆了,不过很容易发现是sojson的样子,这并不影响我们逆向,我们使用http://tool.yuanrenxue.com/decode_obfuscator这个网站可以解密这些js代码,尽管解密的代码看着很头疼,但是已经比原始的好太多了。

  

  解密后可以得到各个地区的ip和网址以及对应的地区代码:

  回到抓包中,我们观察到这时发送了一个获取验证码的请求:

  

  注意到通过分析这个url,我们发现请求来自如下图,我们注意到getyzmxx这个函数,来自eab23.js这个文件里,我们提取这个文件使用ob解密。

  

  ob解密后的数据如下:

  我们注意到key9值的位置,

  这里需要知道$["nnyd"]["yzm"]的具体函数,分析后如下:

  这里只展示了部分数据,同时注意到一个参数,后面用得到:

  如果有经验,你会知道可能和RSA加密相关,事实也是如此,上面已经对key9的算法位置分析清楚了,下面对flwq39进行分析,实际上,flwq39也是在这个文件中,我使用vscode对解密后的js代码进行了格式化,并查找了flwq39这个关键字,发现如图:

  

  因此,我们继续分析会发现该参数是在请求前拼接完成的,并且关键字本身被替换了:

  

  反向找到调用的函数就会发现最终是调用了RSA加密算法,其中PublicKey就是

  在验证码获取后返回包如下:

  其中key1是经过base64编码的图片数据,key2是验证码的时间,另外注意到key3和key4及key6。

  其中key4分为4种情况分别为输入全部、黄色、红色、蓝色,对应00,01,02,03。余下的参数在验证阶段用到。

  同理,在查验阶段,请求如下:

  https://fpcy.anhui.chinatax.gov.cn/NWebQuery/vatQuery?callback=jQuery11020854931324645166_1625223145135&key1=034012000211&key2=12345678&key3=20210702&key4=123456&fplx=10&yzm=MK&yzmSj=2021-07-02+18%3A34%3A48&index=43017c78ec891a4b9406501694f0b479&key6=402887f17a53027c017a66d4d62d72d0&publickey=2021-07-02+18%3A34%3A48&key9=ac558f9ae05a94c21dc504f5d8882b9d&_=1625223145137&flwq39=Ky8pYUqln7zaEZcxF9XZw3fAsiOM%2F92RmTxy%2BNAtDo4f1h3c1yHQJZNESl5Nz9Xq5Mu7bEeBkFlPgerOBnR1pnLviLn4WLkMTtzsLy%2BMe2wPu%2B%2FFaiszckIGS%2F1Z5YZ4zusosj68YLZ0hRk53UWbrWz9xg%2BC3XRGwEWyqbzg0XE%3D

  这里注意到

  这里的key9和flwq39在

  这个对应的函数中,key9和flwq39算法和上面的类似。

  此外注意到fplx这种参数,也在这几个js文件中,这里给出具体的函数名:

  通过使用php的v8js拓展,我们可以实现接口编写:

  

  

  二者结果一致。

  至此,全部参数已经解密部分完毕。

  第三步,算法的完全还原,脱离js环境,这里我使用C#实现算法还原和脱离

  首先,我们需要知道的是在核心的算法中,源代码使用了ob进行了混淆,我们使用第三方软件进行初次还原时,也只能还原一部分,核心的内容基本会被还原,但是生成的代码还是无法完全被理解阅读,基于此,需要二次还原,这里注意到Ob混淆的核心思想,是一个大数组和若干个解密函数,后续的代码里不断的调用解密函数进行解密。

  设计如下:通过分析可以注意到解密函数的前缀是_开头的,后续是)]或其他的组合,因此,我们需要使用提取函数名,在调用时,才能知道那些函数可以还原,同时在提取时也随同获取调用的参数,如果参数中包含变量,则直接忽略,并在调用成功后进行替换。

  通过上述操作,我们就能最大程度还原出原始的代码段。

  接着,彻底逆向还原使用其他语言改写,如果你看过本文,并对相关js有分析,你大概会知道,核心部分就是涉及几个加密算法,如md5和移位的一些操作。但其核心的算法如下:

  第一个是Gen函数

  

  第二个是key9

  

  其他的类似。部分代码如下图: