JS逆向百例医保局SM2SM4国产

我国知名研究白癜风的专家 https://wapjbk.39.net/yiyuanfengcai/ys_bjzkbdfyy/2840/

声明

本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!

逆向目标

目标:医疗保障局公共查询

主页:aHR0cHM6Ly9mdXd1Lm5oc2EuZLmNuL25hdGlvbmFsSGFsbFN0LyMvc2VhcmNoL21lZGljYWw=

接口:aHR0cHM6Ly9mdXd1Lm5oc2EuZLmNuL2VidXMvZnV3dS9hcGkvbnRobC9hcGkvZml4ZWQvcXVlcnlGaXhlZEhvc3BpdGFs

逆向参数:RequestPayload的encData和signData、RequestHeaders的x-tif-nonce和x-tif-signature

逆向过程

抓包分析

来到公共查询页面,点击翻页,就可以看到一个POST请求,RequestPayload的参数部分是加密的,主要是appCode、encData和signData参数,同样返回的数据也有这些参数,其加密解密方法是一样的,其中encType和signType分别为SM4和SM2,所以大概率这是国密算法了,有关国密算法K哥前期文章有介绍:《爬虫逆向基础,认识SM1-SM9、ZUC国密算法》,此外请求头还有x-tif-nonce和x-tif-signature参数,如下图所示:

参数逆向

直接全局搜索encData或signData,搜索结果仅在app.1.js有,非常明显,上面还有设置header的地方,所有参数都在这里,埋下断点,可以看到这里就是加密的地方,如下图所示:

这里的加密函数,主要都传入了一个e参数,我们可以先看一下这个e,里面的参数含义如下:

addr:医疗机构详细地址,默认空;

medinsLvCode:医疗机构等级代码,默认空;

medinsName:医疗机构名称,默认空;

medinsTypeCode:医疗机构类型代码,默认空;

pageNum:页数,默认1;

pageSize:每页数据条数,默认10;

regnCode:医疗机构所在地代码,默认(北京市);

sprtEcFlag:暂时不知其含义,默认空。

等级代码、类型代码、所在地代码,都是通过请求加密接口得到的,他们的加密和解密方法都一样,在最后的完整代码里有分享,这里不再赘述。其他参数比如appCode,是在JS里写死的。

我们再观察一下整个JS文件,在头部可以看到.call语句,并且有exports关键字,很明显是一个webpack形式的写法。

我们回到加密的地方,从上往下看,整个函数引用了很多其他模块,如果想整个扣下来,花费时间肯定是无比巨大的,如果想直接拿下整个JS,再将参数导出,这种暴力做法可是可以,但是整个JS有七万多行,运行效率肯定是有所影响的,所以观察函数,将不用的函数去掉,有用的留下来,是比较好的做法,观察functiond,第一行vart=n("6c27").sha,点进去来到createOutputMethod方法,这里整个是一个SHA算法,从这个方法往下整个copy下来即可,如下图所示:

这里要注意的是,观察这个函数后面导出的sha实际上是调用了createMethod这个方法,那么我们copy下来的方法直接调用createMethod即可,即vart=createMethod(),不需要这些exports了。

另外还有一些变量需要定义,整个copy下来的结构如下:

接着前面的继续往下看,还有一句o=Object(i.a)(),同样点进去直接copy下来即可,这里没有什么需要注意的地方。

再往下看就来到了e.data.signData=p(e),点进functionp,将整个函数copy下来,这时候你本地调试会发现没有任何错误,实际上他这里使用了try-catch语句,捕获到了异常之后就没有任何处理,可以自己加一句console.log(e)来输出异常,实际上他这里会在o.doSignature、e.from两个位置提示未定义,同样的我们可以点进去将函数扣出来,但是后面会遇到函数不断引用其他函数,为了方便,我们可以将其写到webpack里,下面的e.from也是一样。

将模块写成webpack形式,在自执行方法里调用,然后定义全局变量来接收,再将原来的o,e换成全局变量即可,这里还需要注意的一个地方,那就是o.doSignature传入的h,是一个定值,需要定义一下,不然后面解密是失败的。如下图所示:

这里扣webpack模块的时候也需要注意,不要把所有原方法里有的模块都扣出来,有些根本没用到,可以直接注释掉,这个过程是需要有耐心的,你如果全部扣,那将会是无穷无尽的,还不如直接使用整个JS文件,所有有用的模块如下(可能会多,但不会少):

接着原来的说,encData:v("SM4",e)这里用到了functionv,v里面又用到了A、g等函数,全部扣下来即可,同时还需要注意,前面所说的e在A函数里也用到了,同样需要换成我们自己定义的全局变量,如下图所示:

到此加密用到的函数都扣完了,此时我们可以写一个方法,对加密的过程进行封装,使用时只需要传入类似以下参数即可:

{"addr":"","regnCode":"","medinsName":"","sprtEcFlag":"","medinsLvCode":"","medinsTypeCode":"","pageNum":1,"pageSize":10}

如下图所示getEncryptedData就是加密方法:

那么解密方法呢?很明显返回的数据是encData,直接搜索encData就只有三个结果,很容易找到就行functiony,同样的,这里要注意把e.from改成我们自定义的e_.Buffer.from,另外我们也可以将header参数的生成方法也封装成一个函数,便于调用。

完整代码

GitHub


转载请注明:http://www.aierlanlan.com/grrz/5115.html

  • 上一篇文章:
  •   
  • 下一篇文章: