浅笑博客
日日行,不怕千万里;时时学,不怕千万卷
浅笑博客
域名被劫持显示“请点击继续访问”客户端和python请求解决方案
域名被劫持显示“请点击继续访问”客户端和python请求解决方案

最近,无邪官网由于更换了域名和主机,经常访问时出现“请点击继续访问的情况”,导致目前的采集发帖失效,同时,给用户带来了较不好的体验。

http://blog.qianxiao.fun/wp-content/uploads/2020/12/2020-12-18-21-28-47-的屏幕截图-1024x576.png

于是,试图去解决。首先研究了好久,这个问题是怎么出现的,网站程序没有设置这一步啊,通过查阅资料发现,应该为使用了高仿主机导致的域名劫持。

通过反复查看网页源码发现,它这个代码是随机的,每次点击执行的是不同的函数,而且点击的内容也是随机变化的,有时a标签,有时p标签,有时input标签等等,而且事件有的是onclick,有时onmouseup等等。

如:
<html><body><br><br><br><center><h3><a href="#" onmouseover="fj(142)">&#x8BF7;&#x70B9;&#x51FB;&#x7EE7;&#x7EED;&#x8BBF;&#x95EE;</a></h3></center><script>var hj="",ij="",lj,jj=new Array(),kj;function fj(gj){for(lj=0;lj<kj.length;lj++)jj[lj]=kj.charCodeAt(lj);for(lj=1;lj<=46;lj++){jj[lj]=(((jj[lj]+jj[lj+1])&0xff)>>2)|((((jj[lj]+jj[lj+1])&0xff)<<6)&0xff);}lj=3;while(true){if(lj>45)break;jj[lj]=(((jj[lj]+194)&0xff)+94)&0xff;jj[lj]=(jj[lj]+0)&0xff;lj++;}lj="lj=2;do{jj[lj]=(((((jj[lj]<<7)&0xff)|(jj[lj]>>1))-124)&0xff)^jj[49];}while(++lj<=47);";eval(lj);kj="";for(lj=1;lj<jj.length-1;lj++)if(lj%5)kj+=String.fromCharCode(jj[lj]^gj);lj=eval;lj(kj);}kj="\xf9:\xadwh\x270\xa7mp_\xdd\xfay\xea\x22{,\xab4\x12/\x80?v\x07\xda\xfb[L\xab@\x97h_Q\xf5)\xdd)\x9d\xc6\xc94I-\x09\xe4\xef";</script><script>var u=2;for(;u==1;u++);</script></body></html>

再如:
<html>
 <head></head>
 <body>
  <br />
  <br />
  <br />
  <center>
   <h3><em style="cursor:pointer;text-decoration:underline">请点击继续访问</em></h3>
  </center>
  <script>var qj="",rj="",uj,sj=new Array(),tj;function oj(pj){for(uj=0;uj<tj.length;uj++)sj[uj]=tj.charCodeAt(uj);uj=44;while(uj>=2){sj[uj]=((((~sj[uj])&0xff)<<3)&0xff)|(((~sj[uj])&0xff)>>5);sj[uj]=sj[uj]^sj[45];uj--;}uj="uj=3;while(uj<=44){sj[uj]=(sj[uj]+sj[uj+1])&0xff;uj++;}";eval(uj);uj=1;for(;;){if(uj>43)break;sj[uj]=(((((-sj[uj])&0xff)>>5)|((((-sj[uj])&0xff)<<3)&0xff))>>6)|((((((-sj[uj])&0xff)>>5)|((((-sj[uj])&0xff)<<3)&0xff))<<2)&0xff);uj++;}tj="";for(uj=1;uj<sj.length-1;uj++)if(uj%8)tj+=String.fromCharCode(sj[uj]^pj);eval("uj=eval");uj(tj);}tj="I\x9f\xb7\x9c~\x86u\x9e\xbf?\xd92\xc5<\xd09\xd2\xd9=\x08\xf9\x11>\x183\xb3\x8bf\x81i\x82d\x91\xdfn\xc4i\xc4=\xc3g7\x03,\xda-";document.getElementsByTagName("em")[0].onmouseover=function(){oj(91);};</script>
  <script>var u=2;for(;u==1;u++);</script>
 </body>
