2022年4月30日更新:
有两个个开源的项目可以看看
https://github.com/CC11001100/crawler-js-hook-framework-public
https://github.com/LoseNine/Restore-JS
从公众号妄为写代码
的作者那学来的,由公众号菜鸟学Python编程
整理。我直接抄过来,顺便解释一下。
首先需要个油猴插件:
- fq之后,在谷歌浏览器商店就能搜到,油猴的英文名:
Tampermonkey
, - 国内网络的话,链接:https://pan.baidu.com/s/15ouGX7WVQ6lZxnfrcrlK6w
提取码:4xqs- 离线安装自己去搜怎么装。如果装失败了,就把Tampermonkey_v4.5.crx的后缀crx改为rar,然后解压,然后找到下图
加载已解压的扩展程序
选中刚才解压的文件夹就好了。
- 离线安装自己去搜怎么装。如果装失败了,就把Tampermonkey_v4.5.crx的后缀crx改为rar,然后解压,然后找到下图
脚本
脚本内的注释不要删,尤其是@run-at document-start
先上脚本再解释。
// ==UserScript==
// @name Hook global
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author 悦来客栈的老板+妄为写代码+萌木盖
// @include *
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
//全局变量 监控
var t = window._t;
var window_flag = '_t';
var window_value = window[window_flag];
Object.defineProperty(window, window_flag, {
get: function() {
console.log('Getting window._t',window_value);
return t;
},
set: function(val) {
console.log('Setting window._t', val);
debugger;
t = val;
return t;
}
});
})();
- hook的关键代码:
@run-at document-start
意思为脚本将尽快注入。
- 还一个主要函数是
defineProperty
他监控函数值,set该值和get该值都会调用这里面的两个方法。 -
此脚本是针对一号店的登录页面,其他网站需根据想监控的数据改对象名和变量值(看图)
- 改完脚本在油猴插件添加新脚本,并启用就好。
开始用:
新打开一个标签页,按下F12,并在地址栏输入:
开始调试
再之后的调试就不讲了。就是正常的调试流程。如果有人感兴趣,去公众号搜
菜鸟学Python编程
里的爬虫入门之查找JS入口篇(七) --- 补充
更新:
服务器返回的加密的字符串,解密出来也是字符串。但是字符串取值不那么方便,因此加密前先用 JSON.strify字符化,然后再用 JSON.parse还原。所有遇到返回乱码可hookJSON.parse
var rparse = JSON.parse;
JSON.parse = function(a) {
console.log("Detect Json.parse", a);
return rparse(a);
}
其他脚本:
摘自https://mp.weixin.qq.com/s/CQlT4GJ2gVnzOww0rE5NRA
笔记一: 蔡老板的入口文章系列 其中一个需要自己完成的hook脚本。
// ==UserScript==
// @name HOOK 遍历
// @namespace http://tampermonkey.net/
// @version 0.1
// @description day day up
// @author FY
// @include *
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
!function () {
'use strict';
var source = ['DeCode','EnCode','decodeData','base64decode','md5','decode','btoa','MD5','RSA','AES','CryptoJS','encrypt','strdecode',"encode",'decodeURIComponent','_t','JSON.stringify','String.fromCharCode','fromCharCode'];
console.log("开始测试是否有解密函数");
let realCtx, realName;
function getRealCtx(ctx, funcName) {
let parts = funcName.split(".");
let realCtx = ctx;
for(let i = 0; i < parts.length - 1; i++) {
realCtx = realCtx[parts[i]];
}
return realCtx;
}
function getRealName(funcName) {
let parts = funcName.split(".");
return parts[parts.length - 1];
}
function test(ctx) {
for(let i = 0; i < source.length; i++) {
let f = source[i];
let realCtx = getRealCtx(ctx, f);
let realName = getRealName(f);
let chars = realCtx[realName];
if (chars != undefined){
console.log("发现可疑函数:", f);
console.log(chars);
console.log("---------------------");
}else{
console.log("未发现:", f);
}
}
}
test(window);
}();
})();
开启脚本后找一个网站测试,打开控制台刷新网页后打印如下内容。
我们可以看到,脚本检测出了许多疑似加密函数的内容,我们可以把之前遇到过的类似的需要解密的函数写进一个数组里,然后依次查询是否有这样的函数。
笔记二:上一个脚本只是检测是否有加密函数,接下来完善一下,打印出加密函数的返回值,也就是直接hook到结果。
// ==UserScript==
// @name HOOK ALL end
// @namespace http://tampermonkey.net/
// @version 0.1
// @description day day up!
// @author FY
// @include *
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
var source = ['DeCode','EnCode','decodeData','base64decode','md5','decode','btoa','MD5','RSA','AES','CryptoJS','encrypt','strdecode',"encode",'decodeURIComponent','_t','JSON.stringify','String.fromCharCode','fromCharCode'];
console.log("开始测试是否有解密函数");
let realCtx, realName;
function getRealCtx(ctx, funcName) {
let parts = funcName.split(".");
let realCtx = ctx;
for(let i = 0; i < parts.length - 1; i++) {
realCtx = realCtx[parts[i]];
}
return realCtx;
}
function getRealName(funcName) {
let parts = funcName.split(".");
return parts[parts.length - 1];
}
function hook(ctx, funcName, level, originFunc) {
ctx[funcName] = function(a){
console.log("level:" + level + " function:" + funcName,a);
console.log(originFunc.toString());
console.log(originFunc.toString);
debugger;
return originFunc(a);
};
}
function test(ctx, level) {
for(let i = 0; i < source.length; i++) {
let f = source[i];
let realCtx = getRealCtx(ctx, f);
let realName = getRealName(f);
let chars = realCtx[realName];
hook(realCtx, realName, level, chars);
}
}
test(window, 1);
})();
也是循环遍历 然后打印出函数的定义和返回值。
笔记三 : 需要更直观的看出加密函数内部调用的函数名。
// ==UserScript==
// @name HOOK 二层函数名 end
// @namespace http://tampermonkey.net/
// @version 0.1
// @description day day up!
// @author FY
// @include *
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
var source = ['decodeData','base64decode','md5','decode','btoa','MD5','RSA','AES','CryptoJS','encrypt','strdecode',"encode",'decodeURIComponent','_t','JSON.stringify','String.fromCharCode','fromCharCode'];
console.log("开始测试是否有解密函数");
let realCtx, realName;
function getRealCtx(ctx, funcName) {
let parts = funcName.split(".");
let realCtx = ctx;
for(let i = 0; i < parts.length - 1; i++) {
realCtx = realCtx[parts[i]];
}
return realCtx;
}
function getRealName(funcName) {
let parts = funcName.split(".");
return parts[parts.length - 1];
}
function hook(ctx, funcName, level, originFunc) {
ctx[funcName] = function(a){
console.log("level:" + level + " function:" + funcName,a);
let regexp = / [\S]*\(.*\)\;/g;
let match = originFunc.toString().match(regexp)
console.log(match);
debugger;
return originFunc(a);
};
}
function test(ctx, level) {
for(let i = 0; i < source.length; i++) {
let f = source[i];
let realCtx = getRealCtx(ctx, f);
let realName = getRealName(f);
let chars = realCtx[realName];
hook(realCtx, realName, level, chars);
}
}
test(window, 1);
})();
可以看出就是多写了一个正则,匹配出加密函数内部调用的函数名。