SGII PHP 加密工具

屏幕快照 2018-11-11 下午1.01.39.png


下载地址:https://www.sourceguardian.com/downloads/windows/11.2/SourceGuardian-11.2-Evaluation.exe


这款软件是采用QT编写的一个PHP加密软件,安装后会在安装目录生成一个Loaders文件夹。里面存放的是各个系统,以及对应的各个PHP版本的插件。


软件结构:

1、加密端

2、解密端(以PHP插件形式实现)


选择创建一个工程:

屏幕快照 2018-11-11 下午1.05.59.png


总体来说使用起来不难,缺点是无法选择整个工程目录。


Lock(锁定选项):如锁定ip,不过由于是体验版,是没有办法勾选的。

Advanced(高级选项): 如使用标签,这里直接默认。


加密的时候不要选择7.2的php版本,软件会提示找不到加密链接库,我看了一下这个库是在它的安装目录的,不过它还是找不到,有可能是动态加载有问题吧。这里我选择了PHP7.1的选项。


加密前:

<?php 
echo "我是加密过的文件。";
?>


加密后:

<?php
if(!function_exists('sg_load')){$__v=phpversion();$__x=explode('.',$__v);$__v2=$__x[0].'.'.(int)$__x[1];$__u=strtolower(substr(php_uname(),0,3));$__ts=(@constant('PHP_ZTS') || @constant('ZEND_THREAD_SAFE')?'ts':'');$__f=$__f0='ixed.'.$__v2.$__ts.'.'.$__u;$__ff=$__ff0='ixed.'.$__v2.'.'.(int)$__x[2].$__ts.'.'.$__u;$__ed=@ini_get('extension_dir');$__e=$__e0=@realpath($__ed);$__dl=function_exists('dl') && function_exists('file_exists') && @ini_get('enable_dl') && !@ini_get('safe_mode');if($__dl && $__e && version_compare($__v,'5.2.5','<') && function_exists('getcwd') && function_exists('dirname')){$__d=$__d0=getcwd();if(@$__d[1]==':') {$__d=str_replace('\\','/',substr($__d,2));$__e=str_replace('\\','/',substr($__e,2));}$__e.=($__h=str_repeat('/..',substr_count($__e,'/')));$__f='/ixed/'.$__f0;$__ff='/ixed/'.$__ff0;while(!file_exists($__e.$__d.$__ff) && !file_exists($__e.$__d.$__f) && strlen($__d)>1){$__d=dirname($__d);}if(file_exists($__e.$__d.$__ff)) dl($__h.$__d.$__ff); else if(file_exists($__e.$__d.$__f)) dl($__h.$__d.$__f);}if(!function_exists('sg_load') && $__dl && $__e0){if(file_exists($__e0.'/'.$__ff0)) dl($__ff0); else if(file_exists($__e0.'/'.$__f0)) dl($__f0);}if(!function_exists('sg_load')){$__ixedurl='http://www.sourceguardian.com/loaders/download.php?php_v='.urlencode($__v).'&php_ts='.($__ts?'1':'0').'&php_is='.@constant('PHP_INT_SIZE').'&os_s='.urlencode(php_uname('s')).'&os_r='.urlencode(php_uname('r')).'&os_m='.urlencode(php_uname('m'));$__sapi=php_sapi_name();if(!$__e0) $__e0=$__ed;if(function_exists('php_ini_loaded_file')) $__ini=php_ini_loaded_file(); else $__ini='php.ini';if((substr($__sapi,0,3)=='cgi')||($__sapi=='cli')||($__sapi=='embed')){$__msg="\nPHP script '".__FILE__."' is protected by SourceGuardian and requires a SourceGuardian loader '".$__f0."' to be installed.\n\n1) Download the required loader '".$__f0."' from the SourceGuardian site: ".$__ixedurl."\n2) Install the loader to ";if(isset($__d0)){$__msg.=$__d0.DIRECTORY_SEPARATOR.'ixed';}else{$__msg.=$__e0;if(!$__dl){$__msg.="\n3) Edit ".$__ini." and add 'extension=".$__f0."' directive";}}$__msg.="\n\n";}else{$__msg="<html><body>PHP script '".__FILE__."' is protected by <a href=\"http://www.sourceguardian.com/\">SourceGuardian</a> and requires a SourceGuardian loader '".$__f0."' to be installed.<br><br>1) <a href=\"".$__ixedurl."\" target=\"_blank\">Click here</a> to download the required '".$__f0."' loader from the SourceGuardian site<br>2) Install the loader to ";if(isset($__d0)){$__msg.=$__d0.DIRECTORY_SEPARATOR.'ixed';}else{$__msg.=$__e0;if(!$__dl){$__msg.="<br>3) Edit ".$__ini." and add 'extension=".$__f0."' directive<br>4) Restart the web server";}}$__msg.="</body></html>";}die($__msg);exit();}}return sg_load('EE9BD0F64756CAF8AAQAAAAXAAAABGgAAACABAAAAAAAAAD/708p7efzY8vEJAIiMlALizqvEH2zqhMpGayGy5oilahf8T+QfrOHwQPxt4SA2yDO/8qgGmF/BW7f3LWq6YZs4+rZ87Tmt83zMbJ0IjxCZcpcNYosriE1QEkn7H3j2iA2EaiYiPF/3IBHAAAAqAAAAD+D1xFfCOXFoy0wsjLyrC8DqN4PQUN997mRZ1+klqtTkAtw4Tdj6gmh4/HlDbck0oX1kQzRqvWxsNOe0omII0NKw9ybtHYskm+Ed6hYnwODI6rfXCH/TQKH1R6IFNTwrpM+5hnIbX60YpBTxecGUWgBEv1CVsDzYQqFPkSucK7OdaIaYM8sVnfW9EwwoZV/bi+gb/aZDvgMyDnmktk3Ew42BXukNRZNtQAAAAA=');


