我写了一个dll扩展来解密加密过的php文件,该dll应该能够在每次请求到来时(在编译前)对加密过的php文件进行解密。
但是我的测试情况是我所加载的dll并没有做任何动作。另外我也不太知道怎么调试,我直接在函数里面printf也没有显示相应的内容/*
  +----------------------------------------------------------------------+
  | PHP Version 5                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2010 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP license,      |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | [email protected] so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author:                                                              |
  +----------------------------------------------------------------------+
*//* $Id: header 297205 2010-03-30 21:09:07Z johannes $ */#ifdef HAVE_CONFIG_H
#include "config.h"
#endif#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_hello.h"
#include "encode.h"#define CRYPT_FLAG_LEN  9
#define CRYPT_FLAG  "shi_style"
extern char* CRYPT_KEY;
/* If you declare any globals in php_hello.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(hello)
*//* True global resources - no need for thread safety here */
static int le_hello;/* {{{ hello_functions[]
 *
 * Every user visible function must have an entry in hello_functions[].
 */
const zend_function_entry hello_functions[] = {
PHP_FE(confirm_hello_compiled, NULL) /* For testing, remove later. */
PHP_FE(sayHello,NULL)
{NULL, NULL, NULL} /* Must be the last line in hello_functions[] */
};
/* }}} */FILE* ext_decode(FILE *fp){
struct stat fbuf;
int str_len = 100;
char *file_str=0;
char * str_buf=0;
int fsize;
fstat(fileno(fp),&fbuf);
fsize = fbuf.st_size;
file_str = (char*)malloc(fsize+1);
fread(file_str,fsize,1,fp);
fclose(fp);
fdecode(file_str,&str_buf,CRYPT_KEY);
fp = tmpfile();
fwrite(str_buf,strlen(str_buf),1,fp);
if(str_buf!=0)
free(str_buf);
if(file_str!=0)
free(file_str);
return fp;
}ZEND_API zend_op_array* (*old_compile_file)(zend_file_handle* file_handle,int type TSRMLS_DC);
ZEND_API zend_op_array* my_compile_file(zend_file_handle* file_handle,int type TSRMLS_DC){//int type TSRMLS_DC这两个参数的具体作用?
FILE * fp;
char* buf = (char*)malloc(CRYPT_FLAG_LEN+1);

// printf("123");
if(zend_is_executing(TSRMLS_C)){
char *stmp = get_active_function_name(TSRMLS_C);
fclose(fopen("test.t","ab+"));
if(stmp){
if(strcasecmp(stmp,"show_source")==0 || strcasecmp(stmp,"highlight_file")==0){
return NULL;
}
}
}
fp = fopen(file_handle->filename,"ab+");
// php_printf("ddddd");
if(!fp){
return old_compile_file(file_handle,type TSRMLS_CC);
}
fread(buf,CRYPT_FLAG_LEN,1,fp);
if(memcmp(buf,CRYPT_FLAG,CRYPT_FLAG_LEN)==0){
return old_compile_file(file_handle,type TSRMLS_CC);
}

if(file_handle->type==ZEND_HANDLE_FP) fclose(file_handle->handle.fp);
if(file_handle->type==ZEND_HANDLE_FD) close(file_handle->handle.fd);
file_handle->handle.fp = ext_decode(fp);
file_handle->type = ZEND_HANDLE_FP;
file_handle->opened_path = expand_filepath(file_handle->filename,NULL TSRMLS_CC); 
return old_compile_file(file_handle,type TSRMLS_CC);
}
/* {{{ hello_module_entry
 */
