PHP 之源代码加密与解密,加密后可直接运行

方式一:

<?php
/**
 * Created by PhpStorm.
 * User: Yang
 * Date: 2019/10/16
 * Time: 10:25
 */


class Encipher {

    private $_sourceFile = '';
    private $_encodedFile = '';
    private $_comments = array(
        'Author: Yang',
        'Email: 1017836267@qq.com'
    );

    public function __construct($sourceFile, $encodeFile, $comments = array())
    {
        !empty($sourceFile) && $this->_sourceFile = $sourceFile;
        !empty($encodeFile) && $this->_encodedFile = $encodeFile;
        !empty($comments) && $this->comments = (array)$comments;

        if (empty($this->_sourceFile) || !file_exists($this->_sourceFile)) {
            exit("Source file does not exist.");
        }
        if (empty($this->_encodedFile) || !file_exists($this->_encodedFile)) {
            //如果源文件不存在,则创建
            fopen($this->_encodedFile, "w");
        }
    }

    /**
     * 返回随机字符串
     * @return string
     */
    private function createRandKey()
    { // 返回随机字符串
        $str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        return str_shuffle($str);
    }

    /**
     * 加密函数
     * @return bool
     */
    public function encode() {
        //随机密匙1
        $k1 = $this->createRandKey();
        //随机密匙2
        $k2 = $this->createRandKey();
        // 获取源文件内容
        $sourceContent = file_get_contents($this->_sourceFile);
        //base64加密
        $base64 = base64_encode($sourceContent);
        //根据密匙替换对应字符。
        $c = strtr($base64, $k1, $k2);
        $c = $k1 . $k2 . $c;
        $q1 = "O00O0O";
        $q2 = "O0O000";
        $q3 = "O0OO00";
        $q4 = "OO0O00";
        $q5 = "OO0000";
        $q6 = "O00OO0";
        $encodeContent = '$' . $q6 . '=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");$' . $q1 . '=$' . $q6 . '{3}.$' . $q6 . '{6}.$' . $q6 . '{33}.$' . $q6 . '{30};$' . $q3 . '=$' . $q6 . '{33}.$' . $q6 . '{10}.$' . $q6 . '{24}.$' . $q6 . '{10}.$' . $q6 . '{24};$' . $q4 . '=$' . $q3 . '{0}.$' . $q6 . '{18}.$' . $q6 . '{3}.$' . $q3 . '{0}.$' . $q3 . '{1}.$' . $q6 . '{24};$' . $q5 . '=$' . $q6 . '{7}.$' . $q6 . '{13};$' . $q1 . '.=$' . $q6 . '{22}.$' . $q6 . '{36}.$' . $q6 . '{29}.$' . $q6 . '{26}.$' . $q6 . '{30}.$' . $q6 . '{32}.$' . $q6 . '{35}.$' . $q6 . '{26}.$' . $q6 . '{30};eval($' . $q1 . '("' . base64_encode('$' . $q2 . '="' . $c . '";eval(\'?>\'.$' . $q1 . '($' . $q3 . '($' . $q4 . '($' . $q2 . ',$' . $q5 . '*2),$' . $q4 . '($' . $q2 . ',$' . $q5 . ',$' . $q5 . '),$' . $q4 . '($' . $q2 . ',0,$' . $q5 . '))));') . '"));';
        $headers = array_map('trim', array_merge(array('/*'), $this->_comments, array('*/')));
        $enCode = "<?php"."\r\n".implode("\r\n", $headers) . "\r\n".$encodeContent."\r\n"."?>";
        $file = fopen($this->_encodedFile, 'w');
        return fwrite($file, $enCode) or die('写文件错误');
    }
}


$e = new Encipher("index.php", "test_1.php");
$e ->encode();
echo "加密成功";

 

方式一改进版:

<?php
/**
 * Created by PhpStorm.
 * User: Yang
 * Date: 2019/10/16
 * Time: 10:25
 */


class Encipher
{

