您的位置:首页 > 编程语言 > C语言/C++

程序删除自己,改写自己

2016-01-05 20:31 465 查看
程序删除自己改写自己

有这样一个问题:让程序本身能限制它的运行次数,比如只能运行5次。
目前使用的方法大都是通过读取和改写外部文件的数据来判断运行的次数,比如增加配置文件(.inf),读写系统注册表,或增加其它类似文件。也就是说,程序运行要依靠外部数据来判断运行次数。
有没有不依靠外部数据的呢。。。
有这样想法:程中文件本身有一个数据5,当这个程序结束时,把这个5变成其它数,比如4,当下次运行的时候取读4,运行结束时再把4变成3,此下去。。。这样就能通过这个数字的变化来控制程序运行次数。
大家都知道一个windows应用程序在运程中,所占用的程序文件是不能常规删除和改写的。这就是说,程序在磁盘上的文件里面的这个“10”不能在运行时改写,文件被系统写保护了(可以读取)。
现在请做这样一件事:新建一个文本文件A.txt,然后在里面写入del %0,保存之后把A.txt文件后缀后改掉,变成A.bat。del %0的意思删除文件本身。这样就建成了一个批处理文件,双击它就能运行了。双击它之后A.bat文件没了!(至于为啥windows程序不能删除自己,bat批处理文件可以删除自己,我也说不清楚,我对cmd没深入了解)

程序思路是这样的:
1、程序hello.exe读取自己到内存中
2、hello.exe在内存中查找“5:次数在这里”这个字符串
3、将上步查找到的“5:次数在这里”这个字符串改写为“4:次数在这里”
4、将内存中的全部数据写入temp.exe文件
5、hello.exe先建立temp.bat文件,调用temp.bat文件后退出
6、temp.bat先删除hello.exe,再将temp.exe改名为hello.exe,后最删除自已

我用的环境是dev-c++,win8系统,能够正常编译执行。(直接copy回去研究吧,呵呵)

 

 

#include <iostream>
#include <stdlib.h>
#include <string.h>

struct file_inf{char* name;long len;};//用来存储文件的信息

void* mem_with_file(struct file_inf&);//将文件读入内存,并返回内存的地址。文件的长度,文件名存入file_inf结构体
char* file_with_mem(struct file_inf&,void*);//将内存中的内容写入文件
void* write_mem(char *dest,char *src, int n);//更改内存中的数据
char* search_bite(void *buffer, size_t count,char* str);//查找内存中的数据
bool  write_bat(char*); // 用来建立bat文件
char* FileName(char*);//获取文件名
//以上函数的具实现,请下main函数后面的定义

int main(int argc, char** argv)
{
file_inf testfile;
testfile.name=argv[0];//程序的文件名
testfile.len=0;
void* p=mem_with_file(testfile);//打开程序本身文件,并将文件内容读入内存
testfile.name="temp.exe";//默认为本程序的文件名,要更改
char* A="5:次数在这里";//用于存储程序运行次数的数据,初始为5 ,要定义为常量
//不能用A[]="5:次数在这里"这条句,常量在编译时就已经存入了,要用变量
char temp[50];
strcpy(temp,A);
char* s=search_bite(p,testfile.len,temp);//在内存中查找 5:password 这个字符串
//if(s!=NULL){printf("find!\n");}else{printf("Can not find!\n");};//显示查找结果
int times=atoi(A);//将字符串转化成数字,数字应该是5
if(times==0){
free(p);
p=NULL;
printf("次数达到0\n",times);//次数限制相关的语句可以放在这里了
getchar();//暂停以便看到输出的信息
return 0;
}else{
printf("剩余次数%d\n",times);
}
temp[0] ='0'+times-1;//将字符5变成字符4
if(s!=NULL)write_mem(s,temp,strlen(temp));//更改内存中的数据(以字符串改写的方式)
file_with_mem(testfile,p);// 将内存中的改好的数据写入文件
free(p);//小小内存泄露哦
p=NULL;
char* MyFileName=FileName(argv[0]);
write_bat(MyFileName);//建立bat文件
printf("q%c %d3299%d\n有想法可以讨论下\n按任意键继续。。。\n",'q',411,56);// 不喜欢就关掉吧,呵呵
getchar();//暂停程序,这里你可以查看程序生成的临时文件
system("start temp.bat") ;
return 0;
}

void* mem_with_file(file_inf& _inf )
{
long L;//文件长度单位:字节
FILE* fp;
void* addr=NULL;
fp=fopen(_inf.name,"rb");//二进制方式读取文本内容,换行占两个字节
//if(fp==NULL) { printf("file can not open!\n");return NULL;}else{printf("file open!\n");};
fseek(fp,0,2);//文件内指向末尾
L=(long)ftell(fp);//文件长度
addr=malloc(L);//分配内存空间
if(addr!=NULL)
{
fseek(fp,0,0);//文件内指向开头
long i=fread(addr,1,L,fp);
_inf.len=i;
} else {
printf("addr is NULL !\n");return NULL;
}
fclose(fp);
return addr;
}

char* file_with_mem(struct file_inf& _inf,void* buffer)
{
FILE* fp;
fp=fopen(_inf.name,"wb");//二进制方式,新建一个二进制文件,已存在的文件将被删除,只允许写
fwrite(buffer,1,_inf.len,fp);
fclose(fp);
return _inf.name;
}

void* write_mem(char *dest,char *src, int n)// 将src中的前n个字节复制到dest
{
if(n>strlen(src)) return NULL;
return strncpy(dest,src,n);
}

char* search_bite(void *buffer, size_t count,char* str)//在以buffer为始地点,count为度长度的一块内存中查找str,若找到返回找到的位置
{
if(strlen(str)>count) return NULL;
for(size_t i=0;i<=count-strlen(str);i++)
{
char* p=strstr((char*)buffer+i,str);
if(p!=NULL) return p;
}
return NULL;
}

bool write_bat(char* fileName)
{
FILE* fp;
fp=fopen("temp.bat","w");//文本方式,新建文件,已存在的文件将被删除,只允许写
if(fp==NULL) { printf("file can not open!\n");return false;}
else
{//以下是写入bat文件的具体内容
fprintf(fp,"\
@echo off\n\
if exist %s del %s\n\
if exist temp.exe ren temp.exe %s\n\
del %%0 & taskkill  /f /im cmd.exe\n",fileName,fileName,fileName);
};
fclose(fp);
return true;
}

char* FileName(char* PathName){
for(int i=strlen(PathName);i>0;i--){
if(PathName[i-1]=='\\'||PathName[i-1]=='/')
return &(PathName[i]);
};
return NULL;
}

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息