激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - PHP教程 - 如何使用PHP Embed SAPI實現Opcodes查看器

如何使用PHP Embed SAPI實現Opcodes查看器

2020-11-30 16:17PHP教程網 PHP教程

這篇文章主要介紹了如何使用PHP Embed SAPI實現Opcodes查看器的相關資料,需要的朋友可以參考下

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腳本解析器了, 我的例子:

?
1
2
3
4
5
6
7
8
9
#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

?
1
2
3
4
5
6
7
8
9
CC = gcc
CFLAGS = -I/usr/local/include/php/ \
   -I/usr/local/include/php/main \
   -I/usr/local/include/php/Zend \
   -I/usr/local/include/php/TSRM \
   -Wall -g
LDFLAGS = -lstdc++ -L/usr/local/lib -lphp5
ALL:
 $(CC) -o embed embed.cpp $(CFLAGS) $(LDFLAGS)

編譯成功以后, 運行,我們可以看到, stdout輸出 Hello World!

基于這個,我們就可以很容易的實現一個類似于vld的Opcodes dumper:
首先我們定義opcode的轉換函數(全部的opcodes可以查看Zend/zend_vm_opcodes.h);

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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的輸出函數:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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的輸出函數:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);
  }
 }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main(int argc, char **argv){
 zend_op_array *op_array;
 zend_file_handle file_handle;
 if(argc != 2) {
  printf("usage: op_dumper <script>\n");
  return 1;
 }
 PHP_EMBED_START_BLOCK(argc,argv);
 printf("Script: %s\n", argv[1]);
 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);
 if(!op_array) {
  printf("Error parsing script: %s\n", file_handle.filename);
  return 1;
 }
 dump_op_array(op_array);
 PHP_EMBED_END_BLOCK();
 return 0;
}

編譯,運行測試腳本(sample.php):

 

復制代碼 代碼如下:

sample.php:
   echo "laruence";

 

命令:

 

復制代碼 代碼如下:

./opcodes_dumper  sample.php

 

得到輸出結果(如果你對下面的結果很迷惑,那么建議你再看看我的這篇文章:深入理解PHP原理之Opcodes):

Script: sample.php

opnum   line                         opcode                                      op1                                      op2                                   result
    0      2                      ZEND_ECHO                               "laruence"
    1      4                    ZEND_RETURN                                        1

呵呵,怎么樣,是不是很好玩呢?

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久国产28 | av在线日韩| 一级黄色国产视频 | 欧美性生活区 | 国产在线观看福利 | 中文成人在线 | 欧美乱淫| 精品国产呦系列在线看 | 男女一边摸一边做羞羞视频免费 | 精品一区二区三区在线视频 | 亚洲精品一区二区三区在线看 | xxxx69hd一hd72 | 国产污网站在线观看 | 久久老司机精品视频 | 成人免费淫片 | 亚洲av一级毛片特黄大片 | 国产色91| 午夜影院在线免费观看 | 一区二区三区小视频 | 欧美成人精品欧美一级 | 欧美激情精品久久久久久黑人 | 精品国产一区二区三区天美传媒 | 日本网站在线播放 | 久久精品国产99国产精品澳门 | 欧美a视频在线观看 | 亚洲国产精品久久久久久久久久久 | 欧美成人一区二区三区 | 久久久久久久久久综合 | 涩涩99| 国产一级在线看 | 国产永久免费观看 | 国产午夜亚洲精品 | 国产免费成人 | 中文字幕精品在线观看 | av电影免费观看 | 欧美视频一区二区 | 日本中文字幕高清 | 日本高清黄色片 | 日韩精品一区二区亚洲 | 久久精品黄 | 午夜精品区 |