我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

最近一直在致力于phpsrc内核的编译工作,其实主要目的是调试安装实验一下几个相关扩展。其中一个扩展是:evalhook。顾名思义,就是挂载eval函数的钩子。那么,这款钩子扩展的效果如何呢?是不是真的能够阻止eval函数呢?

苏南大叔:php扩展,eval钩子如何挂载?如何阻止eval函数? - php-extension-eval
php扩展,eval钩子如何挂载?如何阻止eval函数?(图3-1)

大家好,这里是苏南大叔的“程序如此灵动”博客,这里记录苏南大叔和计算机代码的故事。本文描述php扩展如何拦截eval函数。在实际应用中,经常需要禁用eval函数的执行。那么,在以前的文章里面,苏南大叔使用了suhosin这一款扩展。本文中,苏南大叔实验的这款php扩展名叫evalhook。本文测试环境:centos@7.7.1908php@7.4.28evalhook

源码下载

这款evalhook代码的下载地址是:

苏南大叔:php扩展,eval钩子如何挂载?如何阻止eval函数? - 代码截图
php扩展,eval钩子如何挂载?如何阻止eval函数?(图3-2)

evalhook代码依然非常简单,逻辑几分钟内就可以看完。原本是基于php5写的,不过苏南大叔试了一下,php7下依然可以完美运行。以前苏南大叔测试过另外一款韩国人出品的扩展suhosin,功能比较类似。详情请参考:

扩展编译

扩展编译的话,中规中矩。唯一需要注意的是:如果第二次编译的话,一定记得make clean。否则就可能会看到这样的类似报错信息:

PHP Warning:  PHP Startup: evalhook: Unable to initialize module
Module compiled with module API=20121212
PHP    compiled with module API=20190902
These options need to match in Unknown on line 0

扩展的编译,是和php自身有较大关系的,两者必须保持一致。所以,在扩展的编译过程中,需要指定phpizephp-cofig文件的位置。对于苏南大叔的php@7来说,位置是:

/home/php7/bin/phpize
/home/php7/bin/php-config

命令参考如下:

make clean
/home/php7/bin/phpize
./configure  --with-php-config=/home/php7/bin/php-config
make
make install

这里不用关心evelhook.so文件的位置,只要正确的配置了php-config的位置,扩展就会自动出现在对应的目录里面。如果没有,那么就必然是php-config参数配置错误。make install都是自动复制文件到对应扩展路径的。

效果测试

正常情况下来说,是需要修改php.ini来加载扩展的。但是,苏南大叔非常懒得去配置php.ini,这里使用了php-d参数来加载evalhook.so

这里准备了一个eval.php文件,内部就放了个eval函数的简单调用范例。

$string = "beautiful";
$time = "winter";
$str = 'This is a $string $time morning!';
eval("\$str = \"$str\";");
echo $str;

命令执行:

php -d extension=evalhook.so eval.php

这里需要注意php的路径问题,使用绝对路径是最好的选择。比如:

/home/php7/bin/php -d extension=evalhook.so /home/www/eval.php

因为这个evalhook扩展的效果是:询问你是否执行eval,然后输入y才会继续执行,否则异常退出。所以,必须在命令行下面才能看出效果来,普通的网页情况下,只能陷入无限等待。

Do you want to allow execution? [y/N]
y
This is a beautiful winter morning!
Do you want to allow execution? [y/N]
n
Fatal error: evalhook: script abort due to disallowed eval() in /home/www/eval.php on line 8

关键源码

这里面的关键源码如下:

static zend_op_array *evalhook_compile_string(zval *source_string, char *filename TSRMLS_DC)
{
    int c, len, yes;
    char *copy;
    
    /* Ignore non string eval() */
    if (Z_TYPE_P(source_string) != IS_STRING) {
        return orig_compile_string(source_string, filename TSRMLS_CC);
    }
    
    len  = Z_STRLEN_P(source_string);
    copy = estrndup(Z_STRVAL_P(source_string), len);
    if (len > strlen(copy)) {
        for (c=0; c<len; c++) if (copy[c] == 0) copy[c] == '?';
    }
    
    printf("Script tries to evaluate the following string.\n");
    printf("----\n");
    printf("%s\n", copy);
    printf("----\nDo you want to allow execution? [y/N]\n");
    
    yes = 0;
    while (1) {
        c = getchar();
        if (c == '\n') break;
        if (c == 'y' || c == 'Y') {
            yes = 1;
        }
    }
    if (yes) {
        return orig_compile_string(source_string, filename TSRMLS_CC);
    }
    zend_error(E_ERROR, "evalhook: script abort due to disallowed eval()");
}

稍稍改动一下,就可以做到无条件禁止eval函数的执行。对吧?

苏南大叔:php扩展,eval钩子如何挂载?如何阻止eval函数? - eval逻辑
php扩展,eval钩子如何挂载?如何阻止eval函数?(图3-3)

参考文献

总结

对于黑客来说,eval是执行木马的关键性函数。而对于php代码解密来说,这个eval也是个关键性的函数。所以,仔细研究一下,无论是攻还是防,都是非常重大的功能了。

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   phpsrc