修改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字符串截取中文截取2,单字节截取模式
Dec 10 PHP
php 验证码制作(网树注释思想)
Jul 20 PHP
php中常用的预定义变量小结
May 09 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(九)
Jun 24 PHP
php将access数据库转换到mysql数据库的方法
Dec 24 PHP
PHP数组游标实现对数组的各种操作详解
Jan 26 PHP
Symfony学习十分钟入门经典教程
Feb 03 PHP
Zend Framework教程之Autoloading用法详解
Mar 08 PHP
PHP模板引擎Smarty内置变量调解器用法详解
Apr 11 PHP
Laravel利用gulp如何构建前端资源详解
Jun 03 PHP
PHP中quotemeta()函数的用法讲解
Apr 04 PHP
ThinkPHP5.1+Ajax实现的无刷新分页功能示例
Feb 10 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
wordpress之wp-settings.php
2007/08/17 PHP
php适配器模式介绍
2012/08/14 PHP
PHP中图片等比缩放的实例
2013/03/24 PHP
php实例分享之html转为rtf格式
2014/06/02 PHP
服务器迁移php版本不同可能诱发的问题
2015/12/22 PHP
实例讲解YII2中多表关联的使用方法
2017/07/21 PHP
js类的静态属性和实例属性的理解
2009/10/01 Javascript
文本域中换行符的替换示例
2014/03/04 Javascript
一个JavaScript操作元素定位元素的实例
2014/10/29 Javascript
pc加载更多功能和移动端下拉刷新加载数据
2016/11/07 Javascript
JavaScript中的this陷阱的最全收集并整理(没有之一)
2017/02/21 Javascript
详解用webpack把我们的业务模块分开打包的方法
2017/07/20 Javascript
AngularJS 打开新的标签页实现代码
2017/09/07 Javascript
原生JS实现动态添加新元素、删除元素方法
2019/05/05 Javascript
如何在Angular8.0下使用ngx-translate进行国际化配置
2019/07/24 Javascript
基于vue写一个全局Message组件的实现
2019/08/15 Javascript
vue中 this.$set的用法详解
2019/09/06 Javascript
Vue 实现一个命令式弹窗组件功能
2019/09/25 Javascript
微信小程序实现页面监听自定义组件的触发事件
2020/11/01 Javascript
python实现bitmap数据结构详解
2014/02/17 Python
Python爬虫框架Scrapy实战之批量抓取招聘信息
2015/08/07 Python
Python实现Youku视频批量下载功能
2017/03/14 Python
Python连接Mssql基础教程之Python库pymssql
2018/09/16 Python
Python使用folium excel绘制point
2019/01/03 Python
django ajax发送post请求的两种方法
2020/01/05 Python
Python3中configparser模块读写ini文件并解析配置的用法详解
2020/02/18 Python
python实现电子词典
2020/03/03 Python
调整Jupyter notebook的启动目录操作
2020/04/10 Python
Pycharm的Available Packages为空的解决方法
2020/09/18 Python
Herve Leger官网:标志性绷带连衣裙等
2018/12/26 全球购物
杭州联环马网络笔试题面试题
2013/08/04 面试题
导游词开场白
2015/01/31 职场文书
初中教师个人工作总结
2015/02/10 职场文书
2015年农村党员公开承诺事项
2015/04/28 职场文书
postgresql无序uuid性能测试及对数据库的影响
2021/06/11 PostgreSQL
AndroidStudio图片压缩工具ImgCompressPlugin使用实例
2022/08/05 Java/Android