网络通信 频道

Win9x/Winnt/Win2k/Winxp病毒技术 (1)

 Win32.PurpleMood.6736技术文档 

************************************************* 
病毒名称 :PurpleMood (紫色心情) 
适用环境: Win9x/Winnt/Win2k/Winxp 
编写环境: Win2k,Masm32v6 
简 介:1. 感染本地硬盘和网络上所有exe(GUI)文件 
2. 搜索本地所有邮件地址,将病毒作为附件发送出去 
3. 在Explorer进程中注入线程监控程序的运行。 
4. 每月15日,发作。删除硬盘所有文件。 

完成日期: 2002/6/20 
版  本: v1.0 
大  小: 6736(byte) 
联系地址: XPurpleMood@163.com 
警 告 : 以下程序(方法)可能带有攻击性,仅供技术交流。使用者风险自负!若有其他用途,概与本人无关。万一有转贴,请保持完整性,多谢! 
************************************************* 
工作流程: 
1.首先得到重定位信息,保存在ebx中. 
2.调用GetKBase ,得到Kernel32.dll的基地址。 
3.调用GetAPIz,得到程序将使用的Kernel32中所有API. 
4. 调用PayLoad判断是否满足发作条件,是则删除所有文件。否则继续。 
5.判断是被感染文件还是自身(病毒在系统目录创建PurpleMood.scr). 
6. 是染毒文件,则调用CreatePE来创建PurpleMood.scr,初始化(rtInit)写注册表项所需函数地址。调用MakeSCRAlive使PurpleMood.scr保持活动。 
7. 如果是PurpleMood.scr,则CreateMutex设置标志,然后启动监控线程,感染PE线程,在主线程中发送邮件。 

说明: 
将程序中test@pact518.hit.edu.cn替换为自己的邮件 
pact518.hit.edu.cn替换为自己的smtp服务器。 
在d:建立test目录,里面放几个exe.实验用。 

技巧与难点分析 
1.重定位信息的确定 
VStart: ;virus starts here :) 
call start 
start: 
pop ebx 
sub ebx , offset start 
A dd 0 
这段代码在哪里执行都一样!现在得到的ebx就是重定位信息。 
变量A的偏移就是ebx + offset A.因为offset A是程序的第一条指令放到内存地址0时的偏移,但实际上放到了ebx. 
也可以这么理解: 
执行call start时(相当于push eip+jmp start),eip指向pop ebx,因为eip总是下一条指令的地址。pop ebx就把栈顶的eip存贮到ebx中。start在内存中(虚拟内存)的线形地址就放到ebx中了。那么A的地址显然就是(offset A - offset start)+ebx ,我们先 sub ebx , offset start,这样以后访问A就可以直接写offset A+ebx方便些。两种理解方法实际上是一样的。 

2. RVA的含义 
在CreatePE创建PurpleMood.scr和得到GetProcAddress的时候,多次使用这个概念。 
exe或dll被加载到内存,注意,都是虚拟内存,4G空间。实际上把exe文件拉大了,就好象斜阳把人的影子拉长一样。 
比如exe中代码段在文件偏移200h处,很可能在内存中偏移是1000h处,这个1000h就是RVA.RVA是距离影象的base的偏移。 
下面形象解释: 
在文件的第200h个字节就是代码段的第一条指令了(当然,未必是start).而1000h不是真正地址。比如 exe影象是00400000h,则代码段的第一条指令就是00400000h+1000h了。HMODULE就是DWORD,或者是int *,char *等,都一样。 
我们用HMODULE p=LoadLirary("a.dll"),返回值就是a.dll被加载到内存(4G)的首地址。此时叫做影象(image). 
与offset区别: 
我要说的这个offset是程序中使用的。 
比如写个小程序: 
.data 
b db 0 
a db "abc",0 
.code 
start: 
mov eax,offset a 
... 
那么这个offset a是多少由compiler确定。我想是算出来的。这么计算: 
比如code的RVA是1000h,data的RVA是2000h.ImageBase=00400000h,那么a被加载后的地址就是 
00400000h+2000h+1(b占一个字节),那么offset a编译成00402001。 
事实上,我们的exe总能加载到ImageBase指定的位置,Loader不必在重定位。 
以上分析不保证正确!都是个人理解。 

3. @pushsz 宏. 
@pushsz MACRO str 
LOCAL next 
call next ;执行 call next的时候, eip->db str,0,那么eip就被压栈 
db str,0 
next: 
ENDM 
@pushsz "abc" <=> a db "abc",0 .... mov eax,offset a,push eax 
是在RoachCock的帮助下写的。 

4. CreateRemoteThread网上很多介绍。 
关键是地址问题。同样得到重定位信息。 

5. 几个小问题 
ret 相当于 pop eip. 
ret 4 相当于 pop eip + sub esp,4 
call l 相当于 push eip+ jmp l 
使用api时都保存esi,edi,ebx,ebp他们不会被改变,而ecx,edx等就不保了。需要自己保存。 
mov eax,12345678h 
_CreateRemoteThread = dword ptr $-4 
call eax ;run remote thread! 
_CreateRemoteThread就相当一个标号(比如 start: ... l: ...) 
它指向12345678占用的4个字节。 