</html>
等等

其逻辑呢,大概就是返回一段js函数和一句函数调用(点击事件),这写都是随机的。然后js调用后经过一系列蛇皮操作运算,最终得到一句代码,eval让js执行,从而使得页面跳转。

var ct="",dt="",au,et=new Array(),ft;function at(bt){for(au=0;au<ft.length;au++)et[au]=ft.charCodeAt(au);au=42;do{if(au<1)break;et[au]=(et[au]+154)&0xff;et[au]=(((et[au]^214)<<5)&0xff)|((et[au]^214)>>3);au--;}while(true);au="au=1;do{et[au]=(et[au]>>3)|((et[au]<<5)&0xff);et[au]=(((et[au]+135)&0xff)-73)&0xff;}while(++au<=44);";eval(au);au=43;while(au>=4){et[au]=((et[au]-et[au-1])&0xff)^15;au--;}ft="";for(au=1;au<et.length-1;au++)if(au%8)ft+=String.fromCharCode(et[au]^bt);eval("au=eval");au(ft);}ft="\x1aY\xdb\x1bfD\x0f\x1c\xa5\xf3\xc0\x8e\xcdeuC#\xf0:\x08\xa3@^\xff\\\xf9F \xf0\xc1\xbb\x09~\xc8\xb3\xfbcq\xed\x07\x9d{X\xf2\x9c\x9a";document.getElementsByTagName("strong")[0].onclick=function(){at(165);};

格式化后:
var ct="",dt="",au,et=new Array(),ft;
function at(bt){
 for(au=0;au<ft.length;au++)
  et[au]=ft.charCodeAt(au);
 au=42;
 do{
  if(au<1)
   break;
  et[au]=(et[au]+154)&0xff;
  et[au]=(((et[au]^214)<<5)&0xff)|((et[au]^214)>>3);
  au--;
 }while(true);
 au="au=1;do{et[au]=(et[au]>>3)|((et[au]<<5)&0xff);et[au]=(((et[au]+135)&0xff)-73)&0xff;}while(++au<=44);";
 eval(au);
 au=43;
 while(au>=4){
  et[au]=((et[au]-et[au-1])&0xff)^15;au--;
 }
 ft="";
 for(au=1;au<et.length-1;au++)
  if(au%8)
   ft+=String.fromCharCode(et[au]^bt);
 eval("au=eval");
 au(ft);
}
ft="\x1aY\xdb\x1bfD\x0f\x1c\xa5\xf3\xc0\x8e\xcdeuC#\xf0:\x08\xa3@^\xff\\\xf9F \xf0\xc1\xbb\x09~\xc8\xb3\xfbcq\xed\x07\x9d{X\xf2\x9c\x9a";
document.getElementsByTagName("strong")[0].onclick=function(){at(165);};

转换eval执行语句,代码整理:
var ct="",dt="",au,et=new Array(),ft="\x1aY\xdb\x1bfD\x0f\x1c\xa5\xf3\xc0\x8e\xcdeuC#\xf0:\x08\xa3@^\xff\\\xf9F \xf0\xc1\xbb\x09~\xc8\xb3\xfbcq\xed\x07\x9d{X\xf2\x9c\x9a";
function at(bt){
 for(au=0;au<ft.length;au++)
  et[au]=ft.charCodeAt(au);
 au=42;
 do{
  if(au<1)
   break;
  et[au]=(et[au]+154)&0xff;
  et[au]=(((et[au]^214)<<5)&0xff)|((et[au]^214)>>3);
  au--;
 }while(true);
 au=1;
 do{
  et[au]=(et[au]>>3)|((et[au]<<5)&0xff);
  et[au]=(((et[au]+135)&0xff)-73)&0xff;
 }while(++au<=44);
 au=43;
 while(au>=4){
  et[au]=((et[au]-et[au-1])&0xff)^15;au--;
 }
 ft="";
 for(au=1;au<et.length-1;au++)
  if(au%8)
   ft+=String.fromCharCode(et[au]^bt);
 //eval(ft);//最终执行ft代码字符串
 console.log(ft);
}

