-
-
某版本ACProtect Replace Code处理代码的一点分析
-
发表于:
2006-2-14 10:22
7083
-
某版本ACProtect Replace Code处理代码的一点分析
趁着放假看了一下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原地解码了。
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法