缺点:体积变得庞大不堪,而且依旧依赖于PHP。没有实现分离PHP解释器。

官网:Our PHP encoder protects your PHP code by compiling the PHP source code into a binary bytecode format, which is then 

意思是说会将源码编译成二进制的字节码。但是体验版好像还是字符串,并不是二进制的格式。从还要加<?php ?>就可以看出来,运行还是需要PHP环境。


PHP官网有一个zend的加密,堪称最强。完全脱离PHP,即使你不用php环境依旧可以运行。它自身实现了一套语法解析和执行工具。不过好像更新很慵懒,被好多人弃用。


现如今的加密种类:

1、文本格式加密(不需要插件):毫无加密性。

2、插件形式加密(需要解密插件例如SGII):加密性能一般,有插件完全可以分析出加密流程。

3、虚拟机方式(zend):这样的基本上就是完全实现了一套自身的解析器。也可以解密,但是代价太大。基本没人去做。



js获取cookie

function getCookie(cookieKey){
    var _cookie=document.cookie.split("; ");
    var _ckt="";
    for(j = 0; j < _cookie.length; j++) {
        _ckt= _cookie[j].split("=")
        if(_ckt[0].toLowerCase()==cookieKey.toLowerCase())
            return _ckt[1];
    }
    return "";
}


微信小程序web-view分享页面

屏幕快照 2018-11-06 下午8.17.09.png

截止现在webview本身是不支持分享页面的,不过可以有一个变通的方法。即:通过小程序自身分享带参数。

wx.miniProgram.navigateTo({url: '/path/to/page?id=123'})

上述是跳转页面带参,是一个比较简便的方法。


还有一个:bindmessage 这个是小程序里的webview主动向小程序本身发送消息。但是你发送完毕后,小程序是不会响应的,也许它已经获取到了,只不过不做处理。做处理的时机是在你程序页面后退,组件销毁,分享的时候。注意这里提到了分享。所以完全可以在分享的时候拿到你要传的值,比如说你要传id=123。当你发送完毕后,你可以点击小程序右上角的三个点,然后选择分享就可以获取。不过要事先复写小程序的分享接口。百度一大堆,可自行查阅。


官网传值:

wx.miniProgram.postMessage({ data: 'foo' }) 
wx.miniProgram.postMessage({ data: {foo: 'bar'} })

一般使用第二种,因为这个data必须是一个对象。网上也有人批判文档不严谨,因为第一个很多人都没有实现。我也就没做尝试了。直接用的第二种。在这里注意一下,如果你的html本身带有模板标签,那么你可以在{}括号内加几个空格。因为好多模板标签都不会去渲染你带空格的{}。所以官网给的例子里data前面是有空格的。


坑:

1、data你定义的是对象,但是你获取到的实际是数组。所以你data.foo是拿不到值得。而data[0].foo就可以。

2、data这个对象,也可以说是获取到的数组。当你postMessage多次后,你会发现这个数组是不会清空的。老数据依然存在。


分享完毕后你可以通过onLoad里拿值


onLoad: function(options) { 
// Do some initialize when page load. 
    console.log(options.id); //打印id
},


HBuilderX 测试基座分析

微信截图_20181031145619.png


新建一个项目,Html代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    <title></title>
    <script src="js/mui.min.js"></script>
    <link href="css/mui.min.css" rel="stylesheet"/>
    <script type="text/javascript" charset="utf-8">
      mui.init();
    </script>
</head>
<body>
<button>test</button> 
</body>
</html>


由于云打包还需要填写一些信息,这里就直接模拟器调试了。


微信截图_20181031144857.png


