修改Zend引擎实现PHP源码加密的原理及实践


Posted in PHP onApril 14, 2008

一、基本原理

考虑截获PHP读取源文件的接口。一开始,我考虑从Apache和PHP 之间的接口处处理,参见apache的src/modules/php4/mod_php4.c (这个是PHP用static方式编译进apache,make install 后的文件),在send_php()函数中截获文件指针,采用临时文件的方式,解密后替换文件指针。这种方法经过测试实践,证明是可行的。但是,必须使用两次文件操作,效率低下,而且对于DSO方式不可采用。 双缘敬老院

由此,重新考虑截获PHP读取文件并装载至缓存的过程,经过费力的寻找,发现在Zend引擎中zend-scanner.c是做此处理的。开始对此文件修改。照明工程

二、实现方法示意

采用libmcrypt作为加 密模块,现在采用的是DES方法ECB模式加密,

下面是文件加密的源代码:

C++代码
/* ecb.c-------------------cut here-----------*/   
/* encrypt for php source code version 0.99 beta   
we are using libmcrypt to encrypt codes, please   
install it first.   
compile command line:   
gcc -O6 -lmcrypt -lm -o encryptphp ecb.c   
please set LD_LIBRARY_PATH before use.   
GNU copyleft, designed by wangsu , miweicong */   

#define MCRYPT_BACKWARDS_COMPATIBLE 1    
#define PHP_CACHESIZE 8192    
#include < mcrypt.h >    
#include < stdio.h >    
#include < stdlib.h >    
#include < math.h >    
#include < sys/types.h >    
#include < sys/stat.h >    
#include < fcntl.h >    

   
main(int argc, char** argv)    
{    

int td, i,j,inputfilesize,filelength;    
char filename[255];    
char password[12];    
FILE* ifp;    
int readfd;    
char *key;    
void *block_buffer;    
void *file_buffer;    
int keysize;    
int decode=0;    
int realbufsize=0;    
struct stat *filestat;    

   
if(argc == 3) {    
strcpy(password,argv[1]);    
strcpy(filename,argv[2]);    
} else if(argc == 4 && !strcmp(argv[1],"-d")){    
strcpy(password,argv[2]);    
strcpy(filename,argv[3]);    
decode=1;    
printf("Entering decode mode ... n");    
} else {    
printf("Usage: encryptphp [-d] password filenamen");    
exit(1);    
}    

   
keysize=mcrypt_get_key_size(DES);    
key=calloc(1, mcrypt_get_key_size(DES));    

gen_key_sha1( key, NULL, 0, keysize, password, strlen(password));    
td=init_mcrypt_ecb(DES, key, keysize);    

if((readfd=open(filename,O_RDONLY,S_IRUSR|S_IWUSR|S_IRGRP))==-1){    
printf("FATAL: Can't open file to read");    
exit(3);    
}    

filestat=malloc(sizeof(stat));    

fstat(readfd,filestat);    
inputfilesize=filestat- >st_size;    
printf("filesize is %d n",inputfilesize);    
filelength=inputfilesize;    

inputfilesize=((int)(floor(inputfilesize/PHP_CACHESIZE))+1)*PHP_CACHESIZE;    

if((file_buffer=malloc(inputfilesize))==NULL){    
printf("FATAL: can't malloc file buffer.n");    
exit(2);    
}    
if((block_buffer=malloc(PHP_CACHESIZE))==NULL){    
printf("FATAL: can't malloc encrypt block buffer.n");    
exit(2);    
}    

j=0;    
while(realbufsize=read (readfd,block_buffer, PHP_CACHESIZE)){    
printf(".");    
if(!decode){    
if(realbufsize< PHP_CACHESIZE){    
for(i=realbufsize;i< PHP_CACHESIZE;i++){    
((char *)block_buffer)[i]=' ';    
}    
}    
mcrypt_ecb (td, block_buffer, PHP_CACHESIZE);    
} else {    
mdecrypt_ecb (td, block_buffer, realbufsize);    
}    
memcpy(file_buffer+j*PHP_CACHESIZE,block_buffer,PHP_CACHESIZE);    
j++;    
}    

close(readfd);    

if((ifp=fopen(filename,"wb"))==NULL){    
printf("FATAL: file access error.n");    
exit(3);    
}    
fwrite ( file_buffer, inputfilesize, 1, ifp);    

free(block_buffer);    
free(file_buffer);    
free(filestat);    
fclose(ifp);    
printf("n");    

return 0;    

}    
/*--- end of ecb.c ------------------------------------*/   
因为ECB模式是块长度确定的块加密,这里填充了一 些空字符。国际展览

然后,修改php代码中 Zend/zend-scanner.c 如下:

(我的php版本是4.01pl2, SUNsparc/solaris 2.7, gcc 2.95;)

文件前加入:

#define MCRYPT_BACKWARDS_COMPATIBLE 1
#include < mcrypt.h >

然后,注释掉大约3510行前后的YY_INPUT的定义。

然后, 修改大约5150行前后的yy_get_next_buffer()函数:
函数头加上定义:
void *tempbuf;
char *key;
char debugstr[255];
int td,keysize;
int x,y;
FILE *fp;
然后 ,注释掉
YY_INPUT( (&yy_current_buffer- >yy_ch_buf[number_to_move]),
yy_n_chars, num_to_read );
这一句。
改为:

