程序员人生 网站导航

反病毒攻防研究第015篇:病毒感染标志的添加

栏目:互联网时间:2014-11-05 08:17:04

1、前言

        对感染型病毒而言,如果对同1个目标文件屡次进行感染,有可能致使目标文件破坏,使得没法履行。所以病毒程序常常会在第1次感染时对目标文件写进1个感染标志,这样在第2次遇到该文件时,首先判断1下该文件中是不是包括有感染标志,如果有,则不再感染,如果没有感染标志则进行感染(关于文件的感染,可参见《反病毒攻防研究第004篇:利用缝隙实现代码的植入》和《反病毒攻防研究第005篇:添加节区实现代码的植入》)。所谓的感染标志其实就是在PE文件中无关紧要的位置写入的1个字符串,所以感染标志的添加、读取与判断操作,其实就是基本的文件读写操作。

 

2、感染标志的添加

        在PE文件结构中存在着许多不实用的字段,比如在IMAGE_DOS_HEADER中,只有e_magic与e_lfanew这两个字段才是重要的,前者用于验证本文件是不是为PE文件,后者保存着PE文件的偏移位置。因此可以从第2个字段,即e_cblp(Bytes on last page of file)开始,写入我们的感染标志。这里将该标志设定为“Hack”这4个字符。需要注意的是,将感染标志添加到文件中,应当首先将“Hack”转化为106进制数值,然后再反向写入(小端显示),代码以下:

#define VIRUSFLAG 0x6b636148 // 感染标志,这里为“Hack” // 感染标志的写入。3个参数分别为:欲感染文件的句柄、欲写入感染标志的位置 // 和感染标志 BOOL AddSig(HANDLE hFile, DWORD dwAddr, DWORD dwSig) { DWORD dwNum = 0; // 在文件中设置读写位置 SetFilePointer(hFile, dwAddr, 0, FILE_BEGIN); // 写入感染标志 if(WriteFile(hFile, &dwSig, sizeof(DWORD), &dwNum, NULL)) { MessageBox(NULL, "感染标志添加成功!", "提示", MB_OK); return TRUE; } else { MessageBox(NULL, "感染标志添加失败!", "提示", MB_OK); return FALSE; } }
        然后编写检测感染标志的代码:
// 感染标志检测 BOOL CheckSig(HANDLE hFile, DWORD dwAddr, DWORD dwSig) { DWORD dwSigNum = 0; DWORD dwNum = 0; SetFilePointer(hFile, dwAddr, 0, FILE_BEGIN); ReadFile(hFile, &dwSigNum, sizeof(DWORD), &dwNum, NULL); if(dwSigNum == dwSig) { return TRUE; } return FALSE; }
        我们需要令“病毒”程序在每次感染前先调用CheckSig()函数,根据其返回值来判断目标文件是不是已被感染过,然后再决定是不是需要进行感染。主函数代码以下:
#include <windows.h> #define FILENAME "helloworld.exe" // 欲添加感染标志的文件名 #define offsetof(struct_t,member) (size_t)&(((struct_t *)0)-> member) int main() { HANDLE hFile = NULL; hFile = CreateFile(FILENAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(CheckSig(hFile, offsetof(IMAGE_DOS_HEADER, e_cblp), VIRUSFLAG)) { MessageBox(NULL, "本文件已被感染过!", "提示", MB_OK); return ⑴; } AddSig(hFile, offsetof(IMAGE_DOS_HEADER, e_cblp), VIRUSFLAG); return 0; }

        程序将感染标志写入了IMAGE_DOS_HEADER中的e_cblp位置,它不会对程序的履行产生任何影响。这里需要说明的是,程序中我们使用了offsetof()这个宏,它本来是被定义在stddef.h中的,这里我将其拿出来专门定义。这个宏的作用是求某个结构体的特定成员在结构体里面的偏移量,对本程序来讲就是求e_cblp在IMAGE_DOS_HEADER中的偏移,也就是2(由于它之前的e_magic占用了两个字节)。

        这里给大家分析1下(size_t)&(((struct_t*)0)-> member)的意义。首先,(struct_t *)0是1个指向struct_t类型(本程序中为IMAGE_DOS_HEADER)的指针,其指针值为 0,所以其作用就是把从地址 0 开始的存储空间映照为1个struct_t类型的对象。((struct_t *)0)-> member是访问类型中的成员member(本程序中为e_cblp),相应地 &((struct_t *)0)-> member) 就是返回这个成员的地址。由于对象的起始地址为 0,所以成员的地址其实就是相对对象首地址的成员的偏移地址。最后再通过类型转换,转换为 size_t 类型(32位是unsigned int,64位是long unsigned int)。

 

3、程序测试

        为了测试我们的程序,这里照旧使用《反病毒攻防研究第004篇:利用缝隙实现代码的植入》中所编写的“helloworld.exe”程序。将两个程序放在同1个目录下,感染前先用Hex Editor Neo查看1下“helloworld.exe”程序的DOS头部份:

图1 感染前的DOS头

        然后运行本程序,再次查看DOS头部:


图2 感染后的DOS头

        可见,我们的感染是成功的。

 

4、小结

        给文件添加感染标志对文件来讲不会产生任何影响,很多感染型病毒都会给目标文件添加感染标志,比如“熊猫烧香”就会在程序中添加“WhBoy”标志。因此当时李俊所编写的“熊猫烧香”病毒专杀工具(李俊版)就是通过检测文件中是不是有“WhBoy”标志来判断文件是不是被感染,但是这类检测方法却过于粗糙了。
------分隔线----------------------------
------分隔线----------------------------

最新技术推荐