    private $c = '';
    private $_sourceFile = '';
    private $_targetFile = '';
    private $_writeContent = '';
    private $_comments = array(
        'Author: Yang',
        'Email: 1017836267@qq.com'
    );

    public function __construct($sourceFile, $targetFile, $comments = array())
    {
        !empty($sourceFile) && $this->_sourceFile = $sourceFile;
        !empty($targetFile) && $this->_targetFile = $targetFile;
        !empty($comments) && $this->comments = (array)$comments;

        if (empty($this->_sourceFile) || !file_exists($this->_sourceFile)) {
            exit("Source file does not exist.");
        }
        if (empty($this->_targetFile) || !file_exists($this->_targetFile)) {
            //如果源文件不存在,则创建
            fopen($this->_targetFile, "w");
        }
        $this->init();
    }

    private function init()
    {
        $this->q1 = "O00O0O";//base64_decode
        $this->q2 = "O0O000";//$c(原文经过strtr置换后的密文,由 目标字符+替换字符+base64_encode(‘原文内容’)构成)
        $this->q3 = "O0OO00";//strtr
        $this->q4 = "OO0O00";//substr
        $this->q5 = "OO0000";//52
        $this->q6 = "O00OO0";//urldecode解析过的字符串(n1zb/ma5\vt0i28-pxuqy*6%6Crkdg9_ehcswo4+f37j)
    }

    /**
     * 返回随机字符串
     * @return string
     */
    private function createRandKey()
    { // 返回随机字符串
        $str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        return str_shuffle($str);
    }

    /**
     * 写入文件
     * @param $targetFile 写入文件的路径
     * @return $this
     */
    private function write($targetFile)
    {
        $file = fopen($targetFile, 'w');
        fwrite($file, $this->_writeContent) or die('写文件错误');
        fclose($file);
        return $this;
    }

    /**
     * 对明文内容进行加密处理
     * @param $sourceFile  要加密的文件路径
     * @return $this
     */
    private function encodeText($sourceFile)
    {
        //随机密匙1
        $k1 = $this->createRandKey();
        //随机密匙2
        $k2 = $this->createRandKey();
        // 获取源文件内容
        $sourceContent = file_get_contents($sourceFile);
        //base64加密
        $base64 = base64_encode($sourceContent);
        //根据密匙替换对应字符。
        $c = strtr($base64, $k1, $k2);
        $this->c = $k1 . $k2 . $c;
        return $this;
    }

    private function encodeTemplate()
    {
        $encodeContent = '$' . $this->q6 . '=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");$' . $this->q1 . '=$' . $this->q6 . '{3}.$' . $this->q6 . '{6}.$' . $this->q6 . '{33}.$' . $this->q6 . '{30};$' . $this->q3 . '=$' . $this->q6 . '{33}.$' . $this->q6 . '{10}.$' . $this->q6 . '{24}.$' . $this->q6 . '{10}.$' . $this->q6 . '{24};$' . $this->q4 . '=$' . $this->q3 . '{0}.$' . $this->q6 . '{18}.$' . $this->q6 . '{3}.$' . $this->q3 . '{0}.$' . $this->q3 . '{1}.$' . $this->q6 . '{24};$' . $this->q5 . '=$' . $this->q6 . '{7}.$' . $this->q6 . '{13};$' . $this->q1 . '.=$' . $this->q6 . '{22}.$' . $this->q6 . '{36}.$' . $this->q6 . '{29}.$' . $this->q6 . '{26}.$' . $this->q6 . '{30}.$' . $this->q6 . '{32}.$' . $this->q6 . '{35}.$' . $this->q6 . '{26}.$' . $this->q6 . '{30};eval($' . $this->q1 . '("' . base64_encode('$' . $this->q2 . '="' . $this->c . '";eval(\'?>\'.$' . $this->q1 . '($' . $this->q3 . '($' . $this->q4 . '($' . $this->q2 . ',$' . $this->q5 . '*2),$' . $this->q4 . '($' . $this->q2 . ',$' . $this->q5 . ',$' . $this->q5 . '),$' . $this->q4 . '($' . $this->q2 . ',0,$' . $this->q5 . '))));') . '"));';
        $headers = array_map('trim', array_merge(array('/*'), $this->_comments, array('*/')));
        $this->_writeContent = "<?php" . "\r\n" . implode("\r\n", $headers) . "\r\n" . $encodeContent . "\r\n" . "?>";
        return $this;
    }

