Bilindiği gibi yazılan programlar debug
programları ile işleyişleri incelenip farklı işlere
zorlanabilirler. Diğer taraftan sourcer türü programlar
aracılığıyla yazılan programların kaynak kodları
çıkartılabilir. Burada bu türlü işlemlerin nasıl
engelleneceği anlatılmaktadır.

Anti-Debugging metodları iki katagoride
incelenebilir:

1. Koruma Amaçlı;

2. Kendi Kendini Değiştiren Kodlar.

Bu tür koruma metodları bugünlerde en fazla
virüslerde kullanılmaktadır. Bu tür trikler virüsün
yaptığı işin çözülmesini engeller böylece virüsün
nasıl bulaştığı ve orjinal kodu çözülemez. Ayrıca kaynak
kodu da çıkartılamaz. Bu tür örneklere ait kaynak kodlar
dökümanın sonuna doğru verilmiştir.

Bu tür triklerin en fazla kullanım alanı
bulduğu başka bir alan ise kopyalamaya karşı koruma
programlarıdır. Bu tür programlar içeride nasıl kontrol
yaptıkları tespit edilemesin diye Anti-Debug, Anti-Trace ve
Anti-Source metodlarıyla korunmaktadırlar. Dolayısı ile
kırılmaları oldukça güçleşmektedir.

1. Koruma Amaçlı:

Koruma amaçlı metodlar kullanıcının kodu
debug etmesi veya kaynak kodunu çıkartmasını engelemek için
kullanılır. Bu tür metodlar normal çalışma esnasında
düzgün çalışmasına rağmen Debug yapılırken sistemi
sakatlamakta veya Debug programını göçertmektedirler.

1.1. Interrupt”ların devre dışı
bırakılması:

Interrupt”ların devre dışı bırakılması
en çok kullanılan metodlardan biridir. Değişik metodları
vardır.

1.1.1. Donanım kontrolü ile interrupt”ın
devre dışı bırakılması:

Port 21h üzerinden kontrol edilen 8259
Interrupt kontrolcüsüne komut göndererek IRQ hatlarının
devre dışı bırakılması esasına dayanır. Port 21h
adresindeki her bit bir IRQ hattını kontrol eder. Bit 0 IRQ
0″ı, Bit 1 IRQ 1″i şeklinde. Buradan 0-7 arası IRQ”lar kontrol
edilebilir. Bu arada IRQ 1 klavye kontrolcüsünden gelen sinyali
taşır. Klavyeden her tuşa basılışta IRQ1 çağrılır. Bu
IRQ”nun karşılığı olan INTERRUPT CPU tarafından
çağrılarak basılan tuşla ilgili bilginin klavyenin
belleğinden alınması sağlanır. Böylece her tuşa
bastığınızda bilgi uçmaz. Belleğe alınır. Eğer Debug
işlemi esnasında bir sonraki komuta geç komutu verilemezse
program debug edilemez. Basitçe klavyeyi kilitleyerek
kullanıcının bir sonraki tuşa basması engellenir. Böylece
program korunmuş olur.

Örnek:

Adres
Hex
Instruction

CS:0100 E4 21 IN AL,21
CS:0102 0C 02 OR AL,02
CS:0104 E6 21 OUT 21,AL

Diğer taraftan, Klavyeye ait PPI (Programmable
Peripheral Interface)”ın bulunduğu Port 61h”a komut
gönderilerekte klavye kilitlenebilir.

Örnek:

Adres
Hex
Instruction

CS:0100 E4 61 IN AL,61
CS:0102 0C 80 OR AL,80
CS:0104 E6 61 OUT 61,AL

1.1.2. Yazılımla Interrupt”ın devre dışı
bırakılması:

Bu biraz daha kolay bir anti-debugging
metodu”dur. Tüm yapmanız gereken Debugger”lar tarafından
kullanılabileceğini düşündüğünüz interrupt vektörlerini
farklı adreslere yöneltmek veya boşaltmak. Bir başka metod
ise hataları kontrol eden interrupt vektörlerini kendi
üzerinize alarak üstünüze aldığınız hata konrolcüsünün
hatasını devreye sokmak. Unutmamanız gereken işlem bittikten
sonra eski vektörleri yerine getirmenizdir. Interrupt
vektörünü Int 21h”ın 25h fonksiyonunu kullanmak yerine
kendinizin değiştirmesi.Çünki Int 21h”ı
çağırdığınızda debugger bunu anlayıp kendisini zincire
ekleyerek sizi kandırabilir. Bu sebeble gidip kendiniz
değiştirmeniz önerilir. Aşağıdaki örnek interrupt 03h -
Breakpoint interrupt”ının ele geçirilmesi gösterilmektedir.

