fate0 / xmark

A PHP7 extension that can hook most functions/classes and parts of opcodes
BSD 3-Clause "New" or "Revised" License
239 stars 32 forks source link
extension hook php7

xmark

Build Status AppVeyor Status GitHub

中文文档

Table of Contents

Introduction

xmark is a PHP7 extension that provides the following features:

Installation

phpize
./configure
make

download

Example

example:

<?php

function var_dump(...$args) {
    echo "in custom var_dump\n";
    _var_dump(...$args);
}

var_dump("test");

run:

php -d "extension_dir=/tmp/modules/" -d "extension=xmark.so" -d "xmark.enable=1" -d "xmark.rename_functions=var_dump:_var_dump" test.php

result:

var_dump_example

More examples

API

bool xregister_opcode_callback(int $opcode, string $callback);

$callback must be a function name, not a class method, or any other callable。

OPCODE

each opcode callback has a different function description, so let's explain it one by one。

PHP configuration

enable xmark extension:

xmark.enable = 1

enable rename PHP user functions/classes (do not enable this in production envri)

xmark.enable_rename = 1

rename PHP internal functions:

xmark.rename_functions="
    phpinfo:my_phpinfo,
    system:my_system
"

rename PHP internal classes:

xmark.rename_classes="
    PDO:my_POD,
    yyy:_yyy
"

Note

  1. str_replace

str_replace function description:

mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )

$count is a reference parameter,so the correct way to hook str_replace is as follows:

function str_replace($search, $replace, $subject, &$count=NULL) {
    return call_user_func_array("origin_str_replace", array($search, $replace, $subject, &$count));
}

str_replace("a", "e", "hallo world", $count);
var_dump($count);

hook other function with reference parameters are also done as above.

  1. strval

xmark can not hook strval function. because strval is optimized directly in the compile stage, and does not need to be searched by EG(function_table), other similar functions zend_compile.c

  1. getallheaders

xmark can not hook getallheaders function. because getallheaders function is inside the sapi_modulesapi_module initialization time is later than php_extension and zend_extension, so the functions in sapi_module can not be hooked with xmark,fortunately, there are only a few functions in sapi_module.

  1. extract

xmark can hook extract function, but it will affect the original function of extract. because extract will change its own variable scope, extract will look up the last user function int the call stack and then modify its variable scope, when we rename extract to another name and write another extract function in PHP, the extract function we wrote becomes the last user function in the call stack, so extract won't work properly.

other similar functions: Forbid dynamic calls to scope introspection functions

if you just need to monitor the calls to these functions, then I recommend using opcode callback.

  1. array_map

xmark can also hook array_map function,but it may also affect the original function of array_map. because when array_map calls the callback, it will determine whether the function calling array_map has permission to call the corresponding callback.

example:

<?php

function test($callable, $arr) {
    array_map($callable, $arr);
}

class A {
    public function hi() {
        test(array($this, 'hello'), array(1, 2));
    }

    private function hello() {
        echo "hello\n";
    }
}

$a = new A();
$a->hi();

when array_map is called, zend_get_executed_scope will look up the last use function in the call stack and then determine if the user function has permission to call the callback. so it may cause the the call to array_map to fail. the same problem occurs in other internal functions that accept callback parameter.

in summary, if a function depends on or will change the scope of the caller, then you should carefully determine whether the function can still be hooked.

Ref