修改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 相关文章推荐
PHP4在WinXP下IIS和Apache2服务器上的安装实例
Oct 09 PHP
PHP中CURL方法curl_setopt()函数的参数分享
Jan 19 PHP
codeigniter使用技巧批量插入数据实例方法分享
Dec 31 PHP
PHP中SSO Cookie登录分析和实现
Nov 06 PHP
PHP导出带样式的Excel示例代码
Aug 28 PHP
php将文件夹打包成zip文件的简单实现方法
Oct 04 PHP
thinkphp jquery实现图片上传和预览效果
Jul 22 PHP
php PDO实现的事务回滚示例
Mar 23 PHP
PHP开发实现微信退款功能示例
Nov 25 PHP
php+ajax实现商品对比功能示例
Apr 13 PHP
Yii 框架使用数据库(databases)的方法示例
May 19 PHP
PHP正则表达式之RCEService回溯
Apr 11 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和XSL stylesheets转换XML文档
2006/10/09 PHP
PHP判断远程图片是否存在的几种方法
2014/05/04 PHP
微信支付开发教程(一)微信支付URL配置
2014/05/28 PHP
CodeIgniter框架数据库事务处理的设计缺陷和解决方案
2014/07/25 PHP
一个刚完成的layout(拖动流畅,不受iframe影响)
2007/08/17 Javascript
capacityFixed 基于jquery的类似于新浪微博新消息提示的定位框
2011/05/24 Javascript
js数组Array sort方法使用深入分析
2013/02/21 Javascript
引入autocomplete组件时JS报未结束字符串常量错误
2014/03/19 Javascript
JS动态增加删除UL节点LI及相关内容示例
2014/05/21 Javascript
Javascript字符串对象的常用方法简明版
2014/06/26 Javascript
JavaScript中的迭代器和生成器详解
2014/10/29 Javascript
微信小程序 用户数据解密详细介绍
2017/01/09 Javascript
Javascript前端经典的面试题及答案
2017/03/14 Javascript
JavaScript实现的数字与字符串转换功能示例
2017/08/23 Javascript
JavaScript+CSS相册特效实例代码
2017/09/07 Javascript
angularjs实现分页和搜索功能
2018/01/03 Javascript
使用vuex的state状态对象的5种方式
2018/04/19 Javascript
Mint UI实现A-Z字母排序的城市选择列表
2018/12/28 Javascript
js实现数据导出为EXCEL(支持大量数据导出)
2020/03/31 Javascript
[06:14]《辉夜杯》外卡赛附加赛 4支战队巡礼
2015/10/23 DOTA
Python中使用Beautiful Soup库的超详细教程
2015/04/30 Python
实例讲解Python中整数的最大值输出
2019/03/17 Python
Python:slice与indices的用法
2019/11/25 Python
Pyecharts地图显示不完成问题解决方案
2020/05/11 Python
Django 实现图片上传和下载功能
2020/12/31 Python
CSS3属性box-shadow使用指南
2014/12/09 HTML / CSS
美国网上鞋城:Shoeline.com
2016/11/17 全球购物
Perfume’s Club澳大利亚官网:西班牙领先的在线美容店
2021/02/01 全球购物
酒店服务与管理毕业生求职信
2013/11/02 职场文书
大二法学专业职业生涯规划范文
2014/02/12 职场文书
电子商务专业毕业生求职信
2014/06/12 职场文书
一年级语文下册复习计划
2015/01/17 职场文书
2015年推广普通话演讲稿
2015/03/20 职场文书
在校证明模板
2015/06/17 职场文书
职位证明模板
2015/06/23 职场文书
vue实现拖拽交换位置
2022/04/07 Vue.js