zend_module_entry hello_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"hello",
hello_functions,
PHP_MINIT(hello),
PHP_MSHUTDOWN(hello),
PHP_RINIT(hello), /* Replace with NULL if there's nothing to do at request start */
PHP_RSHUTDOWN(hello), /* Replace with NULL if there's nothing to do at request end */
PHP_MINFO(hello),
#if ZEND_MODULE_API_NO >= 20010901
"0.1", /* Replace with version number for your extension */
#endif
STANDARD_MODULE_PROPERTIES
};
/* }}} */#ifdef COMPILE_DL_HELLO
ZEND_GET_MODULE(hello)
#endif/* {{{ PHP_INI
 */
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
    STD_PHP_INI_ENTRY("hello.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_hello_globals, hello_globals)
    STD_PHP_INI_ENTRY("hello.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_hello_globals, hello_globals)
PHP_INI_END()
*/
/* }}} *//* {{{ php_hello_init_globals
 */
/* Uncomment this function if you have INI entries
static void php_hello_init_globals(zend_hello_globals *hello_globals)
{
hello_globals->global_value = 0;
hello_globals->global_string = NULL;
}
*/
/* }}} *//* {{{ PHP_MINIT_FUNCTION
 */
PHP_MINIT_FUNCTION(hello)
{
/* If you have INI entries, uncomment these lines 
REGISTER_INI_ENTRIES();
*/


return SUCCESS;
}
/* }}} *//* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(hello)
{
/* uncomment this line if you have INI entries
UNREGISTER_INI_ENTRIES();
*/
zend_compile_file=old_compile_file;
return SUCCESS;
}
/* }}} *//* Remove if there's nothing to do at request start */
/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(hello)
{
old_compile_file = zend_compile_file;
zend_compile_file = my_compile_file;
//php_printf("hello world--1");
return SUCCESS;
}
/* }}} *//* Remove if there's nothing to do at request end */
/* {{{ PHP_RSHUTDOWN_FUNCTION
 */
PHP_RSHUTDOWN_FUNCTION(hello)
{
return SUCCESS;
}
/* }}} *//* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(hello)
{
php_info_print_table_start();
php_info_print_table_header(2, "hello support", "enabled");
php_info_print_table_end(); /* Remove comments if you have entries in php.ini
DISPLAY_INI_ENTRIES();
*/
}
/* }}} */
/* Remove the following function when you have succesfully modified config.m4
   so that your module can be compiled into PHP, it exists only for testing
   purposes. *//* Every user-visible function in PHP should document itself in the source */
/* {{{ proto string confirm_hello_compiled(string arg)
   Return a string to confirm that the module is compiled in */
PHP_FUNCTION(confirm_hello_compiled)
{
char *arg = NULL;
int arg_len, len;
char *strg; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
return;
} len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "hello", arg);
RETURN_STRINGL(strg, len, 0);
}
PHP_FUNCTION(sayHello){
php_printf("hello world");
}
/* }}} */
/* The previous line is meant for vim and emacs, so it can correctly fold and 
   unfold functions in source code. See the corresponding s just before 
   function definition, where the functions purpose is also documented. Please 
   follow this convention for the convenience of others editing your code.
*/
/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=er
 * vim<600: noet sw=4 ts=4
 */

