Zend引擎安全调试分析基础(PHP7.3.6)
思路
示例代码
# sample.php
<?php
$a = 10;
print_r($a);
?>调试过程
gdb --args /usr/local/php7.3/bin/php sample.phpgef➤ b main Breakpoint 1 at 0x944380: file /opt/php_code/php-7.3.6/sapi/cli/php_cli.c, line 1188. gef➤ r
=image-20241108153106790 gef➤ b php_execute_script Breakpoint 2 at 0x58751dbca9bf: file /opt/php_code/php-7.3.6/main/main.c, line 2537. gef➤ c

gef➤ b zend_execute_scripts Breakpoint 3 at 0x58751dc655b5: file /opt/php_code/php-7.3.6/Zend/zend.c, line 1549.

struct _zend_op_array { /* Common elements */ zend_uchar type; zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string *function_name; zend_class_entry *scope; zend_function *prototype; uint32_t num_args; uint32_t required_num_args; zend_arg_info *arg_info; /* END of common elements */ int cache_size; /* number of run_time_cache_slots * sizeof(void*) */ int last_var; /* number of CV variables */ uint32_t T; /* number of temporary variables */ uint32_t last; /* number of opcodes */ zend_op *opcodes; void **run_time_cache; HashTable *static_variables; zend_string **vars; /* names of CV variables */ uint32_t *refcount; int last_live_range; int last_try_catch; zend_live_range *live_range; zend_try_catch_element *try_catch_array; zend_string *filename; uint32_t line_start; uint32_t line_end; zend_string *doc_comment; int last_literal; zval *literals; void *reserved[ZEND_MAX_RESERVED_RESOURCES]; };

gef➤ print *op_array
gef➤ print op_array->opcodes[0]
struct _zend_op { const void *handler; znode_op op1; znode_op op2; znode_op result; uint32_t extended_value; uint32_t lineno; zend_uchar opcode; zend_uchar op1_type; zend_uchar op2_type; zend_uchar result_type; };
# cat -n sample.php 1 <?php 2 $a = 10; 3 print_r($a); 4 ?>

handler = 0x58751dd3fa12 <execute_ex+19145>gef➤ x/i 0x58751dd3fa12 0x58751dd3fa12 <execute_ex+19145>: call 0x58751dd254a0 <ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLER>

typedef struct _zval_struct zval;struct _zval_struct { zend_value value; /* value */ union { struct { ZEND_ENDIAN_LOHI_3( zend_uchar type, /* active type */ zend_uchar type_flags, union { uint16_t call_info; /* call info for EX(This) */ uint16_t extra; /* not further specified */ } u) } v; uint32_t type_info; } u1; union { uint32_t next; /* hash collision chain */ uint32_t cache_slot; /* cache slot (for RECV_INIT) */ uint32_t opline_num; /* opline number (for FAST_CALL) */ uint32_t lineno; /* line number (for ast nodes) */ uint32_t num_args; /* arguments number for EX(This) */ uint32_t fe_pos; /* foreach position */ uint32_t fe_iter_idx; /* foreach iterator index */ uint32_t access_flags; /* class constant access flags */ uint32_t property_guard; /* single property guard */ uint32_t constant_flags; /* constant flags */ uint32_t extra; /* not further specified */ } u2; };typedef union _zend_value { zend_long lval; /* long value */ double dval; /* double value */ zend_refcounted *counted; zend_string *str; zend_array *arr; zend_object *obj; zend_resource *res; zend_reference *ref; zend_ast_ref *ast; zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; struct { uint32_t w1; uint32_t w2; } ww; } zend_value;gef➤ print *value $2 = { value = { lval = 0xa, dval = 4.9406564584124654e-323, counted = 0xa, str = 0xa, arr = 0xa, obj = 0xa, res = 0xa, ref = 0xa, ast = 0xa, zv = 0xa, ptr = 0xa, ce = 0xa, func = 0xa, ww = { w1 = 0xa, w2 = 0x0 } }, u1 = { v = { type = 0x4, type_flags = 0x0, u = { call_info = 0x0, extra = 0x0 } }, type_info = 0x4 }, u2 = { next = 0x0, cache_slot = 0x0, opline_num = 0x0, lineno = 0x0, num_args = 0x0, fe_pos = 0x0, fe_iter_idx = 0x0, access_flags = 0x0, property_guard = 0x0, constant_flags = 0x0, extra = 0x0 } }if (ZEND_CONST_COND(value_type & (IS_VAR|IS_CV), 1) && Z_ISREF_P(value))static zend_always_inline zend_uchar zval_get_type(const zval* pz) { return pz->u1.v.type; }


# define Z_TYPE_INFO_REFCOUNTED(t) (((t) & Z_TYPE_FLAGS_MASK) != 0)static zend_always_inline uint32_t zend_gc_addref(zend_refcounted_h *p) { ZEND_RC_MOD_CHECK(p); return ++(p->refcount); }gef➤ print &variable_ptr->value->counted->gc->refcount $8 = (uint32_t *) 0xa
#define ZEND_VM_NEXT_OPCODE_EX(check_exception, skip) \ CHECK_SYMBOL_TABLES() \ if (check_exception) { \ OPLINE = EX(opline) + (skip); \ } else { \ OPLINE = opline + (skip); \ } \ ZEND_VM_CONTINUE()#define HYBRID_NEXT() goto *(void**)(OPLINE->handler)
Last updated