趁着放假看了一下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 ecx, ecx
006885C2
006885C2 CheckNextRetRVA: ; ...
006885C2 mov ebx, ss:lpRetRVATable[ebp+ecx*4] ; 加壳时生成的返回地址表
006885C9 add ebx, ss:dwImageBase[ebp]
006885CF cmp eax, ebx
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 esi, eax
006885F4 push esi
006885F5 push ecx
006885F6 mov al, ss:dwKey[ebp]
006885FC or al, al ; Key是否为0?
006885FE jnz short KeyNonZero
00688600 nop
00688601 nop
00688602 nop
00688603 nop
00688604 mov eax, ss:dwImageBase[ebp]
0068860A mov esi, [eax+IMAGE_DOS_HEADER.e_lfanew]
0068860D add esi, ss:dwImageBase[ebp]
00688613 add esi, IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint
00688616 lodsd ; Key为零就从EP重新生成,
00688616 ; 这样脱壳后的程序解码就会错误
00688617 mov bl, al
00688619 add bl, ah
0068861B shr eax, 10h
0068861E add bl, al
00688620 add bl, ah
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 eax, eax
00688637 jnz short RestoreReplaceCodeHerein
00688639 nop
0068863A nop
0068863B nop
0068863C nop
0068863D popa
0068863E mov edi, ss:dwDefaultHeapMem[ebp]
00688644 mov eax, 0Ah
00688649 mul ecx
0068864B add edi, eax
0068864D mov ecx, 0Ah
00688652 mov bl, ss:dwKey[ebp] ; 取出Key到bl
00688658 jmp short RestoreReplaceCodeInHeap
00688658 ; ----------------------------------------------------------------------------
0068865A db 3 dup(90h)
0068865D ; ----------------------------------------------------------------------------
0068865D
0068865D RestoreReplaceCodeHerein: ; ...
0068865D popa
0068865E mov edi, esi ; edi = esi
0068865E ; 在原位置恢复ReplaceCode
00688660 mov ecx, 0Ah
00688665 mov bl, ss:dwKey[ebp]
0068866B
0068866B RestoreReplaceCodeInHeap: ; ...
0068866B lodsb
0068866C xor al, bl ; 对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 edi, ebp
00688685 add eax, edi
00688687 mov [esi-4], eax ; 修改call DecryptReplaceCode
00688687 ; 为call ReplaceCode
0068868A pop edi
0068868B push edi
0068868C xor ecx, ecx
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 esi, ecx
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 eax, ebx
006886CE rol eax, 13h
006886D1 xor eax, edx
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原地解码了。
[注意]APP应用上架合规检测服务,协助应用顺利上架!