宝塔木马查杀工具 5.1改进
木马查杀工具 5.1插件
目前已经总结了常见的木马脚本的特征,写了一套有效的识别方案。后续会继续加大样本库,收集最新的webshell。本代码已经彻底放弃了原有的插件核心功能。本插件的逻辑是宁可杀错也不能放过,所以凡是无法正常识别混淆过的代码就列为嫌疑对象。
缺点:
1.特征库太少,没有接入云查杀,变形的未知webshell没法精准识别
感谢:
1.感谢不知名hacker上传webshell,让我有机会优化查杀功能。
插件目录:
/www/server/panel/plugin/webshell_check
改进方案:
1.使用特征码和行为分析查杀
更新日志:
2024/5/22:
1.加入特诊查杀来扫描针对性webshell。
2.上传功能脚本也加入了查杀逻辑。
2024/5/20:
1.加入白名单添加功能。
2.优化查杀规则。
2024/3/7:
1.去除bt Api查杀引擎。
2.加入白名单。
3.加入自研Webshell引擎。
webshell_check_main.py改进
# coding: utf-8
# +-------------------------------------------------------------------
# | 宝塔Linux面板 x7
# +-------------------------------------------------------------------
# | Copyright (c) 2015-2017 宝塔软件(http://bt.cn) All rights reserved.
# +-------------------------------------------------------------------
# | Author: lkqiang<lkq@bt.cn>
# +-------------------------------------------------------------------
# | webshell 扫描插件
# +--------------------------------------------------------------------
import sys
if not '/www/server/panel/class/' in sys.path:
sys.path.insert(0, '/www/server/panel/class/')
import json, os, time, public, string, re, hashlib,requests,subprocess,panelTask
class webshell_check_main:
__count=0
__size="/www/server/panel/plugin/webshell_check/size.txt"
__shell="/www/server/panel/plugin/webshell_check/shell.txt"
__shella="/www/server/panel/plugin/webshell_check/log.txt"
__whitelist="/www/server/panel/plugin/webshell_check/whitelist.txt"
__user={}
def __init__(self):
try:
self.__user = json.loads(public.ReadFile('/www/server/panel/data/userInfo.json'))
except:
pass
'''
@name 获取目录下的所有php文件
@param path 文件目录
@return list
'''
def get_dir(self, path):
return_data = []
data2 = []
[[return_data.append(os.path.join(root, file)) for file in files] for root, dirs, files in os.walk(path)]
for i in return_data:
if str(i.lower())[-4:] == '.php':
data2.append(i)
return data2
'''
@name 读取文件内容
@param filename 文件路径
@return 文件内容
'''
def ReadFile(self,filename, mode='rb'):
import os
if not os.path.exists(filename): return False
try:
fp = open(filename, mode)
f_body = fp.read()
fp.close()
except Exception as ex:
if sys.version_info[0] != 2:
try:
fp = open(filename, mode, encoding="utf-8")
f_body = fp.read()
fp.close()
except Exception as ex2:
return False
else:
return False
return f_body
'''
@name 获取文件的md5值
@param filename 文件路径
@return MD5
'''
def read_file_md5(self, filename):
if os.path.exists(filename):
with open(filename, "rb") as f:
content = f.read()
m = hashlib.md5()
m.update(content)
return m.hexdigest()
else:
return False
'''
@name 上传到云端判断是否是webshell
@param filename 文件路径
@param url 云端URL
@return bool
'''
def webshellchop(self,filename,url):
try:
upload_url =url
size = os.path.getsize(filename)
if size > 1024000: return False
if len(self.__user)==0:return False
md5=self.read_file_md5(filename)
#shell_insert={'filename':filename,"type":"start","md5": md5}
#self.syslogcc(shell_insert)
file_type=self.Intelligence_engine(filename)
print('file_type',file_type)
#self.syslogcc(filename+" file_type:"+file_type)
if file_type!='':
# self.syslogcc(filename+'文件为木马')
print('%s文件为木马 md5:%s' % (filename,md5))
shell_insert={'filename':filename,"md5": md5,"file_type":file_type}
if os.path.exists(self.__shell):
public.WriteFile(self.__shell,json.dumps(shell_insert)+"\n","a+")
else:
public.WriteFile(self.__shell,json.dumps(shell_insert)+"\n")
print('%s可疑文件,建议手工检查' % filename)
return True
return False
upload_data = {'inputfile': self.ReadFile(filename), "md5":md5,"path":filename,"access_key": self.__user['access_key'], "uid": self.__user['uid'],"username":self.__user["username"]}
upload_res = requests.post(upload_url, upload_data, timeout=20).json()
self.syslogcc(upload_res)
if upload_res['msg']=='ok':
if (upload_res['data']['data']['level']==5):
print('%s文件为木马 hash:%s' % (filename,upload_res['data']['data']['hash']))
shell_insert={'filename':filename,"md5":upload_res['data']['data']['hash']}
if os.path.exists(self.__shell):
public.WriteFile(self.__shell,json.dumps(shell_insert)+"\n","a+")
else:
public.WriteFile(self.__shell,json.dumps(shell_insert)+"\n")
return True
else:
file_type=self.Intelligence_engine(filename)
if len(file_type)>=1:
self.syslogcc(filename+'文件为木马')
print('%s文件为木马 md5:%s' % (filename,md5))
shell_insert={'filename':filename,"md5": md5}
if os.path.exists(self.__shell):
public.WriteFile(self.__shell,json.dumps(shell_insert)+"\n","a+")
else:
public.WriteFile(self.__shell,json.dumps(shell_insert)+"\n")
print('%s可疑文件,建议手工检查' % filename)
return True
return False
return False
return False
except:
return False
'''
@name 上传到宝塔云端
@param filename 文件路径
@return bool
'''
def send_baota2(self, filename):
cloudUrl = 'http://www.bt.cn/api/panel/btwaf_submit'
pdata = {'codetxt': self.ReadFile(filename), 'md5': self.read_file_md5(filename), 'type': '0',
'host_ip': public.GetLocalIp(), 'size': os.path.getsize(filename)}
ret = public.httpPost(cloudUrl, pdata)
return True
'''
@name 启发查杀
@param filename 文件路径
@return string
'''
def Intelligence_engine(self,filename):
#self.syslogcc(filename)
php_code=public.ReadFile(filename)
md5_hash = self.read_file_md5(filename)
with open(self.__whitelist, 'r', encoding='utf-8') as file:
content = file.read()
if md5_hash in content:
return ''
if self.is_php_code_obfuscated(filename)==True:
#self.syslogcc(filename+" is_php_code_obfuscated")
suspect=4
rule="confuse,"
#规则精准命中
if '$_FILES' in php_code:
if '<form' in php_code:
return 'php.webshell.uploaded'
if self.check_for_variable_functionsB(php_code)==True:
if 'eval' in php_code:
return 'php.webshell.execute.'
pattern = r'<\?php\s+include\s*\(\s*[\'"](?P<filename>[^"\']*\.jpg)[\'"]\s*\)\s*;\s*\?>'
matches = re.findall(pattern, php_code)
for match in matches:
return 'php.webshell.jpg'
if 'eval' in php_code:
rule=rule+'eval(,'
suspect=suspect+2
elif 'call_user_func_array' in php_code:
rule=rule+'call_user_func_array,'
suspect=suspect+2
elif 'function_exists' in php_code:
rule=rule+'function_exists,'
suspect=suspect+2
elif 'call_user_func' in php_code:
rule=rule+'call_user_func,'
suspect=suspect+2
if 'phpjiami.com' in php_code:
rule=rule+'phpjiami.com,'
suspect=suspect+3
if 'PHPJiaMi.Com' in php_code:
rule=rule+'phpjiami.com,'
suspect=suspect+3
if 'namespace' in php_code:
rule=rule+'namespace'
suspect=suspect-2
if '\n' not in content:
rule=rule+'none\n'
suspect=suspect+2
if self.contains_complex_strings(php_code)==True:
rule=rule+'Encrypted Content'
#发现加密内容
suspect=suspect+2
if 'http://thinkphp.cn All rights reserved' in php_code:
rule=rule+'http://thinkphp.cn,'
suspect=suspect-2
if 'require_once' in php_code:
rule=rule+'require_once,'
suspect=suspect-3
if 'DOCTYPE html' in php_code:
rule=rule+'DOCTYPE html,'
suspect=suspect-2
if self.check_for_variable_functionsA(php_code):
suspect=suspect+2
rule=rule+' check_for_variable_functionsA,'
if self.check_for_variable_functionsB(php_code):
suspect=suspect+1
rule=rule+' check_for_variable_functionsB,'
#self.syslogcc("aaaaa223")
shell_insert={'filename':filename,"suspect":suspect,"rule":rule}
#self.syslogcc(shell_insert)
if suspect>=8:
shell_insert={'filename':filename,"suspect":suspect,"rule":rule}
#self.syslogcc(shell_insert)
return 'Intelligence engine01'
else:
return ''
return ''
def check_for_variable_functionsA(self,php_code):
patterns =[
# r"\b\$?\w+\s*\(\s*(.*?)\s*\)",# 查找所有匹配项
r"\$\w+\s*\(\s*\$\_\w+\['\w+'\]\s*\)\s*;",
]
for pattern in patterns:
matches = re.findall(pattern, php_code)
for match in matches:
return True
return False
def check_for_variable_functionsB(self,php_code):
patterns =[
# r"\b\$?\w+\s*\(\s*(.*?)\s*\)",# 查找所有匹配项
r'\$_(POST|GET|SESSION|REQUEST)|php://input',
]
for pattern in patterns:
matches = re.findall(pattern, php_code)
for match in matches:
return True
return False
'''
@name 判断php脚本是否包含敏感字
@param filename 文件名称
@return bool
'''
def check_string_in_list(self,filename, list_to_search):
string_to_check=public.ReadFile(filename)
for item in list_to_search:
if item in string_to_check:
return True
else:
return False
#判断是否存在人看不出的加密内容
def contains_complex_strings(self,content):
# 正则表达式匹配由大小写字母、数字、加号、斜杠等组成的字符串
# 注意:这只是一个示例,可能需要根据实际情况进行调整
pattern = r'[A-Za-z0-9+/=]+'
matches = re.findall(pattern, content)
# 如果找到匹配项且匹配项长度足够长(例如,至少20个字符)
# 则认为包含“不可识别内容”
for match in matches:
if len(match) >= 80: # 根据需要调整这个阈值
return True # 返回True和匹配的字符串
return False
'''
@name 判断php是否被混淆
@param php_code php代码
@return bool
'''
def is_php_code_obfuscated(self,filename):
# 读取PHP文件内容
php_code=public.ReadFile(filename)
# 定义一些常见的Webshell特征
# 注意:这些特征可能需要根据实际情况进行更新或扩展
patterns = [
r'\$_(GET|POST|REQUEST)\[.*\]\s*=\s*shell_exec', # 执行shell命令
r'\$_(GET|POST|REQUEST)\[.*\]\s*=\s*system', # 执行系统命令
r'\$_(GET|POST|REQUEST)\[.*\]\s*=\s*eval', # 执行PHP代码
r'\b\$?\w+\s*\(\s*(.*?)\s*\)',#检查变量函数
r'\b(base64_decode|gzuncompress|gzdecode|str_rot13)\b',# 检查是否存在编码或解码函数
r'[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]',# 检查是否存在字符串加密或混淆
r'\b(eval|call_user_func[_array])\b',#检查是否存在复杂的嵌套结构
# 添加更多特征...
]
# 使用正则表达式检查每个特征
for pattern in patterns:
if re.search(pattern, php_code):
return True # 找到Webshell特征
return False # 未找到Webshell特征
'''
@name 加入白名单
@param input_string php代码
'''
def add_whitelist(self,filename):
md5_hash = self.read_file_md5(filename)
# whitelist=self.ReadFile(self.__whitelist)
with open(self.__whitelist, 'r', encoding='utf-8') as file:
content = file.read()
if md5_hash not in content:
if os.path.exists(self.__whitelist):
public.WriteFile(self.__whitelist,md5_hash+"\n","a+")
return True
else:
public.WriteFile(self.__whitelist,md5_hash+"\n")
return True
return False
'''
@name 上传文件入口
@param filename 文件路径
@return bool
'''
def upload_file_url2(self, filename,url):
try:
if os.path.exists(filename):
ret=self.webshellchop(filename,url)
if ret:
return True
return False
else:
return False
except:
return False
def syslogcc(self,shell_insert):
if os.path.exists(self.__shella):
public.WriteFile(self.__shella,json.dumps(shell_insert)+"\n","a+")
else:
public.WriteFile(self.__shella,json.dumps(shell_insert)+"\n")
'''
@name 获取云端URL地址
@return URL
'''
def get_check_url(self):
try:
ret=requests.get('http://www.bt.cn/checkWebShell.php').json()
if ret['status']:
return ret['url']
return False
except:
return False
'''
@name 上传文件
@param data 文件路径集合
@return 返回webshell 路径
'''
def upload_shell(self, data):
if len(data) == 0: return []
return_data = []
url=self.get_check_url()
if not url: return []
count=0
for i in data:
count+=1
if self.upload_file_url2(i,url):
return_data.append(i)
schedule=("%.2f" % (float(count)/float(self.__count)*100))
public.WriteFile(self.__size,str(schedule))
return return_data
'''
@name 获取当前目录下所有PHP文件
'''
def getdir_list(self, path_data):
if os.path.exists(str(path_data)):
return self.get_dir(path_data)
else:
return False
'''
@name 扫描webshell入口函数
@param path 需要扫描的路径
@return webshell 路径集合
'''
def san_dir(self, path):
self.__count=0
#self.hmscan(path)
#河马查杀
file = self.getdir_list(path)
if not file:
return []
##进度条
print(file)
self.__count=len(file)
return_data = self.upload_shell(file)
#写结果
return return_data
#河马查杀
def hmscan(self, path):
ress=public.ExecShell("/www/server/panel/plugin/webshell_check/hm scan "+path+"/")
#self.syslogcc("河马扫描")
#self.syslogcc(path)
text=public.ReadFile("/www/server/panel/plugin/webshell_check/result.csv")
# 将文本按行分割
lines = text.strip().split('\n')
# 跳过标题行,只处理包含路径的行
php_paths = [line.split(',')[-1].strip() for line in lines[1:] if ',' in line]
# 输出结果
for path in php_paths:
self.syslogcc(path)
return true
# 返回站点
def return_site(self, get):
data = public.M('sites').field('name,path').select()
ret = {}
for i in data:
ret[i['name']] = i['path']
return public.returnMsg(True, ret)
def return_python(self):
if os.path.exists('/www/server/panel/pyenv/bin/python'):return '/www/server/panel/pyenv/bin/python'
if os.path.exists('/usr/bin/python'):return '/usr/bin/python'
if os.path.exists('/usr/bin/python3'):return '/usr/bin/python3'
return 'python'
def san_path(self,get):
if os.path.exists(self.__size):
os.remove(self.__size)
if os.path.exists(self.__shell):
os.remove(self.__shell)
if not 'path' in get:return public.returnMsg(False, "目录不存在")
if not os.path.exists(get.path):return public.returnMsg(False, "目录不存在")
file_count = self.getdir_list(get.path)
print(file_count)
if not file_count or len(file_count)==0:return public.returnMsg(False, "当前目录下没有PHP文件")
#检查当前是否存在有运行的查杀进程
webshell_count=public.ExecShell("ps -aux |grep webshell_check_main.py |wc -l")
try:
count=int(webshell_count[0].strip())
if count>2:
pid = public.ExecShell("ps -aux | grep webshell_check_main.py | grep -v grep | awk '{print $2}'")
public.ExecShell("kill -9 {}".format(pid[0].strip()))
# return public.returnMsg(False, "当前存在木马查杀进程。不支持同时运行多个查杀进程")
except:
return public.returnMsg(False, "启动扫描进程失败,请检查是否存在查杀进程")
shell="%s /www/server/panel/plugin/webshell_check/webshell_check_main.py %s &"%(self.return_python(),get.path.strip())
public.ExecShell(shell)
return public.returnMsg(True, "已经启动扫描进程")
#获取进度
def get_san(self,get):
if not os.path.exists(self.__size):return 0
data3=public.ReadFile(self.__size)
if isinstance(data3,str):
data3=data3.strip()
try:
data=int(float(data3))
except:
data=0
return data
return 0
#读取扫描后的文件
def get_shell(self,get):
time.sleep(1)
ret=[]
count=1
ret.append(["序号", "md5", "路径","特征"])
if not os.path.exists("/www/server/panel/plugin/webshell_check/shell.txt"):return []
f = open("/www/server/panel/plugin/webshell_check/shell.txt",'r')
for i in f:
try:
i=i.strip()
i=json.loads(i)
ret.append(["%s"%count,"%s"%i['md5'],i['filename'],i['file_type']])
count+=1
except:
continue
return ret
#提交误报
def send_baota(self,get):
self.add_whitelist(get.filename)
return public.returnMsg(True, "提交误报完成"+get.filename)
def remove_file(self,get):
import files
data=files.files()
get.path=get.filename
return data.DeleteFile(get)
def shell_update(self,get):
public.ExecShell("/www/server/panel/plugin/webshell_check/hm update")
return public.returnMsg(True, '更新成功!')
#创建定时任务计划,进行安全扫描
def Scheduledplan(self,get):
public.ExecShell("/www/server/panel/plugin/webshell_check/hm update")
return public.returnMsg(True, '更新成功!')
if __name__ == "__main__":
data=webshell_check_main()
path = sys.argv[1]
file = data.getdir_list(path)
print(file)
data.san_dir(path)
index.html 改进
<style>
.conter_box {
display: none;
}
.conter_box.active {
display: block;
}
#webshell_table td span{
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.box_table_conter{
height: 390px;
}
#webshell_table td{
height: 35px;
display: inline-block;
}
#webshell_table td:first-child{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
</style>
<div class="bt-form">
<div class="bt-w-main">
<!--菜单部分-->
<div class="bt-w-menu">
<p class="bgw">扫描木马</p>
</div>
<!--内容部分-->
<div class="bt-w-con pd15">
<div class="plugin_body">
<!--内容部分-->
<div class="conter_box active">
<div class="_header">
<select class="bt-input-text mr5" style="width:180px" name="site_list"></select>
<button class="btn btn-success btn-sm va0 mb15" id="san_webshell_event">扫描木马</button>
<button class="btn btn-success btn-sm va0 mb15" style="" id="update_hm">更新河马</button>
<button class="btn btn-success btn-sm va0 mb15" style="float:right" id="open_windwos_aliyun">阿里查杀</button>
</div>
<div class="box_table_conter divtable">
<table class="table table-hover">
<thead>
<tr>
<th style="width: 30%;">文件名称</th>
<th style="width: 30%;">MD5值</th>
<th style="width: 30%;">特征</th>
<th style="text-align: right;width: 10%;">操作</th>
</tr>
</thead>
<tbody></tbody>
</table>
<div class="Tbody" style="overflow:auto;max-height:350px">
<table class="table table-hover">
<thead></thead>
<tbody id="webshell_table"></tbody>
</table>
</div>
</div>
<ul class="help-info-text c7">
<li style="color:red">本次查杀由长亭牧云强力驱动</li>
<li style="color:red">如果文件存在误报。直接点击误报即可</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<script>
var hm_shell = {
plugin_name: 'webshell_check',
progress: '',
init: function () {
var _this = this;
$('.layui-layer-page').width(900);
this.return_site_req(function (res) {
var _option = '',
rdata = res.msg;
for (var i in rdata) {
_option += '<option value="' + rdata[i] + '">' + i + '</option>'
}
$('[name="site_list"]').html(_option);
});
$(".bt-w-menu p").click(function () {
var index = $(this).index();
$(this).addClass('bgw').siblings().removeClass('bgw');
$('.conter_box').eq(index).show().siblings().hide();
switch (index) {
case 0:
break;
}
});
// 扫描
$('#san_webshell_event').click(function(){
_this.start_scanning({path:$('[name="site_list"]').val()})
});
// 更新
$('#update_hm').click(function(){
_this.shell_update(function(res){
layer.msg(res.msg,{icon:res.status?1:2})
})
})
//跳转到阿里云webshell查杀
$('#open_windwos_aliyun').click(function(){
var myNewWindow = window.open("https://ti.aliyun.com/#/webshell", "myNewWindow");
})
},
// 启动扫描
start_scanning: function (obj) {
var _html = '',_this = this;
this.open_scanning({path:obj.path},function(res){
layer.msg(res.msg,{icon:res.status?1:2})
if(res.status){_this.create_progress_view()}
});
},
// 创建扫描视图
create_progress_view: function(){
var _this = this;
progress = layer.open({
type: 1,
closeBtn: 2,
title: false,
shade: 0,
area: '400px',
content: '<div class="pro_style" style="padding: 20px;"><div class="progress-head">正在扫描中,扫描进度...</div>\
<div class="progress">\
<div class="progress-bar progress-bar-success progress-bar-striped" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 0%">\
<span class="sr-only">0%</span>\
</div>\
</div>\
</div>\
</div>',
success:function(){
_this.detect_progress();
}
})
},
// 扫描进度
detect_progress:function(){
var _this = this;
this.get_san(function(pro){
if(pro !== 100){
if (pro > 100) pro = 100;
if (pro !== NaN) {
$('.pro_style .progress-bar').css('width', pro + '%');
$('.pro_style .sr-only').html(pro + '%');
}
setTimeout(function () {
_this.detect_progress();
}, 1000);
}else{
layer.close(progress);
_this.get_dir_table();
}
})
},
// 获取扫描结果
get_dir_table:function(){
var _html = '',_array = [],filename = '';
this.get_shell(function(res){
if(res.length > 0){
for (var i = 1; i < res.length; i++) {
_array = res[i][2].split('/');
filename = _array[_array.length -1];
_html += '<tr name="tr'+i+'">\
<td style="width: 30%;"><a href="javascript:;" title="打开文件'+res[i][2]+'" class="btlink" onclick="OnlineEditFile(0,\''+ res[i][2] +'\')">'+filename+'</td>\
<td style="width: 30%;"><span style="'+(res[i][1].indexOf('建议清理') !== -1 ? ('color:red'):'')+'">'+res[i][1]+'</span></td>\
<td style="width: 20%;">'+res[i][3]+'</td>\
<td style="text-align: right;width: 20%;">\
<a class="btlink" onclick="hm_shell.baota_detect(\''+ res[i][2] + '\')">提交误报</a> | \
<a class="btlink" style="color:red" onclick="hm_shell.del_file(\''+ res[i][2] + '\','+i+')">删除文件</a>\
</td>\
</tr>'
}
}else{
_html = '<tr><td colspan="3" style="text-align:center">暂无数据</td></tr>'
layer.msg('未扫描到木马文件',{icon:1})
}
$('#webshell_table').html(_html);
})
},
// 宝塔检测
baota_detect:function(path){
this.send_baota({filename:path},function(res){
layer.msg(res.msg,{icon:res.status?1:2,timeout:4000})
})
},
// 宝塔加入白名单
baota_baimingdan:function(path){
this.send_baimingdan({filename:path},function(res){
layer.msg(res.msg,{icon:res.status?1:2,timeout:4000})
})
},
// 第三方检测
three_detect:function(path){
this.upload_file_url({filename:path},function(res){
layer.msg(res.msg,{icon:res.status?1:2,timeout:4000})
})
},
// 删除文件
del_file:function(path,index){
var _this = this;
layer.confirm('是否要删除【'+path+'】文件,请确认',{title: '删除文件'},function(){
_this.remove_file({filename:path},function(res){
if(res.status){
$('#webshell_table [name=tr'+index+']').remove();
}
layer.msg(res.msg,{icon:res.status?1:2,timeout:4000})
})
})
},
return_site_req: function (clk) {
this.send({
tips: '正在获取站点列表,请稍候...',
method: 'return_site',
success: function (res) {
if (clk) clk(res)
}
})
},
open_scanning:function(obj,clk){
this.send({
tips: '启动扫描进程中,请稍候...',
method: 'san_path',
data: {path: obj.path},
success: function (res) {
if (clk) clk(res);
}
});
},
get_san:function(clk){
this.send({
load: 3,
method: 'get_san',
success: function (res) {
if (clk) clk(res)
}
})
},
get_shell:function(clk){
this.send({
load: 3,
method: 'get_shell',
success: function (res) {
if (clk) clk(res)
}
})
},
send_baota:function(obj,clk){
this.send({
tips: '宝塔检测中,请稍候...',
method: 'send_baota',
data: {filename: obj.filename},
success: function (res) {
if (clk) clk(res);
}
})
},
send_baimingdan:function(obj,clk){
this.send({
tips: '正在加入白名单,请稍候...',
method: 'add_whitelist',
data: {filename: obj.filename},
success: function (res) {
if (clk) clk(res);
}
})
},
upload_file_url:function(obj,clk){
this.send({
tips: '第三方检测中,请稍候...',
method: 'upload_file_url',
data: {filename: obj.filename},
success: function (res) {
if (clk) clk(res);
}
})
},
remove_file:function(obj,clk){
this.send({
tips: '正在删除文件中,请稍候...',
method: 'remove_file',
data: {filename: obj.filename},
success: function (res) {
if (clk) clk(res);
}
})
},
shell_update:function(clk){
this.send({
tips: '更新河马中,请稍候...',
method: 'shell_update',
success: function (res) {
if (clk) clk(res);
}
});
},
// 请求封装
send: function (obj) {
var loadT = '';
if (obj.load == undefined) obj.load = 0;
if (obj.url == undefined) {
if (obj.plugin_name === undefined && this.plugin_name !== undefined) obj.plugin_name = this
.plugin_name
if (!obj.plugin_name || !obj.method) {
layer.msg('插件类名称,或插件方法名称缺失!', {
icon: 2
});
return false;
}
}
if (obj.load === 0 || obj.tips != undefined) {
loadT = layer.msg(obj.tips, {
icon: 16,
time: 0,
shade: 0.3
});
} else if (obj.load === 1 || (obj.tips == undefined && obj.load == undefined)) {
loadT = layer.load();
}
$.ajax({
type: 'POST',
url: obj.url != undefined ? obj.url : ('/plugin?action=a&name=' + obj.plugin_name +
'&s=' + obj.method),
data: obj.data || {},
timeout: obj.timeout || 99999999,
complete: function (res) {
if (obj.load === 0 || obj.load === 1) layer.close(loadT);
},
success: function (rdata) {
if (obj.check) {
obj.success(rdata);
return
}
if (rdata.status === false) {
layer.msg(rdata.msg, {
icon: 2
});
return false;
}
obj.success(rdata);
},
error: function (ex) {
if (!obj.error) {
obj.msg || obj.msg == undefined ? layer.msg('请求过程发现错误!', {
icon: 2
}) : '';
return;
}
return obj.error(ex);
}
});
}
}
hm_shell.init();
</script>