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核心動態調試關於弱類型比較》