重构函数和反射
2个知识点
- 重写内置函数
- 访问私有方法或者变量
重写内置函数
代码如下
<?php
function sha1(){
return 'success';
}
echo sha1();
?>
这样直接重写一个sha1函数会报错
Fatal error: Cannot redeclare sha1() in C:\Users\j7ur8\Desktop\php\index.php on line 5
可以试试增加一个namespace,代码如下
<?php
namespace interesting;
function sha1(){
return 'success';
}
echo sha1();
成功返回success。我们可以把平常我们编写代码时调用的方法想象成是一个public类的方法,也就是我们本来就在一个public函数中编写代码,调用public内置的方法。php支持使用namespace来解释重复出现的变量和方法,所以我们可以使用namespace来重写namespace下的sha1函数。
访问私有方法或者属性
利用反射Reflecttion(PHP 5, PHP 7)
调用私有方法
<?php
class Example1{
private $_prop = 'test';
}
$r = function(Example1 $e){
return $e->_prop;
};
$a = new Example1();
$rfp = new ReflectionProperty('Example1','_prop');
$rfp->setAccessible(true);
var_dump($rfp->getValue($a));
//结果输出:string 'test' (length=4)
?>
带参数的
public function callPrivateMethod($object, $methodName)
{
$reflectionClass = new \ReflectionClass($object);
$reflectionMethod = $reflectionClass->getMethod($methodName);
$reflectionMethod->setAccessible(true);
$params = array_slice(func_get_args(), 2); //get all the parameters after $methodName
return $reflectionMethod->invokeArgs($object, $params);
}
私有属性
<?php
class Foo {
private function myPrivateMethod() {
return 7;
}
}
$method = new ReflectionMethod('Foo', 'myPrivateMethod');
$method->setAccessible(true);
echo $method->invoke(new Foo);
// echos "7"
?>
反射命名空间
反射一个类也可以通过反射命名空间来搞 国赛中的payload为:
<?php
$ref_class=new ReflectionClass('\interesting\FlagSDK');
$instance=$ref_class->newInstance();
$method=$ref_class->getmethod('getHash');
$method->setAccessible(true);
echo $method->invoke($instance);
?>
无论是反射方法还是属性都有一步时setAccessible,关于反射属性和方法也还有一些其他方法。
利用Closure类(PHP 5 >= 5.3.0, PHP 7)
访问属性
<?php
class Example1{
private $_prop = 'test';
}
$r = function(Example1 $e){
return $e->_prop;
};
$a = new Example1();
$r = Closure::bind($r,null,$a);
var_dump($r($a));
//结果输出:string 'test' (length=4)
更改属性
<?php
class Example1{
private $_prop = 'test';
}
$a = new Example1();
$r = Closure::bind(function & (Example1 $e) {
return $e->_prop;
}, null, $a);
$cake = & $r($a);
$cake = 'lie';
var_dump($r($a));
利用Closure类访问方法
PHP7可使用
<?php
class Foo {
private $bar = "Foo::Bar";
private function add_ab($a, $b) {
return $a + $b;
}
}
$foo = new Foo;
$getFooBar = function() {
return $this->bar;
};
echo $getFooBar->call($foo);
$getFooAddAB = function() {
return $this->add_ab(func_get_args()[0],func_get_args()[1]);
};//func_get_arg(0)
var_dump($getFooAddAB->call($foo, 33, 6)); // Prints 39
PHP5和PHP7可使用
<?php
class Foo {
private $bar = "Foo::Bar";
private function add_ab($a, $b) {
return $a + $b;
}
}
$foo = new Foo;
$getFooBarCallback = function() {
return $this->bar;
};
$getFooBar = $getFooBarCallback->bindTo($foo, 'Foo');
echo $getFooBar(); // Prints Foo::Bar
$getFooAddABCallback = function() {
return call_user_func_array(array($this, 'add_ab'), func_get_args());
};
$getFooAddAB = $getFooAddABCallback->bindTo($foo, 'Foo');
echo $getFooAddAB(33, 6);