这个病毒的多态的,因此不太好处理,其会感染exe和scr文件,
在PE头中会留下love(evol)标志,可能会多次感染。

病毒入口,作用为解码:

代码:

00415000 > /EB 00           jmp     short 00415002              ; 多态
00415002   \FC              cld
00415003    87DB            xchg    ebx, ebx
00415005    F5              cmc
00415006    55              push    ebp
00415007    8BEC            mov     ebp, esp
00415009    E8 11000000     call    0041501F
0041500E    E8 B7000000     call    004150CA
00415013    EB 00           jmp     short 00415015
00415015    87DB            xchg    ebx, ebx
00415017    EB 00           jmp     short 00415019
00415019    90              nop
0041501A    E9 32000000     jmp     00415051
0041501F    67:64:FF36 0000 push    [dword fs:0]
00415025    67:64:8926 0000 mov     [fs:0], esp
0041502B    012D BA504100   add     [4150BA], ebp
00415031    31DB            xor     ebx, ebx
00415033    68 00000100     push    10000                            ; UNICODE "=::=::\"
00415038    68 00000080     push    80000000
0041503D    53              push    ebx
0041503E    53              push    ebx
0041503F    68 00040000     push    400
00415044    68 00000080     push    80000000
00415049    53              push    ebx
0041504A    53              push    ebx
0041504B    FF15 9C634000   call    [<&KERNEL32.GetModuleHandleA>]   ; kernel32.GetModuleHandleA
00415051    EB 00           jmp     short 00415053
00415053    F9              stc
00415054    F5              cmc
00415055    89DB            mov     ebx, ebx
00415057    29C0            sub     eax, eax
00415059    FEC8            dec     al
0041505B    08C0            or      al, al
0041505D    74 04           je      short 00415063
0041505F  ^ 75 F8           jnz     short 00415059
00415061    EB 67           jmp     short 004150CA
00415063    F9              stc
00415064    FC              cld
00415065    89DB            mov     ebx, ebx
00415067    F8              clc
00415068    29D2            sub     edx, edx
0041506A    29C9            sub     ecx, ecx
0041506C    EB 00           jmp     short 0041506E
0041506E    F8              clc
0041506F    B1 1F           mov     cl, 1F        ; 密钥, 会变
00415071    8D52 01         lea     edx, [edx+1]
00415074    49              dec     ecx
00415075  ^ 75 FA           jnz     short 00415071
00415077    F9              stc
00415078    E8 00000000     call    0041507D      ; 得到加密代码的位置
0041507D    5F              pop     edi          ; 得到加密代码的位置
0041507E    87DB            xchg    ebx, ebx
00415080    F8              clc
00415081    81C7 5A000000   add     edi, 5A        ; 得到加密代码的位置
00415087    57              push    edi
00415088    29F6            sub     esi, esi
0041508A    81F6 00290000   xor     esi, 2900           ; 加密代码的长度,可能会变, 2900为正常,
00415090    EB 00           jmp     short 00415092      ; 如果大于2900则多余部份是被偷掉的代码,需要复制回去
00415092    89D2            mov     edx, edx
00415094    8607            xchg    [edi], al
00415096    89D2            mov     edx, edx
00415098    F5              cmc
00415099    89D2            mov     edx, edx
0041509B    87DB            xchg    ebx, ebx
0041509D    66:31D0         xor     ax, dx              ; 解码方法,可能会变
004150A0    8607            xchg    [edi], al
004150A2    FC              cld
004150A3    87DB            xchg    ebx, ebx
004150A5    90              nop
004150A6    EB 00           jmp     short 004150A8
004150A8    89D2            mov     edx, edx
004150AA    FC              cld
004150AB    90              nop
004150AC    90              nop
004150AD    89D2            mov     edx, edx
004150AF    47              inc     edi
004150B0    4E              dec     esi
004150B1    EB 00           jmp     short 004150B3
004150B3    FC              cld
004150B4    09F6            or      esi, esi
004150B6  ^ 75 DC           jnz     short 00415094
004150B8    5F              pop     edi                         ; 解码完成
004150B9    BD 00000000     mov     ebp, 0
004150BE    8B55 F8         mov     edx, [ebp-8]
004150C1    67:64:8916 0000 mov     [fs:0], edx
004150C7    C9              leave
004150C8    FFE7            jmp     edi                         ; 跳到解密后的代码去

解密后的代码:
代码:

004150D7    E8 00000000     call    004150DC                    ; 计算返回地址
004150DC    8B0424          mov     eax, [esp]                  
004150DF    FC              cld
004150E0    8998 33300000   mov     [eax+3033], ebx
004150E6    8B88 EE280000   mov     ecx, [eax+28EE]    ;偏移28EE+5的地方是是否偷call的标志
004150EC    8B5C24 04       mov     ebx, [esp+4]
004150F0    81E1 00000080   and     ecx, 80000000
004150F6    74 2D           je      short 00415125
004150F8    59              pop     ecx
004150F9    89B0 37300000   mov     [eax+3037], esi
004150FF    57              push    edi
00415100    8F80 3B300000   pop     [dword eax+303B]
00415106    80B8 F2280000 E>cmp     [byte eax+28F2], 0E8  ; 偏移28F2+5的地方是被偷掉的call
0041510D    75 0D           jnz     short 0041511C
0041510F    0398 F3280000   add     ebx, [eax+28F3]
00415115    8B5B 02         mov     ebx, [ebx+2]
00415118    FF33            push    [dword ebx]
0041511A    EB 08           jmp     short 00415124
0041511C    8B98 F4280000   mov     ebx, [eax+28F4]
00415122    FF33            push    [dword ebx]
00415124    5B              pop     ebx
00415125    55              push    ebp
00415126    8BE8            mov     ebp, eax
00415128    816C24 04 DC800>sub     [dword esp+4], 80DC         ; 计算被偷代码的地址
00415130    81ED 05103600   sub     ebp, 361005
00415136    8B7C24 04       mov     edi, [esp+4]
0041513A    8DB5 00393600   lea     esi, [ebp+363900]
00415140    B9 00000000     mov     ecx, 0                                  ; 恢复被偷掉的代码
00415145    F3:A4           rep     movs [byte es:edi], [byte esi]          ; 恢复被偷掉的代码
00415147    E8 B1000000     call    004151FD
0041514C    8BC8            mov     ecx, eax
0041514E    E8 AA000000     call    004151FD
00415153    2BC1            sub     eax, ecx
00415155    74 79           je      short 004151D0
00415157    3D 000C0000     cmp     eax, 0C00
0041515C    77 72           ja      short 004151D0
0041515E    81E3 00F0FFFF   and     ebx, FFFFF000                           ; 如果差值小于0C00则真正的病毒体就会运行起来了
00415164    817B 4E 5468697>cmp     [dword ebx+4E], 73696854
0041516B    74 08           je      short 00415175
0041516D    81EB 00010000   sub     ebx, 100
00415173  ^ 75 EF           jnz     short 00415164
00415175    8BC3            mov     eax, ebx
00415177    0343 3C         add     eax, [ebx+3C]
0041517A    66:8138 5045    cmp     [word eax], 4550        ; 定位Kernel32.dll的PE头
0041517F  ^ 75 EC           jnz     short 0041516D
00415181    8B50 78         mov     edx, [eax+78]
00415184    03D3            add     edx, ebx
00415186    8B72 20         mov     esi, [edx+20]
00415189    8B4A 18         mov     ecx, [edx+18]
0041518C    03F3            add     esi, ebx
0041518E    51              push    ecx
0041518F    AD              lods    [dword esi]
00415190    03C3            add     eax, ebx
00415192    66:8178 02 7450 cmp     [word eax+2], 5074
00415198    75 09           jnz     short 004151A3
0041519A    8178 05 6F63416>cmp     [dword eax+5], 6441636F    ; 取得GetProcAddress的地址
004151A1    74 05           je      short 004151A8
004151A3  ^ E2 EA           loopd   short 0041518F
004151A5    59              pop     ecx
004151A6    EB 28           jmp     short 004151D0
004151A8    290C24          sub     [esp], ecx
004151AB    8B72 24         mov     esi, [edx+24]
004151AE    59              pop     ecx
004151AF    03F3            add     esi, ebx
004151B1    0FB7044E        movzx   eax, [word esi+ecx*2]
004151B5    8B7A 1C         mov     edi, [edx+1C]
004151B8    03FB            add     edi, ebx
004151BA    8B3487          mov     esi, [edi+eax*4]
004151BD    03F3            add     esi, ebx
004151BF    8D85 40113600   lea     eax, [ebp+361140]
004151C5    66:8B50 E9      mov     dx, [eax-17]
004151C9    E8 34000000     call    00415202
004151CE    EB 47           jmp     short 00415217
004151D0    8B85 F3383600   mov     eax, [ebp+3638F3]
004151D6    25 00000080     and     eax, 80000000
004151DB    74 1E           je      short 004151FB
004151DD    8B7C24 04       mov     edi, [esp+4]
004151E1    8DB5 F7383600   lea     esi, [ebp+3638F7]
004151E7    A5              movs    [dword es:edi], [dword esi]    ; 恢复被偷掉的call
004151E8    A4              movs    [byte es:edi], [byte esi]
004151E9    8BB5 3C403600   mov     esi, [ebp+36403C]
004151EF    8BBD 40403600   mov     edi, [ebp+364040]
004151F5    8B9D 38403600   mov     ebx, [ebp+364038]
004151FB    5D              pop     ebp
004151FC    C3              retn                                        ; 跳到oep或被偷掉的call的地方继续执行