看这个界面感觉还是蛮不错的,点击按钮也有一些效果。不过后来更改了下代码。然后直接Ctrl+S。随着一些输出信息结束,发现模拟器的界面竟然也变化了。要知道,如果是正常的开发,这种上传操作,肯定会覆盖APP,导致APP关闭,然后在启动的。而这个却没有这一变化。于是感觉实际是一个webview。ADB通知APP重载而已。


验证如下:


首先查看这个基座的界面节点信息:


微信截图_20181031145109.png


展开树结构到最后一个节点,可以发现是一个WebView。而它载入的URL可以通过输出信息来查看。


微信截图_20181031145134.png

在内存卡的Android目录下面。逐级展开这个目录,会发现自己写的代码。


微信截图_20181031145209.png


这是HBuilder调试基座的一些信息,如果真实的APP也是这样的结构,这样的方式存储。那么就会存在一个问题。。。

AndroPHP App 逆向分析

AndroPHP 运行于安卓系统的服务器软件。

博客:http://hex.ro/wp/blog/php-and-lighttpd-for-android/

原贴:http://forum.xda-developers.com/showthread.php?t=1242144


images20141225135052066_info320X570.jpg


从网络上查找来看,这个软件已经不再更新,分析的版本也是现今为止能下载到的最新版本即:1.2


App运行流程如下:

屏幕快照 2018-10-27 上午12.24.11.png


大致:软件运行 -> 是否存在默认配置 -> 进行相应配置变量填充 -> 解压软件包(files)-> 效验版本 -> 设置文件权限 -> 判断是否Root -> 启动软件服务


是否存在默认配置

        setContentView(C0037R.layout.activity_main);
        setRequestedOrientation(1);
        Bundle extras = getIntent().getExtras();
        Intent intent = new Intent(this, DisplayNotification.class);
        intent.putExtra("NotifID", 1);
        startActivity(intent);
        SharedPreferences defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        this.port = defaultSharedPreferences.getString("updates_port", "8080");
        this.wwwroot = defaultSharedPreferences.getString("updates_path", "/mnt/sdcard/www");
        this.isRoot = defaultSharedPreferences.getBoolean("enable_root", false);
        this.mServer = new Server(this, this.port, this.wwwroot, this.isRoot);
        if (extras != null && extras.getBoolean("changes")) {
            this.mServer.stopServer();
            SystemClock.sleep(500);
            startServer();
        }
        this.startButton = (ToggleButton) findViewById(C0037R.id.toggleButton1);
        this.exitButton = (Button) findViewById(C0037R.id.exitButton);
        this.exitButton.setOnClickListener(new C00122());
        this.hideButton = (Button) findViewById(C0037R.id.hideButton);
        this.hideButton.setOnClickListener(new C00183());
        ((Button) findViewById(C0037R.id.setting)).setOnClickListener(new C00354());
        this.startButton.setOnClickListener(new C00325());
        this.ip = getLocalIpAddress();
        this.portt = this.port;
        if (this.ip == null) {
            this.ip = "localhost";
        }
        if (this.portt.equals("80")) {
            this.portt = "";
        }
        if (!this.portt.equals("")) {
            this.portt = ":" + this.portt;
        }
        TextView textView = (TextView) findViewById(C0037R.id.textLink);
        textView.setText("http://" + this.ip + this.portt);
        textView.setOnClickListener(new C00426());
        TextView textView2 = (TextView) findViewById(C0037R.id.TextLinkmyadmin);
        textView2.setText("http://" + this.ip + this.portt + "/phpmyadmin");
        textView2.setOnClickListener(new C00157());
        controlServer(true, 999999999);

解压软件包(files)

    public void checkVersion() {
        Object obj = null;
        File file = new File(this.serverPath + "/version");
        String readTextFile = readTextFile(this.serverPath + "/version");
        if (file.exists()) {
            if (readTextFile == null) {
                obj = 1;
            }
            if (!readTextFile.trim().equals(this.version)) {
                obj = 1;
            }
        } else {
            obj = 1;
        }
        if (obj != null) {
            deleteFolder(this.serverPath + "/phpmyadmin");
            deleteFolder(this.serverPath + "/php");
            deleteFolder(this.serverPath + "/mysql");
            deleteFolder(this.serverPath + "/lighttpd");
            deleteFolder(this.serverPath + "/lib");
            deleteFolder(this.serverPath + "/binary");
            extractZipFile();
            copyFileFromAssets("conf/version", this.serverPath + "/version");
        }
    }

置文件权限

