如何使用PHP嵌入SAPI实现操作码查看器

如何使用PHP嵌入SAPI实现操作码查看器
PHP提供了一个嵌入的SAPI,这意味着PHP允许你调用由C或C++语言PHP /泽提供的功能,本文实现了一个基于PHP操作码查看器嵌入SAPI。
首先,下载编译PHP源代码,和我使用PHP5.3α2
输入目录

配置文件扫描与文件配置文件一起进行配置。

/制作

安装

最后,记得要复制生成的libphp5.so的运行时库的目录,我直接复制到/lib /,否则会报告错误当你运行你自己的嵌入式程序

。 /嵌入:加载共享库时出错:libphp5.so:不能打开共享对象文件:

如果你不熟悉PHP SAPI,我建议你看看我的文章:对Zend SAPIs有深刻的理解(Zend SAPI内部)

此时,您可以在您的C代码中嵌入PHP脚本解析器,这是我的示例:
#包括 / / php_embed SAPI嵌入。H
int main(int argc、argv { } { char *)
php_embed_start_block(argc、argv);
char *脚本=print'hello世界!;
zend_eval_string(脚本、空,
简单的Hello World程序tsrmls_cc);
php_embed_end_block();
返回0;
}

然后你要指出包括路径,一个简单的makefile
CC = GCC
CFLAGS =我/ usr / / /当地包括PHP /
我/ usr / / /当地包括PHP /主要
我/ usr / / /当地包括PHP Zend /
我/ usr / / /当地包括PHP / TSRM
-墙- G
lstdc LDFLAGS建立= - + L / usr /局部/库lphp5
所有:
o嵌入(CC)embed.cpp美元$(CFLAGS)$(LDFLAGS建立)
在编译成功,运行,我们可以看到,stdout输出hello world!

基于此,我们可以很容易地实现一个操作码翻车机类似VLD:

首先,我们定义操作码转换功能(所有的操作码,可以看到Zend / zend_vm_opcodes。H);
char * opname(zend_uchar码){
开关(码){
案例zend_nop:返回zend_nop ;打破;
案例zend_add:返回zend_add ;打破;
案例zend_sub:返回zend_sub ;打破;
案例zend_mul:返回zend_mul ;打破;
案例zend_div:返回zend_div ;打破;
案例zend_mod:返回zend_mod ;打破;
案例zend_sl:返回zend_sl ;打破;
案例zend_sr:返回zend_sr ;打破;
案例zend_concat:返回zend_concat ;打破;
案例zend_bw_or:返回zend_bw_or ;打破;
案例zend_bw_and:返回zend_bw_and ;打破;
案例zend_bw_xor:返回zend_bw_xor ;打破;
案例zend_bw_not:返回zend_bw_not ;打破;
…*省略号…
默认值:返回未知;打破;
然后机制及其Znode输出函数定义:
char * format_zval(zval * Z)
{
静态数据的缓冲区buffer_len } {;
Int len;
开关(Z >类型){
案例is_null:
返回null;
案例is_long:
案例is_bool:
Snprintf(缓冲区,buffer_len,%d
返回缓冲区;
案例is_double:
Snprintf(缓冲区,buffer_len,% F
返回缓冲区;
案例is_string:
Snprintf(缓冲区,buffer_len,%s
返回缓冲区;
案例is_array:
案例is_object:
案例is_resource:
案例is_constant:
案例is_constant_array:
返回;
违约:
返回未知;
}
}
char * format_znode(znode×n){
静态数据的缓冲区buffer_len } {;
开关(n>op_type){
案例is_const:
返回format_zval(n>u.constant);
打破;
案例is_var:
Snprintf(缓冲区,buffer_len,$ % d
返回缓冲区;
打破;
案例is_tmp_var:
Snprintf(缓冲区,buffer_len,~ %d
返回缓冲区;
打破;
违约:
返回;
打破;
}
}
然后op_array输出函数的定义:
无效dump_op(zend_op *运算,int Num){
printf(% % % % 5d 5d 30s 040s % 040s % 040s
Opname(OP ->码),
format_znode(OP -> OP1),
format_znode(OP -> OP2),
format_znode(OP ->结果));
}
无效dump_op_array(zend_op_array * op_array){
如果(op_array){
int i;
printf(% % % % 5s 5s 30s 040s % 040s % 040s
为(i = 0;我最后;i + +){
dump_op(op_array ->操作码,{我},我);
}
}
}

最后,程序的主要功能是:
int main(int argc、argv char *){
zend_op_array * op_array;
zend_file_handle file_handle;
如果(argc!= 2){
printf(用法:op_dumper ;
返回1;
}
php_embed_start_block(argc、argv);
Printf (script:%s
file_handle.filename = argv { 1 };
file_handle.free_filename = 0;
file_handle.type = zend_handle_filename;
file_handle.opened_path = null;
op_array = zend_compile_file(file_handle,zend_include tsrmls_cc);
如果(!op_array){
printf(分析脚本时出错:%s
返回1;
}
dump_op_array(op_array);
php_embed_end_block();
返回0;
}

编译、运行测试脚本(示例PHP):

复制代码代码如下所示:

Sample.php:

回声laruence ;
秩序:

复制代码代码如下所示:

opcodes_dumper sample.php /。
得到的输出(如果你困惑的下面,结果那就建议你看我的文章:一看PHP的原则操作码的深刻理解):

脚本:sample.php
opnum线码OP1 OP2的结果

02 zend_echolaruence

14 zend_return 1

哦,怎么了不是很有趣吗
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部