本人水平较低,写这篇文章主要是想向大家学习,本人不解之处望各位能给与解答,并恳请大家指正错误。
工具: trw2000
目标: dbpe 2.33
一、随机改变关键代码的内存地址
动态加载dbpe 2.33 开始不远处看到如下代码
call @1
@1: pop ebp
sub ebp 406913
call 指令将eip进栈,下一句pop ebp 运行后ebp的值为当前代码的内存地址。减去一个固定值,将得到相对偏移量,运用以上两句代码可以对程序进行重定位,以后的代码采用如下形式间址寻址:
MOV EAX, [EBP+412345]
也就是说,代码放到任何地址都不会发生内存寻址错误。后面程序会使用CreateFileMapping、MapViewOfFile等API函数申请一段内存地址,用REP
MOVB将代码转移过去,这样程序每次运行,关键部分的代码地址都会不同,达到反跟踪的目的.
二、花指令的使用
Dbpe的花指令共有五种
1、
0167:004FE036 PUSHF
0167:004FE037 PUSH BYTE +10
设定循环次数
0167:004FE039 JNC
004FE046 没用
0167:004FE03B JMP SHORT 004FE03F
0167:004FE03D DB C1
花指令
0167:004FE03E DB 51
花指令
0167:004FE03F CALL 004FE04A
0167:004FE044 DB CA
花指令
0167:004FE045 DB 11
花指令
0167:004FE046 JNC 004FE03F
0167:004FE048 POP EBX
0167:004FE049 DB CD
花指令
0167:004FE04A ADD ESP,BYTE +04
平衡堆栈
0167:004FE04D JMP SHORT 004FE051
0167:004FE04F DB 99
花指令
0167:004FE050 DB EB
花指令
0167:004FE051 DEC DWORD [ESP]
0167:004FE054 JNO 004FE057
没用
0167:004FE056 DB E8
0167:004FE057 JNS 004FE039
判断[ESP]是否=-1,不等则转
0167:004FE059 JPE 004FE05C
0167:004FE05B DB 75
花指令
0167:004FE05C ADD ESP,BYTE +04
平衡堆栈用
0167:004FE05F POPF
0167:004FE060 JMP SHORT 004FE063
0167:004FE062 DB 75
处理方法将第一句改为JMP 4FE063,后面的改为NOP
2、
0167:004FE063 PUSHF
0167:004FE064 JC 004FE070
0167:004FE066 JMP SHORT 004FE069
0167:004FE068 DB 63
0167:004FE069 CALL 004FE073
0167:004FE06E JMP SHORT 004FE0E7
0167:004FE070 JC 004FE066
0167:004FE072 DB 83
0167:004FE073 ADD ESP,BYTE +04
0167:004FE076 POPF
0167:004FE077 JMP SHORT 004FE07A
0167:004FE079 DB 75
0167:004FE07A PUSH EAX
处理办法,将这些代码直接改为nop
3 常规的花指令
jz @1
jnz @1
db xx
花指令
@1 xxxxxx
4 jc
@1
jnc @1
db xx
@1 xxxxxx
5
jno @1
jne @1
db xx
@1 xxxxxx
3 4 5 三种花指令,直接改为nop即可,用程序实现自动取出花指令很容易,VB部分代码如下,data()为读入的文件byte代码
Private Sub DeFlower(StartPos As Long, EndPos As Long)
Dim i As Long
For i = StartPos To EndPos
'discard the flower instruction
as such
'pushf
'push 10 ...
If Hex(data(i)) + Hex(data(i +
1)) + Hex(data(i + 2)) + Hex(data(i + 3)) + Hex(data(i + 4)) + Hex(data(i
+ 5)) + Hex(data(i + 6)) = "9C6A1073BEB2" Then
data(i) = &HE9
data(i + 1) = &H28
data(i + 2) = 0
data(i + 3) = 0
data(i + 4) = 0
Call ChangData(i, 5, 44)
i = i + 44
GoTo sw
End If
'discard the flower instruction as such
'pushf
'jc xxxxxxxx ...
If Hex(data(i)) + Hex(data(i + 1)) + Hex(data(i + 2)) + Hex(data(i + 3)) +
Hex(data(i + 4)) = "9C72AEB1" Then
data(i) = &HEB
data(i + 1) = &H15
Call ChangData(i, 2, 22)
i = i + 22
GoTo sw
End If
'discard the flower instruction
as such
'jz xxxxxxxx
'jnz xxxxxxxx ...
If Hex(data(i)) + Hex(data(i + 1)) + Hex(data(i + 2)) + Hex(data(i + 3)) =
"743751" Then
Call ChangData(i, 0, 4)
i = i + 4
GoTo sw
End If
'discard the flower instruction
as such
'jc xxxxxxxx
'jnc xxxxxxxx ...
If Hex(data(i)) + Hex(data(i + 1)) + Hex(data(i + 2)) + Hex(data(i + 3)) =
"723731" Then
Call ChangData(i, 0, 4)
i = i + 4
GoTo sw
End If
'discard the flower instruction
as such
'jpe xxxxxxxx
'jpo xxxxxxxx ...
If Hex(data(i)) + Hex(data(i + 1)) + Hex(data(i + 2)) + Hex(data(i + 3)) =
"7A37B1" Then
Call ChangData(i, 0, 4)
i = i + 4
GoTo sw
End If
sw:
Next i
End Sub
Private Sub ChangData(Pos As Long,
StartPos As Integer, EndPos As Integer)
For j = Pos + StartPos To Pos + EndPos
data(j) = &H90
Next j
End Sub
三、UPX解码
用以上方式去处花指令,只能去处很小的一部分,因为程序大量的代码是一段一段解码后运行,解码一段,运行一段,内存中不出现完全解码的文件,这样可以有效的对付反跟踪。处理办法是:多次运行去花程序。
大段的代码软件使用了upx加解密,程序开始处使用了一次,后面恢复被加密程序各个段使用的也是这种方式。
0167:004FE0F0 PUSH BYTE +04
0167:004FE0F2 PUSH DWORD 1000
0167:004FE0F7 PUSH EAX
0167:004FE0F8 PUSH BYTE +00
0167:004FE0FA CALL NEAR [EBP+004384F6] -〉VirtualAlloc
申请一段内存地址 返回值eax=申请内存的首地址
push eax
push ebx 4fe3c5加密段首地址
call 4fe234 upx解码程序
返回值=解码字节
后面用rep movsb将解密后代码写回4fe3c5,再用VirtualAlloc释放申请的内存,一般来说,解密后的代码大于解密前的,但D.Boy在程序中预留了位置,这样就可以先将解密的数据W成一个文件,贴到程序的对应位置,前面用一个JMP指令跳过解码的指令。去花指令。
四、垃圾指令与MMX
程序用CPUID指令判断CPU是否支持MMX指令集,如果支持就用MMX指令动态解密运行,代码中间插入了大量的垃圾代码来干扰跟踪者的视线。如
mov eax , 47ad4470
mov ebx , 6421c319 垃圾代码
movq mm2,mm3
sub ebx, ebx 垃圾代码
pcmpeqd mm0, mm1
mmx指令集网上有大量的介绍,中英文都有,这里就不细说了。但这段代码很长,而且是翻译一段,运行一段,这里需要一定的耐心。
五、利用int3反跟踪
这里看看如下代码,这是去处花指令的,以后同
sidt [esi]
取中断向量表
mov esi, [esi+2]
mov ax, [esi+18]
取int3的原入口地址,
mov bx, [esi+1e]
mov [ebp+xxxx] ,ax 保存int3的原入口地址
mov [ebp+yyyy] ,bx
mov eax , 4241aa
add eax ,ebp
eax为新的int3入口地址
mov [esi+18], ax
将int3的入口地址指向自己的程序
mov shr eax,10
mov [esi+1e],ax
利用如上代码,就改变了int3的入口地址,跳是软件如trw2000也会将int3的入口地址指向自己的程序,这样就可以有效的对付大部分调试软件,这里第一次设定的将int3的入口地址为52f876,执行52f876的代码时,获得的是ring0级权限。自己的程序也可以用这种方法获得ring0级权限。
程序利用int3跳到自己的代码部分解密下一段代码,同时设定新的入口,另一个分支是call ebx。看看如下代码:
CMP EAX,52554E53
JNZ 0052F8EF
CALL EBX
程序后半部用到
IRET
0052F8EF CMP EBX,554E434F
JNZ NEAR 0052FB58
0052F905 MOV AH,[ESI]
解密
XOR AH,AL
NOT AH
MOV [ESI],AH
INC ESI
DEC ECX
解密长度,开始几段都相同
CMP ECX,BYTE +00
JNZ NEAR 0052F905
DEC AL
下一段解密XOR的值为这次的减1
LEA EDI,[EBP+00437D36]
SIDT [EDI]
重设INT3的入口地址
MOV EDI,[EDI+02]
MOV EBX,[ESP]
*注1
CMP BYTE [EBX],E9
E9 为JMP
JNZ 0052FA82
ADD EBX,BYTE +05
JMP的指令长度,INT3设到JMP的下一句
JMP 0052FA94
0052FA82 ADD EBX,BYTE +02
0052FA94 MOV [EDI+18],BX
SHR EBX,10
MOV [EDI+1E],BX
MOV EBX,0155
MOV DR7,EBX
*注2
MOV EBX,554E434F
0052FB58 IRET
*注1:INT3执行后,先将标志寄存器内容入栈,CS寄存器扩展到32位入栈,EIP入栈,执行IRET时以相反出栈,[ESP]为INT3下一句的地址
*注2:DR7为调试控制寄存器,只有在ring0权限时才能操作此寄存器,以后的代码中还会见到dr0 dr1 dr2 dr3,它们是调试断点寄存器,dr6为调试状态寄存器。
这段代码也是解密一段执行一段,去花程序不起作用,但这段代码长度结构都相同,我猜想是由程序自动生成的,这样就可以把这段w出来,用自己的程序解密(代码略),找到代码开始变化时地址位置,手动跟踪时直接跳过去,到后面大段解码完成后,将解码后的代码写回源程序,去掉解码部分代码。这种方法还是很繁琐,大家有好的方法如能告知不胜感激。
六、判断中断向量
sidt [esi]
取中断向量表
mov esi, [esi+2]
mov ax, [esi+2e0]
mov bx, [esi+6]
xor ax ,bx
jnz error
如果没有跟踪软件时ax与bx的值相同,如果不同那么……
七、判断驻留程序
push 0
push 0
push 0
push 0
push 0
push 0
push esi
call CreateFileA
cmp eax , -1
jnz error
esi 指向的内容\\.\BW2K\.\\, \\.\SUPERBPM\.\\ \\.\ICEDUMP\.\\ \\.\REGVXD\.\\
\\.\NTICE\.\\ \\.\SIWVID\.\\ \\.\SICE\.\\
\\.\FILEVXD\.\\
如果这几种程序没有驻留,CreateFileA返回值eax应为ffffffff,程序就用此方法反跟踪
八、文件校验
文件校验共出现两次
@1 mov bl, [edi] edi代码地址
xor bl,cl
add eax, ebx
inc edi
dec ecx
cmp ecx ,0 长度
jnz @1
lea ebx,[ebp+42cf59]
cmp [ebp+42d1a8] ,eax 比较校验和是否相当
jnz error
利用prodump抓取的影像文件的校验和,与原来的肯定要不同
九、利用定时器反跟踪
push ebx
push 1f4
push xxx
push xxx
call SetTimer
定时器的时间间隔为500ms,ebx指向事件代码,事件代码用到了上面提到的int3反跟踪技术获得ring0权限,这样程序运行后打开调试软件也会被程序发现。
十、不明之处
代码如下
mov eax, [fs:word 30] 不明
push 0
call GetModuleHandleA
test edx,edx
不明
jns error
cmp [edx+8], -1
不明
jnz error
mov [edx+50], 1000
不明
mov [edx+6] , 1010
不明
。。。。。。
eax的返回之正确为400000,edx的值为819xxxxx,怀疑与线程有关,执行到mov [edx+6] , 1010时死机,不明所以,望指教。
SWay[CCG]
讨论:
SWay[CCG]:
程序运行时edi=需要计算的代码地址,ecx=1c000,相当于下面的说明语句 for(cl=0x1c000;cl=0;cl--) { sum+=[EDI]^CL; edi++; } if (sum<>CorrectSum) error; |
飞叶流枫 |
|
swift |
|