Location: PHPKode > scripts > Solace script maze > solace-script-maze/phpmorph.php
<?

class phpmorph {

    var $options = array();
    var $reserved = array('include', 'include_once', 'require', 'return', 'eval', 'isset', 'count', 'for', 'foreach', 'if', 'while', 'echo', 'print', 'list', 'or', 'and', 'xor', 'declare');
    var $reserved_vars = array('_ENV', '_SERVER', '_GET', '_POST', '_REQUEST', 'GLOBALS');
    var $var_prefix = 'V';
    var $morph_level = 0;
    var $current_morph_level = 0;
    var $allvars = array();
    var $vars = array();
    var $vars_fixed = array();
    var $trace_info = array();
    var $debug = 0;
    
    
    //=========================================================
    function phpmorph() {
        $o = &$this->options;

        $p = 'obfuscate';
        $o[$p]['enable'] = 1;
        $o[$p]['variables'] = 1;
        
        $p = 'string';
        $o[$p]['enable'] = 1;
        $o[$p]['chance'] = 100;
        $o[$p]['chance_split'] = 50;
        $o[$p]['min_len'] = 7;
        
        $p = 'string2';
        $o[$p]['enable'] = 1;
        $o[$p]['chance'] = 100;

        $p = 'func';
        $o[$p]['enable'] = 1;
        $o[$p]['chance'] = 100;

        $p = 'eval_calls';
        $o[$p]['enable'] = 1;
        $o[$p]['chance'] = 100;

        $p = 'eval_op';
        $o[$p]['enable'] = 1;
        $o[$p]['chance'] = 30;
        $o[$p]['max_len'] = 70;

        $p = 'func_defs';
        $o[$p]['enable'] = 1;
        $o[$p]['chance'] = 100;
        $o[$p]['morph_body'] = 1;
        $o[$p]['body_base64'] = 1;
        $o[$p]['evaled_creation'] = 1;

        $p = 'process';
        $o[$p]['clear_vars'] = 1;
    }

    //=========================================================
    function to_log($msg) {
        echo "$msg\n";
    }

    //=========================================================
    function chance($percent) {
        return (rand(1, 100) <= $percent);
    }

    //=========================================================
    function space_nonphp(&$phpsource) {
        $s = $phpsource;
        preg_match_all("/\?>(.+?)<\?/s", $s, $regs, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);
        for ($i=0; $i<count($regs); $i++) {
            $s = substr($s, 0, $regs[$i][1][1]).str_repeat(' ', strlen($regs[$i][1][0])).substr($s, $regs[$i][1][1] + strlen($regs[$i][1][0]));
        }
        return $s;
    }

    //=========================================================
    function in_string($pos, &$str) {
        if (!$this->in_php($pos, $str)) return false;
        $s = substr($str, 0, $pos);
        $s = $this->space_nonphp($s);
        $dblqnum = preg_match_all("/(?<!\\\)\"/", $s, $matches);
        $qnum = preg_match_all("/(?<!\\\)'/", $s, $matches);
        return (($qnum%2) or ($dblqnum%2));
    }

    //=========================================================
    function in_php($pos, &$str) {
        $s = substr($str, 0, $pos);
        $po = substr_count($s, '<?');
        $pc = substr_count($s, '?>');
        return ($po > $pc);
    }

    //=========================================================
    function gen_str($len, $a = '123456789') {
        $code = '';
        for ($i=1;$i<=$len;$i++) $code .= $a[rand(0, strlen($a)-1)];
        return $code;
    }

    //=========================================================
    function gen_varname($len, $store = false) {
        do {
            $name = $this->var_prefix.$this->gen_str($len);
        } while ((isset($this->vars[$name])) or (isset($this->allvars[$name])));
        if ($store) $this->vars[$name] = '';
        return $name;
    }

    //=========================================================
    function get_func_alias($func) {
        $a = array_flip($this->vars);
        if (array_key_exists("'$func'", $a))
            return '$'.$a["'$func'"];
        return false;
    }

    //=========================================================
    function split_string($s) {
        if (strlen($s) < 4) return array($s);
        if ((strlen($s) - substr_count($s, '\\')) < 3) return array($s);
        $i = 0;
        do {
            $p = rand(2, strlen($s)-2);
        } while ((($s[$p-1] == '\\') or ($s[$p] == '\\') or ($s[$p-1] == "'")) and ($i++ < 10));
        if ($i == 10) return array($s);
        $a[] = substr($s, 0, $p);
        $a[] = substr($s, $p);
        return $a;
    }