1. 主要函数说明 
1.1 GetKBase 
功能:获得Kernel32.dll模块的首地址 
原理:主线程执行的第一条指令应该是BaseThreadStart的指令,在这个函数中调用的VStart(程序入口),返回地址进栈, 
既程序执行完时,应该返回到BaseStartProcess函数。这个函数在Kernel32中,它的指令地址就在kernel32模块空间中并且大于HModule以它为基础,以64k(10000h)(分配粒度)为单位向上搜索具有PE结构的模块。 

1.2 GetAPIz 
功能: 得到将使用的Kernel32中的API线形地址 
原理: 分析K32模块,在它的EXPORT表中找到GetProcAddress的地址。然后,利用GetProcAddress得到其他函数地址。 

1.3 EnumDir 
功能: 遍历指定目录,寻找指定类型的文件。 
输入: DirName : DWORD ,FileType:DWORD 
局部变量:LOCAL hSearch : DWORD 
LOCAL DirorFile[MAX_PATH] : DWORD 
DirName是常量。DirorFile存放中间过程,有时是DirName\*.*、有时是 
DirName\FileName或DirName\DirName. 
得到一个文件后,判断是否是目录。 
1. 是,则递归调用EnumDir,参数是DirorFile。 
2. 否,则调用AnFile,分析文件,做相应处理。 

1.4 AnFile FileName:DWORD,FileType: DWORD 
功能:分析文件类型(FileType) 
1. FILE_ALL: 删除文件 
2. FILE_EXE: 调用InfectFile感染 
3. FILE_HTM: 调用ParseHTM分析 

1.5 InfectFile PROC FileName : DWORD 
功能: 感染FileName指定文件 
流程: 
1. 打开文件,分析文件,是否是合法的PE文件,不是则返回。 
2. 查看感染标,已经感染则返回。 
3. 判断文件是否有剩余空间存放病毒的Section,没有则返回。 
4. 更新文件,添加新节,写入病毒代码,设置新节为可读可写可执行。 
5. 设置感染标志。 

1.6 PEThread PROC MReloc : DWORD 
功能:遍历硬盘和网络,得到目录后调用EnumDir。休眠后重复上述过程。 
说明:Meloc参数为主线城的ebx,既重定位信息,因为新线城的Register已经清0。 

1.7 EnumNetWork PROC pNetResource : DWORD 
功能: 遍历网络的实现函数,使用MPR函数,得到一个目录后调用EnumDir,类型为FILE_EXE. 

1.8 EnumDisk PROC DirName : DWORD,FileType : DWORD 
功能: 遍历硬盘的实现函数,从c->z,得到一个目录后(如‘C:'')后调用EnumDir。 

1.9 MailThread 
功能:邮件线程,位于主线程。 
1.9.1. 调用MailInit,对PurpleMood.scr进行Base64编码,存贮在动态分配的内存中,保留内存地址在Base64_Encoded_Data。 
初始化Socket函数。 
1.9.2 开始调用EnumDisk,参数为FILE_HTM,寻找*.htm*文件。EnumDisk得到的参数以"c:"开始,将其作为目录,调用EnumDir,EnumDir找到一个.htm*后调用ParseHTM,在其中搜索mailto:字符串,其后既是MailAddr了。找到后,调用SendMail发送出去,PurpleMood.scr作为附件。然后继续分析这个htm,寻找其他邮件地址,直到文件末尾。然后返回到AnFile,在返回到EnumDir,寻找下一个htm. 
1.9.3 遍历硬盘后,休息一天,重新开始。 

2.0 CreatePE 
功能:在系统目录创建一个PurpleMood.scr 
创建类型为CREATE_NEW,既如果已经存在就返回。 
文件头从MDosStub开始,这个DosStub是最小的,只有一个IMAGE_DOS_HEADER那么大。没有int 21h只类的语句,所以在Dos下不能运行。先写入文件头,在写入病毒代码,FileAliagment=200h 

2.1 MonitorThread PROC MReloc : DWORD 
找到Explorer进程,插入rtThreadStart->rtThreadEnd的代码,监视PurpleMood.scr的运行和注册表的Run项. 
Meloc和PEThread一样,同样是ebx. 
2.1.1: LoadLibrary(PSAPI) 
2.1.2: 初始化需要的api. 
2.1.3: EnumProcesses,分析每个进程。 
2.1.4: 分析过程 
1. OpenProcess (注意权限) 
2. EnumProcessModules,GetModuleBaseNameA 
3. 是Explorer.exe吗?不是返回,分析下一个进程。 
4. 是: 
1) VirtualAllocEx 2)WriteProcessMemory 3)CreateRemoteThread 


2.2 MakeSCRAlive 
1. OpenMutex(..."GetProcAddress") 
成功说明,PurpleMood.scr在运行中。立即ReleaseMutex并CloseHandle。 
这样可以避免,PurpleMood关闭后,Explorer的线程因为OpenMutex过而认为PurpleMood还在运行。 
失败,则调用RunPE,运行PurpleMood.scr. 
2. RegisterPE,在Software\Microsoft\Windows\CurrentVersion\Run写入PurpleMood,保证开机运行。 

2.3 CreatePE 
1. 在系统目录创建PurpleMood.scr,如果已经存在则返回。 
2. 写入文件头 
3. 写入病毒体。

 

转载地址:http://www.netsp.com.cn/Article/netsafe/virus/200607/20060721201219.html

0
相关文章