宝塔木马查杀工具 5.1改进

木马查杀工具 5.1插件
缺点:
1.查杀效率低
2.查杀依靠MD5,变形,未知完全无解

插件目录:

/www/server/panel/plugin/webshell_check

改进方案:
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
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)
            self.syslogcc(filename+"       :"+file_type)
            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
            
            
            
            
            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):
        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=5
            rule=""
            if '<?php' not in php_code:
                rule=rule+'?php'
                suspect=suspect-3
            if 'require_once' in php_code:
                rule=rule+'require_once'
                suspect=suspect-3
            if 'call_user_func' in php_code:
                rule=rule+'call_user_func'
                suspect=suspect+2
            if 'http://thinkphp.cn All rights reserved' in php_code:
                rule=rule+'http://thinkphp.cn'
                suspect=suspect-2
            if 'eval' in php_code:
                rule=rule+'eval('
                suspect=suspect+2
            if 'call_user_func_array' in php_code:
                rule=rule+'call_user_func_array'
                suspect=suspect+2
            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'
            shell_insert={'filename':filename,"suspect":suspect,"rule":rule}   
            self.syslogcc(shell_insert)   
            if suspect>=7:
                return 'Intelligence engine01'
                
        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'\b\$_POST\b|\b\$_GET\b|\b\$_SESSION\b|\b\php://input\b|\b\$_REQUEST\b',
             ]
        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
    '''    
    @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+")
             else:
               public.WriteFile(self.__whitelist,md5_hash+"\n")
    
    
    '''
    @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
        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 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']])
                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("./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: 35%;">文件名称</th>
                                    <th style="width: 45%;">MD5值</th>
                                    <th style="text-align: right;width: 20%;">操作</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: 35%;"><a href="javascript:;" title="打开文件'+res[i][2]+'" class="btlink" onclick="OnlineEditFile(0,\''+ res[i][2] +'\')">'+filename+'</td>\
                            <td style="width: 45%;"><span style="'+(res[i][1].indexOf('建议清理') !== -1 ? ('color:red'):'')+'">'+res[i][1]+'</span></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})
            })
        },
        // 第三方检测
        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);
                }
            })
        },
        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>

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。