tempbuf=malloc(num_to_read);
if((yy_n_chars=fread(tempbuf,1,num_to_read,yyin))!=0){
/*decode*/
#define password "PHPphp111222"
#define debug 0

keysize=mcrypt_get_key_size(DES);
key=calloc(1, mcrypt_get_key_size(DES));
gen_key_sha1( key, NULL, 0, keysize, password, strlen(password));
td=init_mcrypt_ecb(DES, key, keysize);
mdecrypt_ecb(td, tempbuf, yy_n_chars);
memcpy((&yy_current_buffer- >yy_ch_buf[number_to_move]),tempbuf,yy_n_chars);
if(debug){
fp=fopen("/tmp/logs","wb");
fwrite("nstartn",7,1,fp);
fwrite(tempbuf,1,yy_n_chars,fp);
fwrite("nenditn",7,1,fp);
fclose(fp);
}
}
free(tempbuf);

然后,编译php,按正常方法安装即可,因为我对于libtool不太熟悉,因此我选择static方式,并在 configure时加入了--with-mcrypt,这样我就不用自己手工修改Makefile 电缆桥架

三、测试及结果

编译php,apache后,用ecb.c编译出来的encryptphp加密了几个文件,分别为< 1K,10K+,和40K+,在处理 40K大小文件时出错,别的文件均正常。塑胶地板

这是因为块的ECB加密方式决定了必须使用定长块,所以,请 诸位同好指点采用何种流加密方式可以兼顾到zend每次读取8192字节的缓存处理方式。(其他平台上 zend每次读取的块长度可能有所不同) 

PHP 相关文章推荐
PHP的ASP防火墙
Oct 09 PHP
解决MySQL中文输出变成问号的问题
Jun 05 PHP
PHP垃圾回收机制简单说明
Jul 22 PHP
php header Content-Type类型小结
Jul 03 PHP
discuz程序的PHP加密函数原理分析
Aug 05 PHP
9个经典的PHP代码片段分享
Dec 18 PHP
php使用post数组的键值创建同名变量并赋值的方法
Apr 03 PHP
使用PHP实现下载CSS文件中的图片
Dec 06 PHP
浅析Yii2中GridView常见操作
Apr 22 PHP
在IIS下安装PHP扩展的方法(超简单)
Apr 10 PHP
thinkPHP多表查询及分页功能实现方法示例
Jul 03 PHP
php7中停止php-fpm服务的方法详解
May 09 PHP
php5 mysql分页实例代码
Apr 10 #PHP
Smarty安装配置方法
Apr 10 #PHP
PHP程序员编程注意事项
Apr 10 #PHP
php下使用以下代码连接并测试
Apr 09 #PHP
也谈php网站在线人数统计
Apr 09 #PHP
php实现的在线人员函数库
Apr 09 #PHP
PHP循环获取GET和POST值的代码
Apr 09 #PHP
You might like
php+javascript的日历控件
2009/11/19 PHP
Laravel框架使用Redis的方法详解
2018/05/30 PHP
基于jQuery试卷自动排版系统
2010/07/18 Javascript
Dom 是什么的详细说明
2010/10/25 Javascript
Js 时间间隔计算的函数(间隔天数)
2011/11/15 Javascript
node.js 使用ejs模板引擎时后缀换成.html
2015/04/22 Javascript
轻松实现Bootstrap图片轮播
2020/04/20 Javascript
图文详解Heap Sort堆排序算法及JavaScript的代码实现
2016/05/04 Javascript
easyui messager alert 三秒后自动关闭提示的实例
2016/11/07 Javascript
详解JavaScript数组过滤相同元素的5种方法
2017/05/23 Javascript
微信小程序顶部可滚动导航效果
2017/10/31 Javascript
vue中倒计时组件的实例代码
2018/07/06 Javascript
详解Vscode中使用Eslint终极配置大全
2019/11/08 Javascript
简单了解Vue + ElementUI后台管理模板
2020/04/07 Javascript
用PyQt进行Python图形界面的程序的开发的入门指引
2015/04/14 Python
在Python中使用元类的教程
2015/04/28 Python
非递归的输出1-N的全排列实例(推荐)
2017/04/11 Python
对python dataframe逻辑取值的方法详解
2019/01/30 Python
Python实现的登录验证系统完整案例【基于搭建的MVC框架】
2019/04/12 Python
python logging模块的使用总结
2019/07/09 Python
django使用admin站点上传图片的实例
2019/07/28 Python
python双端队列原理、实现与使用方法分析
2019/11/27 Python
使用python+poco+夜神模拟器进行自动化测试实例
2020/04/23 Python
python基于openpyxl生成excel文件
2020/12/23 Python
python中Mako库实例用法
2020/12/31 Python
利用CSS3实现平移动画效果示例代码
2016/10/12 HTML / CSS
从一次项目重构说起CSS3自定义变量在项目的使用方法
2021/03/01 HTML / CSS
挪威太阳镜和眼镜网上商城:SmartBuyGlasses挪威
2016/08/20 全球购物
哥伦比亚加拿大官网:Columbia Sportswear Canada
2020/09/07 全球购物
英国领先的在线鱼贩:The Fish Society
2020/08/12 全球购物
计算机个人求职信范例
2014/01/24 职场文书
我的中国梦演讲稿1000字
2014/08/19 职场文书
市级三好学生事迹材料
2014/08/27 职场文书
关于环保的广播稿
2015/12/17 职场文书
redis连接被拒绝的解决方案
2021/04/12 Redis
python 如何在list中找Topk的数值和索引
2021/05/20 Python