现在这么卷,学个java都要精通jvm。所以学习php还是要了解了解底层的,下面简单介绍一下php源码的编译。
环境配置和简单调试
首先需要Vistual Studio 2019,在网上随便下载一个就可。
为什么不推荐别的,因为有可能缺少环境,导致要单独去配置环境,非常不方便。
php源码下载:https://windows.php.net/downloads/releases/archives/
选择一个对应的版本就可。
将源码解压到一个名字好一点的文件夹下面,执行VS给的命令行程序。
x64 Native Tools Command Prompt for VS 2019
可以看到出现了没有bison命令的问题,这里需要在网站上下载一个带bison的exe可执行文件。
http://gnuwin32.sourceforge.net/packages/bison.htm
安装bison后,会自动添加该文件的环境变量,可以输入这个命令进行尝试。
重新执行configure.bat进行配置 configure.bat --disable-all --enable-cli --enable-debug
配置成功后,使用nmake命令就可以对php源码进行编译了。
使用vscode打开,在.vscode下编辑launch.js文件,配置如下。
如果没有window启动这个选项,可以检查检查是否安装了c/c++拓展。
在打开的目录下随便建立一个test.php文件,最好建立到x64\Debug_TS目录下面。
在sapi/cli/php-cli文件下的第1197行打下断点,运行test.php这个文件。
可以看到,这里进入了php-cli.c,在断点处停下了。
附加到进程调试
新建文件夹__Workspace,将需要调试的代码放到该文件夹下。并启动php服务器。
选择windows附加到进程
在进行调试之前,选择php的进程即可。每次访问都会经过下面的函数进行处理。
php反序列化Rce底层的实现
这里贴出代码
<?php
class Rce{
public $var1;
function __destruct()
{
system($this->var1);
}
}
unserialize('O:3:"Rce":1:{s:4:"var1";s:6:"whoami";}');
由于这里使用了unserialize函数,全局搜索Function(serialize)
可以发现,在路径ext\standard\var.c下有这个函数的声明。打上断点进行调试,如下
可以看到上面的p指针,指向了我们传入的变量,并且对双引号进行转义。
下面的一些没有进入if的语句就直接跳过,相关的赋值在变量窗口中已经写清楚。这里调用php_var_unserialize_get_allowed_classes函数,但是classes变量本身为空指针,所以说这里什么都没干。
接下里就是重要的函数了PHP_VAR_UNSERIALIZE_DESTROY
,我们的反序列化,通常由销毁对象的方法__destruct来触发
查看函数,可以发现,全局函数调用的API为php_var_unserialize_destroy(php_unserialize_data_t d)
单步进入这个函数
可以看到这里存储了对象的第一个属性的指针
在进行free空间的时候,会将这里的函数执行。然后一层层返回,直到退出函数,这里的调用栈非常长,可以自行调试。
继续跟进,直到退出函数,这里会执行system命令。
这里调用的是php_exec_ex函数,跟进查看
后面就不说了,从php_exec继续跟进可以完成命令的执行。