在Firefox里用光大网银

// WIP,光大网银很多javascript代码貌似在ff下就有问题,这里只是说ActiveX的问题

光大网银用了ActiveX,于是看上去很难在别的系统/浏览器下用。

但其实就结果来说,那个ActiveX控件没啥用……

页面上有三个<object>,其中一个啥sign貌似啥都没干,另外俩负责加密密码/提交。

提交登录表单的时候,多数域都是空的。根据观察,控件就填了一个域:Password

为了观察那个控件都调了啥加密函数,找了个很好用的工具,叫WinAPIOverride。粗粗一看调了若干Crypt* API,于是缩小范围到各个Crypt*函数上。分析记录在 http://wiki.henryhu.net/wiki/CEB

最后发现这个控件很匮乏,在用公钥加密了密码之后(公钥在JS里……),它蛋疼的生成了一个随机数加密了一下,之后有解密了一把,最后完全没用…… 而那个Password域,内容其实就是密码加密结果反过来之后base64一把……

分析的时候有个地方很奇怪。看上去CryptEncrypt()的输入每次都一样,但是结果每次不同…… 后来自己写了个程序试试发现的确每次不同…… 再次看见网上说,加密时候会随机pad到block长度,才理解……

接下来嘛,写个Greasemonkey脚本来帮助登录。第一步就是把那几个控件替换成我们的对象。替换完之后,可以登录过第一步了,之后手机短信验证还是不成。看console里有个错说HiddenSubmitArea不存在,于是插入一个进去…… 这货找遍各个地方都没找到,貌似也没啥用。

这样就可以过短信验证了…… 进去之后貌似还是有一些js错误,慢慢来…… 反正可以登录了。

作为库调用跟踪工具,WinAPIOverride还是挺好用的,功能上类似于ltrace,还有调试器的一部分功能,可以在库函数调用前后断下来,观察内存/寄存器等。IEinspector作为分析IE数据包的工具也不错,看上去比HttpFox功能更多…… 只是要收钱。

Greasemonkey代码:

// ==UserScript==
// @name        cebbank
// @namespace   net.henryhu
// @description ceb bank
// @include     https://www.cebbank.com/per/perlogin*
// @include     https://www.cebbank.com/per/prePerlogin.do?_locale=zh_CN
// @version     1
// @grant       none
// ==/UserScript==
 
function reset() {
    console.log('reset');
}
 
function publicKeyBlob(blob) {
    console.log('blob: ' + blob);
}
 
function commit(field) {
    console.log("commit: " + field);
}
 
function submit(formName) {
    console.log('submit: ' + formName);
    form = document.forms[formName];
    form.Password.value = '';
    form.submit();
}
 
function HiddenSubmitArea(foo) {
    console.log('HiddenSubmitArea: ' + foo);
}
 
oldpc = document.getElementById('powercommit');
newpc = document.createElement('div');
newpc.id = 'powercommit';
newpc.reset = reset;
newpc.submit = submit;
 
oldpp = document.getElementById('powerpassword');
newpp = document.createElement('input');
newpp.id = 'powerpassword';
newpp.type = 'password';
newpp.publicKeyBlob = publicKeyBlob;
newpp.commit = commit;
 
counter = document.createElement('input');
counter.value = 1;
counter.id = 'counter';
document.body.appendChild(counter);
 
if (oldpc) {
    oldpc.parentNode.replaceChild(newpc, oldpc);
    console.log("replaced pc");
}
 
if (oldpp) {
    oldpp.parentNode.replaceChild(newpp, oldpp);
    console.log("replaced pp");
}
 
window.HiddenSubmitArea = HiddenSubmitArea;