原文地址:https://blog.zsxsoft.com/post/40
这次RCTF2019中,我出了一题SourceGuardian解密。和Hook zend_compile_string
就能解决php_screw
、php-beast
等扩展一样,没有对PHP总体的执行流程做出较大更改的扩展,依然有通用的(或是较为通用的)破解方案。这其中,SourceGuardian就是一个例子。这篇文章将从Zend虚拟机的角度来谈这一类加密的破解方案。
这一题的题目和Writeup见:https://github.com/zsxsoft/my-ctf-challenges/tree/master/rctf2019/sourceguardian
我们首先需要熟悉PHP代码执行的流程──即,PHP到底是如何加载文件并执行的。PHP代码由于历史原因较为散乱,因此入手点很多。经过分析后,我认为从php-cli
入手是一个不错的选择。
https://github.com/php/php-src/blob/php-7.3.5/sapi/cli/php_cli.c#L937
让我们来整理一遍吧。第一步:打开文件句柄,CLI在这里顺便处理以#!/bin/php
开头的可执行文件,防止该头被输出。
if (cli_seek_file_begin(&file_handle, script_file, &lineno) != SUCCESS) {
第二步:调用php_execute_script
。这个函数同时负责把auto_prepend
引入。
php_execute_script(&file_handle);
往下看php_execute_script
的代码:
https://github.com/php/php-src/blob/7208826fdeb2244136c11a2e3b31948dfac549a3/main/main.c#L2650
它调用了
retval = (zend_execute_scripts(ZEND_REQUIRE, NULL, 3, prepend_file_p, primary_file, append_file_p) == SUCCESS);
往下看zend_execute_scripts
,其代码如下:
op_array = zend_compile_file(file_handle, type);
if (file_handle