浏览器加载页面然后执行脚本,这里是因为存在浏览器环境,能够加载DOM JS这些才能够执行脚本。jsdom可以做浏览器环境的一个替代,使用nodejs jsdom加载DOM JS后,再执行脚本也是可以的,当然jsdom也是可以被检测的。
var express = require('express');
var router = express.Router();
const jsdom = require('jsdom');
const {JSDOM} = jsdom;
const { Script } = require("vm");
var http = require('http');
var url = require('url');
var mysleep = function(time) {
dellsfl = false;
var startTime = new Date().getTime() + parseInt(time, 10);
while(new Date().getTime() < startTime) {
}
dellsfl = true;
};
var mmm = 10;
//jsdom配置
var options = {
url: "https://xxx.xxx.chinatax.gov.cn:8443/",
referrer: "https://dppt.xxx.chinatax.gov.cn:8443/",
contentType: "text/html",
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
includeNodeLocations: false, //保留由HTML解析器生成的位置信息,允许您使用nodeLocation()方法(如下所述)检索它。
runScripts: "dangerously",//在页面内启用脚本
beforeParse(window) {//在解析任何HTML并使用节点填充文档之前 这里可以改一些环境参数
window.document.childNodes.length === 0;
window.someCoolAPI = () => { /* ... */ };
window.alert = function alert(){};
window.navigation = {};
window.document.cookie = '';
window.innerWidth = 1920;
window['UAParser'] = function(){};
var UAParser = function(){};
var XMLHttpRequest = window.XMLHttpRequest;
XMLHttpRequest.prototype.open = function(){
//debugger;
};
XMLHttpRequest.prototype.send = function(){
//debugger;
};
XMLHttpRequest.prototype.setRequestHeader = function(a,b){
//debugger;
};
window.XMLHttpRequest = XMLHttpRequest;
var navigator = window.navigator;
window.navigator = navigator;
var document = window.document;
var location = window.location;
document.createElement = function createElement(tagName){
var tagname = tagName.toLowerCase() + "";
if(tagname === 'canvas'){
return {
'getContext':function(b){
if(b === '2d'){
return {
'rect':function(a,b,c,d){
},
'isPointInPath':function(a,b,c){
if(a == b){
return false;
}
return true;
},
'textBaseline':'alphabetic',
'fillStyle':'#000000',
'fillRect':function(a,b,c,d){
},
'font':'10px sans-serif',
'fillText':function(a,b,c){
},
'globalCompositeOperation':'source-over',
'beginPath':function(){
},
'arc':function(a,b,c,d,e,f){
},
'closePath':function(){
},
'fill':function(a){
},
};
}
if(b === 'webgl'){
return {
'getParameter':function(m){
if(m == 37445){
return 'Google Inc. (NVIDIA)';
}
if(m == 37446){
return 'ANGLE (NVIDIA, NVIDIA GeForce RTX 2060 Direct3D11 vs_5_0 ps_5_0, D3D11)';
}
},
'getExtension':function(g){
if(g === 'WEBGL_debug_renderer_info'){
return {
'UNMASKED_VENDOR_WEBGL':37445,
'UNMASKED_RENDERER_WEBGL':37446
};
}
},
'getSupportedExtensions':function(){
return ["ANGLE_instanced_arrays","EXT_blend_minmax","EXT_color_buffer_half_float","EXT_disjoint_timer_query","EXT_float_blend","EXT_frag_depth","EXT_shader_texture_lod","EXT_texture_compression_bptc","EXT_texture_compression_rgtc","EXT_texture_filter_anisotropic","EXT_sRGB","KHR_parallel_shader_compile","OES_element_index_uint","OES_fbo_render_mipmap","OES_standard_derivatives","OES_texture_float","OES_texture_float_linear","OES_texture_half_float","OES_texture_half_float_linear","OES_vertex_array_object","WEBGL_color_buffer_float","WEBGL_compressed_texture_s3tc","WEBGL_compressed_texture_s3tc_srgb","WEBGL_debug_renderer_info","WEBGL_debug_shaders","WEBGL_depth_texture","WEBGL_draw_buffers","WEBGL_lose_context","WEBGL_multi_draw"];
}
};
}
if(b === 'experimental-webgl'){
return {
};
}
},
'style':{
'display':''
},
'toDataURL':function(){//canvas的指纹,暂时写死 test
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfQAAADICAYAAAAeGRPoAAAAAXNSR0IArs4c6QAACHNJREFUeF7t1QENAAAIwzDwbxodLMXBe5LvOAIECBAgQOC9wL5PIAABAgQIECAwBt0TECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBAy6HyBAgAABAgEBgx4oUQQCBAgQIGDQ/QABAgQIEAgIGPRAiSIQIECAAAGD7gcIECBAgEBAwKAHShSBAAECBAgYdD9AgAABAgQCAgY9UKIIBAgQIEDAoPsBAgQIECAQEDDogRJFIECAAAECBt0PECBAgACBgIBBD5QoAgECBAgQMOh+gAABAgQIBAQMeqBEEQgQIECAgEH3AwQIECBAICBg0AMlikCAAAECBA71UQDJ6RV1xQAAAABJRU5ErkJggg==';
}
};
}
}
},
cookieJar: new jsdom.CookieJar()
};
//中文文档 https://segmentfault.com/a/1190000014844043
//cnpm install canvas --save 安装包 否则报错
router.post('/getSt', function(request, response, next) {
var html = request.body.html;
//解码
var b = new Buffer(html, 'base64');
html = b.toString();
//html = decodeURI(html);
var result = {};
result.code = '0';
result.message = '处理成功';
if(html === '' || html == null || html == undefined){
result.code = '-1';
result.message = '参数html为空';
response.writeHead(200, {'Content-Type': 'application/json'});
response.end(JSON.stringify(result));
return;
}
try {
//获取函数 ]();}}i(
var index1 = html.indexOf('}}}i(')+'}}}i('.length;
var index2 = html.indexOf('!function(b,a)');
var functionName = html.substring(index1,index2-2);
html = html.substring(html.indexOf('/body'));
var myscript = html.substring(html.indexOf('<script>')+'<script>'.length,html.indexOf('</script>'));
let dom = new JSDOM(
`<html><body></body></html>`,
// html,
options
);
//console.log(dom.window.document.cookie);
// const dom = new JSDOM(``, { runScripts: "outside-only" });
var eval = dom.window.eval;
// 匿名的立即执行函数,因访问了全局变量a,所以也是一个闭包
!(function test (ee){
//mmm = 100;
ee(myscript);//这里多次执行导致内存未释放
var st = ee('window.'+functionName);
result.data = st;
console.log('st res',st);
})(eval);
dom.window.location.href = 'https://dppt.xxx.chinatax.gov.cn:8443/';
mysleep(200);
dom.window.close();
dom = null;
console.log('dom',dom);
response.writeHead(200, {'Content-Type': 'application/json'});
response.end(JSON.stringify(result));
} catch (error) {
console.log(error);
var result = {};
result.code = '-1';
result.message = error.message != undefined?error.message:error.data;
response.writeHead(200, {'Content-Type': 'application/json'});
response.end(JSON.stringify(result));
}finally{
// dom = new JSDOM;
dom = null;
// dom = new JSDOM(
// `<html><body></body></html>`,
// options
// );
}
});
module.exports = router;