一、基本原理 考虑截获PHP读取源文件的接口。一开始,我考虑从Apache和PHP之间的接口处处理,参见apache的src/modules/php4/mod_php4.c(这个是PHP用static方式编译进apache,makeinstall后的文件),在send_php()函数中截获文件指针,采用临时文件的方式,解密后替换文件指针。这种方法经过测试实践,证明是可行的。但是,必须使用两次文件操作,效率低下,而且对于DSO方式不可采用。双缘敬老院 由此,重新考虑截获PHP读取文件并装载至缓存的过程,经过费力的寻找,发现在Zend引擎中zend-scanner.c是做此处理的。开始对此文件修改。照明工程 二、实现方法示意 采用libmcrypt作为加密模块,现在采用的是DES方法ECB模式加密, 下面是文件加密的源代码: C++代码 /ecb.c-------------------cuthere-----------/ /encryptforphpsourcecodeversion0.99beta weareusinglibmcrypttoencryptcodes,please installitfirst. compilecommandline: gcc-O6-lmcrypt-lm-oencryptphpecb.c pleasesetLD_LIBRARY_PATHbeforeuse. GNUcopyleft,designedbywangsu,miweicong/ #defineMCRYPT_BACKWARDS_COMPATIBLE1 #definePHP_CACHESIZE8192 #include<mcrypt.h> #include<stdio.h> #include<stdlib.h> #include<math.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> main(intargc,char*argv) { inttd,i,j,inputfilesize,filelength; charfilename[255]; charpassword[12]; FILEifp; intreadfd; charkey; voidblock_buffer; voidfile_buffer; intkeysize; intdecode=0; intrealbufsize=0; structstatfilestat; if(argc==3){ strcpy(password,argv[1]); strcpy(filename,argv[2]); }elseif(argc==4&&!strcmp(argv[1],"-d")){ strcpy(password,argv[2]); strcpy(filename,argv[3]); decode=1; printf("Enteringdecodemode...n"); }else{ printf("Usage:encryptphp[-d]passwordfilenamen"); exit(1); } keysize=mcrypt_get_key_size(DES); key=calloc(1,mcrypt_get_key_size(DES)); gen_key_sha1(key,NULL,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'topenfiletoread"); exit(3); } filestat=malloc(sizeof(stat)); fstat(readfd,filestat); inputfilesize=filestat->st_size; printf("filesizeis%dn",inputfilesize); filelength=inputfilesize; inputfilesize=((int)(floor(inputfilesize/PHP_CACHESIZE))+1)PHP_CACHESIZE; if((file_buffer=malloc(inputfilesize))==NULL){ printf("FATAL:can'tmallocfilebuffer.n"); exit(2); } if((block_buffer=malloc(PHP_CACHESIZE))==NULL){ printf("FATAL:can'tmallocencryptblockbuffer.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,PHP_CACHESIZE); }else{ mdecrypt_ecb(td,realbufsize); } memcpy(file_buffer+jPHP_CACHESIZE,PHP_CACHESIZE); j++; } close(readfd); if((ifp=fopen(filename,"wb"))==NULL){ printf("FATAL:fileaccesserror.n"); exit(3); } fwrite(file_buffer,1,ifp); free(block_buffer); free(file_buffer); free(filestat); fclose(ifp); printf("n"); return0; } /---endofecb.c------------------------------------/ 因为ECB模式是块长度确定的块加密,这里填充了一些空字符。国际展览 然后,修改php代码中Zend/zend-scanner.c如下: (我的php版本是4.01pl2,SUNsparc/solaris2.7,gcc2.95;) 文件前加入: #defineMCRYPT_BACKWARDS_COMPATIBLE1 #include<mcrypt.h> 然后,注释掉大约3510行前后的YY_INPUT的定义。 然后,修改大约5150行前后的yy_get_next_buffer()函数: 函数头加上定义: voidtempbuf; charkey; chardebugstr[255]; inttd,keysize; intx,y; FILEfp; 然后,注释掉 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,num_to_read,yyin))!=0){ /decode/ #definepassword"PHPphp111222" #definedebug0 keysize=mcrypt_get_key_size(DES); key=calloc(1,mcrypt_get_key_size(DES)); gen_key_sha1(key,keysize); mdecrypt_ecb(td,tempbuf,yy_n_chars); memcpy((&yy_current_buffer->yy_ch_buf[number_to_move]),yy_n_chars); if(debug){ fp=fopen("/tmp/logs","wb"); fwrite("nstartn",7,fp); fwrite(tempbuf,yy_n_chars,fp); fwrite("nenditn",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每次读取的块长度可能有所不同) (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|