我们要写清除该病毒修复文件的专杀工具只需要重点关注以上代码就可以了。除此之外需要注意一下病毒会hook几个函数, 
在访问文件和创建进程的时候进行感染:

代码:

7C956DDF ntdll.ZwCreateFile            E8 65BA6303     call    7FF92849
7C956DE4                               BA 0003FE7F     mov     edx, 7FFE0300
7C956DE9                               FF12            call    [edx]
7C956DEB                               C2 2C00         retn    2C

7C956E7F ntdll.ZwCreateProcess         E8 19BA6303     call    7FF9289D
7C956E84                               BA 0003FE7F     mov     edx, 7FFE0300
7C956E89                               FF12            call    [edx]
7C956E8B                               C2 2000         retn    20

7C956E8F ntdll.ZwCreateProcessEx       E8 16BA6303     call    7FF928AA
7C956E94                               BA 0003FE7F     mov     edx, 7FFE0300
7C956E99                               FF12            call    [edx]
7C956E9B                               C2 2400         retn    24

7C95730F ntdll.ZwOpenFile              E8 82B56303     call    7FF92896
7C957314                               BA 0003FE7F     mov     edx, 7FFE0300
7C957319                               FF12            call    [edx]
7C95731B                               C2 1800         retn    18


病毒感染可分为三种情况:
1. 修改EntryPoint使程序入口指向病毒体入口,病毒运行后会路到原始入口点(OEP)继续执行
2. 覆盖EntryPoint处的代码,病毒运行后会恢复EntryPoint的原始代码,然后跳回去继续执行
3. 修改EntryPoint下的某一个call, 使其call到病毒体(可能会修改多个,多次感染的情况), 病毒体运行后会恢复这个call,然后
   跳回这个call的原始地址去继续执行。

我们要写清除工具需要区分出这3种情况:
1. 取得被加密代码的长度,如果长度大于$2900则代表其是覆盖oep类型的(即上面说的第2种情况)
2. 如果长度等于$2900则代表其是修改EntryPoint类型的(即上面说的第1种情况)
3. 解密代码,判断偏移28EE+5的地方是是否偷call的标志,如果是则代表是偷call类型的(即上面说的第3种情况)

分析清楚了病毒的形态及原理我们便可以写专杀工具了,程序基本思路如下:

1. 程序恢复内存中被Hook的api:
    复制一份ntdll.dll到临时目录,重命名为res.dll,加载,然后依次对各进程中的被hook的api进行检查, 如果发现前5个字节
    跟临时目录下的ntdll.dll的相应函数对应的头5个字节不一样,则代表被hook了,于是恢复之。

2. 扫描内存:
    取得进程列表,对进程所在路径下的文件进行扫描。如果发现被染毒则会提示用户,是否需要结束进程杀毒。(这样做比较人性化,
  得到用户的许可才杀进程,举个例,用户开的一个Word程序被染毒,而用户此时没有存盘,如果强杀进程,用户就要哭了。。。
  可能有其他类似情况)

3. 杀毒:
    查杀毒均采用UNICODE路径,这样可以避免一些路径太深(超过260字节)而查杀不到。
    3.1) 从PE头的偏移8的位置判断是否病毒标志love(evol),如果有则是病毒
    3.2) 如果扩展扫描模式打开的情况下会对代码进行分析,满足代码特征的就是病毒。
    3.3) 确定是病毒后就该清除病毒了, 在确认是病毒的情况下会有如下处理:
  3.3.1) 确定病毒类型,方法见上面
        3.3.2) 根据解密后的代码确定病毒体执行完后继续运行的地址,如果是第1,2种情况的病毒则返回地址是OEP,第3种情况的
               返回地址是被偷的Call, 这是最复杂的,因为病毒是多态的,因此要解析很多代码情况, 具体见程序代码
        3.3.2) 根据病毒类型来恢复代码,如果长度大于$2900,则把多出的部份恢复到OEP的位置,否则恢复被偷的call
        3.3.3) 清除Image.PNtHeaders.FileHeader.TimeDateStamp的病毒标志
        3.3.4) 保存文件,重复3.1(因为可能被多次感染)

4. 关于解密代码的Key的运算方法
    因为解密后的代码基本上来说是固定的,我们可以从前两个指令的字节码来推出解密用的Key、步进和运算方法,具体见
    代码中的  TScanThread.GetDecryptKey, 解码Key定义如下:
  
  TDecodeMethod = (METHOD_XOR, METHOD_SUB, METHOD_ADD);
  
  TDecryptKey = packed record
    Key: Byte;
    IncQty: Byte;
    DecodeMethod: TDecodeMethod;
  end;

程序源代码见附件