修改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 相关文章推荐
cache_lite试用
Feb 14 PHP
php htmlentities和htmlspecialchars 的区别
Aug 18 PHP
PHP安全技术之 实现php基本安全
Sep 04 PHP
理解和运用PHP中的多态性[译]
Aug 02 PHP
php绘制一个矩形的方法
Jan 24 PHP
php实现用已经过去多长时间的方式显示时间
Jun 05 PHP
Ubuntu VPS中wordpress网站打开时提示”建立数据库连接错误”的解决办法
Nov 03 PHP
详解php用curl调用接口方法,get和post两种方式
Jan 13 PHP
浅谈PHP的排列组合(如输入a,b,c 输出他们的全部组合)
Mar 14 PHP
PHP4和PHP5版本下解析XML文档的操作方法实例分析
May 20 PHP
laravel5表单唯一验证的实例代码
Sep 30 PHP
Thinkphp 框架基础之入口文件功能、定义与用法分析
Apr 27 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
fleaphp常用方法分页之Pager使用方法
2011/04/23 PHP
php内核解析:PHP中的哈希表
2014/01/30 PHP
php魔术函数__call()用法实例分析
2015/02/13 PHP
php查看网页源代码的方法
2015/03/13 PHP
正确的PHP匹配UTF-8中文的正则表达式
2015/05/13 PHP
ThinkPHP3.2.2实现持久登录(记住我)功能的方法
2016/05/16 PHP
PHP中让json_encode不自动转义斜杠“/”的方法
2017/02/28 PHP
jQuery 动态酷效果实现总结
2009/12/27 Javascript
通过判断JavaScript的版本实现执行不同的代码
2010/05/11 Javascript
jquery实现商品拖动选择效果代码(自写)
2013/05/28 Javascript
js Date概念详细介绍
2013/11/22 Javascript
利用js读取动态网站从服务器端返回的数据
2014/02/10 Javascript
jQuery EasyUI 布局之动态添加tabs标签页
2015/11/18 Javascript
jQuery EasyUI之验证框validatebox实例详解
2017/04/10 jQuery
jQuery实现的简单无刷新评论功能示例
2017/11/08 jQuery
webpack4的迁移的使用方法
2018/05/25 Javascript
在小程序开发中使用npm的方法
2018/10/17 Javascript
Vue项目路由刷新的实现代码
2019/04/17 Javascript
原生JavaScript实现日历功能代码实例(无引用Jq)
2019/09/23 Javascript
python集合类型用法分析
2015/04/08 Python
Python网络爬虫项目:内容提取器的定义
2016/10/25 Python
Python中的日期时间处理详解
2016/11/17 Python
详谈Python基础之内置函数和递归
2017/06/21 Python
Django跨域请求问题的解决方法示例
2018/06/16 Python
Python 对输入的数字进行排序的方法
2018/06/23 Python
python使用matplotlib模块绘制多条折线图、散点图
2020/04/26 Python
tensorflow模型的save与restore,及checkpoint中读取变量方式
2020/05/26 Python
Python pysnmp使用方法及代码实例
2020/08/24 Python
实验教师岗位职责
2014/02/13 职场文书
《高尔基和他的儿子》教学反思
2014/04/09 职场文书
国贸专业求职信
2014/06/28 职场文书
自动化专业大学生职业生涯规划范文:爱拚才会赢
2014/09/12 职场文书
2014年宣传部工作总结
2014/11/12 职场文书
2016年12月份红领巾广播稿
2015/12/21 职场文书
Spring Cache和EhCache实现缓存管理方式
2021/06/15 Java/Android
Python+Pillow+Pytesseract实现验证码识别
2022/05/11 Python