document.getElementsByTagName("strong")[0].onclick=function(){at(165);};

首先解决App端体验问题,由于论坛App由fa开发,直接在网页加载完毕后注入js使其自动帮我们点击即可,关键是注入的js怎么找到那句关键调用是关键。虽然其每次返回的内容极其随机,但是通过大量测试发现,总体上还是有几点关键的,比如文字显示都是“请点击继续访问”,设置的关键函数调用要么在html中直接通过属性设置,要么在js中通过document找到控件后设置事件等。一步一步来,慢慢实现,通过关键字符判断,依次测试解决不同情况,最终代码如下。

加载Js([[
if(document.body.innerText.indexOf('请点击继续访问')!=-1){
  var scripttext = '';
  for(var i=0;i<document.scripts.length;i++){
    scripttext += document.scripts[i].innerText;
  }
  if(scripttext.indexOf('=function(){')!=-1){
    var a = scripttext.substr(scripttext.indexOf('=function(){')+12);
    var b = a.substr(0,a.indexOf(')')+1);
    eval(b);
  }else if(document.body.innerHTML.indexOf(')">')!=-1){
    var a = document.body.innerHTML.indexOf(')">');
    var b = document.body.innerHTML.substr(0,a+1);
    var c = b.substr(b.lastIndexOf('"')+1);
    eval(c);
  }else{
    alert('未知情况1,请联系浅笑\n'+document.body.innerHTML);
  }

}else if(document.querySelector("*[value*='请点击继续访问']")!=null){
  var scripttext = '';
  for(var i=0;i<document.scripts.length;i++){
    scripttext += document.scripts[i].innerText;
  }
  if(scripttext.indexOf('=function(){')!=-1){
    var a = scripttext.substr(scripttext.indexOf('=function(){')+12);
    var b = a.substr(0,a.indexOf(')')+1);
    eval(b);
  }else{
    var a = document.body.innerHTML.indexOf(')"');
    if(a!=-1){
      var b = document.body.innerHTML.substr(0,a+1);
      var c = b.substr(b.lastIndexOf('"')+1);
      eval(c);
    }else{
      alert('未知情况2,请联系浅笑\n'+document.body.innerHTML);
    }
  }
}
]])

注意:eval函数是js中用来js执行一段字符串代码的,非常有用。

然后就是python的采集发帖的解决,由于js模拟请求,这里并没有什么关键cookie什么的,python也不能在请求一个地址时进行js注入执行,那么就要更深入的分析了,分析通过调用那句关键函数,看看最后浏览器是干了什么。

将关键js粘贴进浏览器控制台(这里要注意要手动将转换所有eval函数调用的代码,否则测试执行抱错,同时要将最终的eval调用取消掉,打印出最终eval调用的代码字符串),然后通过调用发现,最终调用的代码字符串为window.open(……)或window.location=……的语句。

var ct="",dt="",au,et=new Array(),ft="\x1aY\xdb\x1bfD\x0f\x1c\xa5\xf3\xc0\x8e\xcdeuC#\xf0:\x08\xa3@^\xff\\\xf9F \xf0\xc1\xbb\x09~\xc8\xb3\xfbcq\xed\x07\x9d{X\xf2\x9c\x9a";
function at(bt){
 for(au=0;au<ft.length;au++)
  et[au]=ft.charCodeAt(au);
 au=42;
 do{
  if(au<1)
   break;
  et[au]=(et[au]+154)&0xff;
  et[au]=(((et[au]^214)<<5)&0xff)|((et[au]^214)>>3);
  au--;
 }while(true);
 au=1;
 do{
  et[au]=(et[au]>>3)|((et[au]<<5)&0xff);
  et[au]=(((et[au]+135)&0xff)-73)&0xff;
 }while(++au<=44);
 au=43;
 while(au>=4){
  et[au]=((et[au]-et[au-1])&0xff)^15;au--;
 }
 ft="";
 for(au=1;au<et.length-1;au++)
  if(au%8)
   ft+=String.fromCharCode(et[au]^bt);
 //eval(ft);//最终执行ft代码字符串
 console.log(ft);
}
at(165);
http://blog.qianxiao.fun/wp-content/uploads/2020/12/2020-12-18_21-47-1024x508.png

