病毒的自我复制

    技术2023-05-06  72

    对静态开源文件进行复制

      设置两个指针,一个指向源文件为srcpf,一个指向目的文件为destpf。为实现用户可控的操作方式,允许输入复制次数,但同时为防止无限次复制导致磁盘损坏,因此设置循环次数上限为1000次。同时,由于各用户磁盘分卷存在差异,因此允许用户对目标地址进行设置;同时在该地址后加上文件名对地址进行测试,以验证并保证地址的可行性。随后,利用fread()函数和fwrite()函数进行文件的读写。需要注意的是,为防止文件名重复,需要对每次循环的文件名进行部分修改,故更改字符“0”使其每次增加1。最后,若复制成功,则输出提示成功字样。   具体代码如下:

    #include<stdio.h> #include<string.h> #include<windows.h> int main(){ int N; do{ printf("请输入复制次数:"); scanf("%d", &N); if(N > 1000) printf("------复制次数过大建议更改!------\n"); }while(N > 1000); FILE *destpf = NULL, *srcpf = NULL; char dest[1000], filename[16]={'c', 'o', 'p', 'y','0', '.', 'c', 'p', 'p', '\0'}; do{ printf("请输入目标地址:"); scanf("%s", &dest); strcat(dest, filename); destpf = fopen(dest, "w+"); if(destpf == NULL) printf("------目标地址无效,请重新输入!------\n"); }while(destpf == NULL); srcpf = fopen("copy.cpp", "r+"); if(!srcpf){ printf("------打开源文件失败!------\n"); system("pause"); return 0; } int size; char temp; rewind(srcpf); while(size = (fread(&temp, sizeof(char), 1, srcpf))) fwrite(&temp, sizeof(char), 1, destpf); fclose(destpf); int len = strlen(dest); for(int i = 1; i < N; i++){ dest[len - 5] += 1; destpf = fopen(dest, "w+"); rewind(srcpf); while(size = (fread(&temp, sizeof(char), 1, srcpf))) fwrite(&temp, sizeof(char), 1, destpf); fclose(destpf); } fclose(srcpf); destpf = srcpf = NULL; printf("------文件已成功复制!------\n"); system("pause"); return 0; }

      对该程序进行测试,当输入超过1000的复制次数时,提示“次数过多”,如下:

      当输入的地址不合法时,提示重新输入直至地址合法,如下:

      当输入正确地址时,按要求在指定地址复制文件并提示“成功复制!”,如下:

      在指定位置查看文件是否成功复制如下:

      观察到,文件已成功复制到指定路径,数量一致且命名数字递增。打开复制文件对内容进行测试,观察到内容也成功被复制,如下:

    对静态二进制文件流进行复制

      由于Windows的exe文件采用了PE文件的组织格式,用fopen()等函数无法操作,需要采用文件流的方式进行复制工作,恰好C++的iostream的子类提供了以文件流方式读取的接口。   引用头文件“fstream”即File Stream中的ifstream类和oftream类。其中ifstream表示从主存中以文件流方式载入一个文件到内存中,由于实验要求完成二进制文件的复制,因此使用参数“ios::binary”以二进制形式载入文件。与之对应的,ofstream表示将内存中的文件以文件流方式转存至主存中,其同样提供了参数“ios::binary”来完成二进制形式的写入方式。注意到,其参数继承于“ios”,因此同样需要包含头文件“ios”。   为提高交互能力和个性化设置,用户可自行设定复制的目的地址。与静态开源文件的路径检测方式不同,此处笔者使用了新的检测方式,来提供另一种路径检测的思路。使用头文件“io.h”中定义的access()函数,其参数包括“filepath”和“mode”,其中filepath可以为文件或文件夹;mode为检测形式,我们使用参数0表示仅检测该路径是否存在。   由于不确定要复制的二进制文件长度,因此每次复制一个字符,直到遇到文件尾,同时使用gcount()函数来确定成功复制的字符长度,当其大于0是进行复制写入操作,以保证每次操作的正确性。   根据上述描述,编写程序代码如下:

    #include<iostream> #include<io.h> #include<string> #include<fstream> #include<ios> #include<windows.h> using namespace std; const int BUFFER_SIZE=4; void update(ifstream &in, char *filename){ std::streamsize length; char buffer[2]; ofstream destfile(filename, ios::binary); while(!in.eof()){ in.read(buffer, 1); length = in.gcount(); if (length > 0) destfile.write(buffer, length); } in.close(); destfile.close(); } int main(){ int N; do{ printf("请输入复制次数:"); scanf("%d", &N); if(N > 1000) printf("------复制次数过大建议更改!------\n"); }while(N > 1000); char dest[1000]; int flag; do{ printf("请输入目标地址:"); scanf("%s", &dest); flag = access(dest, 0); if(flag != 0) printf("------目标地址无效,请重新输入!------\n"); }while(flag != 0); ifstream srcfile("F:\\copyexe.exe"); if(!srcfile){ printf("------打开源文件失败!------\n"); system("pause"); return 0; } srcfile.close(); char filetail[16]={'c', 'o', 'p', 'y','0', '.', 'e', 'x', 'e', '\0'}; strcat(dest, filetail); int len = strlen(dest); for(int i = 0; i < N; i++){ dest[len - 5] = '0' + i; ifstream srcfile("F:\\copyexe.exe", ios::binary); update(srcfile, dest); } printf("------文件已成功复制!------\n"); system("pause"); return 0; }

      该复制程序对文件复制数量进行了限制,最大复制数量为1000,当超过阈值时提示“复制次数过多”,如下:

      检测access()函数使用的正确性,观察,非法路径是否会被成功拦截,如下:

      当输入有效地址后完成复制并给用户提示,如下:

      在指定地址下查看复制是否成功,观察到出现指定次数个文件,如下:

      打开运行,其功能保持和源程序的一致性,如下:

    Processed: 0.013, SQL: 9