1.简介

PE文件插入程序经常用于恶意代码感染其他程序.本文介绍3种方式:空闲空间, 新增节,在最后一个节中插入程序.

 

2.空闲空间插入程序

大部分PE文件的节因为文件对齐而产生一些空闲空间,所以可以将程序插入到这些空间中,然后修改入口点,或者修改入口点代码跳到该处执行,执行完后跳回

OEP.

程序1:获取PE文件中节的空间可用情况

.386
.model flat, stdcall  ;32 bit memory model
option casemap :none  ;case sensitive

include msvcrt.inc
include windows.inc
include kernel32.inc

includelib msvcrt.lib
includelib kernel32.lib

.data
format        db        '%-10s%-15p',0ah,0dh,0
titleinfo    db        '名称      可用空间',0ah,0dh,0
titlehead    db        'head',0
sectionname    dword    0
buffer        db        100 dup (0)
filename    db        MAX_PATH dup(0)
scanff        db        '%s',0
imagebase    dword    0
psection    dword   0
.code
loadpe    proc @FileName:dword
    LOCAL hFile
    LOCAL hMap
    LOCAL @imagebase
    pushad
    invoke CreateFile,@FileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0
    mov hFile,eax
    invoke CreateFileMapping,hFile,0,PAGE_READONLY,0,0,0
    mov hMap,eax
    invoke MapViewOfFile,hMap,FILE_MAP_READ,0,0,0
    mov @imagebase,eax
    invoke CloseHandle,hFile
    invoke CloseHandle,hMap
    popad
    mov    eax,@imagebase
    ret

loadpe endp

unloadpe proc imageBase
    
    invoke UnmapViewOfFile,imageBase
    ret

unloadpe endp
_RVAToOffset proc _lpFileHead,_dwRVA
  local @dwReturn
  
  pushad
  mov esi,_lpFileHead
  assume esi:ptr IMAGE_DOS_HEADER
  add esi,[esi].e_lfanew
  assume esi:ptr IMAGE_NT_HEADERS
  mov edi,_dwRVA
  mov edx,esi
  add edx,sizeof IMAGE_NT_HEADERS
  assume edx:ptr IMAGE_SECTION_HEADER
  movzx ecx,[esi].FileHeader.NumberOfSections
  ;遍历节表
  .repeat
    mov eax,[edx].VirtualAddress
    ;计算该节结束RVA,不用Misc的主要原因是有些段的Misc值是错误的!
    add eax,[edx].SizeOfRawData 
    .if (edi>=[edx].VirtualAddress)&&(edi<eax)
      mov eax,[edx].VirtualAddress
      ;计算RVA在节中的偏移
      sub edi,eax                
      mov eax,[edx].PointerToRawData
      ;加上节在文件中的的起始位置
      add eax,edi                
      jmp @F
    .endif
    add edx,sizeof IMAGE_SECTION_HEADER
  .untilcxz
  assume edx:nothing
  assume esi:nothing
  mov eax,-1
@@:
  mov @dwReturn,eax
  popad
  mov eax,@dwReturn
  ret
_RVAToOffset endp
start:
    invoke crt_scanf,offset scanff,offset filename
    invoke crt_printf,offset titleinfo
    invoke loadpe,offset filename
    
    mov imagebase,eax
    assume esi:NOTHING
    assume esi:ptr IMAGE_SECTION_HEADER
    mov ebx,imagebase
    assume ebx:ptr IMAGE_DOS_HEADER
    mov eax,[ebx].e_lfanew
    add eax,imagebase
    add eax,4
    assume eax:ptr    IMAGE_FILE_HEADER
    
    
    movzx edi,[eax].NumberOfSections
;    mov edx,eax
;    add edx,sizeof IMAGE_FILE_HEADER
;    assume edx:ptr IMAGE_OPTIONAL_HEADER32
;    mov edx,[edx].FileAlignment
    sub eax,4
    add eax,sizeof IMAGE_NT_HEADERS32
    mov psection,eax
    assume eax:ptr IMAGE_SECTION_HEADER
    invoke _RVAToOffset,imagebase,[eax].VirtualAddress
    mov esi,eax
    add esi,imagebase     ;指向第一个节
    
    ;assume psection:ptr IMAGE_SECTION_HEADER
    mov ebx,imagebase
    assume ebx:ptr IMAGE_DOS_HEADER
    mov eax,[ebx].e_lfanew
    add eax,sizeof IMAGE_NT_HEADERS32
    mov ebx,eax
    mov ax,di
    mov ecx,sizeof IMAGE_SECTION_HEADER
    mul ecx
    xchg ebx,eax;执行完后,ebx是节表头大小,eax是dos头+nt头大小
    add ebx,eax
    add ebx,imagebase
    mov eax,esi
    sub eax,ebx

    invoke crt_sprintf,offset buffer,offset format,offset titlehead,eax
    invoke crt_printf,offset buffer
    
    ;edi作为计数器,psection指向节表头
    .while 1
        .break .if edi==0    
        ;mov ebx,psection
        ;assume ebx:ptr IMAGE_SECTION_HEADER
    ;    invoke _RVAToOffset,imagebase,
    ;    mov sectionname,eax
    ;    mov eax,imagebase
    ;    add sectionname,eax
        mov ebx,psection
        assume ebx:ptr IMAGE_SECTION_HEADER
        mov eax,[ebx].Misc.VirtualSize;对齐前尺寸
        mov ebx,[ebx].SizeOfRawData;对齐后尺寸
        sub ebx,eax
        invoke RtlZeroMemory,offset buffer,100
        invoke crt_sprintf, offset buffer,offset format,psection,ebx
        invoke crt_printf,offset buffer
        dec edi    
        add psection,sizeof IMAGE_SECTION_HEADER
    .endw
    invoke unloadpe,imagebase
    invoke ExitProcess,0

;########################################################################



end start

 

 

3.新增节中插入程序

(1).将新增节放在文件尾部,而且将该节的节区头增加到节区头部分的最后.

(2).需要做:文件头部修改节数量字段, 在文件头部节区头增加一个IMAGE_SECTION_DESCRIPTOR

实例代码:

 

4.在最后一节插入程序

(1).在最后一节的空闲空间中插入程序是最简单有效的

(2).思路:

将附加代码附加到最后一节中->修正最后一个节表的字段:SizeOfRawData,PointerToRawData,Characteristics->修正PE文件头字段:

SizeOfImage,AddressEntryPoint