    //=========================================================
    function morph_string($str, $q = "'") {
        if (strlen($str) < $this->options['string']['min_len']) return "$q$str$q";
        $chance = $this->options['string']['chance_split'];
        if ($this->chance($chance)) {
            $as = $this->split_string($str);
        } else
            $as[] = $str;
        foreach ($as as $s) {
            if (strlen($s) < 30) $m = rand(0,3);
                else $m = rand(0,2);
            switch ($m) {
                case 0:
                    $as2[] = "$q$s$q";
                    break;
                case 1:
                    $alias = $this->get_func_alias('strrev');
                    if (!$alias) $alias = 'strrev';
                    $s = str_replace("\\$q", $q, $s);
                    $s = strrev($s);
                    $s = str_replace($q, "\\$q", $s);
                    $as2[] = "$alias($q".$s."$q)";
                    break;
                case 2:
                    $alias = $this->get_func_alias('str_rot13');
                    if (!$alias) $alias = 'str_rot13';
                    $s = str_rot13($s);
                    $as2[] = "$alias($q".$s."$q)";
                    break;
                case 3:
                    $alias = $this->get_func_alias('base64_decode');
                    if (!$alias) $alias = 'base64_decode';
                    $s = str_replace("\\$q", $q, $s);
                    $s = base64_encode($s);
                    $as2[] = "$alias($q".$s."$q)";
                    break;
            }
        }
        $s = implode('.', $as2);
        return $s;
    }

    //=============================================================
    function nonbracketed_explode($spl, &$l, $br = '{}') {
        $n = 0;
        $a = explode($spl, $l);
        foreach($a as $k => $s) {
            for ($i=0;$i<strlen($s);$i++) {
                if ($s[$i] == $br[0]) $n++; else
                if ($s[$i] == $br[1]) $n--;
            }
            $ss .= $spl.$s;
            if ($n == 0) {
                $b[] = trim($ss, $spl);
                $ss = '';
            }
        }
        if ($ss) $b[] = trim($ss, $spl);
        return $b;
    }

    //=============================================================
    function get_bracketed($s, $pos, $br = '{}') {
        $i = $pos;
        $opened = false;
        $n = 0;
        while ((!$opened or $n) and ($i<strlen($s))) {
            if ($s[$i] == $br[0]) {
                if (!$opened) $opened = true;
            }
            if ($s[$i] == $br[0]) $n++; else
            if ($s[$i] == $br[1]) $n--;
            $i++;
        }
        return $i;
    }

    //=========================================================
    function morph_func_def($phpsource, $funcdef, &$rep) {
        preg_match("/function\s*([a-zA-Z0-9_]+)\s*\((.*?)\)\s*\{/s", $funcdef, $matches);
        $body = substr($funcdef, strlen($matches[0]));
        $body = substr($body, 0, strlen($body)-strlen(strrchr($body, '}')));
        $body = trim($body);
        if ($this->options['func_defs']['morph_body']) {
            $morpher = new phpmorph;
            $morpher->options['process']['clear_vars'] = 0;
            $morpher->options['eval_op']['enable'] = 0;
            $morpher->vars = $this->vars;
            $body = $morpher->process('<'.'? {MORPH_VARS}'.$body.'?'.'>', 1);
            $body = trim(substr($body, 2, strlen($body) - 4));
            $body = preg_replace("/{[A-Z_]+}/", '', $body);
            unset($morpher);
        }
        $name = $matches[1];
        $newname = $this->gen_varname(3, true);
        $this->vars_fixed[] = $newname;
        $args = $matches[2];
        if ($this->options['func_defs']['body_base64']) {
            $line = $this->trace_info['func'];
            $lines_prefix = $line?str_repeat("\n", $line - 1):'';
            $body = base64_encode($lines_prefix.$body);
            if ($this->options['func_defs']['evaled_creation']) {
                $s = "\$$newname=create_function('$args',base64_decode('$body'));";
                $line = $this->trace_info['eval'];
                $lines_prefix = $line?str_repeat("\n", $line - 1):'';
                $s = $lines_prefix.$s;
                $s = "eval(base64_decode('".base64_encode($s)."'));";
            } else
                $s = "\$$newname=create_function('$args',base64_decode('$body'));";
        } else {
            $body = str_replace('\\', '\\\\', $body);
            $body = str_replace("'", "\'", $body);
            $body = preg_replace("/[\r\n\s]+/", ' ', $body);
            $s = "\$$newname=create_function('$args','$body');";
        }
        $rep[] = array('pos' => strpos($phpsource, $funcdef), 'len' => strlen($funcdef), 'new' => $s);
        preg_match_all("/$name\(/", $phpsource, $matches, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);
        for ($i=1; $i<count($matches); $i++) {
            $rep[] = array('pos' => $matches[$i][0][1], 'len' => strlen($matches[$i][0][0]), 'new' => "\$$newname(");
        }
    }

