憨憨也能写出PE病毒

导语

这是我软件安全作业,希望对想要学习PE病毒编写的同学们有所帮助。

目标

编写一个PE文件传染程序infect.exe,功能要求如下:

  1. infect.exe运行后,向同目录下的notepad.exe程序植入“病毒载荷”代码.
  2. infect.exe不能重复传染notepad.exe.
  3. notepad.exe被植入“病毒载荷”后,具备如下行为:一旦执行,就会向其所在目录写入一个txt文件,文件名为:学号-姓名.txt,文件内容为空。注意:这里的姓名和学号要改为同学自己的名字和学号。

基本思路

infect.exe的目标是向notepad.exe插入一段病毒载荷,也就是说我们要向一个已知的PE文件插入一段代码,使他能做到我们想要它做到的,但是实际上它并不应该能做到的功能。
一般来说PE病毒的载荷插入方式有两种,其一是在节之间插入,其二是新建节插入。
在节之间插入的好处是不用改entrypoint,在shellcode里不需要jmp回原本的entrypoint,基本上顺着执行原本的PE文件的过程中就可以将你的shellcode执行了,而缺点也显而易见,节之间的空间可能不足,可能出现无法植入shellcode的情况,而如果要利用多个节之间的空间的话就意味着载荷得分段执行,寄存器堆栈的状态都很可能变化,因此编写shellcode非常困难。
而新建节和节之间插入的优缺点刚好相反。相较之下更改entrypoint是比足够简单的,因此我们选择新建节植入shellcode。

具体实现

借鉴了网上很多的代码,大部分是使用handle非常便捷的修改了PE头的各个字段,而我由于太菜了加上正好需要具体理解PE格式,所以采用了最简单的文件指针的操作。

新建节

由之前博客的内容可知,新建节要修改的内容有

  1. PE头中的fileheader字段(IMAGE_NT_HEADERS.FileHeader的内容)
  2. PE头中的optionalheader字段(IMAGE_NT_HEADERS.OptionalHeader的内容)
  3. 新节的节首部各个字段(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

你可能感兴趣的:(安全)