417 12
发新话题
打印

[Zend Other] dezend 实战 - ZEND反编译之路

本主题由 cfan 于 2008-3-17 10:39 设置高亮
执行引擎

struct _zend_executor_globals {
zval **return_value_ptr_ptr;

zval uninitialized_zval;
zval *uninitialized_zval_ptr;

zval error_zval;
zval *error_zval_ptr;

zend_function_state *function_state_ptr;
zend_ptr_stack arg_types_stack;

/* symbol table cache */
HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
HashTable **symtable_cache_limit;
HashTable **symtable_cache_ptr;

zend_op **opline_ptr;

zend_execute_data *current_execute_data;

HashTable *active_symbol_table;
HashTable symbol_table; /* main symbol table */

HashTable included_files; /* files already included */

jmp_buf bailout;

int error_reporting;
int orig_error_reporting;
int exit_status;

zend_op_array *active_op_array;
函数符号表
HashTable *function_table; /* function symbol table */
HashTable *class_table; /* class table */
HashTable *zend_constants; /* constants table */

long precision;

int ticks_count;

zend_bool in_execution;
zend_bool bailout_set;
zend_bool full_tables_cleanup;

/* for extended information support */
zend_bool no_extensions;

#ifdef ZEND_WIN32
zend_bool timed_out;
#endif

HashTable regular_list;
HashTable persistent_list;

zend_ptr_stack argument_stack;
int free_op1, free_op2; //分别对应PHP4 PHP5的操作码是否应该释放掉
int (*unary_op)(zval *result, zval *op1);
int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC);

zval *garbage[2];
int garbage_ptr;

zval *user_error_handler;
zend_ptr_stack user_error_handlers;

/* timeout support */
int timeout_seconds;

int lambda_count;

HashTable *ini_directives;

void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};
一個偽裝成白癡的天纔!

TOP

zend_hash_update(
CG(function_table),
opline->op1.u.constant.value.str.val,
opline->op1.u.constant.value.str.len,
&op_array,
sizeof(zend_op_array),
(void **) &CG(active_op_array)
);

这也应该是Optimizer与源码的区别
源码使用zend_hash_update
Optimizer使用zend_hash_quick_update

#define zend_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest) \
zend_hash_add_or_update(ht, arKey, nKeyLength, pData, nDataSize, pDest, HASH_UPDATE)

ZEND_API int zend_hash_add_or_update(
HashTable *ht, 函数表
char *arKey, 函数名
uint nKeyLength, 函数名长度
void *pData, 函数内部实现的操作码
uint nDataSize, 操作码大小
void **pDest, 与当前活动的函数操作码连接起来,从而可让函数找到它内部的实现
int flag)

解析执行时
从函数表中查找也是采用
zend_hash_quick_find而不是zend_hash_find
一個偽裝成白癡的天纔!

TOP

如何找到一个函数内部的操作码

zval *fname = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);

if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) {
zend_error(E_ERROR, "Unknown function: %s()", fname->value.str.val);
}

EX(opline)->opcode 当前执行的操作码

typedef struct _zend_execute_data {
zend_op *·opline; //当前操作码
zend_function_state function_state; // 函数状态
zend_function *fbc; /* Function Being Called */
zend_class_entry *ce;
object_info object;
temp_variable *Ts; //临时变量
zend_bool original_in_execution;
zend_op_array *op_array; //操作码数组
struct _zend_execute_data *prev_execute_data; //前一个执行单元
} zend_execute_data;

typedef struct _zend_op {
zend_uchar opcode; //操作码,Optimizer与Zend引擎是不一致的
znode result;
znode op1; //PHP4的 znode
znode op2;
ulong extended_value;
uint lineno;
} zend_op;


关于变量类型的一些信息
typedef struct _znode {
int op_type; //常量,还是变量,临时变量
union {
zval constant;

zend_uint var;
zend_uint opline_num; /* Needs to be signed */
zend_uint fetch_type;
zend_op_array *op_array;
struct {
zend_uint var; /* dummy */
zend_uint type;
} EA;
} u;
} znode;
znode记录一个变量的属性,函数名,变量名,类名

从znode中找到函数名/变量名


