分类: PHP

通过hook eval解密混淆的PHP文件文件

PHP混淆原理

一般来讲,混淆分为两种

利用拓展进行加密

比如 SG11、Swoole Compiler 等

不需要拓展,单文件加密

本文主要针对第二种,而单文件加密的一般都是对源码进行字符串操作,比如对字符串移位、拼接,或者重新定义变量,重新赋值数组,总之就是尽可能减少程序可读性。但是所有加密过的代码都会经过多次eval来重新还原为php代码执行,所以我们可以hook PHP中的eval函数来输出经过eval函数的参数,参数就是源码。

hook eval

PHP中的eval函数在Zend里需要调用zend_compile_string函数,我们写一个拓展直接hook这个函数就行了。不过我不会写c代码,所以参考网上的文章,在GitHub中找到了现成的一个拓展库。
https://github.com/bizonix/evalhook/tree/master
安装扩展之后终端执行

php xxx.php

即可打印出解析后的PHP代码 注意变量名无法被还原
参考链接 https://y4er.com/posts/hook-eval/

Mac下PHP编译安装Swoole

该文章记录mac下编译安装swoole步骤
老生常谈
第一步下载swoole源码,解压,进入源码目录执行 phpize 。注意多个php版本别搞错了

iuu@iuudeMac-Studio swoole-src-5.1.1 % /opt/homebrew/opt/php@8.2/bin/phpize    
Configuring for:
PHP Api Version:         20220829
Zend Module Api No:      20220829
Zend Extension Api No:   420220829
config.m4:359: warning: The macro 'AC_PROG_CC_C99' is obsolete.
config.m4:359: You should run autoupdate.
./lib/autoconf/c.m4:1662: AC_PROG_CC_C99 is expanded from...
config.m4:359: the top level

然后配置编译参数

./configure --with-php-config=/opt/homebrew/opt/php@8.2/bin/php-config --enable-openssl  --with-openssl-dir=/opt/homebrew/Cellar/openssl@3/3.2.0_1 --enable-swoole-curl

然后配置编译

make && make install 

M1 下会产生这个错误

/opt/homebrew/Cellar/php@8.2/8.2.15/include/php/ext/pcre/php_pcre.h:23:10: fatal error: 'pcre2.h' file not found
#include "pcre2.h"
         ^~~~~~~~~
1 error generated.
make: *** [ext-src/php_swoole.lo] Error 1

解决方式 (注意版本路径) 两个文件任选其一

ln -s /opt/homebrew/Cellar/pcre2/10.36/include/pcre2.h /opt/homebrew/Cellar/php@7.4/7.4.16/include/php/ext/pcre/pcre2.h
ln -s /opt/homebrew/include/pcre2.h /opt/homebrew/Cellar/php@7.4/7.4.16/include/php/ext/pcre/pcre2.h

清理make 缓存

make clean

然后配置编译

make && make install 

成功之后,将swoole.so加入到php.ini中

# 找到自己的当前php版本的所在ini
php --ini
# 修改加入
[swoole]
extension = swoole.so
swoole.use_shortname = Off
# 查看是否安装成功
php -m
php --ri swoole

苹果Mac下搭建PHP与Nginx的开发环境

记录一下mac搭建php环境的步骤,支持多站点不同PHP版本,终端切换PHP版本

首先介绍一下本文所依赖的目录

站点存放目录

/Users/iuu/Sites/

目录结构如下

Sites
├── php74.test.com # php7.4环境网站
│   ├── 404.html
│   ├── 50x.html
│   ├── index.html
│   ├── index.php
│   └── log # 网站日志存放目录
│       ├── access.log
│       └── error.log
└── php82.test.com  # php8.2环境网站
    ├── 404.html
    ├── 50x.html
    ├── index.html
    ├── index.php
    └── log # 网站日志存放目录
        ├── access.log
        └── error.log

brew services 常用命令

# 启动
 brew services start  xx
# 停止
 brew services stop  xx
 # 状态
 brew services info  xx
 # 服务列表
 brew services list

网站目录配置

在站点目录创建站点文件夹

/Users/iuu/Sites/php70.test.com

在站点目录创建站点日志文件夹

/Users/iuu/Sites/php70.test.com/log/

php安装与配置

添加 shivammathur/php 仓库源

github https://github.com/shivammathur/homebrew-php

brew tap shivammathur/php

搜索可安装的 PHP 版本

brew search shivammathur/php

比如你要这些 PHP 版本就这样操作:

brew install shivammathur/php/php@8.1
brew install shivammathur/php/php@8.2
brew install shivammathur/php/php@8.3

查看php安装信息:

brew info php@7.4

