学习《Windows信息安全原理与实践》书过程中相关介绍,书中给的VC代码,闲暇将其改成汇编,供汇编初学者参考,大虾们飘过。
PE程序自免疫技术程序设计一:改进程序节表结构
原理:
插入方式的PE文件型病毒利用了每个字节对齐原因,程序实际的代码或数据可能没有占满该节,还有不少空余字节空间,病毒在空白区插入病毒。每节都存在空余字节空间,剩余空间大小由对应节表决定。节表结构中的联合Misc字段VirtualSize为该节的实际大小,该节实际占用空间有节表结构中字段SizeOfRawData得到。
SizeOfRawData减去VirtualSize的大小就是剩余空间的大小。病毒也要计算剩余空间的大小以判断是否可以插入病毒代码,如果空间不够,该种病毒就会放弃感染。这就可以启发我们,如果有意将字段VirtualSize修改的和SizeOfRawData一样大,而且在空白区填上随机数据,就可以欺骗以插入方式感染的病毒了。

代码实现:
(1)  得到节个数
由DOS头结构字段e_lfanew定位PE头结构位置,读取PE头,在其包含的文件头中得到节个数字段NumberOfSections。
(2)  读节表
依据节个数分配节表缓冲区,读取所有节表到缓冲区。
(3)  计算节空白区文件偏移和大小
遍历每个节,空白区的文件偏移等于该节文件偏移(字段PointerToRawData)加上该节大小(字段VirtualSize)。空白区大小为该节实际占用磁盘空间(字段SizeOfRawData)减去该节实际大小(字段VirtualSize)得到。
(4)  生成随机数据填充空白区
(5)  修改节表结构,让缓冲区中每个节表的字段VirtualSize等于字段SizeOfRawData,将缓冲区数据写入原节表位置。

下面是我自己讲《Windows信息安全原理与实践》中书上的VC程序改写成汇编语言的。 
.586p
.model flat, stdcall
option casemap :none   ; case sensitive
include c:\masm32\include\windows.inc
include c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\kernel32.lib
include c:\masm32\include\user32.inc
includelib c:\masm32\lib\user32.lib 
include  c:\masm32\include\comdlg32.inc
includelib c:\masm32\lib\comdlg32.lib
include c:\masm32\include\masm32.inc   ;这是Alloc函数所需的文件
includelib c:\masm32\lib\masm32.lib    ;这是Alloc函数所需的Lib文件



.data
  stOFAddr        OPENFILENAME  <>
  szTitle         db            "ChangeSection",0
  szFileName  db        MAX_PATH dup (?)
        szExtPe    db        'PE Files',0,'*.exe;*.dll;*.scr;*.fon;*.drv',0
            db        'All Files(*.*)',0,'*.*',0,0
        hFile           dd            ?
        dos_header      IMAGE_DOS_HEADER <>
  nt_header       IMAGE_NT_HEADERS <>
  section_header  IMAGE_SECTION_HEADER <>
  nBytesRead      dd            ?
  pos             dd            ?
  len             dd            ?
  arrayWrite      dd            ?
  sectionHeaderPos dd           ?
  successTip      db            "    ChangeSection Succeded!   ",0
.code 