public void setPermissions() {
        Exception e;
        try {
            File file = new File(this.serverPath + "/lighttpd/lighttpd");
            try {
                FileUtils.chmod(file, 511);
                FileUtils.chmod(new File(this.serverPath + "/lighttpd/killall"), 511);
                FileUtils.chmod(new File(this.serverPath + "/mysql/mysqld"), 511);
                FileUtils.chmod(new File(this.serverPath + "/php/php"), 511);
                FileUtils.chmod(new File(this.serverPath + "/mysql/data").getParentFile(), 511);
                FileUtils.chmod(new File(this.serverPath + "/mysql/data/mysql").getParentFile(), 511);
            } catch (Exception e2) {
                e = e2;
                File file2 = file;
                e.printStackTrace();
            }
        } catch (Exception e3) {
            e = e3;
            e.printStackTrace();
        }
    }

修改配置文档

    public void setupConfigs() {
        File file = new File(this.wwwroot);
        if (!file.exists()) {
            file.mkdir();
        }
        String str = "";
        saveTextFile(this.serverPath + "/lighttpd/lighttpd.conf", readTextFileFromAssets("conf/lighttpd.conf").replace("${wwwroot}", this.wwwroot).replace("${port}", this.port).replace("${serverpath}", this.serverPath).replace("${logpath}", this.serverPath + "/lighttpd/tmp"));
        str = "";
        saveTextFile(this.serverPath + "/mysql/my.cnf", readTextFileFromAssets("conf/my.cnf").replace("${serverpath}", this.serverPath));
        str = "";
        saveTextFile(this.serverPath + "/php/php.ini", readTextFileFromAssets("conf/php.ini").replace("${serverpath}", this.serverPath));
        saveTextFile(this.wwwroot + "/phpinfo.php", "<?php \n   echo phpinfo();  \n?>");
        if (!file.exists()) {
            file.mkdir();
            try {
                FileUtils.chmod(file, 509);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

判断系统权限

    public static void runCommand(String str) {
        try {
            OutputStream outputStream = Runtime.getRuntime().exec("sh").getOutputStream();
            Log.d("", "runCommand() cmd=" + str);
            writeLine(outputStream, str);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void runSuCommand(String str) {
        try {
            OutputStream outputStream = Runtime.getRuntime().exec("su -c sh").getOutputStream();
            Log.d("", "runSuCommand() cmd=" + str);
            writeLine(outputStream, str);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

启动软件服务

 public void reloadServer() {
        checkVersion();
        stopServer();
        setupConfigs();
        setPermissions();
        String str = "-D -f " + this.serverPath + "/lighttpd/lighttpd.conf";
        String str2 = "--defaults-file=" + this.serverPath + "/mysql/my.cnf";
        String stringBuilder = new StringBuilder(String.valueOf(String.valueOf(this.serverPath + "/php/php -a -b 127.0.0.1:9009"))).append(" ").append("-c " + this.serverPath + "/php/php.ini").toString();
        String stringBuilder2 = new StringBuilder(String.valueOf(String.valueOf(this.serverPath + "/mysql/mysqld"))).append(" ").append(str2).toString();
        String stringBuilder3 = new StringBuilder(String.valueOf(String.valueOf(this.serverPath + "/lighttpd/lighttpd"))).append(" ").append(str).toString();
        execCommand(stringBuilder);
        execCommand(stringBuilder3);
        execCommand(stringBuilder2);
        if (this.isRoot) {
            runSuCommand(stringBuilder);
            runSuCommand(stringBuilder3);
            runSuCommand(stringBuilder2);
            return;
        }
        runCommand(stringBuilder);
        runCommand(stringBuilder3);
        runCommand(stringBuilder2);
    }

MySql配置文档

[client]
port=3306
socket=${serverpath}/mysql/tmp/mysql.sock
character-sets-dir=${serverpath}/mysql/share/charsets/
[mysqld_safe]
socket = ${serverpath}/mysql/tmp/mysql.sock
nice  = 0
[mysql]
default-character-set=utf8
[mysqld]
port=3306
socket=${serverpath}/mysql/tmp/mysql.sock
character-sets-dir=${serverpath}/mysql/share/charsets/
basedir="${serverpath}/mysql/"
datadir="${serverpath}/mysql/data/"
tmpdir ="${serverpath}/mysql/tmp/"
character-set-server=utf8
default-storage-engine=MYISAM
max_connections=255
query_cache_size=0
table_cache=256
tmp_table_size=18M
thread_cache_size=8
myisam_max_sort_file_size=100G
myisam_sort_buffer_size=35M
key_buffer_size=25M
read_buffer_size=64K
read_rnd_buffer_size=256K
sort_buffer_size=256K

流程大致如上所示,当然还有一些其他的零碎操作,不一一赘述。总体来看这款软件看着只是一个“指令集和”将你安装的步骤省略罢了。由于这款软件不再更新,在一些较新的机器上运行会出现服务开启错误的问题,可以更换一个类似的软件KsWeb。其原理跟这款软件大同小异,只是一直在更新,所以界面效果会好一些。



实现:

一个简单的本地Mysql