修改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 相关文章推荐
图形数字验证代码
Oct 09 PHP
php入门学习知识点六 PHP文件的读写操作代码
Jul 14 PHP
php中instanceof 与 is_a()区别分析
Mar 03 PHP
php使用simplexml_load_file加载XML文件并显示XML的方法
Mar 19 PHP
Zend Framework动作助手(Zend_Controller_Action_Helper)用法详解
Mar 05 PHP
PHP 生成微信红包代码简单
Mar 25 PHP
windows下的WAMP环境搭建图文教程(推荐)
Jul 27 PHP
php大小写转换函数(strtolower、strtoupper)用法介绍
Nov 17 PHP
PHP操作Postgresql封装类与应用完整实例
Apr 24 PHP
网站被恶意镜像怎么办 php一段代码轻松搞定(全面版)
Oct 23 PHP
PHP中有关长整数的一些操作教程
Sep 11 PHP
详解Go与PHP的语法对比
May 29 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中的array_filter()函数去掉多维空值的代码分享
2012/09/07 PHP
php 人员权限管理(RBAC)实例(推荐)
2017/05/24 PHP
PHP中$GLOBALS与global的区别详解
2019/03/21 PHP
我也种棵OO树JXTree[js+css+xml]
2007/04/02 Javascript
JavaScript加密解密7种方法总结分析
2007/10/07 Javascript
js运动框架_包括图片的淡入淡出效果
2013/05/11 Javascript
原生JS可拖动弹窗效果实例代码
2013/11/09 Javascript
jquery 根据name名获取元素的value值
2015/02/27 Javascript
javascript学习笔记之函数定义
2015/06/25 Javascript
前端程序员必须知道的高性能Javascript知识
2016/08/24 Javascript
浅谈函数调用的不同方式,以及this的指向
2017/09/17 Javascript
如何利用@angular/cli V6.0直接开发PWA应用详解
2018/05/06 Javascript
微信小程序实现留言板
2018/10/31 Javascript
Vue实现移动端左右滑动效果的方法
2018/11/27 Javascript
Node.js 如何利用异步提升任务处理速度
2019/01/07 Javascript
其实你可以少写点if else与switch(推荐)
2019/01/10 Javascript
微信小程序tabBar 返回tabBar不刷新页面
2019/07/25 Javascript
vue实现拖拽的简单案例 不超出可视区域
2019/07/25 Javascript
超详细的5个Shell脚本实例分享(值得收藏)
2019/08/15 Javascript
jQuery实现简单弹幕效果
2019/11/28 jQuery
启动targetcli时遇到错误解决办法
2017/10/26 Python
numpy判断数值类型、过滤出数值型数据的方法
2018/06/09 Python
python opencv人脸检测提取及保存方法
2018/08/03 Python
纯python进行矩阵的相乘运算的方法示例
2019/07/17 Python
python实现计算器功能
2019/10/31 Python
Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性(推荐)
2020/07/03 Python
如何使用python-opencv批量生成带噪点噪线的数字验证码
2020/12/21 Python
HTML5之SVG 2D入门7—SVG元素的重用与引用
2013/01/30 HTML / CSS
JD Sports瑞典:英国领先的运动时尚商店
2018/01/28 全球购物
Chain Reaction Cycles俄罗斯:世界上最大的在线自行车商店
2019/08/27 全球购物
Happy Socks英国官网:购买五颜六色的袜子
2020/11/03 全球购物
《蒙娜丽莎之约》教学反思
2014/02/27 职场文书
司考复习计划
2015/01/19 职场文书
军训个人总结
2015/03/03 职场文书
幼儿园庆六一主持词
2015/06/30 职场文书
大学生奖学金获奖感言(范文)
2019/08/15 职场文书