侯体宗的博客
  • 首页
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

如何使用PHP Embed SAPI实现Opcodes查看器

php  /  管理员 发布于 7年前   140

PHP提供了一个Embed SAPI,也就是说,PHP容许你在C/C++语言中调用PHP/ZE提供的函数。本文就通过基于Embed SAPI实现一个PHP的opcodes查看器。

首先,下载PHP源码以供编译, 我现在使用的是PHP5.3 alpha2

进入源码目录:

 ./configure --enable-embed --with-config-file-scan-dir=/etc/php.d --with-mysql  --with-config-file-path=/etc/
 ./make
 ./make install

最后,记得要将生成的libphp5.so复制到运行时库的目录,我直接拷贝到了/lib/, 否则会在运行你自己的embed程序的时候报错:

./embed: error while loading shared libraries: libphp5.so: cannot open shared object file: No such file or directory

如果你对PHP的SAPI还不熟悉的话,我建议你看看我的这篇文章:深入理解Zend SAPIs(Zend SAPI Internals)
这个时候,你就可以在你的C代码中,嵌入PHP脚本解析器了, 我的例子:

#include "sapi/embed/php_embed.h"int main(int argc, char * argv[]){ PHP_EMBED_START_BLOCK(argc,argv); char * script = " print 'Hello World!';"; zend_eval_string(script, NULL,          "Simple Hello World App" TSRMLS_CC); PHP_EMBED_END_BLOCK(); return 0;}

然后就是要指明include path了,一个简单的Makefile

CC = gccCFLAGS = -I/usr/local/include/php/ \   -I/usr/local/include/php/main \   -I/usr/local/include/php/Zend \   -I/usr/local/include/php/TSRM \   -Wall -gLDFLAGS = -lstdc++ -L/usr/local/lib -lphp5ALL: $(CC) -o embed embed.cpp $(CFLAGS) $(LDFLAGS)

编译成功以后, 运行,我们可以看到, stdout输出 Hello World!

基于这个,我们就可以很容易的实现一个类似于vld的Opcodes dumper:
首先我们定义opcode的转换函数(全部的opcodes可以查看Zend/zend_vm_opcodes.h);

char *opname(zend_uchar opcode){ switch(opcode) {  case ZEND_NOP: return "ZEND_NOP"; break;  case ZEND_ADD: return "ZEND_ADD"; break;  case ZEND_SUB: return "ZEND_SUB"; break;  case ZEND_MUL: return "ZEND_MUL"; break;  case ZEND_DIV: return "ZEND_DIV"; break;  case ZEND_MOD: return "ZEND_MOD"; break;  case ZEND_SL: return "ZEND_SL"; break;  case ZEND_SR: return "ZEND_SR"; break;  case ZEND_CONCAT: return "ZEND_CONCAT"; break;  case ZEND_BW_OR: return "ZEND_BW_OR"; break;  case ZEND_BW_AND: return "ZEND_BW_AND"; break;  case ZEND_BW_XOR: return "ZEND_BW_XOR"; break;  case ZEND_BW_NOT: return "ZEND_BW_NOT"; break;  /*...省略 ....*/  default : return "UNKNOW"; break;

然后定义zval和znode的输出函数:

 char *format_zval(zval *z){ static char buffer[BUFFER_LEN]; int len; switch(z->type) {  case IS_NULL:   return "NULL";  case IS_LONG:  case IS_BOOL:   snprintf(buffer, BUFFER_LEN, "%d", z->value.lval);   return buffer;  case IS_DOUBLE:   snprintf(buffer, BUFFER_LEN, "%f", z->value.dval);   return buffer;  case IS_STRING:   snprintf(buffer, BUFFER_LEN, "\"%s\"", z->value.str.val);   return buffer;  case IS_ARRAY:  case IS_OBJECT:  case IS_RESOURCE:  case IS_CONSTANT:  case IS_CONSTANT_ARRAY:   return "";  default:   return "unknown"; }}char * format_znode(znode *n){ static char buffer[BUFFER_LEN]; switch (n->op_type) {  case IS_CONST:   return format_zval(&n->u.constant);   break;  case IS_VAR:   snprintf(buffer, BUFFER_LEN, "$%d", n->u.var/sizeof(temp_variable));   return buffer;   break;  case IS_TMP_VAR:   snprintf(buffer, BUFFER_LEN, "~%d", n->u.var/sizeof(temp_variable));   return buffer;   break;  default:   return "";   break; }}

 然后定义op_array的输出函数:

void dump_op(zend_op *op, int num){ printf("%5d %5d %30s %040s %040s %040s\n", num, op->lineno,   opname(op->opcode),   format_znode(&op->op1),   format_znode(&op->op2),   format_znode(&op->result)) ;}void dump_op_array(zend_op_array *op_array){ if(op_array) {  int i;  printf("%5s %5s %30s %040s %040s %040s\n", "opnum", "line", "opcode", "op1", "op2", "result");  for(i = 0; i < op_array->last; i++) {   dump_op(&op_array->opcodes[i], i);  } }}

最后,就是程序的主函数了:

int main(int argc, char **argv){ zend_op_array *op_array; zend_file_handle file_handle; if(argc != 2) {  printf("usage: op_dumper 
								
  • 分类目录
  • 人生(杂谈)
  • 技术
  • linux
  • Java
  • php
  • 框架(架构)
  • 前端
  • ThinkPHP
  • 数据库
  • 微信(小程序)
  • Laravel
  • Redis
  • Docker
  • Go
  • swoole
  • Windows
  • Python
  • 苹果(mac/ios)
  • 相关文章
  • Laravel从Accel获得5700万美元A轮融资(0个评论)
  • PHP 8.4 Alpha 1现已发布!(0个评论)
  • 用Time Warden监控PHP中的代码处理时间(0个评论)
  • 在PHP中使用array_pop + yield实现读取超大型目录功能示例(0个评论)
  • Property Hooks RFC在PHP 8.4中越来越接近现实(0个评论)
  • 近期文章
  • 在windows10中升级go版本至1.24后LiteIDE的Ctrl+左击无法跳转问题解决方案(0个评论)
  • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
  • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
  • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
  • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
  • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
  • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
  • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
  • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(95个评论)
  • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
  • 近期评论
  • 122 在

    学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
  • 123 在

    Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
  • 原梓番博客 在

    在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
  • 博主 在

    佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
  • 1111 在

    佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
  • 2016-10
  • 2016-11
  • 2017-06
  • 2017-07
  • 2017-08
  • 2017-09
  • 2017-11
  • 2017-12
  • 2018-01
  • 2018-02
  • 2018-03
  • 2020-03
  • 2020-04
  • 2020-05
  • 2020-06
  • 2020-07
  • 2020-09
  • 2021-02
  • 2021-03
  • 2021-04
  • 2021-05
  • 2021-06
  • 2021-07
  • 2021-08
  • 2021-09
  • 2021-10
  • 2021-11
  • 2021-12
  • 2022-01
  • 2022-02
  • 2022-05
  • 2022-06
  • 2022-07
  • 2022-08
  • 2022-09
  • 2022-10
  • 2022-11
  • 2022-12
  • 2023-01
  • 2023-02
  • 2023-03
  • 2023-04
  • 2023-05
  • 2023-06
  • 2023-07
  • 2023-08
  • 2023-09
  • 2023-10
  • 2023-11
  • 2023-12
  • 2024-01
  • 2024-02
  • 2024-03
  • 2024-04
  • 2024-05
  • 2024-06
  • 2024-07
  • 2024-09
Top

Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

侯体宗的博客