软件自毁初探
今天在看《加密解密全攻略》的时候,看到了软件自毁技术的介绍,感觉挺有意思的。其基本原理是:
鉴于单纯设置一个计数器易被查出,通过修改使其不起作用。即通过数据文件,软件执行前通过关键字找到计数基数,然后计算和判别,如果在合理范围,则设定新的关键字,将计数基数放在新关键字指定的位置;不合理, 则启动自毁程序。
例:
位置:0 1 2 3 4 5 6 7 8 9 0
数据:X U T N 0 7 a h d g A
上例中关键字位置为4、5,找到0、7,根据0、7从0开始的第七个数就是基数。
该书上提供了一段实现代码,我实现了一下,发现代码中有很多的错误,我将程序做了一些更改和修正,终于得到正确结果。
例子是限制使用次数为n=4,即第五次的时候自毁。初始数据文件为data.dat,原始数据为alksd30jasldkjfhsaKD60hsajkfh,50nbv,938kjlsfh,9843Ark,cn9qow72r74398r uebfdh 91, 8reiuy hc84y7rh8hjf
代码
#include<stdio.h>
#include<time.h>
#include <stdlib.h>
#include<io.h>
void kill(void); //自毁函数
main()
{
FILE *fp1;
char ch,iasc1,iasc2;//iasc1、iasc2要比较的基数
int x,x1,x2,x3,x4,i,c,n;
srand((unsigned)time(NULL));//初始化随机数
if((fp1=fopen("data.dat","r+b"))==NULL)
{
printf("\n cannot open data.dat file\n");
exit(1);
}
/*取出数据文件中第一个关键字,即基数的位置的位置,第一个关键字放在数据文件的20、21位上*/
fseek(fp1,20,0);
ch=getc(fp1);
x=((int)(ch))&0x0ff;
x=x-0x30;
x2=x*10;
ch=getc(fp1);
x=((int)(ch))&0x0ff;
x=x-0x30;
x2=x2+x;
/*取出数据文件中的第二个关键字,第二个关键字放在数据文件的5、6位上*/
fseek(fp1,5,0);
ch=getc(fp1);
x=((int)(ch))&0x0ff;
x=x-0x30;
x1=x*10;
ch=getc(fp1);
x=((int)(ch))&0x0ff;
x=x-0x30;
x1=x1+x;
/*根据第一个关键字,找出第一个基数的位置*/
fseek(fp1,x1,0);
ch=getc(fp1);
x=((int)(ch))&0x0ff;
x=x-0x30;
x3=x*10;
ch=getc(fp1);
x=((int)(ch))&0x0ff;
x=x-0x30;
x3=x3+x;
/*根据第二个关键字,找出第二个基数的位置*/
fseek(fp1,x2,0);
ch=getc(fp1);
x=((int)(ch))&0x0ff;
x=x-0x30;
x4=x*10;
ch=getc(fp1);
x=((int)(ch))&0x0ff;
x=x-0x30;
x4=x4+x;
/*取出第一个基数*/
fseek(fp1,x3,0);
iasc1=getc(fp1);
/*取出第二个基数*/
fseek(fp1,x4,0);
iasc2=getc(fp1);
/*根据第一、第二个基数的ascii码大小进行比较,其差必须为1。由于设定了使用次数为4次,基数从
A开始,因此第一个基数的ascii码必须在65-68中,第二必须在98-101中*/
n=((int)(iasc2-iasc1)&0x0ff)-32;
if (n!=1) kill();
if(iasc1<65||iasc1>68) kill();
if(iasc2<98||iasc2>101) kill();
/*判定正确,则判定部分结束,设置下一次的数据文件,基数为原始基数的技术上加1*/
iasc1=iasc1+1;
iasc2=iasc2+1;
fseek(fp1,0,0);
for (i=0;i<100;i++)//书籍产生原始数据文件
{
c=rand()%3;
if (c==0){ch=(char)rand()%9;ch=ch+0x30;};
if (c==1){ch=(char)rand()%26;ch=ch+0x41;};
if (c==2){ch=(char)rand()%26;ch=ch+0x61;};
putc(ch,fp1);
}
x4=rand()%98;//随机一个基数的存放位置,注意有限定条件,4、5、6、19、20、21位置上空出
while(x4==4||x4==5||x4==6||x4==19||x4==20||x4==21)
x4=rand()%98;
x3=rand()%98;
while(x4==x3||x4==x3+1||x3==x4+1||x3==4||x3==5||x3==6
||x3==19||x3==20||x3==21)
x3=rand()%98;
fseek(fp1,x4,0);
putc(iasc2,fp1);
fseek(fp1,x3,0);
putc(iasc1,fp1);
x2=rand()%98;
while(x2==4||x2==5||x2==6||x2==19||x2==20||x2==21||
x2==x3||x2==x3+1||x3==x2+1||x2==x4||x2==x4+1||x4==x2+1)
x2=rand()%98;
x1=rand()%98;
while(x1==4||x1==5||x1==6||x1==19||x1==20||x1==21||x1==x3||
x1==x3+1||x3==x1+1||x1==x4||x1==x4+1||x4==x1+1||x1==x2||x1==x2+1||x2==x1+1)
x1=rand()%98;
/*将基数的位置放入随机产生的位置*/
ch=(char)((x4/10)+0x30);
fseek(fp1,x2,0);
putc(ch,fp1);
ch=(char)((x4%10)+0x30);
putc(ch,fp1);
ch=(char)((x3/10)+0x30);
fseek(fp1,x1,0);
putc(ch,fp1);
ch=(char)((x3%10)+0x30);
putc(ch,fp1);
/*将基数的位置的存储位置放入5、6、20、21的位置*/
ch=(char)((x2/10)+0x30);
fseek(fp1,20,0);
putc(ch,fp1);
ch=(char)((x2%10)+0x30);
putc(ch,fp1);
ch=(char)((x1/10)+0x30);
fseek(fp1,5,0);
putc(ch,fp1);
ch=(char)((x1%10)+0x30);
putc(ch,fp1);
fclose(fp1);
/*end of test*/
printf("The program is running correct!!!");
}
void kill(void)
{
int i,len,fd,offset;
char ch;
FILE *fp2;
printf("\n\nerror!!!");
fp2=fopen("sefd.exe","wb");//自毁程序,sefd.exe为我编译产生的可执行文件
fd=fileno(fp2);
len=filelength(fd);
for(i=0;i<100;i++)
{
offset=rand()%(len+1);
ch=rand()%255;
fseek(fp2,offset,0);
putc(ch,fp2);
}
fclose(fp2);
exit(1);
}
/*end*/