解决方案 »

  1.   

    也就是说zend_compile_file没有被调用,或者说zend_compile_file在你赋值之前就被调用了?有没可能是解密错文件了?
      

  2.   

    不知道问题具体处在哪,只能靠猜的了
    BEGIN_EXTERN_C()
    ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
    END_EXTERN_C()
    如果每有这句则链接dll提示 unresolved external symbol _zend_compile_file就是找不到外部的这个链接符号。
    上面三句则是以c的方式来编译该函数。
    有没可能是这里出问题呢?
      

  3.   

    哈哈,楼主连发三贴,已经不能再发言了吧 :)
    我来帮你打个岔吧。虽然我不知道你这个问题到底出在哪里,但如果是我的话,我一定先解决“调试”问题,哪怕是采用最笨的办法,把调试信息输出到一个外部文件里去。总要先搞清楚程序的走向,步步为营,才好发现问题、解决问题。如果压根没有任何输出信息的话,那就很有可能是某种设置错误导致加载失败。
    ————————————————————————————————
    基于CSDN论坛提供的插件扩展功能,自己做了个签名档工具,分享给大家,欢迎技术交流 :)
      

  4.   


    如果扩展代码没问题的话,可能是并没有让PHP正确加载这个扩展,参考:[原创]快速开发一个PHP扩展 这个是LINUX下的
      

  5.   

    如果是WINDOWS下的话,使用dl函数进行加载,参考:
    dl
    (PHP 4, PHP 5)dl — Loads a PHP extension at runtime说明
    bool dl ( string $library )
    Loads the PHP extension given by the parameter library. Use extension_loaded() to test whether a given extension is already available or not. This works on both built-in extensions and dynamically loaded ones (either through php.ini or dl()). Warning 
    This function has been removed from some SAPI's in PHP 5.3. 参数library 
    This parameter is only the filename of the extension to load which also depends on your platform. For example, the sockets extension (if compiled as a shared module, not the default!) would be called sockets.so on Unix platforms whereas it is called php_sockets.dll on the Windows platform. The directory where the extension is loaded from depends on your platform: Windows - If not explicitly set in the php.ini, the extension is loaded from C:\php4\extensions\ (PHP4) or C:\php5\ (PHP5) by default. Unix - If not explicitly set in the php.ini, the default extension directory depends on whether PHP has been built with --enable-debug or not 
    whether PHP has been built with (experimental) ZTS (Zend Thread Safety) support or not 
    the current internal ZEND_MODULE_API_NO (Zend internal module API number, which is basically the date on which a major module API change happened, e.g. 20010901) 
    Taking into account the above, the directory then defaults to <install-dir>/lib/php/extensions/ <debug-or-not>-<zts-or-not>-ZEND_MODULE_API_NO, e.g. /usr/local/php/lib/php/extensions/debug-non-zts-20010901 or /usr/local/php/lib/php/extensions/no-debug-zts-20010901. 
    返回值
    成功时返回 TRUE, 或者在失败时返回 FALSE. If the functionality of loading modules is not available or has been disabled (either by setting enable_dl off or by enabling 安全模式 in php.ini) an E_ERROR is emitted and execution is stopped. If dl() fails because the specified library couldn't be loaded, in addition to FALSE an E_WARNING message is emitted. 范例Example #1 dl() examples<?php
    // Example loading an extension based on OS
    if (!extension_loaded('sqlite')) {
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            dl('php_sqlite.dll');
        } else {
            dl('sqlite.so');
        }
    }// Or, the PHP_SHLIB_SUFFIX constant is available as of PHP 4.3.0
    if (!extension_loaded('sqlite')) {
        $prefix = (PHP_SHLIB_SUFFIX === 'dll') ? 'php_' : '';
        dl($prefix . 'sqlite.' . PHP_SHLIB_SUFFIX);
    }
    ?> 
      

  6.   

    呵呵谢谢楼上二位,
    我自己琢磨了一下发现是zend_compile_file这个函数有问题unresolved external symbol _zend_compile_file (找不到这个外部符号)应该是缺少对应的lib文件,但是我又不知道是哪个(查了好久没查到)
    之前的错误主要是因为BEGIN_EXTERN_C()
    ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
    END_EXTERN_C() 没有加 extern。这样相当于重新定义了一个zend_compile_file所以链接没报错,执行的时候没有效果!
    所以现在问题又回到了unresolved external symbol _zend_compile_file这个上面
      

  7.   

    我查了一下源代码,zend_compile_file 是在 zend_compile.c 里面定义的一个变量,在 zend_compile.h 中有外部变量声明,在 zend.c 中对其进行了赋值,其它的地方都只是使用这个变量(按函数指针来调用其指向的函数)。我在 Windows 版的 PHP 运行包的 php5ts.lib 里看到有 zend_compile_file。hope it helps !
    ————————————————————————————————
    基于CSDN论坛提供的插件扩展功能,自己做了个签名档工具,分享给大家,欢迎技术交流 :)
      

  8.   

    我在php5ts.lib 里面也看到有 _zend_compile_file...
      

  9.   

    这段代码我见过linux的源码。
    他的意思是:php core把zend_execute 和 zend_compile_file定义为两个函数指针。你可以用自己的execute和cpmpile替换他们来编译执行php脚本。
    你这段代码的意思是定义一个my_compile_file函数替换zend_compile_file,在my_compile_file 里先调用你的解码函数ext_decode再用zend_compile_file编译返回。
    你可以试试这两种解决方法:
    1.尝试包含他的头文件:zend_compile_file 定义在Zend/zend_compile.h头文件中。
    2.通过ext_skel 创建一个扩展把你的源码拷贝进去编译。