Start:
  invoke  RtlZeroMemory,offset stOFAddr,sizeof OPENFILENAME
  mov  stOFAddr.lStructSize,sizeof OPENFILENAME
        push  NULL
  pop  stOFAddr.hwndOwner
  mov  stOFAddr.lpstrFilter,offset szExtPe
  mov  stOFAddr.lpstrFile,offset szFileName
  mov  stOFAddr.nMaxFile,MAX_PATH
  mov  stOFAddr.Flags,OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST
  invoke  GetOpenFileName,offset stOFAddr
  .if  ! eax
    jmp  @F
  .endif
  invoke  CreateFile,offset szFileName,GENERIC_ALL ,FILE_SHARE_READ or \
      FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
        .if  eax !=  INVALID_HANDLE_VALUE
      mov  hFile,eax
      invoke ReadFile, hFile, offset dos_header, sizeof IMAGE_DOS_HEADER, offset nBytesRead, NULL  
      movzx     eax,  dos_header.e_magic
      ;检查PE文件是否有效
      .if     eax == 5a4dh
             invoke SetFilePointer, hFile, dos_header.e_lfanew, NULL, FILE_BEGIN
             invoke ReadFile, hFile, offset nt_header, sizeof IMAGE_NT_HEADERS, offset nBytesRead, NULL
             .if    nt_header.Signature == 4550h
                    movzx   esi,nt_header.FileHeader.NumberOfSections
                    cmp     esi,1
                    jb      NoSection
                    xor     ebx, ebx
              LoopSections:
                    mov     eax, dos_header.e_lfanew
                    add     eax, sizeof IMAGE_NT_HEADERS
                    mov     edx, ebx
                    imul    edx, sizeof IMAGE_SECTION_HEADER
                    add     eax, edx
                    mov     sectionHeaderPos, eax
                    ; 读取节表
                    invoke SetFilePointer, hFile, sectionHeaderPos, NULL, FILE_BEGIN
                    invoke ReadFile, hFile, offset section_header, sizeof IMAGE_SECTION_HEADER, offset nBytesRead, NULL
                    ; 填充节中空白数据
                    mov  eax, section_header.PointerToRawData
                    add  eax, section_header.Misc.VirtualSize
                    mov  pos,eax
                    mov  eax, section_header.SizeOfRawData
                    sub  eax, section_header.Misc.VirtualSize
                    mov  len, eax
                    invoke  Alloc,len
              mov     dword ptr [arrayWrite], eax
              xor     ecx,ecx
        Goon:
              mov eax, dword ptr [arrayWrite]
              add eax, ecx
              mov byte ptr[eax], 41h
              inc ecx
              cmp ecx, len
                    jb Goon   
              invoke SetFilePointer, hFile, pos, NULL, FILE_BEGIN
                    invoke WriteFile, hFile, arrayWrite, len, offset nBytesRead, NULL   
                    ; 修改节表 
                    mov    eax, section_header.SizeOfRawData
                    mov    section_header.Misc.VirtualSize, eax 
                    invoke SetFilePointer, hFile, sectionHeaderPos, NULL, FILE_BEGIN
                    invoke WriteFile, hFile, offset section_header, sizeof IMAGE_SECTION_HEADER, offset nBytesRead, NULL                  
                    invoke Free, dword ptr [arrayWrite]
              inc  ebx
              dec  esi
              cmp  esi,0
              ja   LoopSections
             NoSection: 
                     invoke CloseHandle, hFile
                     invoke MessageBox, NULL, offset successTip, offset szTitle, MB_OK     
             .endif
      .endif
  .endif
@@:
  invoke ExitProcess,0
end Start

  • 标 题:答复
  • 作 者:laowanghai
  • 时 间:2009-04-29 08:06

PE程序自免疫技术程序设计二:禁止插入新节
原理:
以附加方式感染的病毒,要添加新节就必须同时插入一个对应的新节表。能够插入新节表的前提是最后一个节表与第一个节区之间足以放下一个节表结构。而很多情况下编译器生成的可执行文件在上述之间还余有足够放多个节表的空间。
如果把文件头和节表下移,且修改定位文件头位置的指针(DOS头结构字段e_lfanew),那么病毒就无法插入新节了。

代码实现:
(1) 得到节区个数
由DOS头结构字段e_lfanew定位PE头结构位置,读取PE头,在其包含的文件头中得到节个数字段NumberOfSections。
(2)   分配缓冲区,将PE头结构和所有节表读到缓冲区。
(3)   计算移动到的文件偏移,移动数据的长度为PE头结构大小(sizeof(IMAGE_NT_HEADERS))加上所有节表结构的大小为(sizeof(IMAGE_SECTION_HEADER)*nt_header.FileHeader.NumberOfSections)。移动到的位置为第一节区的文件偏移(psection_header[0].PointerToRawData),减去移动数据的长度。将缓冲区数据写入文件该位置。
(4)  修改DOS头结构e_lfanew,并将该结构重新写入原位置。

