使用v8js在php中运行javascript代码
@(脸红)最近写了个cloudflare的bypass脚本后,有写了一个某论坛的bypass,一看是此论坛只是简单的用js设置cookie,正则表达式取cookie即可破之,第二天发现换成了js计算aes加密了,先分析了js脚本,得知使用aes-256-cbc加密,但是密文和key和iv不知怎么还原(我还是太菜了),于是google搜索'php run javascript'找到了这个硬核扩展
介绍
google v8是由google开发的javascript引擎,它的第一个版本发布时间好像和chrome发布时间一致,v8是开源的,它也被使用在chromium和chrome中.
v8js是一个php的扩展,它将php代码中的javascript代码交给v8解析和运行,所以v8js依赖v8.
环境
- ubuntu16.04 x64
- google v8 5.6
- python 2.7或以上
- gcc 4.6或以上
- php7或以上(php5可以使用v8js旧版本)
- git
- glib2-devel
- build-essential
编译google v8
v8js给出的介绍中使用了ubuntu/debian的官方仓库中的libv8-dev,但仓库中的v8版本已经很老旧,使用此版本将无法顺利编译v8js,而官方提到了pinepain仓库,次仓库中的v8版本最低为7.0,但此版本对于v8js太新,同样无法正常编译,经过一番搜寻最终确定了v8的5.6版本可以在编译v8js(2.1.0)时正常使用,于是我们需要编译此版本的v8,经过google搜索得到的几篇文章,加上自己的测试得出安装方式.
首先安装必备组件和设置git
apt-get install build-essential git python libglib2.0-dev
git config --global user.email "[email protected]"
git config --global user.name "Shira Kagurazaka"
git设置这一步骤可以忽略,但是google搜索得到的文章中有人反映不设置git的话后面会出错误
然后拉取工具并设置临时变量环境
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=`pwd`/depot_tools:"$PATH"
中间断开的话需要重新设置环境变量,或者可以考虑将其加入用户变量文件中
然后拉取google v8并切换到早期的5.6版本
fetch v8
cd ./v8
git checkout 5.6.326.12
gclient sync
拉取将会持续很长时间我的几台机器最短5分钟最长接近两小时
拉取完成后准备编译
tools/dev/v8gen.py -vv x64.release
echo is_component_build = true >> out.gn/x64.release/args.gn
ninja -C out.gn/x64.release
这里执行ninja命令也会非常的慢,我的4核8g执行了40分钟左右
然后开始编译安装,当然编译速度和ninja执行的速度差不多
make library=shared snapshot=off native
如果机器拥有多核,可以在后面加入-j
参数使用多核,生产服务器建议使用核心数量4分之3进行编译
由于不存在make install
所以我们需要将用到的文件手动复制出来/usr
和/opt/v8
各一份
mkdir -p /opt/v8/{lib,include}
cp out.gn/x64.release/lib*.so out.gn/x64.release/*_blob.bin /opt/v8/lib/
cp -R include/* /opt/v8/include/
cp out.gn/x64.release/lib*.so out.gn/x64.release/*_blob.bin /usr/lib/
cp -R include/* /usr/include/
cp out/native/lib.target/lib*.so /usr/lib/
cp -R include/* /usr/include
当然也可以指定其他目录或者只保留/usr
部分,看别人的文章在/opt/v8
中保留了一份于是自己也就保留了一份
安装v8js扩展
查看php的手册时发现可以使用pecl
,所以就直接使用了pecl
进行编译安装,首先安装pear组件
apt install php-pear -y
如果使用了第三方仓库或者其他版本php那么需要安装对应版本的pear才可以(比如安装时php名称为php7
则pear名称应该为php7-pear
)
然后更新pear仓库列表,不更新的话安装时可能不是最新的版本
pecl channel-update pecl.php.net
然后开始使用pecl编译安装v8js,如需指定版本可以在后面加上版本号,如:v8js-2.0.0
pecl install v8js
当出现以下提示时输入/opt/v8
或者直接回车(将使用/usr/lib
目录)或者刚刚编译后复制到的其它目录
Please provide the installation prefix of libv8 [autodetect] :
编译完成后Installing
的值就是编译后so文件的绝对路径,在php.ini
中引用它并重启fpm
[v8js]
extension=v8js.so
然后使用phpinfo()
将会出现v8js的信息,这时就可以使用它了,如果在此页面没有v8js信息,请尝试将配置文件中extension=v8js.so
的路径改为绝对路径
v8js的使用和注意
官网只有这一个示例,并且没有详细的说明
<?php
$v8 = new V8Js();
/* basic.js */
$JS = <<< EOT
len = print('Hello' + ' ' + 'World!' + "\\n");
len;
EOT;
try {
var_dump($v8->executeString($JS, 'basic.js'));
} catch (V8JsException $e) {
var_dump($e);
}
?>
解释一下这一段,首先实例化v8js,然后声明一个变量,内容为js脚本,然后通过executeString
执行它,并通过catch来捕获js中的异常(各种js错误),其中第一个参数为js脚本,第二个参数为文件名,这里的文件名在php手册中的解释貌似是方便debug使用的暂存文件名,然后executeString
在手册中还有第三个参数,这个参数和用处目前没明白,手册给出的值有V8Js::FLAG_NONE
和V8Js::FLAG_FORCE_ARRAY
,我在运行同一段js时改变第三个参数得到的结果相同.
这段js代码会直接输出hello world而不是executeString
将它返回
根据官网的介绍executeString
将会返回js中最后的一个变量
所以,如果我们需要js中的执行结果我们需要这样写
<?php
$v8 = new V8Js();
$JS = <<< EOT
var a = "hello world";
a;
EOT;
$res = $v8->executeString($JS);
这样php中的$res
将会是js中的hello word
使用时注意
v8js中不支持console
,document
,alert
等对象,因为v8并不是一个实际的窗口,如果js代码中包含这些,将会出现错误,输出可以使用print
代替
executeString
只能返回js中最后一个变量,如需获取js中的多个变量,则需要创建一个对象将所有需要的结果赋值给这个对象,然后获取这个对象.
编译最后出现
Makefile:181: recipe for target 'v8js.lo' failed
make: *** [v8js.lo] Error 1
ERROR: `make' failed
请教该如果修改
需要提供更详细的信息,在这些信息的上面应该还会有更详细的错误信息