完美世界逆向分析案例
案例url:https://passport.wanmei.com/login?location=L3NhZmUv
逆向分析思路:
1)寻找加密参数
输入用户名和密码后,点击登录按钮,通过抓包工具捕获点击登录按钮后发起请求对应的相关数据包。
2)全局搜索加密参数
打开全局搜索框:点击右上角的三个点,打开search表示的全局搜索框即可,在其内部搜索password。在这些数据包中重点关注js文件对应的代码,在其内部找寻加密解密的相关操作。
3)定位到正确的加密断点位置
定位一个js数据包,点击左下角的大括号进行js文件代码的格式化显示。在该数据包内部代码中点击一下,按下Ctrl+F进行局部搜索,搜索password即可,在可疑加密的位置打下断点即可。在可疑之处打上断点后,需要基于抓包工具进行请求的重新发送,查看是否会停留在断点的位置,寻找到正确的加密断点位置
4)改写JS加密函数
通过上面的断点位置分析,断点代码的关键字:setPublicKey,encrpt,通过这两个关键字确定该算法为非对称秘钥加密算法。e.setPublicKey($('#e').val()); 该行代码是在设置公钥,因此函数的参数应该是公钥表示的字符串。
//改写之前
var e = new JSEncrypt();
e.setPublicKey($('#e').val());
if (!isUsbkey) {
$("#logintype").val("normal");
var p = e.encrypt(passwd);
$("#password").val(p);
return true;
}
//$('#e').val()就是公钥表示的字符串。$('#e').val()的意思是,获取id为e的标签中存储的数据值,将该数据值作为公钥使用。
//经过多次断点测试对比,公钥是写死的,不需要去动态获取,此处的公钥为:
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjfeE0MIYsZes/HwV06/kvRw34Hmhn9WPt0feLPp1PVqdqZz1/xFvPPEAJ/lAvfqt5kyn+A06bvYXIhizTjlOzPgLE4897ihuSYXgfwcUshPZvydRLbftU6Exj5SLbv5tw4GInbgQv7RWLWOKyQA81q6lWae2Kcgd1XpDRsQNXVwIDAQAB"
//改写之后,公钥可以写死放进去,这里只是没有放而已
function getPwd(password, pubkey) {
var e = new JSEncrypt();
e.setPublicKey(pubkey);
var p = e.encrypt(password);
return p;
};
5)构建函数上下文
改写完JS加密函数之后,缺少函数执行所需要的上下文,我们需要定位到setPublicKey函数和encrypt函数的实现代码(鼠标可以放在函数名上,出现的提示框中点击就可以进入到函数的实现中,就可以查看函数的实现代码)
这里经过分析发现该两个函数的代码实现都在jsencrypt.min.js:formatted文件中,并且通过该文件的命名和首行注释判断整个文件都是加密算法所需要的上下文代码。
这里直接copy全部代码到js改写工具中加载代码进行检查是否存在语法错误,发现出现报错,经过对比分析发现是编码错误。直接将js代码粘贴到发条改写工具中,可能会出现编码问题,则可以将js代码先粘贴到pycharm中,再将pycharm中的代码复制粘贴到发条改写工具中,不要点击格式化按钮,然后直接点击加载代码按钮,会出现一个错,定位在了s = "…",可以将该行代码删除,自己重新写一遍即可!至此编码问题就解决了!
解决完上面的编码问题之后再次加载代码,发现出现'navigator' 未定义的错误,直接在首行navigator = this;,出现'window' 未定义也同样操作
至此,加载代码成功,全部问题已解决,可以在改写工具上去调用getPwd函数
6)python运行
import execjs
node = execjs.get()
fp = open('wanmeishijie.js','r',encoding='utf-8') # 编码,不行就gbk
ctx = node.compile(fp.read())
pwd = "123456"
key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjfeE0MIYsZes/HwV06/kvRw34Hmhn9WPt0feLPp1PVqdqZz1/xFvPPEAJ/lAvfqt5kyn+A06bvYXIhizTjlOzPgLE4897ihuSYXgfwcUshPZvydRLbftU6Exj5SLbv5tw4GInbgQv7RWLWOKyQA81q6lWae2Kcgd1XpDRsQNXVwIDAQAB"
jsFunc = 'getPwd("%s","%s")'%(pwd,key)
result = ctx.eval(jsFunc)
print(result)
写好上面的代码,报错JSEncrypt is not defined,这里隐藏了一个坑
经过分析,报错原因是因为代码中var t 都是局部变量,后面的 t.JSEncrypt 在pycharm中产生了歧义,由于发条改写工具是js环境,所以上面在改写工具中没有报错,但是pycharm是兼容js和python的,其中产生了某种错误,导致调用失败
解决办法就是将 t.JSEncrypt 改为 JSEncrypt 就行了,这样重新定义的 JSEncrypt 就是一个全局变量,再次运行就不会报错了