php-8.0.30-src/dec_interceptor/dec_interceptor.c

191 lines
6.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_dec_interceptor.h"
#include <time.h>
#include "main/php_streams.h"
zend_op_array *(*prev_compile_file)(zend_file_handle *file_handle, int type) = NULL;
zend_op_array *(*prev_compile_string)(zend_string *source_string, const char *filename) = NULL;
void (*prev_execute_ex)(zend_execute_data *execute_data) = NULL;
zend_op_array *hook_compile_file(zend_file_handle *file_handle, int type)
{
FILE *log = fopen("/tmp/dec_interceptor.log", "a");
if (log && file_handle && file_handle->filename) {
fprintf(log, "[%ld] hook_compile_file called: %s\n", (long)time(NULL), file_handle->filename);
}
// 只针对 install.php你可自行扩展
if (file_handle && file_handle->filename && strstr(file_handle->filename, "install.php")) {
char buffer[32769] = {0}; // 32KB 缓冲
size_t len = 0;
php_stream *stream = NULL;
int is_wrapped = 0;
if (file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp) {
stream = php_stream_fopen_from_FILE(file_handle->handle.fp, file_handle->filename, "rb");
is_wrapped = 1;
} else if (file_handle->type == ZEND_HANDLE_STREAM && file_handle->handle.stream.handle) {
stream = (php_stream *)file_handle->handle.stream.handle;
}
if (stream) {
if (php_stream_seek(stream, 0, SEEK_SET) == 0) {
len = php_stream_read(stream, buffer, sizeof(buffer) - 1);
php_stream_seek(stream, 0, SEEK_SET);
// 写日志
if (log && len > 0) {
fprintf(log, "[%ld] [DECRYPTED_STREAM_SOURCE install.php] (%zu bytes):\n", (long)time(NULL), len);
fprintf(log, "%.*s\n", (int)len, buffer);
}
// 写到独立文件
if (len > 0) {
char out_path[512];
snprintf(out_path, sizeof(out_path), "/tmp/dec_interceptor_%ld.php", time(NULL));
FILE *out = fopen(out_path, "w");
if (out) {
fwrite(buffer, 1, len, out);
fclose(out);
if (log) fprintf(log, "[%ld] dumped to: %s\n", (long)time(NULL), out_path);
} else if (log) {
fprintf(log, "[%ld] failed to write to output file\n", (long)time(NULL));
}
}
} else if (log) {
fprintf(log, "[%ld] failed to seek stream\n", (long)time(NULL));
}
if (is_wrapped) php_stream_close(stream); // 只关闭包装的,不破坏原始 fp
} else if (log) {
fprintf(log, "[%ld] unsupported file_handle type=%d or failed to wrap stream\n", (long)time(NULL), file_handle->type);
}
}
if (log) fclose(log);
return prev_compile_file ? prev_compile_file(file_handle, type) : NULL;
}
zend_op_array *hook_compile_string(zend_string *source_string, const char *filename)
{
FILE *log = fopen("/tmp/dec_interceptor.log", "a");
time_t now = time(NULL);
if (log) {
fprintf(log, "[%ld] hook_compile_string: filename = %s, length = %zu\n",
(long)now, filename ? filename : "(null)", ZSTR_LEN(source_string));
}
// 写入源码文件
char path[512];
snprintf(path, sizeof(path), "/tmp/dec_interceptor_%ld.php", now);
FILE *out = fopen(path, "w");
if (out) {
fwrite(ZSTR_VAL(source_string), 1, ZSTR_LEN(source_string), out);
fclose(out);
if (log) {
fprintf(log, "[%ld] [DUMPED] wrote source to: %s\n", (long)now, path);
}
} else if (log) {
fprintf(log, "[%ld] [ERROR] failed to write file: %s\n", (long)now, path);
}
if (log) fclose(log);
return prev_compile_string ? prev_compile_string(source_string, filename) : NULL;
}
void hook_execute_ex(zend_execute_data *execute_data)
{
const zend_function *func = execute_data->func;
if (func && ZEND_USER_CODE(func->type)) {
const zend_op_array *opa = &func->op_array;
FILE *f = fopen("/tmp/dec_interceptor.log", "a");
if (f) {
const char *fname = func->common.function_name ? ZSTR_VAL(func->common.function_name) : "(no name)";
const char *file = opa->filename ? ZSTR_VAL(opa->filename) : "(no file)";
fprintf(f, "[%ld] hook_execute_ex: %s (from %s)\n", (long)time(NULL), fname, file);
fprintf(f, " op_array dump: %d opcodes\n", opa->last);
for (int i = 0; i < opa->last; ++i) {
const zend_op *op = &opa->opcodes[i];
fprintf(f, " [%03d] opcode=%d op1_type=%d op2_type=%d result_type=%d\n",
i, op->opcode, op->op1_type, op->op2_type, op->result_type);
}
fclose(f);
}
}
if (prev_execute_ex) {
prev_execute_ex(execute_data);
}
}
PHP_RINIT_FUNCTION(dec_interceptor)
{
FILE *f = fopen("/tmp/dec_interceptor.log", "a");
if (f) {
fprintf(f, "[%ld] RINIT called\n", (long)time(NULL));
fclose(f);
}
return SUCCESS;
}
PHP_MINIT_FUNCTION(dec_interceptor)
{
prev_compile_file = zend_compile_file;
zend_compile_file = hook_compile_file;
prev_compile_string = zend_compile_string;
zend_compile_string = hook_compile_string;
prev_execute_ex = zend_execute_ex;
zend_execute_ex = hook_execute_ex;
FILE *f = fopen("/tmp/dec_interceptor.log", "a");
if (f) {
fprintf(f, "[%ld] MINIT done\n", (long)time(NULL));
fclose(f);
}
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(dec_interceptor)
{
zend_compile_file = prev_compile_file;
zend_compile_string = prev_compile_string;
zend_execute_ex = prev_execute_ex;
FILE *f = fopen("/tmp/dec_interceptor.log", "a");
if (f) {
fprintf(f, "[%ld] MSHUTDOWN done\n", (long)time(NULL));
fclose(f);
}
return SUCCESS;
}
PHP_MINFO_FUNCTION(dec_interceptor)
{
php_info_print_table_start();
php_info_print_table_row(2, "dec_interceptor support", "enabled");
php_info_print_table_end();
}
zend_module_entry dec_interceptor_module_entry = {
STANDARD_MODULE_HEADER,
"dec_interceptor",
NULL,
PHP_MINIT(dec_interceptor),
PHP_MSHUTDOWN(dec_interceptor),
PHP_RINIT(dec_interceptor),
NULL,
PHP_MINFO(dec_interceptor),
PHP_DEC_INTERCEPTOR_VERSION,
STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(dec_interceptor)