static inline zval *_get_zval_ptr(znode *node, temp_variable *Ts, int *should_free TSRMLS_DC)
{
switch(node->op_type) {
case IS_CONST:
*should_free = 0;
return &node->u.constant;
break;
case IS_TMP_VAR:
*should_free = 1;
return &Ts[node->u.var].tmp_var;
break;
case IS_VAR:
if (Ts[node->u.var].var.ptr) {
PZVAL_UNLOCK(Ts[node->u.var].var.ptr);
*should_free = 0;
return Ts[node->u.var].var.ptr;
} else {
*should_free = 1;

switch (Ts[node->u.var].EA.type) {
case IS_OVERLOADED_OBJECT:
Ts[node->u.var].tmp_var = get_overloaded_property(&Ts[node->u.var] TSRMLS_CC);
Ts[node->u.var].tmp_var.refcount=1;
Ts[node->u.var].tmp_var.is_ref=1;
return &Ts[node->u.var].tmp_var;
break;
case IS_STRING_OFFSET: {
temp_variable *T = &Ts[node->u.var];
zval *str = T->EA.data.str_offset.str;

if (T->EA.data.str_offset.str->type != IS_STRING
|| (T->EA.data.str_offset.offset<0)
|| (T->EA.data.str_offset.str->value.str.len <= T->EA.data.str_offset.offset)) {
zend_error(E_NOTICE, "Uninitialized string offset: %d", T->EA.data.str_offset.offset);
T->tmp_var.value.str.val = empty_string;
T->tmp_var.value.str.len = 0;
} else {
char c = str->value.str.val[T->EA.data.str_offset.offset];

T->tmp_var.value.str.val = estrndup(&c, 1);
T->tmp_var.value.str.len = 1;
}
PZVAL_UNLOCK(str);
T->tmp_var.refcount=1;
T->tmp_var.is_ref=1;
T->tmp_var.type = IS_STRING;
return &T->tmp_var;
}
break;
}
}
break;
case IS_UNUSED:
*should_free = 0;
return NULL;
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
return NULL;
}


函数状态

typedef struct _zend_function_state {
HashTable *function_symbol_table;
zend_function *function;
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
} zend_function_state;
一個偽裝成白癡的天纔!

TOP

EG中的
zend_op_array *active_op_array;


EX中
zend_op_array *op_array; //操作码数组

是不是一样的 


看一下操作码数组的结构

struct _zend_op_array {
zend_uchar type; /* MUST be the first element of this struct! */

zend_uchar *arg_types; /* MUST be the second element of this struct! */
char *function_name; /* MUST be the third element of this struct! */

zend_uint *refcount;

zend_op *opcodes; //第一个操作码指针
zend_uint last, size;

zend_uint T;

zend_brk_cont_element *brk_cont_array;
zend_uint last_brk_cont;
zend_uint current_brk_cont;
zend_bool uses_globals;

/* static variables support */
HashTable *static_variables;

zend_op *start_op;
int backpatch_count;

zend_bool return_reference;
zend_bool done_pass_two;

char *filename;

void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};
一個偽裝成白癡的天纔!

TOP

可以使vld能够dump出函数内部的opcode

zend_function *function_ptr;

if (op_temp->opcode == ZEND_DO_FCALL) {
zval *fname = &(op_temp->op1.u.constant);
fprintf(stderr, "call function: %s()\n", fname->value.str.val);
zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &function_ptr);
if (function_ptr->type == ZEND_USER_FUNCTION) {
fprintf(stderr, "It's User Function\n");
vld_dump_oparray((zend_op_array *) function_ptr);
}
}
一個偽裝成白癡的天纔!

TOP

awatch executor_globals.in_execution
跟踪 zend_excute

awatch executor_globals.opline_ptr

===========================
zval_ptr_dtor(&retval);

ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC)
{
#if DEBUG_ZEND>=2
printf("Reducing refcount for %x (%x): %d->%d\n", *zval_ptr, zval_ptr, (*zval_ptr)->refcount, (*zval_ptr)->refcount-1);
#endif
(*zval_ptr)->refcount--;
if ((*zval_ptr)->refcount==0) {
zval_dtor(*zval_ptr);
safe_free_zval_ptr(*zval_ptr);
} else if (((*zval_ptr)->refcount == 1) && ((*zval_ptr)->type != IS_OBJECT)) {
(*zval_ptr)->is_ref = 0;
}
}
一個偽裝成白癡的天纔!

TOP

目前国内掌握了dezend的,应该再加上一个
http://www.mmscn.org/index.php?showforum=18

TOP

 417 12
发新话题