下面是我自己讲《Windows信息安全原理与实践》中书上的VC程序改写成汇编语言的。
.586p
.model flat, stdcall
option casemap :none   ; case sensitive
include c:\masm32\include\windows.inc
include c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\kernel32.lib
include c:\masm32\include\user32.inc
includelib c:\masm32\lib\user32.lib 
include  c:\masm32\include\comdlg32.inc
includelib c:\masm32\lib\comdlg32.lib
include c:\masm32\include\masm32.inc   ;这是Alloc函数所需的文件
includelib c:\masm32\lib\masm32.lib    ;这是Alloc函数所需的Lib文件



.data
  stOFAddr        OPENFILENAME  <>
  szTitle         db            "ChangeSection",0
  szFileName  db        MAX_PATH dup (?)
        szExtPe    db        'PE Files',0,'*.exe;*.dll;*.scr;*.fon;*.drv',0
            db        'All Files(*.*)',0,'*.*',0,0
        hFile           dd            ?
        dos_header      IMAGE_DOS_HEADER <>
  nt_header       IMAGE_NT_HEADERS <>
  section_header  IMAGE_SECTION_HEADER <>
  nBytesRead      dd            ?
  pos             dd            ?
  len             dd            ?
  endPoint        dd            ?
  arrayWrite      dd            ?
  sectionHeaderPos dd           ?
  successTip      db            "    ProtectSection Succeded!   ",0
.code 

Start:
  invoke  RtlZeroMemory,offset stOFAddr,sizeof OPENFILENAME
  mov  stOFAddr.lStructSize,sizeof OPENFILENAME
        push  NULL
  pop  stOFAddr.hwndOwner
  mov  stOFAddr.lpstrFilter,offset szExtPe
  mov  stOFAddr.lpstrFile,offset szFileName
  mov  stOFAddr.nMaxFile,MAX_PATH
  mov  stOFAddr.Flags,OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST
  invoke  GetOpenFileName,offset stOFAddr
  .if  ! eax
    jmp  @F
  .endif
  invoke  CreateFile,offset szFileName,GENERIC_ALL ,FILE_SHARE_READ or \
      FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
        .if  eax !=  INVALID_HANDLE_VALUE
      mov  hFile,eax
      invoke ReadFile, hFile, offset dos_header, sizeof IMAGE_DOS_HEADER, offset nBytesRead, NULL  
      movzx     eax,  dos_header.e_magic
      ;检查PE文件是否有效
      .if     eax == 5a4dh
             invoke SetFilePointer, hFile, dos_header.e_lfanew, NULL, FILE_BEGIN
             invoke ReadFile, hFile, offset nt_header, sizeof IMAGE_NT_HEADERS, offset nBytesRead, NULL
             .if    nt_header.Signature == 4550h
                    movzx   esi,nt_header.FileHeader.NumberOfSections
                    cmp     esi,1
                    jb      NoSection
                    xor     ebx, ebx
                    ;读取第一个节表
                    invoke ReadFile, hFile, offset section_header, sizeof IMAGE_SECTION_HEADER, offset nBytesRead, NULL
                    
                    mov  eax, section_header.PointerToRawData
                    mov  endPoint, eax
                    mov  eax, sizeof IMAGE_NT_HEADERS
                    mov  ebx, sizeof IMAGE_SECTION_HEADER
                    imul ebx, esi
                    add  eax, ebx
                    mov  len, eax
                    mov  eax, endPoint
                    sub  eax, len
                    mov  pos, eax
                    invoke  Alloc,len
              mov     dword ptr [arrayWrite], eax
              
                    invoke SetFilePointer, hFile, dos_header.e_lfanew, NULL, FILE_BEGIN
                    invoke ReadFile, hFile, arrayWrite, len, offset nBytesRead, NULL
                    invoke SetFilePointer, hFile, pos, NULL, FILE_BEGIN
                    invoke WriteFile, hFile, arrayWrite, len, offset nBytesRead, NULL
                    mov    eax, pos
              mov    dos_header.e_lfanew,eax
              invoke SetFilePointer, hFile, 0, NULL, FILE_BEGIN
              invoke WriteFile, hFile, offset dos_header, sizeof IMAGE_DOS_HEADER, offset nBytesRead, NULL
             NoSection: 
                     invoke CloseHandle, hFile
                     invoke MessageBox, NULL, offset successTip, offset szTitle, MB_OK     
             .endif
      .endif
  .endif
@@:
  invoke ExitProcess,0
end Start