Örnek:

Adres
Hex
Instruction

CS:0100 EB 04 JMP 0106
CS:0102 00 00 ADD [BX+SI],AL
CS:0104 00 00 ADD [BX+SI],AL
CS:0106 31 C0 XOR AX,AX
CS:0108 8E C0 MOV ES,AX
CS:010A 26 8B 1E 0C 00 MOV BX,ES:[000C]
CS:010F 89 1E 02 01 MOV [0102],BX
CS:0113 26 8B 1E 0E 00 MOV BX,ES:[000E]
CS:0118 89 1E 04 01 MOV [0104],BX
CS:011C 26 C7 06 4C 00 00
00
MOV Word Ptr
ES:[000C],0000
CS:0123 26 C7 06 4E 00 00
00
MOV Word Ptr
ES:[000E],0000

1.1.3. Vektör Ayarlamaları

Bu metod interrupt vektörleri üzerinde
oynayarak, bu vektörlere akışı yönlendirmeye dayanır. Bu
tür bir işlem kodçözücü kodda da kullanılmaktadır. (Bkz.
2.1) Bu metodda bilgiler interrupt vektörlerinin işaret ettiği
yerde tutulur. Elbetteki normal çalışma esnasında 01h, 03h
kullanılmaz. Tabi debug etmeyi düşünmüyorsanız. Bu metod
gayet güzel çalışmaktadır.

Örnek:

Adres
Hex
Instruction

CS:0100 31 C0 XOR AX,AX
CS:0102 8E D0 MOV SS,AX
CS:0104 BC 0E 00 MOV SP,000E
CS:0107 2E 8B 0E 34 12 MOV CX,CS:[1234]
CS:010C 50 PUSH AX
CS:010D 31 C8 XOR AX,CX
CS:010F 21 C5 AND BP,AX
CS:0111 58 POP AX
CS:0112 E2 F8 LOOP 010C

1.1.4. Interrupt Yerdeğiştirme

Bu biraz çatlakça bir trik. Ve sadece
programınızın artık daha fazla debug istemediğini
düşünüyorsanız kullanın. Interrupt 16h ve 21h”ın
vektörlerini 01h ve 03h”a kopyalamakla ne yapılabilir. Normal
bir çalışmada böyle bir şey yapılmaz. Eğer kullanıcı
programı debug etmek isterse programın içinde geçen INT 01
komutları normal bir INT komutuna döndürmek zorundadır. Bu
trik çok etkili olabilir. Çünki herhangi bir şekilde CD01(INT
01)”i CD16 (INT 16)”ya değiştirmek kolaydır. Ancak Int
03″için özel komut olan 0CCh tek byte”tır. ve iki byte”lık
bir komutla değiştirilemez.

Örnek:

Adres
Hex
Instruction

CS:0100 FA CLI
CS:0101 31 C0 XOR AX,AX
CS:0103 8E C0 MOV ES,AX
CS:0105 26 A1 84 00 MOV AX,ES:[0084]
CS:0109 26 A3 04 00 MOV ES:[0004],AX
CS:010D 26 A1 86 00 MOV AX,ES:[0086]
CS:0111 26 A3 06 00 MOV ES:[0006],AX
CS:0115 B4 4C MOV AH,4C
CS:0117 CD 01 INT 01

1.2. Zaman Kontrolü:

Nispeten daha az kullanılan bir metoddur.
Ancak programın çalışması esnasında tüm interrupt”ları
devre dışı bırakan debuggerları (Örnek: Borland Turbo
Debugger) devre dışı bırakmak için gayet kullanışlı bir
metoddur. Bu metod basitçe saati kontrol eder ve değişene
kadar kısır döngüde bekler. Bu değer interrupt 08h
tarafından değiştirilir. Diğer bir örnek eğer Port 21h”dan
okunan değer (IN) 01h ile OR”lanır ve tekrar Port 21h”a
yazılsa bile (IRQ 0″ı devreye sokar) Eğer hala devreye
girmemiş ise o zaman debugger aktiftir. Şunu dikkate almak
gerekiyor. Bu metod RUN yapılıyorsa etkindir. Eğer TRACE veya
STEP by STEP çalıştırılsa çalışmaz.

Örnek:

Adres
Hex
Instruction