    /**
     * 获取解密后内容
     * @param $sourceFileContent 解密前内容
     * @return $this
     */
    private function decodeTemplate($sourceFileContent)
    {
        //以eval为标志 截取为数组,前半部分为密文中的替换掉的函数名,后半部分为密文
        $m = explode('eval',$sourceFileContent);
        //对系统函数的替换部分进行执行,得到系统变量
        $varStr = substr($m[0],strpos($m[0],'$'));
        //执行后,后续就可以使用替换后的系统函数名
        eval($varStr);
        //判断是否有密文
        if(!isset($m[1])){
            return $this;
        }

        //对密文进行截取 {$this->q4}  substr
        $star =  strripos($m[1],'(');
        $end = strpos($m[1],')');
        $str = ${$this->q4}($m[1],$star,$end);
        //对密文解密 {$this->q1}  base64_decode
        $str = ${$this->q1}($str);
        //截取出解密后的  核心密文
        $evallen = strpos($str,'eval');
        $str = substr($str,0,$evallen);
        //执行核心密文 使系统变量被赋予值 $O0O000
        eval($str);
        $this->_writeContent = ${$this->q1}(
            ${$this->q3}(
                ${$this->q4}(
                    ${$this->q2},${$this->q5}*2
                ),
                ${$this->q4}(
                    ${$this->q2},${$this->q5},${$this->q5}
                ),
                ${$this->q4}(
                    ${$this->q2},0,${$this->q5}
                )
            )
        );
        return $this;
    }

    /**
     * 加密函数
     */
    public function encode()
    {
        $this->encodeText($this->_sourceFile)->encodeTemplate()->write($this->_targetFile);
        echo 'encode-----解密前文件:'.$this->_sourceFile.'-----解密后文件:'.$this->_targetFile.'-----ok<br/>';
    }

    /**
     * 解密函数
     */
    public function decode()
    {
        $sourceFileContent = file_get_contents($this->_sourceFile);
        $this->decodeTemplate($sourceFileContent)->write($this->_targetFile);
        echo 'decode-----解密前文件:'.$this->_sourceFile.'-----解密后文件:'.$this->_targetFile.'-----ok<br/>';
    }
}

$e = new Encipher("login_2.php", "login_3.php");
$e->encode();

$e = new Encipher("login_3.php", "login_4.php");
$e->decode();

批量加密解密没有做

 

 方式二:

require_once "./doEncode.php";

$app = str_replace('\\', '/', dirname(__FILE__));
$encipher = new DoCodeLock($app."/test", $app."/test");

$encipher->encode();

doEncode.php

<?php
/**
 * Created by PhpStorm.
 * User: 25754
 * Date: 2019/10/16
 * Time: 9:32
 */

class DoCodeLock
{
    /**
     * The file/path which you want to encode.
     */
    public $source_file = '';

    /**
     * The file/path which you want to save the encoded file/path.
     */
    public $encoded_file = '';

    /**
     * Default comments.
     */
    public $comments = array(
        'Author: Yang',
        'Email: 1017836267@qq.com'
    );

    /**
     * advanced encryption
     */
    public $advancedEncryption = false;

    /**
     * variable name length.
     */
    public $varnameLength = 8;