    //=========================================================
    function morph_func($func) {
        $newname = $this->gen_varname(3);
        if ($func[0] == '$') {
            $this->vars[$newname] = "'".trim($func, '$')."'";
            return "\$\$$newname";
        } else {
            $a = array_flip($this->vars);
            if (array_key_exists("'$func'", $a)) {
                $newname = $a["'$func'"];
            } else {
                $this->vars[$newname] = "'$func'";
            }
        }
        $s = "\$$newname";
        return $s;
    }

    //=========================================================
    function morph_eval($funcname, $funcargs) {
        $s = base64_encode("return $funcname($funcargs);");
        $s = "eval(base64_decode('$s'))";
        return $s;
    }

    //=========================================================
    function morph_obfuscate(&$phpsource) {
        preg_match_all("/([;{}])[\r\n\s]+/s", $phpsource, $out, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);
        $rep = array();
        for ($i=0; $i<count($out); $i++) {
            if (!$this->in_php($out[$i][0][1], $phpsource)) continue;
            if ($this->in_string($out[$i][0][1], $phpsource)) continue;
            $rep[] = array('pos' => $out[$i][0][1], 'len' => strlen($out[$i][0][0]), 'new' => $out[$i][1][0]);
        }
        $phpsource = $this->do_replacements($phpsource, $rep);

        preg_match_all("/\s*([=\+\-\*\/\.\[\]\(\),%])\s*/s", $phpsource, $out, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);
        $rep = array();
        for ($i=0; $i<count($out); $i++) {
            if (!$this->in_php($out[$i][0][1], $phpsource)) continue;
            if ($this->in_string($out[$i][0][1], $phpsource)) continue;
            $rep[] = array('pos' => $out[$i][0][1], 'len' => strlen($out[$i][0][0]), 'new' => $out[$i][1][0]);
        }
        $phpsource = $this->do_replacements($phpsource, $rep);
        
        if ($this->options['obfuscate']['variables']) {
            preg_match_all("/\\\$([A-Za-z0-6_]+)/", $phpsource, $out, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);
            $rep = array();
            $vars = array();
            for ($i=0; $i<count($out); $i++) {
                if ($out[$i][1][0][0] == $this->var_prefix) continue;
                if (in_array($out[$i][1][0], $this->reserved_vars)) continue;
                if (!$this->in_php($out[$i][0][1], $phpsource)) continue;
                $name = $out[$i][1][0];
                if (!isset($vars[$name])) {
                    $vars[$name] = $this->gen_varname(3, true);
                }
                $newname = $vars[$name];
                $rep[] = array('pos' => $out[$i][1][1], 'len' => strlen($name), 'new' => $newname);
            }
            unset($vars);
            $phpsource = $this->do_replacements($phpsource, $rep);
        }
        $phpsource = preg_replace("/(<\?(php)?)\s*/", '\\1 ', $phpsource);
    }

    //=========================================================
    function do_replacements($str, $rep) {
        for ($i=count($rep)-1; $i>=0; $i--) {
            $str = substr($str, 0, $rep[$i]['pos']).$rep[$i]['new'].substr($str, $rep[$i]['pos'] + $rep[$i]['len'], strlen($str));
        }
        return $str;
    }

