Joyber 发布的文章

达到的结果:

count: 5, level: 3
0_1_2
0_1_3
0_1_4
0_2_3
0_2_4
0_3_4
1_2_3
1_2_4
1_3_4
2_3_4

function actionTest($count, $level) {
        echo "count: {$count}, level: {$level}\n";
        foreach (new arrangeIterator($count, $level) as $k=>$v) {
            echo "{$k}\n";
        }
    }


class arrangeIterator implements Iterator {

    private $count, $level;
    private $idxArr = [];

    public function __construct($count, $level) {
        $this->count = $count;
        $this->level = $level;
        $this->idxArr = range(0, $this->level-1);
    }

    /**
     * Return the current element
     * @link  https://php.net/manual/en/iterator.current.php
     * @return mixed Can return any type.
     * @since 5.0.0
     */
    public function current() {
        // TODO: Implement current() method.
        return $this->idxArr;
    }

    /**
     * Move forward to next element
     * @link  https://php.net/manual/en/iterator.next.php
     * @return void Any returned value is ignored.
     * @since 5.0.0
     */
    public function next() {
        // TODO: Implement next() method.
        $i = $this->level-1; //最大下标
        $n = 1;
        $idx = $i;
        while($i>=0) {
            if ($this->idxArr[$i] + 1 > $this->count-$n) {
                $i--;
                $n++;
                continue;
            }
            $idx = $i;
            break;
        }
        $tmp = $this->idxArr[$idx];
        $step = 1;
        for($i=$idx; $i<$this->level; $i++) {
            $this->idxArr[$i]=$tmp+$step;
            $step++;
        }

    }

    /**
     * Return the key of the current element
     * @link  https://php.net/manual/en/iterator.key.php
     * @return mixed scalar on success, or null on failure.
     * @since 5.0.0
     */
    public function key() {
        // TODO: Implement key() method.
        return implode('_', $this->idxArr);
    }

    /**
     * Checks if current position is valid
     * @link  https://php.net/manual/en/iterator.valid.php
     * @return bool The return value will be casted to boolean and then evaluated.
     * Returns true on success or false on failure.
     * @since 5.0.0
     */
    public function valid() {
        // TODO: Implement valid() method.
        return $this->level>0 && $this->idxArr[0] <= $this->count - $this->level && $this->idxArr[$this->level-1] <= $this->count - 1;
    }

    /**
     * Rewind the Iterator to the first element
     * @link  https://php.net/manual/en/iterator.rewind.php
     * @return void Any returned value is ignored.
     * @since 5.0.0
     */
    public function rewind() {
        // TODO: Implement rewind() method.
        $this->idxArr = range(0, $this->level-1);
    }
}

解决思路:
自己搭建一个node环境,通过node执行js代码,求出需要的cookie值即可,优化答案参考:

var x="@chars@toLowerCase@0xEDB88320@onreadystatechange@@@@RegExp@DOMContentLoaded@8@@replace@addEventListener@@length@fromCharCode@createElement@U@toString@Expires@d@challenge@GMT@Jul@return@1@catch@@@3@@0@split@20@search@f@captcha@@cookie@g@JgSe0upZ@join@2B@@reverse@substr@false@@document@innerHTML@a@7@String@parseInt@@36@_p@04@https@2@@@@wT413@@@div@@setTimeout@function@@@var@@6@for@eval@03@1593746256@1500@Path@e@Array@firstChild@@D1@new@QK@@@@@@@@href@charCodeAt@window@try@hantom@@@location@@n@rOm9XFMtA3QKV7nYsPGT4lifyWwkq5vcjH2IdxUoCbhERLaz81DNB6@match@charAt@attachEvent@17@@if@0xFF@while@@@467@@@pathname@else@__jsl_clearance@@Fri@@@".replace(/@*$/,"").split("@"),y="1s D=1p(){1o('2c.25=2c.2t+2c.A.d(/[\\?|&]C-n/,\\'\\')',1z);14.E='2v=1y.2q|x|'+(1p(){1s 1J=[1p(D){q D},1p(1J){q 1J},(1p(){1s D=14.i('1m');D.15='<16 25=\\'/\\'>2d</16>';D=D.1D.25;1s 1J=D.2g(/1e?:\\/\\//)[x];D=D.11(1J.g).3();q 1p(1J){1v(1s 2d=x;2d<1J.g;2d++){1J[2d]=D.2h(1J[2d])};q 1J.H('')}})(),1p(D){q 1w('18.h('+D+')')}],2d=[[[-~[17]]+[(-~[]<<-~[])+(-~[]<<-~[])]],'2e',(-~[]+[]+[]),'1j',(-~[]+[]+[]),'m',(((+!~~{})+[-~(+!~~{})]>>-~(+!~~{}))+[[]][x]),'1H',[(17+[]+[])+[(-~[]<<-~[])+(-~[]<<-~[])]],'j',[(+!~~{})+(-~(+!{})<<(-~[]<<-~[]))],'16',((+!{})+[]+[]),'%I',[(1u+[[]][x])+[(+!~~{})+(-~(+!{})<<(-~[]<<-~[]))],(17+[]+[])+(-~[]+[]+[])],'1F',[(1u+[[]][x])+[(+!~~{})+(-~(+!{})<<(-~[]<<-~[]))]],(27['1c'+'29']+[[]][x]).2h(-~(+!~~{})),'b',[[v+((+!~~{})+[(-~[]<<-~[])])/[(-~[]<<-~[])]]],[(((+!~~{})+[-~(+!~~{})]>>-~(+!~~{}))+[[]][x])+(17+[]+[])],(((+!~~{})+[-~(+!~~{})]>>-~(+!~~{}))+[[]][x]),[(1u+[[]][x])+[-~[17]]]];1v(1s D=x;D<2d.g;D++){2d[D]=1J[[v,r,x,r,x,r,x,r,v,r,x,r,x,r,v,r,v,x,r,1f,v,x,v][D]](2d[D])};q 2d.H('')})()+';l=2x, 1x-p-z 1d:2j:1b o;1A=/;'};2l((1p(){28{q !!27.e;}s(1B){q 12;}})()){14.e('a',D,12)}2u{14.2i('5',D)}",f=function(x,y){var a=0,b=0,c=0;x=x.split("");y=y||99;while((a=x.shift())&&(b=a.charCodeAt(0)-77.5))c=(Math.abs(b)<13?(b+48.5):parseInt(a,36))+y*c;return c},z=f(y.match(/\w/g).sort(function(x,y){return f(x)-f(y)}).pop());

function getJSL() {
    var z = f(y.match(/\w/g).sort(function (x, y) {
        return f(x) - f(y)
    }).pop());
 
    var data = "";
    var initZ = z;
    while (data.indexOf("document.cookie='__jsl") == -1 && z++ - initZ < 20) {
        data = y.replace(/\b\w+\b/g, function (y) {
            return x[f(y, z) - 1] || ("_" + y)
        });
    }
    ;
    console.info(data.slice(data.indexOf("'__jsl_clearance"), data.indexOf("+';Expires")))
    return eval(data.slice(data.indexOf("'__jsl_clearance"), data.indexOf("+';Expires")).replace(/document(.*?)toLowerCase\(\)/g, function (y) {
        return '"www.qqvbc.com/"'
    }));
}

console.info(getJSL());

个人想法:

给公司做数据的时候遇到,某网站有防采集机制
具体情况是 页面直接访问会返回521错误状态,并通过body返回script代码,让浏览器自动刷新,刷新之前会通过js设置一个cookie,这个521会同时设置一个session值

刷新后的请求就会带上session和cookie的值,普通用户访问页面无感知

难点在于获取script代码中的cookie的值,因为这个代码是通过某种机制加密了的,这里重点只说明一下我在这个问题上的解决思路

看下原代码:

//原始代码未加处理
var x="@__jsl_clearance@cookie@1500@@div@36@href@reverse@@split@length@__p@chars@1@if@@@0xEDB88320@@a@e@3@@@parseInt@callP@eval@@hantom@addEventListener@@d@@while@@fromCharCode@F@8@V@for@@@52@onreadystatechange@new@2@toString@25@replace@Jun@4@toLowerCase@X@0xFF@@@rOm9XFMtA3QKV7nYsPGT4lifyWwkq5vcjH2IdxUoCbhERLaz81DNB6@else@@@@function@@@Path@Array@@setTimeout@@Mon@substr@match@captcha@@attachEvent@Expires@@g@join@@HC@location@https@9@@firstChild@@CgkV@5@@GMT@@@@var@DOMContentLoaded@return@false@29@pathname@catch@RegExp@1593393952@D@search@document@0@charAt@window@02@20@@GPhk@charCodeAt@@try@@innerHTML@String@@as@challenge@JgSe0upZ@createElement@433@@f".replace(/@*$/,"").split("@"),y="75 53=4b(){54('65.8=65.7a+65.82.3b(/[\\?|&]59-96/,\\'\\')',4);83.3='2=80.99|84|'+(4b(){75 53=[[30],((-~(+[])<<38)+[[]][84]),[(-~!{}|-~[]-~[])],((-~!{}+[40]>>-~!{})+[]+[[]][84]),[-~(+[])-~(+!+{})-~[(-~{}<<-~{})]],(~~![]+[[]][84]),(-~{}+[[]][84])+(~~![]+[[]][84]),(-~{}+[[]][84])+(-~(+!+{})+[]),(-~{}+[[]][84])+((-~(+[])<<38)+[[]][84]),(-~(+!+{})+[]),[67],(-~{}+[[]][84])+[(-~!{}|-~[]-~[])],(6c+[]),(-~{}+[[]][84]),(-~{}+[[]][84])+(-~{}+[[]][84])],74=52(53.c);32(75 28=84;28<53.c;28++){74[53[28]]=['42','64',(86['21'+'24']+[]+[]).85(-~{})+(86['10'+'24'+'95']+[]+[]).85(-~(+!+{})-~[(-~{}<<-~{})])+(!''+[]+[]).85(1a)+({}+[]+[[]][84]).85(-~((-~(+[])<<-~[]-~[])))+(!/!/+[[]][84]).85(-~[(-~{}<<-~{})]),(((-~(+!+{})^-~(+[])))/(+![])+[]).85(-~(+!+{}))+(6c+[]),'6b','2c','8a','%','81','31',([[]][12]+[]+[[]][84]).85((-~[]<<-~[(-~    {}<<-~{})]))+(+[-~(+[]), (+![])]+[]+[[]][84]).85(-~{}),[(-~!{}|-~[]-~[])],(-~(+!+{})+[])+({}+[]+[[]][84]).85(-~((-~(+[])<<-~[]-~[]))),((-~(+[])<<38)+[[]][84])+(!+{}+[[]][84]).85(~~''),(~~![]+[[]][84])][28]};77 74.62('')})()+';5c=56, 79-3c-88 87:3a:35 71;51=/;'};13((4b(){90{77 !!86.25;}7b(19){77 78;}})()){83.25('76',53,78)}47{83.5b('36',53)}",f=function(x,y){var a=0,b=0,c=0;x=x.split("");y=y||99;while((a=x.shift())&&(b=a.charCodeAt(0)-77.5))c=(Math.abs(b)<13?(b+48.5):parseInt(a,36))+y*c;return c},z=f(y.match(/\w/g).sort(function(x,y){return f(x)-f(y)}).pop());while(z++)try{eval(y.replace(/\b\w+\b/g, function(y){return x[f(y,z)-1]||("_"+y)}));break}catch(_){}

通过node外部执行js代码,拿到计算后的值
一步一步分析后

//尝试转成node可执行代码,node没有window对象

//代码中的window在node中没有,实际上这个是一个障眼法

//(window['callP'+'hantom']+[]+[]) 这个在浏览器里执行一下,其实window也没有这个对象,返回的是 undefined 字符串

//所以 (window['callP'+'hantom']+[]+[]).charAt(-~{}) 执行一个就是执行了 'undefined'.charAt(-~{}) = 'n'

//结论,只需要把window换成node的全局变量global就大功告成

最终方案:
// window 换成 global
// {eval( 换成 {code=(
// 后面加上 ;code = code.match(/document.cookie=(.*)+';/)[1];cookie=eval(code);console.log(cookie);