    public function __construct($source_file = '', $encoded_file = '', $comments = array())
    {
        !empty($source_file) && $this->source_file = $source_file;
        !empty($encoded_file) && $this->encoded_file = $encoded_file;
        !empty($comments) && $this->comments = (array)$comments;

        if (empty($this->source_file) || !file_exists($this->source_file)) {
            exit("Source file/path does not exist.");
        }
        if (empty($this->encoded_file) || !file_exists($this->encoded_file)) {
            exit("Encoded file/path does not exist.");
        }
    }

    public function encode()
    {
        list($paths, $files) = $this->_getPathsAndFiles($this->source_file);
        $this->_createPaths($paths);
        $this->_encryptFiles($files);
    }

    private function _getPathsAndFiles($dir)
    {
        $files = $paths = array();
        if (is_dir($dir)) {
            $_files = scandir($dir);
            foreach ($_files as $key => $file) {
                if ($file == '.' || $file == '..') {
                    continue;
                }
                if (is_dir($dir . "/" . $file)) {
                    $paths[] = $file;
                    list($subPaths, $subFiles) = $this->_getPathsAndFiles($dir . "/" . $file);
                    $subPaths = $this->_addBasePath($subPaths, $file);
                    $subFiles = $this->_addBasePath($subFiles, $file);
                    $paths = array_merge($paths, $subPaths);
                    $files = array_merge($files, $subFiles);
                } else {
                    $files[] = $file;
                }
            }
        } elseif (is_file($dir)) {
            $files[] = basename($dir);
        }
        return array($paths, $files);
    }

    private function _addBasePath($files, $base)
    {
        foreach ($files as $key => $file) {
            $files[$key] = $base . "/" . $file;
        }
        return $files;
    }

    private function _createPaths($paths)
    {
        foreach ($paths as $path) {
            !is_dir($this->encoded_file . "/" . $path) && mkdir($this->encoded_file . "/" . $path, 0700);
        }
    }

    private function _encryptFiles($files)
    {
        foreach ($files as $file) {
            if ($this->advancedEncryption) {
                $this->_encryptFile($file);
            } else {
                $this->_setHumanUnreadable($file);
            }
        }
    }

    private function _setHumanUnreadable($file)
    {
        $code = $this->_getPHPCode($file);
        $regVars = $this->_setVarName($this->_getMatchedVariables($code));
        list($usedFuncs, $funcChars) = $this->_getMatchedFunctions($code);
        if (!empty($usedFuncs)) {
            $_tmp = $this->_setVarName(array('funcStrVar' => ''), $regVars);
            $funcStrVar = $_tmp['funcStrVar'];
            $usedFuncMaps = $this->_setVarName($usedFuncs, $regVars);
            $regVars = array_merge($usedFuncMaps, $regVars);
        } else {
            $usedFuncMaps = array();
        }
        $funcVarDefCode = $this->_getFuncVarDefCode($usedFuncMaps, $funcChars, $funcStrVar);
        $headers = array_map('trim', array_merge(array('<?php', '/*'), $this->comments, array('*/')));
        $enCode = implode("\r\n", $headers) . "\r\n" . $funcVarDefCode . strtr($code, $regVars);
        $this->_saveEncryptFile($file, $enCode);
    }

