文章目录
- 1. 写在前面
- 2. 抓包分析
- 3. 定位分析
- 4. 构建webpack
1. 写在前面
回过头看,已慢慢将JS爬虫逆向类型的文章从0建设到了1,文章所有案例真实且内容有效,加密类型丰富。收获了很多粉丝的关注与支持,非常感谢大家!
往后的时间内,将着手准备在空余时间内开始写关于分布式采集平台在开源情报、网络舆情中的建设技术文章,将自己多年的经验与储备分享出来,这也是一直以来想写的文章题材!
分析目标:
aHR0cHM6Ly93d3cuZ205OS5jb20v
2. 抓包分析
本次目标登录参数加密,老规矩构造用户名密码尝试登录抓包分析一下:
可以看到提交登陆请求重password是我们需要分析的参数,ckcode是验证码,其他都无关紧要
3. 定位分析
尝试使用全局搜索看看password可不可追溯一下,发现common.js、home.min.js两个文件可能大概率有加密操作,代码也不多。先翻翻第一个文件,找到了很显眼的函数,如下所示:
从common.js文件中找到关键代码如下所示:
function Rsa(){
if(typeof JSEncrypt === 'undefined') return;
this.jsencrypt = new JSEncrypt();
// 设置公钥
this.jsencrypt.setPublicKey("-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB-----END PUBLIC KEY-----");
}
/**
* rsa加密
* @param {string} [str] [待加密字符串]
* @return {string} [经过rsa加密的字符串]
*/
Rsa.prototype.encode = function(str,confuse){
var enStr = confuse ? confuse + "|" + str : str;
return encodeURIComponent(this.jsencrypt.encrypt(enStr)); // rsa+uri编码
}
var rsa = new Rsa();
// 针对login接口的登录函数(部分官网在调用)
function lessLogin( params ){
var timestamp = new Date().getTime();
var uname = params['uname'];
var password = rsa.encode(params['password'],timestamp);
var forward = params['forward'];
var remember = params['remember'];
$.ajax({
url : '//passport.gm99.com/login/login',
type : 'get',
data:{ 'encrypt':1, 'uname': uname, 'password': password, 'forward': forward, 'remember': remember },
xhrFields: {
withCredentials: true
},
jsonp: 'callback',
async : true,
dataType : 'jsonp',
success : function(data){
$('head').append(data);
}
});
}
可以看到上面的代码是一个封装了RSA加密函数的函数,RSA()其实是对RSA加密函数进行了再次封装,然后网站调用这个函数来发送登录表单进行验证,它并不是真正的加密函数
在home.min.js文件中找到了如下一行代码:
o = a.encode(t.password, s)
断点重新提交登录,可以发现t.password就是我提交的明文密码。o则是加密后的密文
home.min.js文件的代码一打开就能开到,典型的webpack方式加载模块!
划重点: webpack不是加密代码,而是加载加密模块的方法!结构特征()([])、()({})
结构区别::()([])传递的参数是数组,()({})传递的参数是对象
4. 构建webpack
先不用去管加密代码啥的,我们先构建webpack的结构。这里可以直接用它自己的自执行函数:
!function(t) {
var i = {};
function e(s) {
if (i[s])
return i[s].exports;
var n = i[s] = {
exports: {},
id: s,
loaded: !1
};
return t[s].call(n.exports, n, n.exports, e),
n.loaded = !0,
n.exports
}
}({/*这里是加载模块*/})
上面的代码我们可以在控制台内测试一下,看看如下是否通过:
接下来要做的就是找到加载模块,回到之前t.password那里。一共就两个JS文件,这个地方更像是加密的位置,所以我们分析断点。鼠标查看发现a.encode,直接点击跳转
定位到了如下代码块:
从上述代码分析可以提炼出两个关键点:
加密函数实例化:new r.JSEncrypt
公钥:setPublicKey
至于this.jsencrypt.encrypt(i)不像是实现加密的代码,看起来像是封装加密函数的模块
直接在这一行下断点再次登录,鼠标找到encrypt点击跳转
跳转到如下代码块:
上图所示的代码所在位置在4: function这个加载模块内:
var r = i(4)中的i函数对应加载器函数里面的t[s].call(n.exports, n, n.exports, e)的参数i,即i 等于e,而e就是加载器函数,所以4: function这个加载模块正是加密代码!
最终完整可用的webpack结构加密代码结构如下:
var _Encryp;
var navigator = {};
var window = this;
!function(t) {
var i = {};
function e(s) {
if (i[s])
return i[s].exports;
var n = i[s] = {
exports: {},
id: s,
loaded: !1
};
return t[s].call(n.exports, n, n.exports, e),
n.loaded = !0,
n.exports
}
_Encryp = e;
}({3: function模块, 4: function加密模块})
3: function模块, 4: function加密模块的代码自己扣一下填入上面即可!不会扣的有需要测试学习的也可以私我!
因为代码多达近3000行比较庞大!这里我就不再贴出来了,最终加密需要的参数上面断点信息也可以看到分别是密码、时间戳!如下所示为控制台测试效果:
好了,到这里又到了跟大家说再见的时候了。创作不易,帮忙点个赞再走吧。你的支持是我创作的动力,希望能带给大家更多优质的文章