CS:0100 2B C0 SUB AX,AX
CS:0102 FB STI
CS:0103 8E D8 MOV DS,AX
CS:0105 8A 26 6C 04 MOV AH,[046C]
CS:0109 A0 6C 04 MOV AL,[046C]
CS:010C 3A C4 CMP AL,AH
CS:010E 74 F9 JZ 0109

1.3. Debugger”ı yanıltmak:

Bu metod gayet güzel bir tekniktir. Turbo
Debugger ve benzeri debugger”lar için kullanılır. Bu işlem
bir komutun ortasına atlayarak yapılır. Aslında bir sonraki
komut aptal bir komuttur. ve içerisinde başka bir komutu
içerir. Siz aptal komutu atlayıp gerçek komuta
atladığınızda debugger”ı yanıltmış olursunuz. Ancak
normal step debugger kullanıyorsanız (Örnek Debug veya SymDeb)
bu işe yaramayacaktır. Çünki komutlarınız komut komut
çalıştırıldığından jump ettiği noktada sizi
bekleyecektir.

Örnek:

Adres
Hex
Instruction

CS:0100 E4 21 IN AL,21
CS:0102 B0 FF MOV AL,FF
CS:0104 EB 02 JMP 0108
CS:0106 C6 06 E6 21 00 MOV Byte Ptr
[21E6],00
CS:010B CD 20 INT 20

Şuna dikkat edin :

Adres
Hex
Instruction

CS:0108 E6 21 OUT 21,AL

Dikkat:

Bu trik herhangi bir debugger”ın
çalışmasını etkilemez. Bu sadece kullanıcının başka bir
komutun çalıştırldığını düşünürken başka bir komut
çalıştırılır.

1.4. Check CPU Flags:

This is a nice trick, effective against almost
any real mode debugger. What you should do is simply set the
trace flag off somewhere in your program, and check for it later.
If it was turned on, a debugger runs in the background…

Örnek:

Adres
Hex
Instruction

CS:0100 9C PUSHF
CS:0101 58 POP AX
CS:0102 25 FF FE AND AX,FEFF
CS:0105 50 PUSH AX
CS:0106 9D POPF

Programın ortasında :

Adres
Hex
Instruction

CS:1523 9C PUSHF
CS:1524 58 POP AX
CS:1525 25 00 01 AND AX,0100
CS:1528 74 02 JZ 152C
CS:152A CD 20 INT 20

1.5. Debugger”ın çalışmasını kesme:

Bu teknik debugger RUN modunda iken
çalışmasını keser. Yapacağınız şey programın
içerisinde rastgele yerlere INT 3 komutu yerleştirmek. RUN
modunda olduğunuz halde program hep bir yerlerde kesilir ve siz
sürekli RUN demek durumunda kalırsınız. Bu ise oldukça
sıkıcı bir durum. Eğer debugger dışında iseniz bu bir
çırpıda geçecektir.

Örnek:

Adres
Hex
Instruction

CS:0100 B9 64 02 MOV CX,0264
CS:0103 BE 10 01 MOV SI,0110
CS:0106 AC LODSB
CS:0107 CC INT 3
CS:0108 98 CBW
CS:0109 01 C3 ADD BX,AX
CS:010B E2 F9 LOOP 0106

1.6. Bilgisayarı Stack kullanarak çökertmek:

Bu trik debugger”ların kendi stack”larını
kullanmak yerine kullanıcı programının stack”ını
kullanması esasına dayanır. Eğer debug çalışıyorsa stack
değişecektir. Stack kod alanını gösterdiğinden komutlar
işletilirken aradaki stack bölgesindeki abuk sabuk komutlar
sistemi çökertir. Böylece debug yapılırken sistem çöker.
Eğer debug çalışmıyorsa bu alanlar değişmeyeceğinden
program normal çalışır ve bu alanı geçer.

Önemli not: Bu kodu çalıştırırken CLI
yapıp iş bittikten sonra STI yapmayı unutmayın. Eğer bu
komut aralığında herhangi bir interrupt çağrılırsa bu alan
değişeceğinden bilgisayar olmadık bir yerde çöker.

Örnek:

Adres
Hex
Instruction

CS:0100 8C D0 MOV AX,SS
CS:0102 89 E3 MOV BX,SP
CS:0104 0E PUSH CS
CS:0105 17 POP SS
CS:0106 BC 0B 01 MOV SP,010B
CS:0109 90 NOP
CS:010A 90 NOP
CS:010B EB 02 JMP 010F
CS:010D 90 NOP
CS:010E 90 NOP
CS:010F 89 DC MOV SP,BX
CS:0111 8E D0 MOV SS,AX

