对指定文件及指定特征码进行查杀
首先要求用户输入查杀文件的绝对路径,通过access()函数进行路径正确性的验证。access()函数位于头文件“io.h”中,其存在两个参数,第一个参数为需要验证的目标文件或文件夹路径,第二个参数为验证模式,详细信息如下:
参数 | 对应模式 |
---|---|
F_OK = 0 | 仅判断是否存在 |
X_OK = 1 | 判断是否有执行权限 |
W_OK = 2 | 仅判断是否有写权限 |
R_OK = 4 | 仅判断是否有读权限 |
因此,我们使用参数“0”来检测用户输入地址是否合法。同理完成特征码文件指定路径的验证工作。部分代码如下:
do{
printf("请输入查杀文件绝对路径:");
scanf("%s", &file_addr);
judge = access(file_addr, 0);
if(judge != 0) printf("------------------------\n该路径错误,请重新输入!");
}while(judge != 0);
由于目标查杀文件大小未知,因此不妨设置一个大小为256M的char类型空间来完成对目标文件信息的存储,该大小由MAXSIZE预编译定义。同理,由于特征码一般较为精简,设置存储其的char类型空间为300B,该大小由SIGSIZE预编译定义。这两组存储空间均在程序执行过程中动态申请,具体代码如下:
char *dest_file = (char*)malloc(sizeof(char) * MAXSIZE);
char *sig = (char*)malloc(sizeof(char) * SIGSIZE);
if(dest_file == NULL || sig == NULL){
printf("空间申请失败!\n");
system("pause");
return 0;
}
依次读取两文件信息至内存,读取模式均采用只读方式读取,具体代码如下:
FILE *pf = fopen(file_addr, "r+");
FILE *psig = fopen(sig_addr, "r+");
if(pf == NULL || psig == NULL){
printf("文件载入失败!\n");
system("pause");
return 0;
}
int i = 0;
while(!feof(pf)){
fread(dest_file + i, 1, 1, pf);
i++;
}
fclose(pf);
i = 0;
while(!feof(psig)){
fread(sig + i, 1, 1, psig);
i++;
}
fclose(psig);
当信息加载完成后,使用前期封装好的头文件“BM.h”中的BM()函数来完成特征串的查找工作,具体代码如下:
int dest_len = strlen(dest_file), sig_len = strlen(sig);
bool flag = BM(dest_file, dest_len, sig, sig_len);
if(flag == true){
printf("GET VIRUS!\n");
}
else printf("NO VIRUS!\n");
利用前期实验自行编写的宏病毒文件提取特征码后进行查找测试,验证该程序的正确性,该目标文件及特征码信息如下:
具体完整代码如下:
#include <stdio.h>
#include <io.h>
#include <windows.h>
#include <string.h>
#include "BM.h"
#define MAXSIZE 104857600
#define SIGSIZE 300
int main(){
printf("------该程序将完成对指定文件指定特征码的查杀------\n\n");
char file_addr[1000];
int judge;
do{
printf("请输入查杀文件绝对路径:");
scanf("%s", &file_addr);
judge = access(file_addr, 0);
if(judge != 0) printf("------------------------\n该路径错误,请重新输入!");
}while(judge != 0);
char sig_addr[1000];
do{
printf("请输入特征码所在文件路径:");
scanf("%s", &sig_addr);
judge = access(sig_addr, 0);
if(judge != 0) printf("------------------------\n该路径错误,请重新输入!");
}while(judge != 0);
printf("\n------Result------\n");
char *dest_file = (char*)malloc(sizeof(char) * MAXSIZE);
char *sig = (char*)malloc(sizeof(char) * SIGSIZE);
if(dest_file == NULL || sig == NULL){
printf("空间申请失败!\n");
system("pause");
return 0;
}
FILE *pf = fopen(file_addr, "r+");
FILE *psig = fopen(sig_addr, "r+");
if(pf == NULL || psig == NULL){
printf("文件载入失败!\n");
system("pause");
return 0;
}
int i = 0;
while(!feof(pf)){
fread(dest_file + i, 1, 1, pf);
i++;
}
fclose(pf);
i = 0;
while(!feof(psig)){
fread(sig + i, 1, 1, psig);
i++;
}
fclose(psig);
int dest_len = strlen(dest_file), sig_len = strlen(sig);
bool flag = BM(dest_file, dest_len, sig, sig_len);
if(flag == true){
printf("GET VIRUS!\n");
}
else printf("NO VIRUS!\n");
system("pause");
return 0 ;
}
对指定文件夹及指定特征码进行查杀
程序编写过程,首先利用access()函数对用户输入的地址信息进行检测,当输入地址信息正确后,对目标文件夹字符串进行处理,使其以字符“\”结尾,以完成与SearchFile()函数的接口。接着申请需要存目标文件信息的空间和存特征码的空间,将其两者作为参数传给SearchFile()函数进行处理,以保证空间不会多申请或少申请,同时节省空间的申请时间。接着读取特征码信息至内存中,并将其作为参数传递给SearchFile()函数。随后执行SearchFile()函数,完成对指定文件夹的搜索。当搜索完成后释放申请到的空间信息,并结束程序。具体代码如下:
int main(){
printf("------该程序将完成对指定文件夹下指定特征码的查杀------\n\n");
char file_addr[1000];
int judge;
do{
printf("请输入查杀文件夹绝对路径:");
scanf("%s", &file_addr);
judge = access(file_addr, 0);
if(judge != 0) printf("------------------------\n该路径错误,请重新输入!");
}while(judge != 0);
char sig_addr[1000];
do{
printf("请输入特征码所在文件路径:");
scanf("%s", &sig_addr);
judge = access(sig_addr, 0);
if(judge != 0) printf("------------------------\n该路径错误,请重新输入!");
}while(judge != 0);
printf("\n------Result------\n");
if(file_addr[strlen(file_addr) - 1] != '\\')
strcat(file_addr, "\\");
FILE *psig = fopen(sig_addr, "rb");
if(psig == NULL){
printf("特征码载入失败!\n");
system("pause");
return 0;
}
char *sig = (char*)malloc(sizeof(char) * SIGSIZE);
char *dest_file = (char*)malloc(sizeof(char) * MAXSIZE);
if(sig == NULL || dest_file == NULL){
printf("空间申请失败!\n");
system("pause");
return 0;
}
int i = 0, sig_len;
sig_len = fread(sig, 1, SIGSIZE, psig);
SearchFile(file_addr, sig, sig_len, dest_file);
free(sig);
free(dest_file);
return 0 ;
}
接下来重点解读SearchFile()函数。首先介绍一下位于“io.h”头文件中的存储文件信息的结构体“_finddata_t”,其结构体具体信息如下:
其中,“attrib”记录文件属性,如:是否隐藏、是否为文件夹、是否只读等;“time_create”记录文件创建时间;“time_access”记录文件最后被访问时间;“time_write”记录文件最后被修改时间;“size”记录文件大小;“name”记录文件名,包括文件后缀。
“attrib”作为unsigned类型,通过对应位进行文件属性的存储,而“io.h”头文件中也给出了相关的参数信息,如下:
参数 | 功能 |
---|---|
_A_ARCH | 存档 |
_A_HIDDEN | 隐藏 |
_A_NORMAL | 正常 |
_A_RDONLY | 只读 |
_A_SUBDIR | 文件夹 |
_A_SYSTEM | 系统 |
而对于每一个文件夹,其目录下都存在两个隐藏的文件夹,分别为“.”和“…”,表示上级目录和下级目录。因此在读取文件夹信息时,需要对这两个隐藏文件夹进行过滤。对于文件的搜索,支持通配符搜索,因此当我们对所有类型的文件都进行查杀时,需要将文件路径参数修改为“*.*”结尾。
SearchFile(char *file_addr, char *sig, int sig_len, char *dest_file)函数参数含义如下:“file_addr”为指定搜索的文件夹路径信息;“sig”为特征码字符串首地址;“sig_len”为特征码长度;“dest_file”为目标文件信息加载到的内存首地址。
首先,指定文件搜索类型为所有文件,因此使用通配符“*.*”,如下:
char file[1000];
strcpy(file, file_addr);
strcat(file, "*.*");
接着,声明文件操作结构体FileData,并生成文件操作句柄hfile。利用函数“_findfirst”来找到指定文件夹下的文件,当返回值为-1时,表示该路径下不包含任何文件,此时,对用户进行信息反馈并等待退出程序。代码如下:
struct _finddata_t FileData;
long hfile; //文件操作句柄
if((hfile = _findfirst(file, &FileData)) == -1L){
printf("该路径下不包含任何文件!\n");
_findclose(hfile);
system("pause");
return;
}
接着对文件夹下各文件进行处理。当文件夹为隐藏文件夹时,直接获取下一个文件信息。利用按位与操作判断获取到的文件是否为文件夹,当为文件夹时,需要进入该文件夹再次执行SearchFile()函数,完成深度文件查找;此时需要注意对文件夹路径信息进行更改,以适应SearchFile()函数的操作流程。当获取到的文件为正常文件时,以二进制形式打开文件并存储至dest_file数组中,随后执行BM算法对比是否包含特征码,当包含该特征码信息时,输出当前文件信息。持续循环直至遍历完文件夹。具体代码如下:
int dest_len;
bool flag;
do{
if(!strcmp(FileData.name, ".") || !strcmp(FileData.name, ".."))
continue;
if(FileData.attrib & _A_SUBDIR){
strcpy(file, file_addr);
strcat(file, FileData.name);
strcat(file, "\\");
SearchFile(file, sig, sig_len, dest_file);
}
else{
strcpy(file, file_addr);
strcat(file, FileData.name);
FILE *pf = fopen(file, "rb");
if(pf == NULL){
printf("%s文件载入失败!\n", FileData.name);
continue;
}
dest_len = fread(dest_file, 1, MAXSIZE, pf);
flag = BM(dest_file, dest_len, sig, sig_len);
if(flag == true){
printf("FIND THE VIRUS IN FILE %s\n", FileData.name);
}
}
}while(_findnext(hfile, &FileData) == 0);
_findclose(hfile);
需要注意的是,即使访问的是一个文件夹,利用“FileData.name”获取到的也仅为该文件夹名,并不包含“\”字符,因此在递归进行深度遍历时,需要对传入的地址信息字符串进行添加“\”字符操作。
对该程序进行测试。测试文件夹信息如下,其中“MacroVirus.txt”、“sig.txt”以及“virusin.txt”文件中包含病毒特征码。
指定文件夹下指定特征码查杀程序测试结果如下:
具体完整代码如下:
#include <stdio.h>
#include <io.h>
#include <windows.h>
#include <string.h>
#include "BM.h"
#define MAXSIZE 104857600
#define SIGSIZE 300
void SearchFile(char *file_addr, char *sig, int sig_len, char *dest_file);
int main(){
printf("------该程序将完成对指定文件夹下指定特征码的查杀------\n\n");
char file_addr[1000];
int judge;
do{
printf("请输入查杀文件夹绝对路径:");
scanf("%s", &file_addr);
judge = access(file_addr, 0);
if(judge != 0) printf("------------------------\n该路径错误,请重新输入!");
}while(judge != 0);
char sig_addr[1000];
do{
printf("请输入特征码所在文件路径:");
scanf("%s", &sig_addr);
judge = access(sig_addr, 0);
if(judge != 0) printf("------------------------\n该路径错误,请重新输入!");
}while(judge != 0);
printf("\n------Result------\n");
if(file_addr[strlen(file_addr) - 1] != '\\')
strcat(file_addr, "\\");
FILE *psig = fopen(sig_addr, "rb");
if(psig == NULL){
printf("特征码载入失败!\n");
system("pause");
return 0;
}
char *sig = (char*)malloc(sizeof(char) * SIGSIZE);
char *dest_file = (char*)malloc(sizeof(char) * MAXSIZE);
if(sig == NULL || dest_file == NULL){
printf("空间申请失败!\n");
system("pause");
return 0;
}
int i = 0, sig_len;
sig_len = fread(sig, 1, SIGSIZE, psig);
SearchFile(file_addr, sig, sig_len, dest_file);
free(sig);
free(dest_file);
return 0 ;
}
void SearchFile(char *file_addr, char *sig, int sig_len, char *dest_file){
char file[1000];
strcpy(file, file_addr);
strcat(file, "*.*");
struct _finddata_t FileData;
long hfile; //文件操作句柄
if((hfile = _findfirst(file, &FileData)) == -1L){
printf("该路径下不包含任何文件!\n");
_findclose(hfile);
system("pause");
return;
}
int dest_len;
bool flag;
do{
if(!strcmp(FileData.name, ".") || !strcmp(FileData.name, ".."))
continue;
if(FileData.attrib & _A_SUBDIR){
strcpy(file, file_addr);
strcat(file, FileData.name);
strcat(file, "\\");
SearchFile(file, sig, sig_len, dest_file);
}
else{
strcpy(file, file_addr);
strcat(file, FileData.name);
FILE *pf = fopen(file, "rb");
if(pf == NULL){
printf("%s文件载入失败!\n", FileData.name);
continue;
}
dest_len = fread(dest_file, 1, MAXSIZE, pf);
flag = BM(dest_file, dest_len, sig, sig_len);
if(flag == true){
printf("FIND THE VIRUS IN FILE %s\n", FileData.name);
}
}
}while(_findnext(hfile, &FileData) == 0);
_findclose(hfile);
printf("\n------THAT\'S ALL IN DIR %s------\n", file_addr);
return;
}
多特征码查杀
首先定义存储特征码的文件格式为:病毒名、特征码。根据该特征码文件结构创建病毒特征码结构体,如下:
typedef struct VirSig{
char name[30];
char sig[SIGSIZE];
int len;
}VirSig;
按照文件存储结构读取特征码信息,由于使用fgets()函数会在每一行的信息后读取“\r\n”之后再自动添加“\0”,因此需要对读取到的字符串进行修改,使其成为真正的特征码。代码如下:
int i = 0, node_size;
while(!feof(psig)){
fgets(sig_node[i].name, 30, psig);
fgets(sig_node[i].sig, SIGSIZE, psig);
sig_node[i].len = strlen(sig_node[i].sig);
i++;
}
fclose(psig);
node_size = i;
i--;
while(i--){
sig_node[i].sig[sig_node[i].len - 2] = '\0';
sig_node[i].len -= 2;
}
主函数框架保持不变,对BM算法部分进行循环操作,对病毒特征码结构体中存储的所有特征码进行遍历,验证是否存在病毒。代码如下:
for(int i = 0; i < node_size; i++){
flag = BM(dest_file, dest_len, sig_node[i].sig, sig_node[i].len);
if(flag == true){
printf("FIND THE VIRUS IN FILE %s\nVIRUS TYPE: %s\n", file, sig_node[i].name);
}
}
对该程序进行测试,测试文件夹信息如下。其中“copy.cpp” 、“sigs.txt”中存在复制型病毒;“MacroVirus.txt”、“sig.txt”、“sigs.txt”、“virusin.txt”中存在宏病毒。
对该程序的测试结果如下:
成功执行程序功能,具体代码如下:
#include <stdio.h>
#include <io.h>
#include <windows.h>
#include <string.h>
#include "BM2.h"
#define MAXSIZE 104857600
#define SIGSIZE 300
#define NODESIZE 10
typedef struct VirSig{
char name[30];
char sig[SIGSIZE];
int len;
}VirSig;
void SearchFile(char *file_addr, VirSig *sig_node, int node_size, char *dest_file);
int main(){
printf("------该程序将完成对指定文件夹下指定特征码的查杀------\n\n");
char file_addr[1000];
int judge;
do{
printf("请输入查杀文件夹绝对路径:");
scanf("%s", &file_addr);
judge = access(file_addr, 0);
if(judge != 0) printf("------------------------\n该路径错误,请重新输入!");
}while(judge != 0);
char sig_addr[1000];
do{
printf("请输入特征码所在文件路径:");
scanf("%s", &sig_addr);
judge = access(sig_addr, 0);
if(judge != 0) printf("------------------------\n该路径错误,请重新输入!");
}while(judge != 0);
printf("\n------Result------\n");
if(file_addr[strlen(file_addr) - 1] != '\\')
strcat(file_addr, "\\");
FILE *psig = fopen(sig_addr, "rb");
if(psig == NULL){
printf("特征码载入失败!\n");
system("pause");
return 0;
}
char *dest_file = (char*)malloc(sizeof(char) * MAXSIZE);
VirSig *sig_node = (VirSig*)malloc(sizeof(VirSig) * NODESIZE);
if(dest_file == NULL || sig_node == NULL){
printf("空间申请失败!\n");
system("pause");
return 0;
}
int i = 0, node_size;
while(!feof(psig)){
fgets(sig_node[i].name, 30, psig);
fgets(sig_node[i].sig, SIGSIZE, psig);
sig_node[i].len = strlen(sig_node[i].sig);
i++;
}
fclose(psig);
node_size = i;
i--;
while(i--){
sig_node[i].sig[sig_node[i].len - 2] = '\0';
sig_node[i].len -= 2;
}
SearchFile(file_addr, sig_node, node_size, dest_file);
printf("------THAT IS ALL!------\n");
free(sig_node);
free(dest_file);
return 0 ;
}
void SearchFile(char *file_addr, VirSig *sig_node, int node_size, char *dest_file){
char file[1000];
strcpy(file, file_addr);
strcat(file, "*.*");
struct _finddata_t FileData;
long hfile; //文件操作句柄
if((hfile = _findfirst(file, &FileData)) == -1L){
printf("该路径下不包含任何文件!\n");
_findclose(hfile);
system("pause");
return;
}
int i, dest_len;
bool flag;
do{
if(!strcmp(FileData.name, ".") || !strcmp(FileData.name, ".."))
continue;
if(FileData.attrib & _A_SUBDIR){
strcpy(file, file_addr);
strcat(file, FileData.name);
strcat(file, "\\");
SearchFile(file, sig_node, node_size, dest_file);
}
else{
strcpy(file, file_addr);
strcat(file, FileData.name);
FILE *pf = fopen(file, "rb");
if(pf == NULL){
printf("%s文件载入失败!\n", FileData.name);
continue;
}
dest_len = fread(dest_file, 1, MAXSIZE, pf);
fclose(pf);
for(int i = 0; i < node_size; i++){
flag = BM(dest_file, dest_len, sig_node[i].sig, sig_node[i].len);
if(flag == true){
printf("FIND THE VIRUS IN FILE %s\nVIRUS TYPE: %s\n", file, sig_node[i].name);
}
}
}
}while(_findnext(hfile, &FileData) == 0);
_findclose(hfile);
return;
}