趁着放假看了一下ACProtect(UltraFXP免费版),老掉牙的东西可能已经没什么用了。马上又要开学乐sigh,不知这次脱节又要维持到何年何月。。。

更新了一下blog,欢迎来坐坐~
EVERYTHiNG iS BYTE

     ACProtect采用了ReplaceCode技术,会在加壳时随机替换原来的一些"2+3"或者"3+2"模式的指令为call XXXXXXXX,其中XXXXXXXX为壳内地址。在XXXXXXXX处做一些解码以后在默认堆或者原位置动态还原这些已经添加了垃圾指令的ReplaceCode,然后到那里执行。一旦还原完毕以后,就把call XXXXXXXX中的地址指向还原后的位置,以后再次执行就不必重新还原,以提高程序执行效率。
    在新版的ACProtect中外壳会维护一个计数器计算ReplaceCode的调用次数,只有那些反复被调用的ReplaceCode才会采用永久还原模式进行调用。
    注意ACProtect在还原ReplaceCode的过程中用到了EP的值进行解码,所以脱壳以后的程序要保持原来的EP不变才能成功解码。当然单就ReplaceCode的还原而言可以强制它用自定义的Key来解码,但是程序中其他的SDK解码也用到了EP值,所以要强行修改EP的话必须一并处理。