    //=========================================================
    function process($phpsource, $level = 1, $options = false) {
        if ($options !== false) $o = $options; else $o = &$this->options;
        $this->morph_level = $level;
        $mods = 0;

        if ($o['process']['clear_vars']) {
            $this->allvars = array();
            $this->vars_fixed = array();
        }

        for ($l=1; $l<=$level; $l++) {
        
        $this->current_morph_level = $l;
        if ($o['process']['clear_vars']) $this->vars = array();

        if ($l == 1)
        if ($o['obfuscate']['enable']) {
            $this->morph_obfuscate($phpsource);
        }

        if ($o['func_defs']['enable']) {
            while (preg_match_all("/function\s*([a-zA-Z0-9-_]+)\s*\((.*?)\)\s*\{/s", $phpsource, $out, PREG_OFFSET_CAPTURE + PREG_SET_ORDER)) {
                if (isset($prevcount)) if (count($out) == $prevcount) break;
                $prevcount = count($out);
                $i=0;
                if (!$this->in_php($out[$i][0][1], $phpsource)) continue;
                $len = $this->get_bracketed($phpsource, $out[$i][0][1]);
                $rep = array();
                $s = $this->morph_func_def($phpsource, substr($phpsource, $out[$i][0][1], $len-$out[$i][0][1]), $rep);
                $phpsource = $this->do_replacements($phpsource, $rep);
            }
        }

        if ($o['string']['enable']) {
            preg_match_all("/'(.*?)(?<!\\\)'/s", $this->space_nonphp($phpsource), $out, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);
            $rep = array();
            for ($i=0; $i<count($out); $i++) {
                if (!$this->chance($o['string']['chance'])) continue;
                if (strlen($out[$i][1][0]) == 0) continue;
                $s = $this->morph_string($out[$i][1][0]);
                $rep[] = array('pos' => $out[$i][0][1], 'len' => strlen($out[$i][0][0]), 'new' => $s);
            }
            $phpsource = $this->do_replacements($phpsource, $rep);
        
        }
        
        if ($o['string2']['enable']) {
            preg_match_all("/\"([^\"\$;\r\n\\\]{3,})\"/s", $this->space_nonphp($phpsource), $out, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);
            $rep = array();
            for ($i=0; $i<count($out); $i++) {
                if (!$this->chance($o['string2']['chance'])) continue;
                $s = $this->morph_string($out[$i][1][0], '"');
                $rep[] = array('pos' => $out[$i][0][1], 'len' => strlen($out[$i][0][0]), 'new' => $s);
            }
            $phpsource = $this->do_replacements($phpsource, $rep);
        
        }
        
        if ($o['func']['enable']) {
            preg_match_all('/([A-Za-z$_][A-Za-z0-6_]+?)\s?\(/s', $phpsource, $out, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);
            $rep = array();
            for ($i=0; $i<count($out); $i++) {
                if (!$this->chance($o['func']['chance'])) continue;
                if (!$this->in_php($out[$i][1][1], $phpsource)) continue;
                if ($this->in_string($out[$i][1][1], $phpsource)) continue;
                if (in_array(trim($out[$i][1][0], '$'), $this->vars_fixed)) continue;
                if (in_array($out[$i][1][0], $this->reserved)) continue;
                $s = $this->morph_func($out[$i][1][0]);
                $rep[] = array('pos' => $out[$i][1][1], 'len' => strlen($out[$i][1][0]), 'new' => $s);
            }
            $phpsource = $this->do_replacements($phpsource, $rep);
        }
        
        if ($o['eval_calls']['enable']) {
            preg_match_all("/[\.=;]\s*(([A-Za-z0-6_$]+?)\s*\(([^;'\\\"\.\+\s]*?)\))[;\.\+\s]/s", $phpsource, $out, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);
            $rep = array();
            for ($i=0; $i<count($out); $i++) {
                if (!$this->chance($o['eval_calls']['chance'])) continue;
                if (!$this->in_php($out[$i][1][1], $phpsource)) continue;
                if (in_array($out[$i][2][0], $this->reserved)) continue;
                if (preg_match("/[\(\)]+/", $out[$i][3][0])) continue;
                if ($this->in_string($out[$i][1][1], $phpsource)) continue;
                $s = $this->morph_eval($out[$i][2][0], $out[$i][3][0]);
                $rep[] = array('pos' => $out[$i][1][1], 'len' => strlen($out[$i][1][0]), 'new' => $s);
            }
            $phpsource = $this->do_replacements($phpsource, $rep);
        }
        
        if (strpos($phpsource, 'for') === false)
        if ($o['eval_op']['enable']) {
            preg_match_all("/;([^\?}]+?)(?=;)/s", $phpsource, $out, PREG_OFFSET_CAPTURE + PREG_SET_ORDER);
            $rep = array();
            for ($i=0; $i<count($out); $i++) {
                if (!$this->chance($o['eval_op']['chance'])) continue;
                if (strlen($out[$i][1][0]) > $o['eval_op']['max_len']) continue;
                if (!$this->in_php($out[$i][1][1], $phpsource)) continue;
                if (strpos($out[$i][1][0], '{') !== false) continue;
                if ($this->in_string($out[$i][1][1], $phpsource)) continue;
                if (strtolower($out[$i][1][0]) == 'return') continue;

                $s = "eval(base64_decode('".base64_encode($out[$i][1][0].';')."'))";
                if (strpos($out[$i][1][0], 'return') !== false) $s = 'return '.$s;
                $rep[] = array('pos' => $out[$i][1][1], 'len' => strlen($out[$i][1][0]), 'new' => $s);
            }
            $phpsource = $this->do_replacements($phpsource, $rep);
        }
        
        $vars = '';
        foreach ($this->vars as $name => $value) {
            if ($value <> '') $vars .= "\$$name=$value;";
        }
        $phpsource = str_replace('{MORPH_VARS}', '{MORPH_VARS}'.$vars, $phpsource);
        $this->allvars = $this->allvars + $this->vars;
        $this->vars = array();
        }
        return $phpsource;
    }

}


?>
Return current item: Solace script maze