2016-11-18 92 views
8

PHP7提供了一个称为opcache的字节码缓存机制。我想知道是否有任何方法可以分发并运行PHP脚本(.bin文件扩展名)的“opcached”版本而不分发其源代码。 (我启用了opcache.file_cache指令在php.ini获得.bin文件)。可以在没有源代码的情况下分发PHP7 opcached文件吗?

我认为执行脚本时,PHP7将检查opcache目录相匹配的名称,时间戳的.bin文件,甚至可能一个比较校验和或散列值。如果全部匹配,PHP7将执行.bin文件而不是解析.php文件。即使相应的.php脚本不存在,也许有可能'欺骗'PHP执行.bin文件?

+0

有趣。我认为它可以。 http://gosecure.net/2016/04/27/binary-webshel​​l-through-opcache-in-php-7/ –

+0

你试过iy吗? – RiggsFolly

+0

7不是新的,它是在5.重要的问题将是你为什么要? – 2016-11-18 01:12:28

回答

9

PHP需要能够打开文件以便调用opcache;如果它不存在,它不能被加载中...

让我们look详细,看看我们会玩什么花招:

if (!file_handle->filename || !ZCG(enabled) || !accel_startup_ok) { 
    /* The Accelerator is disabled, act as if without the Accelerator */ 
    return accelerator_orig_compile_file(file_handle, type); 
#ifdef HAVE_OPCACHE_FILE_CACHE 
} else if (ZCG(accel_directives).file_cache_only) { 
    return file_cache_compile_file(file_handle, type); 
#endif 
} else if ((!ZCG(counted) && !ZCSG(accelerator_enabled)) || 
      (ZCSG(restart_in_progress) && accel_restart_is_active())) { 
#ifdef HAVE_OPCACHE_FILE_CACHE 
    if (ZCG(accel_directives).file_cache) { 
     return file_cache_compile_file(file_handle, type); 
    } 
#endif 
    return accelerator_orig_compile_file(file_handle, type); 
} 

我们可以看到,该文件缓存被启用它优先于共享内存缓存。

接下来,我们想看看file_cache_compile_file

  1. block signals
  2. protect shared memory
  3. zend_file_cache_script_load

现在我们来看看zend_file_cache_script_load

  1. open
  2. read headerlayout
  3. verify magic "OPCACHE"
  4. verify system id
  5. optionally validate timestamp
  6. perform read of cached file
  7. verify checksum

所以我们的第一个问题是,system id我不是唯一的,但由以下要素构成:

  1. PHP版本
  2. Zend扩展建立标识
  3. 二进制标识符,包含以下内容:
    1. sizeof(char)
    2. sizeof(int)
    3. sizeof(long)
    4. sizeof(size_t)
    5. sizeof(zend_long)
    6. ZEND_MM_ALIGNMENT
  4. 如果不使用PHP的开发版本(未发行的,从GIT):的二进制
  5. 二进制
  6. ___TIME___编译时
    1. ___DATE__编译日期

PHP的版本和构建标识符是必需的,因为至少下面可能版本之间改变或建立:

  • 为操作码
  • 内部结构
  • 的指令VM序列的布局积分标识符预计(现有控制结构的细节可能会改变)。的foreach)由opcache执行
  • 优化(因为以前的可能被发现是不安全的)

因为一个zval变化与字节序和结构至少布局的二进制标识符是必需的:体系结构可以实现所述尺寸一些基本的编译器类型(long,size_t等)以及这些类型的上限和下限,而endianess可以影响结构中成员的顺序,以及基本编译器类型的二进制表示。

注意,而很多的精力被消耗,以确定当前的系统,应该给你停下来想一想......

禁用时间戳opcache.validate_timestamps=0的验证将允许一个文件缓存条目的加载,即使文件系统上的当前文件是空的。

包含在头文件中的校验和仅用于验证文件的脚本部分(头文件之后),它没有(也不能)包含系统标识符或校验和本身的头部书面。

因此,您可以通过更改缓存文件的header中的系统标识符来使PHP从另一台计算机加载缓存文件,以与目标机器标识符相对应。

你应该吗?

也许为了好玩,但作为部署软件的方法,绝对不是

文件缓存不是为此目的而设计的,加载来自不同架构和构建的缓存会导致PHP崩溃。

+1

感谢您的详细故障! 'opcache.validate_timestamps = 0'和一个零长度的.php文件一起将字节码复制到另一台机器(假设两台机器具有相同的arch和PHP版本)。我明白这不适合“生产”。有没有其他的方式来部署字节码?也许这是[softwarerecs](http://softwarerecs.stackexchange.com/)。 – dasup

+0

如果您想部署混淆代码,请使用混淆普通PHP代码的工具。 – Andrea

相关问题