    private function _encryptFile($file)
    {
        list($enkey, $dekey) = $this->_getKeyPairs();
        $baseCodeOfHostedCode = $this->_getBaseCodeOfHostedCode();
        $decodeCodeOfHostedCode = $this->_getDecodeCodeOfHostedCode($file, $enkey, $dekey);
        $hostedCode = $baseCodeOfHostedCode . $decodeCodeOfHostedCode;

        $regVars = $this->_setVarName($this->_getMatchedVariables($hostedCode));
        list($usedFuncs, $funcChars) = $this->_getMatchedFunctions($hostedCode);
        if (!empty($usedFuncs)) {
            $_tmp = $this->_setVarName(array('funcStrVar' => ''), $regVars);
            $funcStrVar = $_tmp['funcStrVar'];
            $usedFuncMaps = $this->_setVarName($usedFuncs, $regVars);
            $regVars = array_merge($usedFuncMaps, $regVars);
        } else {
            $usedFuncMaps = array();
        }

        //$prefixCode: define function name & base extra code.
        $funcVarDefCode = $this->_getFuncVarDefCode($usedFuncMaps, $funcChars, $funcStrVar);
        $prefixCode = preg_replace("/\r|\n|\s+/is", "", $funcVarDefCode . strtr($baseCodeOfHostedCode, $regVars));

        $headers = array_map('trim', array_merge(array('<?php', '/*'), $this->comments, array('*/')));
        $hookKey = strtr(md5(implode("\r\n", $headers) . "\r\n" . $prefixCode), $enkey, $dekey);
        $evalEmbedCode = $this->_getEvalEmbedCode($decodeCodeOfHostedCode, $regVars, $enkey, $dekey);
        /**
         * eval(base64_decode(
         *     str_replace("\$hookKey", '', strtr($hookKey.$evalEmbedCode, $dekey, $enkey))
         * ));
         * $unset;
         */
        $unset = 'unset(' . $funcStrVar;
        foreach ($regVars as $var) {
            $unset .= ',' . $var;
        }
        $unset .= ');';
        $evalCode = "@eval(" . $regVars["base64_decode"] . "(" . $regVars["str_replace"] . "(" . $regVars["\$hookKey"] . ",''," . $regVars["strtr"] . "('" . $hookKey . $evalEmbedCode . "','" . $dekey . "','" . $enkey . "'))));" . $unset;
        $originalEncodedCode = $this->_getPHPEncode($file, $enkey, $dekey);
        $enCode = implode("\r\n", $headers) . "\r\n" . $prefixCode . $evalCode . "return;?>\r\n" . $originalEncodedCode;
        $this->_saveEncryptFile($file, $enCode, $enkey, $dekey);
    }

    /**
     * The encoded code needs extra code
     */
    private function _getBaseCodeOfHostedCode()
    {
        $code = <<<EOT
            \$farrs   = file(str_replace('\\\\', '/', __FILE__));
            \$enCode  = array_pop(\$farrs);
            \$phpCode = array_pop(\$farrs);
            \$fstrs   = implode('', \$farrs) . substr(\$phpCode, 0, strrpos(\$phpCode, '@ev'));
            \$hookKey = md5(\$fstrs);
            \$farrs   = \$phpCode = \$fstrs = NULL;
EOT;
        return $code;
    }

    /**
     * The encoded code needs decode code
     * if the licence is generated, also need to process it.
     */
    private function _getDecodeCodeOfHostedCode($file, $enkey, $dekey)
    {
        $code = <<<EOT
            eval(base64_decode(strtr(\$enCode, '{$dekey}', '{$enkey}')));
            \$enCode = NULL;
EOT;
        return $code;
    }

    private function _getFuncVarDefCode($usedFuncMaps, $funcChars, $funcStrVar)
    {
        //all the chars of function name
        $funcStr = implode("", $funcChars);

        //set variable name's value for each variable of function name
        $funcVarValArr = $this->_getFuncVarvalArr($usedFuncMaps, $funcChars, $funcStrVar);

        //encoded code define function name string.
        $code = $funcStrVar . "='{$funcStr}';";
        foreach ($usedFuncMaps as $func => $val) {
            $code .= $val . "= " . $funcVarValArr[$func] . ";\n";
        }
        return $code;
    }

    private function _getEvalEmbedCode($decodeCodeOfHostedCode, $regVars, $enkey, $dekey)
    {
        $code = preg_replace("/\r|\n/is", "", strtr($decodeCodeOfHostedCode, $regVars));
        //replace multi space to one, and encode it via base64
        $code = base64_encode(preg_replace("/\s{2,}/is", " ", $code));
        $code = strtr($code, $enkey, $dekey);
        return $code;
    }