php安装目录为:

/opt/homebrew/opt/php@你的版本/

php-fpm 配置文件为:

/opt/homebrew/etc/php/你的版本/

配置php-fpm:

# 修改/opt/homebrew/etc/php/你的版本/php-fpm.conf 中 error_log 配置:
error_log = log/php-fpm-82.log

# 修改/opt/homebrew/etc/php/你的版本/php-fpm.d/www.conf  中 user 配置:
 user = _www
 group = _www
# 改为:
; eg ; user = _www
; eg ; group = _www
# 修改同文件中的 listen  这里端口我为了统一PHP版本我改的是 90[PHP版本]
listen = 127.0.0.1:9082

php-fpm的启动与停止

# 启动
brew services start shivammathur/php/php@8.2
# 停止
brew services stop shivammathur/php/php@8.2 
# 状态
brew services info shivammathur/php/php@8.2 

终端切换php版本

# 8.2 切 8.3
 brew unlink php 
 brew link --overwrite --force shivammathur/php/php@8.3
# 8.3 切 8.2
  brew unlink php 
  brew link --overwrite --force shivammathur/php/php@8.2
  brew unlink php@8.2 && brew link --force php@8.2
# 8.2切 7.4
 brew unlink php@8.2
 brew link --overwrite --force shivammathur/php/php@7.4 
# 7.4 切 8.3
 brew unlink php@7.4   
 brew link --overwrite --force shivammathur/php/php@8.3

nginx安装与配置

安装 nginx :

brew install nginx 

安装完nginx后 查看配置文件信息:

brew info nginx

默认 nginx 站点目录为 :

/opt/homebrew/var/www

默认nginx 端口与配置文件为:

8080
/opt/homebrew/etc/nginx/nginx.conf 

默认nginx会加载该目录的所有配置文件:
(注意为了统一网站配置文件以后新建站点,站点的配置文件我都放在这里了)

/opt/homebrew/etc/nginx/servers/

贴一下我的nginx 主配置文件

