欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

从php内核角度分析php弱类型

来源:本站整理 作者:佚名 时间:2019-03-04 TAG: 我要投稿

在CTF比赛中PHP弱类型的特性常常被用上,但我们往往知其然不知其所以然,究竟为什么PHP是弱类型呢?很少人深究。在这次源码分析的过程中我收获很大,第一次学会了如何深入理解一个问题,虽然花费了我很多时间,但这可以说是一段非常值得的经历。
 
正文
首先引入一个问题,为什么以下结果是恒为真的呢?
var_dump([]>1);
var_dump([]>0);
var_dump([]>-1);
当然实际ctf中问题可能会如下
$_GET[Password]>99999;
当传入Password[]=1
时侯恒为真
当然再换一种形式
var_dump([[]]>[1]);
依旧是恒为真
对于这类问题,很多人都是认为PHP因为它是弱类型语言它就有这种特性
那么为什么PHP会有这种特性呢?
我们首先查阅下PHP手册
http://php.net/manual/en/language.operators.comparison.php#language.operators.comparison.types

在手册中写到,当array和anything进行比较的时候array is always greater
这是一种PHP的定义。
那么究竟PHP到底在哪定义了这种特点呢?
我们依旧不知道。
我们再抛出个问题究竟什么是PHP弱类型呢?
很多人可能会回答弱类型就是弱类型,当传入Password[]=1就会绕过这就是弱类型
这种回答肯定是不妥当的
具体弱类型定义
PHP是弱类型语言,不需要明确的定义变量的类型,变量的类型根据使用时的上下文所决定,也就是变量会根据不同表达式所需要的类型自动转换,比如求和,PHP会将两个相加的值转为long、double再进行加和。每种类型转为另外一种类型都有固定的规则,当某个操作发现类型不符时就会按照这个规则进行转换,这个规则正是弱类型实现的基础。
我们再通过查阅PHP源码来深刻理解PHP弱类型的特点
PHP是开源的一种语言,我们在Github上可以很容易的查询到它的源码
传送门
这里找函数会方便点
当然解释下什么是Zend
Zend是PHP语言实现的最为重要的部分,是PHP最基础、最核心的部分,它的源码在/Zend目录下,PHP代码从编译到执行都是由Zend完成的
至于为什么要查询zend_operators.h这个文件,operator操作符,其他几个文件不像存在比较函数,有的时候查源码时候就是需要靠感觉,这种大项目 函数变量什么的都有规范 一般所见即所得 看懂英语就大概猜得到用途的,
当然这个文件也不一般
我再进行解释下,当然想深入理解可以看这里
PHP在内核中是通过zval这个结构体来存储变量的,它的定义在Zend/zend.h文件里,简短精炼,只有四个成员组成:
我们定位到函数
ZEND_API int ZEND_FASTCALL is_smaller_function(zval result, zval op1, zval *op2);
这里传入了两个值op1,op2,传出一个result
解释下zval类型
zval以一个P结尾的宏的参数大多是zval型变量。 此外获取变量类型的宏还有两个,分别是Z_TYPE和Z_TYPE_PP,前者的参数是zval型,而后者的参数则是*zval。
这样说可能会有些抽象
我们换种方式解释,当再php源码中要想判断一个变量的类型最直接的方式,比如想判断这个变量是否为空
变量->type == IS_NULL
这种方法虽然是正确的,但PHP官网并不建议这么做,PHP中定义了大量的宏,供我们检测、操作变量使用
解释下什么是宏
C语言中允许用一个标识符来标识一个字符串,称为“宏”;标识符为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义时的字符串去代换,简称“宏代换”或“宏展开”。一般形式:#define 宏名 字符串
宏定义说明及注意:
宏定义时用宏名来表示一个字符串,在宏展开时又以该字符串替换了宏名,这只是一个简单的替换;宏定义不需要再行末加分号,若加上分号,则会连分号也会被替换的;宏定义必须在函数外面;宏定义的作用域:从定义命令至程序结束,若想终止宏的作用域,则使用undef命令;宏名在程序中用引号括起来,则预处理程序对其不进行宏替换;宏定义是可以嵌套使用的,在展开时,由预处理程序层层替换;建议在进行宏定义时,尽量使用大写字母表示宏名;可用宏来表示数据类型,使书写方便;对“输出格式”做用定义,可以减少书写麻烦。
PHP建议使用的形式
Z_TYPE_P(变量) == IS_NULL
以一个P结尾的宏的参数大多是zval型变量。 此外获取变量类型的宏还有两个,分别是Z_TYPE和Z_TYPE_PP,前者的参数是zval型,而后者的参数则是*zval
这样我们便可以猜测一下php内核是如何实现gettype这个函数了,代码如下:想要详细了解的可以看这里
//开始定义php语言中的函数gettype
PHP_FUNCTION(gettype)
{
    //arg间接指向调用gettype函数时所传递的参数。是一个zval**结构
    //所以我们要对他使用__PP后缀的宏。
    zval **arg;
    //这个if的操作主要是让arg指向参数~
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
        return;
    }
    //调用Z_TYPE_PP宏来获取arg指向zval的类型。
    //然后是一个switch结构,RETVAL_STRING宏代表这gettype函数返回的字符串类型的值
    switch (Z_TYPE_PP(arg)) {
        case IS_NULL:
            RETVAL_STRING("NULL", 1);
            break;
        case IS_BOOL:
            RETVAL_STRING("boolean", 1);

[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载