修改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 strtok()函数的优点分析
Mar 02 PHP
php弹出对话框实现重定向代码
Jan 23 PHP
PHP中file_exists函数不支持中文名的解决方法
Jul 26 PHP
为PHP安装imagick时出现Cannot locate header file MagickWand.h错误的解决方法
Nov 03 PHP
php文件系统处理方法小结
May 23 PHP
PHP 在数组中搜索给定的简单实例 array_search 函数
Jun 13 PHP
PHP二分查找算法示例【递归与非递归方法】
Sep 29 PHP
基于thinkPHP3.2实现微信接入及查询token值的方法
Apr 18 PHP
PHP基于双向链表与排序操作实现的会员排名功能示例
Dec 26 PHP
php微信开发之音乐回复功能
Jun 14 PHP
YII框架学习笔记之命名空间、操作响应与视图操作示例
Apr 30 PHP
php获取是星期几的的一些常用姿势
Dec 15 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读取flv文件的播放时间长度
2009/09/03 PHP
如何给phpcms v9增加类似于phpcms 2008中的关键词表
2013/07/01 PHP
PHP字符串word末字符实现大小写互换的方法
2014/11/10 PHP
php简单实现无限分类树形列表的方法
2015/03/27 PHP
简单谈谈favicon
2015/06/10 PHP
php如何连接sql server
2015/10/16 PHP
在WordPress中使用wp_count_posts函数来统计文章数量
2016/01/05 PHP
PHP批量去除BOM头内容信息代码
2016/03/11 PHP
Laravel 验证码认证学习记录小结
2019/12/20 PHP
Javascript开发包大全整理
2006/12/22 Javascript
Javascript 表单之间的数据传递代码
2008/12/04 Javascript
jQuery 打造动态下滑菜单实现说明
2010/04/15 Javascript
ie下jquery.getJSON的缓存问题的处理方法
2013/03/29 Javascript
深入理解JavaScript系列(37):设计模式之享元模式详解
2015/03/04 Javascript
jQuery弹出层插件Lightbox_me使用指南
2015/04/21 Javascript
jQuery焦点图切换特效代码分享
2015/09/15 Javascript
详解jQuery中的empty、remove和detach
2016/04/11 Javascript
JavaScript实现替换字符串中最后一个字符的方法
2017/03/07 Javascript
JS实现滚动条触底加载更多
2019/09/19 Javascript
Vue切换组件实现返回后不重置数据,保留历史设置操作
2020/07/21 Javascript
Vue基本指令实例图文讲解
2021/02/25 Vue.js
Python中的with语句与上下文管理器学习总结
2016/06/28 Python
django admin 后台实现三级联动的示例代码
2018/06/22 Python
Python实现Event回调机制的方法
2019/02/13 Python
Python面向对象程序设计类的多态用法详解
2019/04/12 Python
详解vscode实现远程linux服务器上Python开发
2020/11/10 Python
基于pycharm 项目和项目文件命名规则的介绍
2021/01/15 Python
python连接手机自动搜集蚂蚁森林能量的实现代码
2021/02/24 Python
纯CSS3发光分享按钮的实现教程
2014/09/06 HTML / CSS
女娲补天教学反思
2014/02/05 职场文书
教学质量评估实施方案
2014/03/17 职场文书
集中采购方案
2014/06/10 职场文书
教师年度考核自我评鉴
2015/08/11 职场文书
高三化学教学反思
2016/02/22 职场文书
财产分割协议书
2016/03/22 职场文书
Python离线安装openpyxl模块的步骤
2021/03/30 Python