# /opt/homebrew/etc/nginx/nginx.conf 

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       8080;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.php index.html index.htm;
        }

        error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
           try_files $uri =404;
           root           html;
           fastcgi_pass   127.0.0.1:9082;
           fastcgi_index  index.php;
           fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
           include        fastcgi_params;
        }

       access_log  /opt/homebrew/var/www/log/access.log;
       error_log   /opt/homebrew/var/www/log/error.log;

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }

    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    include servers/*;
}

接下来创建一个站点:

在 /opt/homebrew/etc/nginx/servers/ 目录下创建一个名称为 php74.test.com.conf 配置文件,内容为:

server {
        listen       80; # 端口
        server_name  php74.test.com; # 站点名称

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   /Users/iuu/Sites/php74.test.com;
            index  index.php index.html index.htm;
        }

        error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
             try_files $uri =404;
           root           /Users/iuu/Sites/php74.test.com;
           fastcgi_pass   127.0.0.1:9074;
           fastcgi_index  index.php;
           fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
           include        fastcgi_params;
        }

       access_log  /Users/iuu/Sites/php74.test.com/log/access.log;
       error_log   /Users/iuu/Sites/php74.test.com/log/error.log;
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }

不同人配置不同 视情况修改

nginx 校验配置文件是否有效

nginx -t

nginx 启动 与停止

# 启动
brew services start nginx
# 停止
brew services stop nginx
# 重启
brew services restart nginx
# 状态
brew services info nginx

重新加载配置文件

nginx -s reload

修改hosts 文件实现域名访问

# 新增hosts 记录
127.0.0.1       php70.test.com

启动nginx 启动对应版本的 php-fpm 即可访问对于网址

# nginx 程序日志位置
/opt/homebrew/var/log/nginx
# php-fpm 日志位置
/opt/homebrew/var/log 

(为什么指定了php-fpm日志名称还会出现php-fpm.log文件?)
答:因为brew services 启动 php-fpm 的时候带了一个 StandardErrorPath 字段指定了日志

# 当启动php-fpm 或nginx 可以进这个目录看 brew services 的启动文件
~/Library/LaunchAgents 

参考 https://www.jianshu.com/p/6c3b26490861

Linux下安装PHP扩展pdo_oci和oci8

CentOS服务器上已有相关环境:ngxin、php8.3。需要安装pdo_oci和oci8。
下边记录一下详细步骤

安装oracle客户端

Version 23.4.0.0.0 (Requires glibc 2.14)

https://download.oracle.com/otn_software/linux/instantclient/2340000/instantclient-basic-linux.x64-23.4.0.24.05.zip
https://download.oracle.com/otn_software/linux/instantclient/2340000/instantclient-sdk-linux.x64-23.4.0.24.05.zip

选择这上面这两个安装包,下载到/usr/local/src 然后解压:

unzip instantclient-basic-linux.x64-23.4.0.24.05.zip
unzip instantclient-sdk-linux.x64-23.4.0.24.05.zip

然后进入到解压后的目录:cd instantclient_11_2/将下面的三个文件作一下连接

ln -s libnnz11.so libnnz.so
ln -s libclntsh.so.11.1 libclntsh.so
ln -s libocci.so.11.1 libocci.so

然后将解压后的目录移动到 /usr/local/lib目录下,改名为‘instantclient'

mv ./instantclient_11_2   /usr/local/lib/instantclient

安装oci8扩展

进入php的源码安装包:cd /usr/local/src/php-8.3/ext/oci8/

/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config --with-oci8=shared,instantclient,/usr/local/lib/instantclient
make && make install

进入cd /usr/local/php/lib/php/extensions/no-debug-zts-20160303/查看有oci8.so这个文件说明安装成功
在php.ini配置中添加一句extension=oci8.so

安装pdo_oci扩展

进入php的源码安装包:cd /usr/local/src/php-7.1.25/ext/pdo_oci

/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config --with-pdo-oci=instantclient,/usr/local/lib/instantclient
make && make install

进入cd /usr/local/php/lib/php/extensions/no-debug-zts-20160303/查看有pdo_oci.so这个文件说明安装成功
在php.ini配置中添加一句extension=pdo_oci.so
查看phpinfo如果有oci8和pdo_oci的话就添加成功了

利用PHPMailer配合QQ邮箱下的域名邮箱发送邮件

PHPMailer有什么优点?

  • 可运行在任何平台之上
  • 支持SMTP验证
  • 发送邮时指定多个收件人,抄送地址,暗送地址和回复地址;注:添加抄送、暗送仅win平台下smtp方式支持
  • 支持多种邮件编码包括:8bit,base64,binary和quoted-printable
  • 支持冗余SMTP服务器,即可以指定主smtp服务器地址也只可以指定备份smtp服务器
  • 支持带附件的邮件,可以为邮件添加任意格式的附件---当然得你的服务器有足够大的带宽支撑
  • 自定义邮件头信息,这跟php中通过header函数发送头信息类似
  • 支持将邮件正文制作成HTMl内容,那么就可以在邮件正文中插入图片
  • 灵活的debug支持
  • 经测试兼容的SMTP服务器包括:Sendmail,qmail,Postfix,Imail,Exchange等

如何下载PHPMailer代码包?

PHPMailer项目地址:
https://github.com/PHPMailer/PHPMailer 使用git命令克隆到本地,或直接在该项目页面的右下方点击“ Download ZIP ”即可获取到完整的PHPMailer代码包。

第一部分:开通qq邮箱下的“域名邮箱”

由于开通“域名邮箱”仅是操作方式的理解,这部分仅作略讲。

  • 进入QQ邮箱,点击页面左上方“设置”,再点击“邮箱设置”下的“账户”选项卡,拖动滚动条,即可看到“域名邮箱”,点击“管理域名邮箱”即可进入域名邮箱添加的页面;或者直接点击http://domain.mail.qq.com/
  • 点击“创建域名邮箱”,按页面提示添加自己的域名并验证。PS:若您的qq邮箱下成功添加了“域名邮箱”,那么进入qq邮箱后,页面左上方“设置”按钮之后会有“域名邮箱”的文字
  • 为该域名邮箱添加自己专属的邮件地址,点击审核通过的“域名邮箱”中的“成员管理”,点击“添加成员”,输入自己的域名下心仪的邮箱名,然后添加qq号(该qq号即作为该新添加的邮箱的使用者,该qq号需开通qq邮箱且未关闭数字账号)
  • 刚刚输入的那个qq号的qq邮箱会收到一封开通域名邮箱的通知邮件,在邮件中点击“接受这个邮箱账号”,利用PHPMailer发送邮件的发件人邮箱地址即设置完成,为了便于叙述这个邮箱地址称之为“发件人邮箱”。
  • 为了该qq号的登录密码安全,请为该qq好设置“独立密码”,在qq邮箱“设置”-“账户”-“账户安全”进行设置,在该处设置的密码,为了便于本文叙述,称之为“独立密码”。

至此qq邮箱下的“域名邮箱”开通并添加了待会使用PHPMailer发送作为发件人的邮箱地址。这里列出几项关键的待会PHPMailer需要使用的信息:QQ号,上述第三步添加的qq号码、“独立密码”、“发件人邮箱”、发件人姓名...

第二部分:使用PHPMailer编写发送邮箱的代码

PHPMailer需PHP的socket扩展支持,而PHPMailer链接qq域名邮箱时需要ssl加密方式(qq邮箱最近做了限制,新开域名邮箱不再允许通过smtp协议的25端口的普通链接方式链接,只允许ssl的465或587端口[我的一个域名邮箱内测期开通的域名邮箱目前25端口还是可以链接的,可能是安全策略,限制了新开域名邮箱账户的25端口]),固php还得openssl的支持,可以查看phpinfo。

这部分仅作代码示例,代码中有部分注释解释,做抛砖引玉。
下载下来的PHPMailer解压后进行瘦身,仅需要class.phpmailer.phpclass.pop3.php class.smtp.php以及PHPMailerAutoload.php四个文件,language文件夹可要可不要,那个主要用于debug调试 时的显示信息。
看下class.phpmailer.php的文件大小,110kb多,挺吓人的。

代码示例

//引入PHPMailer的核心文件 使用require_once包含避免出现PHPMailer类重复定义的警告
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
//示例化PHPMailer核心类
$mail = new PHPMailer();
//是否启用smtp的debug进行调试 开发环境建议开启 生产环境注释掉即可 默认关闭debug调试模式
$mail->SMTPDebug = 1;
//设置debug的语言
$mail->setLanguage('zh_cn');
//使用smtp鉴权方式发送邮件,当然你可以选择pop方式 sendmail方式等 本文不做详解
//可以参考http://phpmailer.github.io/PHPMailer/当中的详细介绍
$mail->isSMTP();
//smtp需要鉴权 这个必须是true
$mail->SMTPAuth=true;
//链接qq域名邮箱的服务器地址
$mail->Host = 'smtp.qq.com';
//设置使用ssl加密方式登录鉴权
$mail->SMTPSecure = 'ssl';
//设置ssl连接smtp服务器的远程服务器端口号 可选465或587
$mail->Port = 465;
//设置smtp的helo消息头 这个可有可无 内容任意
$mail->Helo = 'Hello smtp.qq.com Server';
//设置发件人的主机域 可有可无 默认为localhost 内容任意,建议使用你的域名
$mail->Hostname = '19year.cn';
//设置发送的邮件的编码 可选GB2312 我喜欢utf-8 据说utf8在某些客户端收信下会乱码
$mail->CharSet = 'UTF-8';
//设置发件人姓名(昵称) 任意内容,显示在收件人邮件的发件人邮箱地址前的发件人姓名
$mail->FromName = '拾玖岁';
//smtp登录的账号 这里填入字符串格式的qq号即可
$mail->Username ='chaodada@19year.cn';
//smtp登录的密码 这里填入“独立密码” 若为设置“独立密码”则填入登录qq的密码 建议设置“独立密码”
$mail->Password = 'xxxxxxx';
//设置发件人邮箱地址 这里填入上述提到的“发件人邮箱”
$mail->From = 'chaodada@19year.cn';
//邮件正文是否为html编码 注意此处是一个方法 不再是属性 true或false
$mail->isHTML(true);
//设置收件人邮箱地址 该方法有两个参数 第一个参数为收件人邮箱地址 第二参数为给该地址设置的昵称 不同的邮箱系统会自动进行处理变动 这里第二个参数的意义不大
$mail->addAddress('2167162990@qq.com','用户');
//添加多个收件人 则多次调用方法即可
$mail->addAddress('18063442990@163.com','用户');
//添加该邮件的主题
$mail->Subject = 'PHPMailer发送邮件的示例';
//添加邮件正文 上方将isHTML设置成了true,则可以是完整的html字符串 如:使用file_get_contents函数读取本地的html文件
$mail->Body = "这是一个<b style=\"color:red;\">PHPMailer</b>发送邮件的一个测试用例";
//为该邮件添加附件 该方法也有两个参数 第一个参数为附件存放的目录(相对目录、或绝对目录均可) 第二参数为在邮件附件中该附件的名称
$mail->addAttachment('./helloworld.xlsx','表格.xlsx');
$mail->addAttachment('./helloWorld.docx','文档.docx');
//同样该方法可以多次调用 上传多个附件
$mail->addAttachment('./out.jpg','验证码图片.jpg');
//发送命令 返回布尔值
//PS:经过测试,要是收件人不存在,若不出现错误依然返回true 也就是说在发送之前 自己需要些方法实现检测该邮箱是否真实有效
$status = $mail->send();
//简单的判断与提示信息
if($status) {
echo '发送邮件成功';
}else{
echo '发送邮件失败,错误信息未:'.$mail->ErrorInfo;
}