您好,欢迎访问一九零五行业门户网

[科普小文章]php内核动态调试关于弱类型比较

0x00 前言
上期的三个白帽挑战题已经结束,但是大家依旧意犹未尽,讨论着 writeup 中的知识点,其中比较有意思的是关于php弱类型的:
array(0)>999999999
这个结果是true的。
群里各位大牛给了各种思考,和相关文章:
php.net/manual/zh/language.operators.comparison.php
但是基本都是别人给出的结论,我不太喜欢结论性的东西,这只让我知道了结果,并不知道为什么有这样的结果。
0x01 php动态调试(php5.6为例)
1.下载解压并安装
# wget http://cn2.php.net/distributions/php-5.6.0.tar.xz # xz -d php-5.6.0.tar.xz # tar vxf php-5.6.0.tar # cd php-5.6.0 # ./configure --enable-debug # make # sudo make install
2.相关文章推荐
《深入理解zend执行引擎(php5)》
《使用vld查看opcode》
《调式php源码》
0x02 opcode分析
可以看出关键操作是is_smaller,如果你仔细看过上面推荐文章就可以找到关键函数
zend_api int compare_function(zval *result, zval *op1, zval *op2 tsrmls_dc) /* {{{ */
0x03 gdb动态调试
注意红框内容,相信看过上边内容的都能看懂(ps:详细内容太多,请先学习推荐文章)
大致逻辑是两个参数进来经过zendi_convert_scalar_to_number函数处理,由于我们一个是数组一个是整形,所以两个参数类型和值都不变
#define zendi_convert_scalar_to_number(op, holder, result) if (op==result) { if (z_type_p(op) != is_long) { convert_scalar_to_number(op tsrmls_cc); } } else { switch (z_type_p(op)) { case is_string: { if ((z_type(holder)=is_numeric_string(z_strval_p(op), z_strlen_p(op), &z_lval(holder), &z_dval(holder), 1)) == 0) { zval_long(&(holder), 0); } (op) = &(holder); break; } case is_bool: case is_resource: zval_long(&(holder), z_lval_p(op)); (op) = &(holder); break; case is_null: zval_long(&(holder), 0); (op) = &(holder); break; case is_object: (holder) = (*(op)); zval_copy_ctor(&(holder)); convert_to_long_base(&(holder), 10); if (z_type(holder) == is_long) { (op) = &(holder); } break; } }
然后再次进入循环到达
} else if (z_type_p(op1)==is_array) { zval_long(result, 1); return success; } else if (z_type_p(op2)==is_array) { zval_long(result, -1); return success;
从opcode可以看到op2为array(0)所以这儿返回-1
最后(z_lval_p(result) < 0)成立,返回true
if (compare_function(result, op1, op2 tsrmls_cc) == failure) { return failure; } zval_bool(result, (z_lval_p(result) < 0)); return success;
转载请注明来自 l.n.'s blog 的《[科普小文章]php内核动态调试关于弱类型比较》
其它类似信息

推荐信息