咱们能够根据其余扩展的config.m4文件来修改为咱们的必要编译配置信息。这里这个模块几乎是一个空的config.m4文件就行,
而后利用phpize来生成configure文件而后是 ./configure && make && make install执行就能编译一份咱们的动态库
test.php
<?php
echo helloworld_module();
?>
输出:
"Hello,world"
完成了PHP扩展,咱们已经深刻了php的c代码内部,可是在一些状况下,这还不够。咱们须要深刻到c语言调用c库的过程中,在linux下面一个很给力的工具是LD_PRELOAD环境变量
LD_PRELOAD环境变量是编译器找到程序中所引用的函数或全局变量所存在的位置的一个过滤器,好比在php的c代码里调用一个开始网络链接的方法connect,事实上就是经过动态连接
去寻找linux的c库的函数connect,这些连接文件通常放在lib下面,这也就为咱们影响php的代码执行提供了一个切入点。由于php程序在动态载入lib下面的函数connect以前会检查LD_PRELOAD
提供的动态库里有没有这个connect函数,咱们能够在这里对php的行为进行干涉。
下面以一个简单的过滤网络访问的例子说明如何实现:
先是一个准备做为LD_PRELOAD环境变量的值的so文件的代码。
lp_demo.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <dlfcn.h>
//定义咱们本身的connect函数
int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t
addrlen){
static int (*connect_linuxc)(int, const struct sockaddr*, socklen_t)=NULL;
unsigned char *ip_char;
//利用 lsym的RTLD_NEXT选项绕过LD_PRELOAD环境变量的connect方法找到c库的函数
if (!connect_linuxc) connect_linuxc=dlsym(RTLD_NEXT,"connect");
ip_char=serv_addr->sa_data;
ip_char+=2;
//192.168.2.3 找到了
if ((*ip_char==192)&&(*(ip_char+1)==168)&&(*(ip_char+2)==2)&&(*(ip_char+3)==3)) {
//简单返回一个权限错误的代码
return EACCES;
}
// 调用真正的connect方法
return connect_linuxc(sockfd,serv_addr,addrlen);
}
编译成so文件
$ gcc -o lp_demo.so -shared lp_demo.c -ldl
测试文件 test.php
<?php
file_get_contents("http://192.168.2.3/");
?>
使用方法
LD_PRELOAD=lp_demo.so php test.php
这样他将不可能访问的到192.168.2.3这种咱们内部的网址。起到一个很好的沙盒做用。
除此以外咱们还能够利用fwrite fopen等函数将php对文件系统的读写操做转移到mencache,nosql之类的后端资源当中。
最后,即便咱们已经深刻了c库的内部,也不意味着咱们走到了最底层,在c库下面,还有一堆sys_开头的函数,他们才是内核空间里的真正函数,在此就不在探讨了。
php