006885B7
006885B7                 call    GetDeltaInEbp
006885BC                 mov     eax, [esp+arg_1C] ; 取得返回地址
006885C0                 xor     ecxecx
006885C2
006885C2 CheckNextRetRVA:                        ; ...
006885C2                 mov     ebxss:lpRetRVATable[ebp+ecx*4] ; 加壳时生成的返回地址表
006885C9                 add     ebxss:dwImageBase[ebp]
006885CF                 cmp     eaxebx
006885D1                 jz      short RetRVAFound
006885D3                 nop
006885D4                 nop
006885D5                 nop
006885D6                 nop
006885D7                 inc     ecx
006885D8                 jmp     short CheckNextRetRVA ; 加壳时生成的返回地址表
006885DA ; ----------------------------------------------------------------------------
006885DA
006885DA RetRVAFound:                            ; ...
006885DA                 mov     ss:lpRetRVATable[ebp+ecx*4], 0
006885E5                 lea     esi, lpEncryptedReplaceCode[ebp; 指向加密的ReplaceCode
006885EB                 mov     eax, 0Ah        ; 每组ReplaceCode长度为10个字节
006885F0                 mul     ecx
006885F2                 add     esieax
006885F4                 push    esi
006885F5                 push    ecx
006885F6                 mov     alss:dwKey[ebp]
006885FC                 or      alal          ; Key是否为0?
006885FE                 jnz     short KeyNonZero
00688600                 nop
00688601                 nop
00688602                 nop
00688603                 nop
00688604                 mov     eaxss:dwImageBase[ebp]
0068860A                 mov     esi, [eax+IMAGE_DOS_HEADER.e_lfanew]
0068860D                 add     esiss:dwImageBase[ebp]
00688613                 add     esi, IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint
00688616                 lodsd                   ; Key为零就从EP重新生成,
00688616                                         ; 这样脱壳后的程序解码就会错误
00688617                 mov     blal
00688619                 add     blah
0068861B                 shr     eax, 10h
0068861E                 add     blal
00688620                 add     blah
00688622                 mov     ss:dwKey[ebp], bl ; 计算以后设为新的Key
00688628
00688628 KeyNonZero:                             ; ...
00688628                 pop     ecx
00688629                 pop     esi
0068862A                 pusha
0068862B                 mov     eax, 2
00688630                 call    GenRand0or1     ; 返回0和1的概率为1:1,
00688630                                         ; 返回0时将ReplaceCode恢复
00688630                                         ; 到默认堆;返回1时恢复在加
00688630                                         ; 密ReplaceCode的原位置
00688635                 or      eaxeax
00688637                 jnz     short RestoreReplaceCodeHerein
00688639                 nop
0068863A                 nop
0068863B                 nop
0068863C                 nop
0068863D                 popa
0068863E                 mov     ediss:dwDefaultHeapMem[ebp]
00688644                 mov     eax, 0Ah
00688649                 mul     ecx
0068864B                 add     edieax
0068864D                 mov     ecx, 0Ah
00688652                 mov     blss:dwKey[ebp; 取出Key到bl
00688658                 jmp     short RestoreReplaceCodeInHeap
00688658 ; ----------------------------------------------------------------------------
0068865A                 db 3 dup(90h)
0068865D ; ----------------------------------------------------------------------------
0068865D
0068865D RestoreReplaceCodeHerein:               ; ...
0068865D                 popa
0068865E                 mov     ediesi        ; edi = esi
0068865E                                         ; 在原位置恢复ReplaceCode
00688660                 mov     ecx, 0Ah
00688665                 mov     blss:dwKey[ebp]
0068866B
0068866B RestoreReplaceCodeInHeap:               ; ...
0068866B                 lodsb
0068866C                 xor     albl          ; 对ReplaceCode进行异或解码
0068866E                 stosb
0068866F                 loop    RestoreReplaceCodeInHeap
00688671                 sub     edi, 0Ah
00688674                 push    edi
00688675                 mov     esi, [esp+4+arg_1C] ; 取得返回地址
00688679                 sub     esi, 4
0068867C                 lodsd
0068867D                 sub     edi, 40240Ch
00688683                 sub     ediebp
00688685                 add     eaxedi
00688687                 mov     [esi-4], eax    ; 修改call DecryptReplaceCode
00688687                                         ; 为call ReplaceCode
0068868A                 pop     edi
0068868B                 push    edi
0068868C                 xor     ecxecx
0068868E
0068868E LoopFixingStack:                        ; ...
0068868E                 cmp     ecx, 8
00688691                 jz      short DoneFixingStack ; 返回地址填入恢复后的ReplaceCode
00688691                                         ; 所在位置
00688693                 nop
00688694                 nop
00688695                 nop
00688696                 nop
00688697                 mov     eax, [esp+ecx*4+4]
0068869B                 mov     [esp+ecx*4+4+var_4], eax ; 修复堆栈环境
0068869E                 inc     ecx
0068869F                 jmp     short LoopFixingStack
006886A1 ; ----------------------------------------------------------------------------
006886A1
006886A1 DoneFixingStack:                        ; ...
006886A1                 mov     [esp+ecx*4+4+var_4], edi ; 返回地址填入恢复后的ReplaceCode
006886A1                                         ; 所在位置
006886A4                 pusha
006886A5                 call    $+5
006886AA                 pop     esi
006886AB                 sub     esi, 6
006886AE                 mov     ecx, 0EDh
006886B3                 sub     esiecx
006886B5                 mov     edx, 78AF007Bh
006886BA                 shr     ecx, 2
006886BD                 sub     ecx, 2
006886C0
006886C0 LoopDestroyDecryptor:                   ; ...
006886C0                 cmp     ecx, 0
006886C3                 jl      short DoneDestroyDecryptor
006886C5                 mov     eax, [esi+ecx*4]
006886C8                 mov     ebx, [esi+ecx*4+4]
006886CC                 xor     eaxebx
006886CE                 rol     eax, 13h
006886D1                 xor     eaxedx
006886D3                 sub     edx, 0BF32A1E8h
006886D9                 mov     [esi+ecx*4], eax ; 加密ReplaceCode解码代码
006886DC                 dec     ecx
006886DD                 jmp     short LoopDestroyDecryptor
006886DF ; ----------------------------------------------------------------------------
006886DF
006886DF DoneDestroyDecryptor:                   ; ...
006886DF                 popa
006886E0                 popa
006886E1                 retn

这部分代码是动态生成的不能直接修改,不过GenRand0or1这个函数没有加密,动动手脚就可以把ReplaceCode原地解码了。