1.7. TD386″yı V8086 modundayken çökertmek:

Bu Turbo Debugger”ın V8086 modulü (TD386)”nü
çökertmek için güzel bir metoddur. Temeli sıfıra bölme
işlemidir. Sıfıra bölme işlemi sistemi çökertip programın
kesilmesine neden olur. Halbuki sıfıra bölme işlemi INT
00h”ı çağırır. Eğer siz INT 00h vektörünü bir sonraki
komuta getirirseniz böylece sistem çakılmadan yoluna devam
eder. Halbuki Turbo Debugger bunu farkettiği anda programı
keser. Normal çalışırken ise sorun çıkmaz.

Önemli not: Eski INT 00h vektörünü
kaydetmeniz gerekiyor. İşiniz bittiğinde bu vektörünü
düzeltin. Eğer bunu yapmazsanız sistem bir sonraki INT 00h
çağrısında çökecektir.

Örnek:

Adres
Hex
Instruction

CS:0100 31 C0 XOR AX,AX
CS:0102 8E D8 MOV DS,AX
CS:0104 C7 06 00 00 12 01 MOV WORD PTR
[0000],0112
CS:010A 8C 0E 02 00 MOV [0002],CS
CS:010E B4 00 MOV AH,00
CS:0110 F6 F4 DIV AH
CS:0112 B8 00 4C MOV AX,4C00
CS:0115 CD 21 INT 21

1.8. Herhangi bir V8086 Prosesini çökertme:

TD386″yı göçertme metodlarından biri
Hatalı Komut işletmektir. Ne yazıkki, V8086 ortamında
çalışan başka bir program tarafından işletilen bir hatalı
komut ta sizin sisteminizi etkileyebilir. Metod sıfıra bölme
metodu ile aynıdır. Ancak bu metodda interrupt 0Dh (13)
kullanılır. İşletilen hatalı bir komut programda bir sonraki
satırdan devam etmenizi sağlar. Ancak Debugger üzerinden
çalıştırıyorsanız işletilen komutla debugger duracak ve
programı kesecektir. Böylece debug yapılması engellenmiş
olur.

Önemli not: Orjinal interrupt vektörlerini
eski değerlerine döndürmezseniz herhangi bir sakatlık
durumunda sistemin çakılmasına neden olur.

Örnek:

Adres
Hex
Instruction

CS:0100 31 C0 XOR AX,AX
CS:0102 8E D8 MOV DS,AX
CS:0104 C7 06 34 00 13 01 MOV WORD PTR
[0034],0113
CS:010A 8C 0E 36 00 MOV [0036],CS
CS:010E 83 3E FF FF 00 CMP WORD PTR
[FFFF],+00
CS:0113 B8 00 4C MOV AX,4C00
CS:0116 CD 21 INT 21

2. Kendi Kendini Değiştiren Kodlar:

2.1. Şifreleme / Çözme algoritmaları :

İlk katagori basit bir kod, bu kod şifrelidir
ve basit bir çözme rutini eklenmiştir. Bu arada eğer debugger
bir breakpoint koymuşsa buda arada kaynayacağından farklı bir
komuta dönüşecektir. Dolayısıyla sistemin çakılmasına
neden olur. Böylece debugging işlemi kesilir. Aşağıdaki
örnek Haifa virüsünden alınmıştır. Eğer siz CS:0110
adresine breakpoint koyacak olursanız, asla bu adrese
ulaşamazsınız. Sebebi işlemin sonucunda ne olacağı kimse
tarafından bilinemez.Dolayısıyla ne kod işletileceği
bilinemez.

Not: eğer trace işlemi için çok fazla
uğraşmak istemiyorsanız. çözme işlemini kodun sonundan
itibaren başlatın. Böylece enazından çok fazla uğraşmadan
debug işlemini gerçekleştirebilirsiniz.

Örnek:

Adres
Hex
Instruction

CS:0100 BB 71 09 MOV BX,0971
CS:0103 BE 10 01 MOV DI,0110
CS:0106 91 XCHG AX,CX
CS:0107 91 XCHG AX,CX
CS:0108 2E 80 35 97 XOR Byte Ptr
CS:[DI],97
CS:010C 47 INC DI
CS:010D 4B DEC BX
CS:010E 75 F6 JNZ 0106
CS:0110 07 POP ES
CS:0111 07 POP ES

2.2. Kendini-Değiştiren Kodlar

