修改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
Dec 14 PHP
smarty的保留变量问题
Oct 23 PHP
PHP文件读写操作之文件写入代码
Jan 13 PHP
PHP读取数据库并按照中文名称进行排序实现代码
Jan 29 PHP
PHP清除字符串中所有无用标签的方法
Dec 01 PHP
学习php设计模式 php实现命令模式(command)
Dec 08 PHP
php短信接口代码
May 13 PHP
PHP递归获取目录内所有文件的实现方法
Nov 01 PHP
PHP进制转换实例分析(2,8,16,36,64进制至10进制相互转换)
Feb 04 PHP
PHP仿tp实现mvc框架基本设计思路与实现方法分析
May 23 PHP
使用vs code编辑调试php配置的方法
Jan 29 PHP
PHP实现笛卡尔积算法的实例讲解
Dec 22 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
解决Laravel无法使用COOKIE和SESSION的问题
2019/10/16 PHP
Javascript开发包大全整理
2006/12/22 Javascript
在jQuery中 常用的选择器介绍
2013/04/16 Javascript
jquery清空textarea等输入框实现代码
2013/04/22 Javascript
利用CSS、JavaScript及Ajax实现高效的图片预加载
2013/10/16 Javascript
JavaScript代码里的判断小结
2016/08/22 Javascript
微信小程序 教程之条件渲染
2016/10/18 Javascript
EasyUI折叠表格层次显示detailview详解及实例
2016/12/28 Javascript
jQuery基于ajax方式实现用户名存在性检查功能示例
2017/02/10 Javascript
jQuery实现模糊查询的方法分析
2018/05/10 jQuery
React 组件渲染和更新的实现代码示例
2019/02/21 Javascript
微信小程序实现拍照画布指定区域生成图片
2019/07/18 Javascript
[05:39]2014DOTA2国际邀请赛 DK晋级胜者组专访战队国士无双
2014/07/14 DOTA
python 网络爬虫初级实现代码
2016/02/27 Python
tensorflow输出权重值和偏差的方法
2018/02/10 Python
python MysqlDb模块安装及其使用详解
2018/02/23 Python
python实现Zabbix-API监控
2018/09/17 Python
python实现微信自动回复机器人功能
2019/07/11 Python
python3利用Axes3D库画3D模型图
2020/03/25 Python
Pyecharts地图显示不完成问题解决方案
2020/05/11 Python
python实现移动木板小游戏
2020/10/09 Python
白兰氏健康Mall:BRAND’S
2017/11/13 全球购物
美国顶级水上运动专业店:Marine Products
2018/04/15 全球购物
瑞典的玛丽小姐:Miss Mary of Sweden
2019/02/13 全球购物
英国婚礼商城:Wedding Mall
2019/11/02 全球购物
乌克兰鞋类购物网站:Eobuv.com.ua
2020/11/28 全球购物
四川internet信息高速公路(C#)笔试题
2012/02/29 面试题
《十六年前的回忆》教学反思
2014/02/14 职场文书
法人任命书范本
2014/06/04 职场文书
超市开店计划书
2014/09/15 职场文书
机关作风建设工作总结
2014/10/23 职场文书
2015年社区国庆节活动总结
2015/07/30 职场文书
回门宴新娘答谢词
2015/09/29 职场文书
jupyter notebook保存文件默认路径更改方法汇总(亲测可以)
2021/06/09 Python
解决SpringCloud Feign传对象参数调用失败的问题
2021/06/23 Java/Android
详解Vue router路由
2021/11/20 Vue.js