    /**
     * get function names and chars for all functions
     */
    private function _getMatchedFunctions($code)
    {
        //match all function name
        preg_match_all("/([a-z_0-9]+)\(/is", $code, $matches);
        $usedFuncs = array_unique($matches[1]);
        if (false !== ($key = array_search('eval', $usedFuncs))) {
            unset($usedFuncs[$key]);
        }

        $funcChars = array_unique(preg_split("//is", implode("", $usedFuncs), -1, PREG_SPLIT_NO_EMPTY));
        shuffle($funcChars);
        return array(array_flip($usedFuncs), $funcChars);
    }

    /**
     * get variable names
     */
    private function _getMatchedVariables($code)
    {
        preg_match_all("/(\\\$[a-z0-9]+)\s*\=/is", $code, $matches);
        return array_flip($matches[1]);
    }

    private function _getFuncVarvalArr($usedFuncMaps, $funcChars, $funcStrVar)
    {
        $funcVarValArr = array();
        foreach ($usedFuncMaps as $func => $_val) {
            $val = "";
            for ($i = 0, $len = strlen($func); $i < $len; $i++) {
                if ($val == "") {
                    $val = $funcStrVar . "{" . array_search($func{$i}, $funcChars) . "}";
                } else {
                    $val = $val . "." . $funcStrVar . "{" . array_search($func{$i}, $funcChars) . "}";
                }
            }
            $funcVarValArr[$func] = $val;
        }
        return $funcVarValArr;
    }

    /**
     * get php pure code, trim php tag
     */
    private function _getPHPCode($file)
    {
        $from = $this->source_file . '/' . $file;
        $str = file_get_contents($from);
        $str = preg_replace("/^[\s\xef\xbb\xbf]*<\?php/is", "", $str);
        $str = trim(preg_replace("/\?>\s*$/is", "", $str));
        return $str;
    }

    /**
     * get php encoded code
     */
    private function _getPHPEncode($file, $enkey, $dekey)
    {
        $code = $this->_getPHPCode($file);
        $enCode = strtr(base64_encode($code), $enkey, $dekey);
        return $enCode;
    }

    private function _getKeyPairs()
    {
        $enkey = $this->_getKeyStr();
        $dekey = $this->_getKeyStr();
        while ($enkey === $dekey) {
            $dekey = $this->_getKeyStr();
        }
        return array($enkey, $dekey);
    }

    private function _getKeyStr()
    {
        $base64str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        for ($i = 127; $i <= 160; $i++) {
            $base64str .= chr($i);
        }
        $baseChars = array_filter(preg_split("//is", $base64str));
        $baseChars[] = 0;
        shuffle($baseChars);
        return implode("", $baseChars);
    }

    private function _setVarName($funcs, $filter = array())
    {
        $length = $this->varnameLength;
        $basestr = $this->_getInvisibleStr($length);
        $count = count($funcs);
        if ($count == 0) {
            return array();
        }
        $varArr = array();
        do {
            $randStr = substr("\$" . str_shuffle($basestr), 0, rand(2, $length));
            if (!in_array($randStr, $varArr) && !in_array($randStr, $filter)) {
                $varArr[] = $randStr;
                $count--;
            }
        } while ($count > 0);
        return array_combine(array_keys($funcs), $varArr);
    }

    /**
     * legal variable names: '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
     * Invisiable string's ascii is from 127 to 255:'[\x7f-\xff][\x7f-\xff]*'
     * param $length  the variable name's length.
     */
    private function _getInvisibleStr($length = 10)
    {
        $str = '';
        for ($i = 0; $i < $length; $i++) {
            $num = rand(127, 255);
            $str .= chr($num);
        }
        return $str;
    }

    private function _saveEncryptFile($file, $enCode, $enkey = null, $dekey = null)
    {
        $to = $this->encoded_file . '/' . $file;
        file_put_contents($to, $enCode);
        echo $to . "\n";
    }
}

 

 参考网址:https://github.com/uniqid/encipher

posted @ 2019-10-16 13:20  样子2018  阅读(6531)  评论(1编辑  收藏  举报