//处理后代码在node一执行就得到了结果: '__jsl_clearance=1593393952.433|0|F4tVniecsHC2cCgkVf5XdaGPhk0%3D'

var x="@__jsl_clearance@cookie@1500@@div@36@href@reverse@@split@length@__p@chars@1@if@@@0xEDB88320@@a@e@3@@@parseInt@callP@eval@@hantom@addEventListener@@d@@while@@fromCharCode@F@8@V@for@@@52@onreadystatechange@new@2@toString@25@replace@Jun@4@toLowerCase@X@0xFF@@@rOm9XFMtA3QKV7nYsPGT4lifyWwkq5vcjH2IdxUoCbhERLaz81DNB6@else@@@@function@@@Path@Array@@setTimeout@@Mon@substr@match@captcha@@attachEvent@Expires@@g@join@@HC@location@https@9@@firstChild@@CgkV@5@@GMT@@@@var@DOMContentLoaded@return@false@29@pathname@catch@RegExp@1593393952@D@search@document@0@charAt@global@02@20@@GPhk@charCodeAt@@try@@innerHTML@String@@as@challenge@JgSe0upZ@createElement@433@@f".replace(/@*$/,"").split("@"),y="75 53=4b(){54('65.8=65.7a+65.82.3b(/[\\?|&]59-96/,\\'\\')',4);83.3='2=80.99|84|'+(4b(){75 53=[[30],((-~(+[])<<38)+[[]][84]),[(-~!{}|-~[]-~[])],((-~!{}+[40]>>-~!{})+[]+[[]][84]),[-~(+[])-~(+!+{})-~[(-~{}<<-~{})]],(~~![]+[[]][84]),(-~{}+[[]][84])+(~~![]+[[]][84]),(-~{}+[[]][84])+(-~(+!+{})+[]),(-~{}+[[]][84])+((-~(+[])<<38)+[[]][84]),(-~(+!+{})+[]),[67],(-~{}+[[]][84])+[(-~!{}|-~[]-~[])],(6c+[]),(-~{}+[[]][84]),(-~{}+[[]][84])+(-~{}+[[]][84])],74=52(53.c);32(75 28=84;28<53.c;28++){74[53[28]]=['42','64',(86['21'+'24']+[]+[]).85(-~{})+(86['10'+'24'+'95']+[]+[]).85(-~(+!+{})-~[(-~{}<<-~{})])+(!''+[]+[]).85(1a)+({}+[]+[[]][84]).85(-~((-~(+[])<<-~[]-~[])))+(!/!/+[[]][84]).85(-~[(-~{}<<-~{})]),(((-~(+!+{})^-~(+[])))/(+![])+[]).85(-~(+!+{}))+(6c+[]),'6b','2c','8a','%','81','31',([[]][12]+[]+[[]][84]).85((-~[]<<-~[(-~    {}<<-~{})]))+(+[-~(+[]), (+![])]+[]+[[]][84]).85(-~{}),[(-~!{}|-~[]-~[])],(-~(+!+{})+[])+({}+[]+[[]][84]).85(-~((-~(+[])<<-~[]-~[]))),((-~(+[])<<38)+[[]][84])+(!+{}+[[]][84]).85(~~''),(~~![]+[[]][84])][28]};77 74.62('')})()+';5c=56, 79-3c-88 87:3a:35 71;51=/;'};13((4b(){90{77 !!86.25;}7b(19){77 78;}})()){83.25('76',53,78)}47{83.5b('36',53)}",f=function(x,y){var a=0,b=0,c=0;x=x.split("");y=y||99;while((a=x.shift())&&(b=a.charCodeAt(0)-77.5))c=(Math.abs(b)<13?(b+48.5):parseInt(a,36))+y*c;return c},z=f(y.match(/\w/g).sort(function(x,y){return f(x)-f(y)}).pop());while(z++)try{code=(y.replace(/\b\w+\b/g, function(y){return x[f(y,z)-1]||("_"+y)}));break}catch(_){};code = code.match(/document\.cookie=(.*)\+';/)[1];cookie=eval(code);