于是就有了这么一个思路,首先获取关键js,想办法转换成python的execjs可以编译运行的js(主要如,删除一些document等的语句),同时需要删除关键函数的最后一句eval函数调用,并想办法加入return那个代码字符串变量的语句,然后想办法获取出关键的函数名和参数,用以execjs调用时传递。

最终实现的代码如下:

r = requests.post(url,data=postbody,headers=headers)
res = HTMLParser().unescape(r.text)
#print(res)
if "请点击继续访问" in res:
	script = re.findall("<script>(.*?)<\/script>",res)[0]
	#print(script)
	func = ''
	#如果关键函数在script标签内
	if script.find('document')!=-1:
		func = script[script.find('=function(){')+12:]
		func = func[0:func.find(';')]#通过关键字符位置截取即可获取函数调用
		script = script[0:script.find('document')]#把js代码中给控件设置事件为关键函数调用的那句代码截去 否则execjs无法调用
	else:#关键函数在html某个标签的属性内
		func = res[0:res.find(')">')+1]
		func = func[func.rfind('"')+1:]#通过关键字符位置截取即可获取函数调用
	funcname = func[0:func.find('(')]#截取获取关键函数名
	funcparm = func[func.find('(')+1:func.find(')')]#截取获取函数参数
	#print(script)
	a = script[0:script.rfind(';}')]#截取到关键函数结束,以便删除最后一句代码并添加return语句
	stack = []
	k = len(a)
	for i in reversed(range(0, len(a))):
		if a[i]==';' and len(stack)==0:
			k = i
			break
		if a[i]==')':
			stack.append(')')
		elif a[i]=='(':
			stack.pop()
		elif a[i]=='"':
			if len(stack)==0:
				stack.append('"')
			else:
				t = stack.pop()
				if t!='"':
					stack.append(t)
					stack.append('"')
			
	#以上代码用借助栈找到倒数第二句代码结束的位置
	a = a[0:k+1]#截取即可截去最后一句eval代码
	b = script[script.rfind(';}')+2:]
	script = a+'return '+b[0:b.find('=')]+';}'+b#添加return语句并拼接成新的python execjs可编译运行的js代码
	#print(func)
	#print(script)
	#print(funcname)
	#print(funcparm)
	ctx = execjs.compile(script+"function eevvaall(a){return eval(a);}");#execjs编译js代码 同时加入eval调用函数以便最终一步的字符串拼接
	res = ctx.call(funcname,funcparm);
	if res[len(res)-1]==')':#一种情况是window.open()
	    res = res[res.find('(')+1:res.rfind(',')]#截取跳转的网站
	else:#另一种情况是window.location=
	    res = res[res.find('=')+1:]#截取跳转的网站
	res = ctx.call('eevvaall',res);#由于跳转的网站里有的还是js变量拼接而成的,再次调用js eval函数转为最终结果
	print(res)
	url = "http://"+wuxiehost+res
	#拼接成最终重定向的地址并重新访问
	r = requests.post(url,data=postbody,headers=headers)

至此,问题解决,虽然没有根本上解决问题,因为使用的是高仿主机,暂时先这么解决。关于本文,如有更好的解决办法或关于本文的不足,欢迎评论交流或不吝指正,谢谢。

没有标签
首页      未分类      域名被劫持显示“请点击继续访问”客户端和python请求解决方案

发表评论

textsms
account_circle
email

浅笑博客

域名被劫持显示“请点击继续访问”客户端和python请求解决方案
最近,无邪官网由于更换了域名和主机,经常访问时出现“请点击继续访问的情况”,导致目前的采集发帖失效,同时,给用户带来了较不好的体验。 于是,试图去解决。首先研究了好久,这…
扫描二维码继续阅读
2020-12-18