2.2.1. Basit Kendini Değiştirme:

Bu metod basit bir şifreleme metodlarına
dayanır. Bir komutu işletmeden evvel değiştirmeye dayanır.
Aşağıdaki örnekte Call işlemi yapıldıktan sonra Call”dan
sonra gelen komut değiştirilir. Eğer “P”/Debug veya F8/Turbo
Debugger ile işletirseniz programın bir anda sonlandığını
göreceksiniz. Trace yaparsanız CD 20 olan bir sonraki komut
trace işlemi esnasında CC 20″ye dönecektir. CC Int 03h”ı
çağırdığından debugger kontrolü ele alabilir. Oysa burası
CALL yapıldıktan sonra rutinin içerisinde başka bir kod ile
değiştirilir.

Örnek:

Adres
Hex
Instruction

CS:0100 E8 04 00 CALL 0107
CS:0103 CD 20 INT 20
CS:0105 CD 21 INT 21
CS:0107 C7 06 03 01 B4 4C MOV Word Ptr
[0103],4CB4
CS:010D C3 RET

Dikkat:

Adres
Hex
Instruction

CS:0103 B4 4C MOV AH,4C

2.2.2. The Running Line (Kendi kendini
şifreleme):

Bu örnek Kendi kendini kontrol eden ve kendi
kendini değiştiren bir koddur. Bazen “The Running
Line” ismiyle anılıur. Bu Serge Pachkovsky tarafından
kodlanmıştır.Basit trik noktaları olan bir gösterimdir.
Ancak burada bahsedilen diğer tekniklerden farklı olarak, Bu
göreceli olarak vektör tablosundaki korumaları engeller. Bu
son derece basitleştirilmiş bir örnektir.

XOR AX, AX
MOV ES, AX
MOV WORD PTR ES:[4*1+0],OFFSET TRACER
MOV WORD PTR ES:[4*1+2],CS
MOV BP, SP
PUSHF
XOR BYTE PTR [BP-1], 1
POPF
MOV AX, 4C00H ; This will not be traced!
DB 3 DUP ( 98H )
DB C5H, 21H
TRACER:
PUSH BP
MOV BP, SP
MOV BP, WORD PTR [BP+2]
XOR BYTE PTR CS:[BP-1], 8
XOR BYTE PTR CS:[BP+0], 8
POP BP
IRET

2.2.3. Prefetch Instruction Queue (PIQ)
Ayarlamaları

Bu metod herhangi bir debugger”ı atlatabilir.
veya herhangi bir bir seferde bir işlem yapan debugger”ları
atlatabilir.PIQ CPU üzerinde bulunur. Komutları işletmeden
evvel belleğe çekilir. Böylece işletmek için tekrar çağrı
yapılmaz. Zaten CPU içerisinde mevcuttur. Eski CPU”larda bu 6
veya 4″tür. Yenilerde ise 25 kadardır. işlem basitçe şu
şekilde tanımlanabilir. Bir şekilde PIQ ile Bellekteki bilgi
farklılaştırılır. Kod bu şekilde yazılır. Eğer debugger
içerisinde ise adım adım program çalıştırıldığından
PIQ her defasında temizlenir. Dolayısıyla her zaman güncel
kalır. Oysa normal çalışma esnasında orjinal kalan ve
değişmeyen PIQ”dan dolayı eski kod işleme sokulur. Ve program
bir sonraki satırı işler geçer. Oysa farklılaşmanın
olmadığında program döner durur.

Örnek:

Adres
Hex
Instruction

CS:0100 B9 75 02 MOV CX,0275
CS:0103 BE 90 01 MOV SI,0190
CS:0106 89 F7 MOV DI,SI
CS:0108 AC LODSB
CS:0109 C7 06 0F 01 24 06 MOV Word Ptr
[010F],0624
CS:010F 34 73 XOR AL,73
CS:0111 AA STOSB
CS:0112 C7 06 0F 01 24 06 MOV Word Ptr
[010F],0624
CS:0118 E2 EE LOOP 0108

Şuna Dikkat edin.

Adres
Hex
Instruction

CS:010F 24 06 AND AL,06

===============================================================================

Açıklamalar:

Program örneklerinde CLI/STI çifti
kullanılmamıştır. Interrupt kontrolü veya üzerine alma
durumlarında bu komutların başta ve sonra yer alması
gereklidir. Bunun sebebi eğer siz interrupt vektörünü
değiştirirken interrupt çağrılırsa sistem çökecektir.