出于方便我直接在cpython的github仓库download zip
注意,以下操作(在ubuntu下)将会使你的python3版本默认为你新构建的python解释器,
因为以下操作会在你的/usr/local/bin/下创建一个python3.12并且新建一个python3指向python3.12,操作前请注意影响。
在cpython主目录下执行以下操作,此处可参考cpython的readme文件
./configure
make
make test
sudo make install
如果上一步你已经完成,那么你现在输入python3应该是你make后的python版本,比如
下面开始修改代码。
十分感谢
https://juejin.cn/post/7023708355608707108
的作者提供此简单对称加密方法。
加密程序代码:
#include
#include
long fileRead(char fileName[50],char **buffer){
//打开文件
FILE *fp = fopen(fileName,"rb");
if(fp == NULL){
printf("open file is failed");
exit(1);
}
//把文件指针移到文件末尾
fseek(fp,0,SEEK_END);
//保存文件的长度
long fileSize = ftell(fp);
//把文件指针移到文件开头
fseek(fp,0,SEEK_SET);
//读取文件,保存到buffer中
*buffer = (char*)malloc(fileSize);
fread(*buffer,1,fileSize,fp);
//关闭文件
fclose(fp);
return fileSize;
}
void fileWrite(char fileName[50],char *buffer,long fileSize){
//创建文件进行写入
FILE *fp = fopen(fileName,"wb");
if(fp == NULL){
printf("open file is failed");
exit(1);
}
fwrite(buffer,1,fileSize,fp);
fclose(fp);
}
void encrypt_decode(char encryptFile[50],char encryptedFile[50],int key){
char *buffer;
long fileSize = fileRead(encryptFile,&buffer);
//加密 / 解密
for(int i = 0; i < fileSize; i++){
buffer[i] = buffer[i]^key;
}
fileWrite(encryptedFile,buffer,fileSize);
}
void encrypt(){
char encryptFile[50];//原文件名
int key;//加密关键字
char encryptedFile[50];//加密后文件名
//输出提示信息
printf("Please input the filename you want to encrypt: ");
scanf("%s",encryptFile);
printf("Please input key:");
scanf("%d",&key);
printf("Please input the encrypted filename:");
scanf("%s",encryptedFile);
encrypt_decode(encryptFile,encryptedFile,key);
}
void decode(){
char encryptedFile[50];//加密后文件名
int key;//加密关键字
char decodeFile[50];//原文件名
//输出提示信息
printf("Please input the encrypted filename: ");
scanf("%s",encryptedFile);
printf("Please input key:");
scanf("%d",&key);
printf("Please input output filename:");
scanf("%s",decodeFile);
encrypt_decode(encryptedFile,decodeFile,key);
}
int main(){
encrypt();
return 0;
}
编译:
gcc -o enc encrypto.c
使用:
通过全文搜索我们找到python读取文件的函数是./Python/pythonrun.c的pyrun_file
在其上方声明解密函数
// ***************************encrypto&decrypto funcs***************************//
long fileRead(const char *fileName,char **buffer){
//打开文件
FILE *fp = fopen(fileName,"rb");
if(fp == NULL){
printf("open file is failed");
exit(1);
}
//把文件指针移到文件末尾
fseek(fp,0,SEEK_END);
//保存文件的长度
long fileSize = ftell(fp);
//把文件指针移到文件开头
fseek(fp,0,SEEK_SET);
//读取文件,保存到buffer中
*buffer = (char*)malloc(fileSize);
fread(*buffer,1,fileSize,fp);
//关闭文件
fclose(fp);
return fileSize;
}
void fileWrite(const char fileName[50],char *buffer,long fileSize){
//创建文件进行写入
FILE *fp = fopen(fileName,"wb");
if(fp == NULL){
printf("open file is failed");
exit(1);
}
fwrite(buffer,1,fileSize,fp);
fclose(fp);
}
void encrypt_decode(const char *encryptFile,const char *encryptedFile,int key){
char *buffer;
long fileSize = fileRead(encryptFile,&buffer);
//加密 / 解密
for(int i = 0; i < fileSize; i++){
buffer[i] = buffer[i]^key;
}
fileWrite(encryptedFile,buffer,fileSize);
}
void encrypt(const char* encryptFile , const char *outFile){
int key = 12;// loubw: 先写死 加密关键字
encrypt_decode(encryptFile,outFile,key);
}
// ***************************encrypto&decrypto funcs***************************//
此处解密密码写死了,加密秘钥应写活,以后再说吧。
按照思路,我们应该在读取文件时知道是加密后的文件时,应该将其先解密,获得一个解密了的暂时文件,再将其通过文件IO打开,再让cpython将代码写进内存,之后就可以将解密获得的暂时文件删除(或者可以解密时直接将其解密到内存文件流,这个之后再优化)。
我们修改的是pyrun_file函数。
static PyObject *
pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals,
PyObject *locals, int closeit, PyCompilerFlags *flags)
{
int isDelete = 0;
char *output = NULL;
// 在此处修改运行文件
// loubw
#ifdef MS_WINDOWS
printf("this cpython can not execute in windows because I have not build it.");
exit(0);
#else // 此分支是unix
char *path_bytes;
PyObject *filebytes = PyUnicode_EncodeFSDefault(filename); // 将filename这个PyObject转换为char*以知道传入的文件名
if (filebytes == NULL) {
PyErr_Clear();
return NULL;
}
path_bytes = PyBytes_AS_STRING(filebytes); // 到这转换成char*结束
const char *pFile;
pFile = strrchr(path_bytes,'.');
if(strcmp(pFile, ".bw")==0){ // 查看文件名是否是以.bw为后缀
output = "tmp";
encrypt(path_bytes, output); // 解码,得到临时文件
filename = PyUnicode_FromString(output); // 将filename重新声明为output并转化为PyObject(因为cpython打开文件的函数_Py_fopen_obj需传入的是PyObject)
fp = _Py_fopen_obj(filename, "rb"); // 将fp重新声明为打开临时文件
isDelete = 1; //此flag是为了将来删除临时文件
}
#endif
PyArena *arena = _PyArena_New();
if (arena == NULL) {
return NULL;
}
mod_ty mod;
mod = _PyParser_ASTFromFile(fp, filename, NULL, start, NULL, NULL,
flags, NULL, arena);
if (closeit) {
fclose(fp);
}
PyObject *ret;
if (mod != NULL) {
ret = run_mod(mod, filename, globals, locals, flags, arena, output,isDelete);
}
else {
ret = NULL;
}
_PyArena_Free(arena);
return ret;
}
由于unix和windows文件打开函数是不一样的(windows字符是wchar),所以windows的我没写。
具体代码目的请查看注释。
删除临时文件的代码在同文件的run_mod函数中,修改如下。
注意最后两个参数delFIle和isDelete是新增的,所以此函数的所有引用都需要修改,
头文件的此函数定义也需要修改。
static PyObject *
run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals,
PyCompilerFlags *flags, PyArena *arena, char *delFile,int isDelete)
{
PyThreadState *tstate = _PyThreadState_GET();
PyCodeObject *co = _PyAST_Compile(mod, filename, flags, -1, arena);
if (co == NULL)
return NULL;
if(isDelete==1){
remove(delFile);
}
if (_PySys_Audit(tstate, "exec", "O", co) < 0) {
Py_DECREF(co);
return NULL;
}
PyObject *v = run_eval_code_obj(tstate, co, globals, locals);
Py_DECREF(co);
return v;
}
在主目录再次执行
sudo make install
我们就拿之前加了密的文件进行测试。
目前只实现了单文件的加密,对于导入非内置库的代码加密还需要研究