|Asm dla badaczy kodu #1|
|Wprowadzenie|

Chyba nikogo nie musze uswiadamiac jak wazna jest znajomosc assemblera dla badaczy kodu. Jezyk ten bedacy mnemonika kodu maszynowego procesorow ulega zatraceniu w dzisiejszych czasach w dobie pakietow typu Visual Microsoftu, Borlanada i innych. Nowoczesni (czytaj. nowi -:)) programisci nie maja nawet pojecia czym jest assebler i jak go ugrysc a przeciez kod asemblera jest esencja programowania i dlatego kazdy badacz kodu musi go poznać. Postanowilem przedstawic wam maly guide wprowadzajacy do asemblera dla wszystkich poczatkujacych crackerów i pod ich kierunkiem pisany. Jest to jedynie schematyczny przeglad podstawowych pojec i instrukcji, który mam nadzieje rozwine w przyszlosci. W ZADNY WYPADKU NIE JEST TO TUTOR programowania w asm, jedynie przedstawia zagadnienia na ktore nalezy zwrocic uwage podczas analizy kodu. No ale mam nadzieje :-) ze kazdy kto to przeczyta wezmie sie za asm'a porzadnie i bedzie pisal w nim programy w razie potrzeby.

[ Rejestry ]

Rejestry sa podstawowym miejscem przechowywania danych. Sa to 16-bitowe komorki procesora. Jest 14 rejestrów i w tym 12 rejestrow danych i adresowych, rejestr wskaznika instrukcji (IP) i rejestr
znacznikow. Rejestry danych i adresowych mozemy podzielic na kilka grup i tak:


AX (akumulator)             --------+
BX (bazowy)                         |----- Rejestry ogólnego
przenzaczenia
CX (licznik)                        |    
DX (danych)                 --------+

SP (wskaznik stosu)         --------+
BP (wskaznik bazy)                  |-----Rejestrywskaznikowe i
indeksowe
SI (index zrodla)                   |
DI (indeks przeznaczenia)   --------+

CS (programu)               --------+
DS (danych)                         |----- Rejstry segmentowe
SS (stosu)                          |
ES (dodatkowy)              --------+

IP (wskaznik instrukcji)
I Rejestr Znacznikow 

Jak oczywiscie kazdy sie zorientowal przy pracy w Win32 rejestry okreslane sa jak EAX, EAX itd, oznacza to ze sa to odpowiedniki powyzszych rejestrow, tyle, ze 32-bitowe.

Chwila wyjasnienia z tymi bitami. Wezmy rejestr AX, ktoryjest 16 bitowy i dzieli sie na dwa podrejestry 8 bitowe AH i AL. Jak wiemy 8 bitow tworzy bajt, ktory przyjumuje wartosc od 0 do 255, czyli
rejestr AH i AL moze miec najwieksza wartosc FFh. Logicznie myslac -:) rejestr 16 bitowy moze przyjac maksymalna wartosc FFFFh itd. (32 bit EAX mam max FFFFFFFFh ups-:)). Chyba kazdy lapie co daja 32
bitowe rejestry i jak zwiekszaja sie mozliwosci.

Warto zapoznac sie z charakterystykami rejestrow, gdzyz kazdy ma swoje wlasne konkretne zastowsowanie. Przegladajac kod programu mozemy zauazyc pewne prawidlowosci, np.

EIP - debugujac pod SoftIce 32bit widzimy, ze rejestr ten wskazuje na aktualny kod instrukcji i mozemy go uzyc np do zalozenia pulapki na danej lini czyli bpx EIP lub dokladniej CS:EIP.

CS - wskazuje segment kodu, czyli jak mamy jakac linie kodu o adresie np. 14F:04033232 to mozemy ja zapisac jako CS:04033232 poniewaz w rejestrze CS jest zachowana wartosc 014F.

DS - podobnie jak powyzej, zawiera adres segmentu dany, jezeli w okienku danych pod SoftIce mamy jakis adres np. 0145:03055555 to DS wskazuje segment 0145.

ESI i EDI sa wskaznikami danych np. do porownan tekstow itp. Wezmy np. instrukcje porownywania w bibliotekach VB - reps cmpsw dla, ktorych w w ds:esi i es:edi zawarte sa adresy tekstow (np. numerow
seryjnych) do porwnania. To samo tyczy sie wielu instrukcji przesylania i porownnywania danych, gdzie przeznaczenie i cel zawarte sa w rejesteach SI i DI np:

LEA SI, ZRODLo ;Zaladowanie adresu zrodla
LEA DI, ES:PRzesznaczenie ;Zaladowanie adresu przezanczenia

MOV CX,100 ;Zaladowanie licznika elementow
MOVS Przeznaczenie,Zrodlo ;Kopiowanie tekstu z jednego
miejsca w innne.

|Rejestry - specyfikacja architektury intela|

Rejestry ogolnego przeznaczenia          Rejestry segmentowe
         AH/AL  AX  (EAX)  Akumulator             CS     Programu
         BH/BL  BX  (EBX)  Bazowy                 DS     Danych
         CH/CL  CX  (ECX)  Licznik                SS     Stosu
         DH/DL  DX  (EDX)  Danych                 ES     Dodatkowy
                                         
 
        (Exx) znaczy  386+ 32 bit rejestr   
 
         Rejestry wskaznikowe                    Rejestry stosu
 
         SI (ESI)  Indeks zrodla                 SP (ESP)  Wskaznik stosu
         DI (EDI)  Indeks przeznaczenia          BP (EBP)  Wskaznik bazy
         IP        Wskaznik instrukcji
 
         FLAGI Rejestr Znacznikow   (zobacz FLAGI)
 
         Specjalne rejestry (386+)
         CR0     Control Register 0        DR0    Debug Register 0 
         CR2     Control Register 2        DR1    Debug Register 1 
         CR3     Control Register 3        DR2    Debug Register 2 
                                           DR3    Debug Register 3
         TR4     Test Register 4           DR6    Debug Register 6
         TR5     Test Register 5           DR7    Debug Register 7
         TR6     Test Register 6
         TR7     Test Register 7

				

Rejestry ogolnego przeznaczenia sa przeznaczzone do przechowywania dowolnych danych i wykonywania roznych operacji (arytmetycznych, logicznych itp) , pelnia takze funkcje specjalne odpowiadajace ich
nazwom.

AX (accumulator) - rejestr ten jest najczesciej uzywany przy operacjach mnozenia i dzielenia, a takze w operacjach logicznych, arytmetycznych i odkladania wynikow wielu operacji. 8 dolnych bitow tego rejstru okresla sie jako rejestr AL, a 8 gornych bitow jako AH

BX (basis) - rejestr bazowy moze byc uzywany jako dwa 8-bitowe rejestry BH i BL, a np. jako 16-bit mozemy go uzyc do utworzenia adresu pamieci, tworzac z rejestrem segmentowym pelny adres -
Segmennt:Offset - DS:BX

CX (count) - rejestr zliczajacy jest wykorzystywany oprocz zliczania takze do przesylania danych. Moze byc takze uzywany jako dwa rejestry 8-bitowe CH i CL.

DX (data) - rejestr danych wykorzystuje sie przy dzieleniu i mnozeniu. Jest takze jedynym rejestrem, w korym mozna podac adres portu w rozkazach wejscia-wyjscia.

Rejestry segmentowe sluza do adresowania pamieci operacyjnej.

CS (code segment) - rejestr wskazuje poczatek segmentu kodu programu, tworzy pelny adres wraz z rejestrem IP - CS:IP. Rozkazy programu, skoki, powroty pobierane sa w odniesieniu do tego
rejestru.

DS (data segment) - rejestr wskazujacy poczatek segmentu danych

SS (stack segment) - rejestr stosu wskazuje poczatek segmentu stosu

ES (extra segment) - rejestr dodatkowu wskazujacy dodatkowy segment danych

Rejestry wskaznikow. Dostep do danych adresowany jest przez polaczenie adresu z rejestru segmentu z przesunieciem pobieranym z innego rejestru min. rejestru wskaznikowego.

SI (source index) - rejestr indeksowy zrodla, najczesciej stosowany przy adresowaniu w innstrukcjach przetwarzajacych lancuchy znakow, tworzy wowczas pelny adres DS:SI

DI (destination index) - rejestr indeksowy przeznaczenia, podobnydo SI uzywany w adresowaniu danych przy przetwarzaniu lancuchow znakow, tworzy wowczas pelny adres ES:DI

SP (stack pointer) - wskaznik stosu tworzy wraz z SS - SS:SP adres danej odeslanej na stos i jest wykorzystywany przy pobieraniu i zapisywaniu danych na stos.

BP (base pointer) - wskaznik bazy uzywany jest podczas operacji niestandardowych np. przy pobieraniu parametrow przekazywanych na stos.

IP (instruction pointer) - wskaznik instrukcji wskazuje na aktualnie wykonywana instrukcje i wraz z rejestrem segmentu kodu tworzy pelny adres - CS:IP. IP wskazuje offset (przesuniecie) wzgledem poczatku segmentu programu.

| Flagi - rejestr znaczników|

Falgi sa komorkami, ktore moga przyjmowac wartosc 0 lub 1 i sa zawarte w rejestrze znacznikow. Odpowiednie ustawienie poszczegolnych flag decyduje o wykonaniu innych instrukcji a szczegolnie instrukci warunkowych. Najszybciej zrozumiec flagi mozna na przykladzie :

CMP AX,BX - Porownaj rejestry AX z BX, jezeli rowne to flaga zerowa Z ustawiona na 1
JZ 0401233 - Jezeli flaga Z ustawiona na 1 to wykonaj skok do adrsu 0401233

Oczywiscie intrukcja CMP ustawia takze inne flagi z zaleznosci od wyniku porownania i podobnie inne instrukcje warunkowych skokow moga sprawdzac takze inne flagi. Szczegolowiej przedstawie to przy omowieniu skokow warunkowych.

Po co nam znajomoasc flag, ano poto aby podzczas analizy kodu wiedziec jaki wynik dalo porownanie danych i czy np. skok zostanie wykonany czy nie. Poza tym debugujac program mozem zmienic dzialanie instrukcji skoku zmieniajac stan znacznikow.

Np. w powyzszym przykladzie AX jest rowne BX i flaga zerowa Z zostala ustawiona na 1 wiec skok warunkowy zostanie wykonany. Jezeli jednak mimo rownosci AX i BX nie chcemy wykonac skoku to podczas sledzenia programu resetujemy flage zerowa. W SoftIce robimy to : r fl z (czyli resetuj flage zerowa) i skok nie zostanie wykonany :-)

Ciekawostki :
Bit 6 rejestru znacznikow - znacznik zera, najwazniejsza przy pierwszych krokach lamania programow. Decyduje o podstawowych skoksach warunkowych :-)

Bit 8 rejestru znacznikow - flaga pracy krokowej (TF - trap flag) ustawia procesor w trybie pracy krokowej w celu uruchomienia programu pod debugerem,

Bit 10 rejestru znacznikow - flaga kierunku (DF - direction flag) wymusza zwiekszania lub zmniejszanie rejestrow indeksowych przy wykonywaniu instrukcji operujacych na lancuchach czyli albo rosnaco albo malejaco (czyli od lewej do prawej albo na odwrot). Czujecie, przeciez numer seryjny mozna spokojnie przeczytac od koncz :-)

|Flagi - Rejestr znaczników - specyfikacja Intel 8086|

Rejestr znacznikow jest 16-bitowym rejestrem, szesc bitow zawiera informacje o stanach, trzy pozwalaja sterowac praca procesora z poziomu programu a dwa pozostale zwiazane sa z trybem wirtualnym.


      |11|10|F|E|D|C|B|A|9|8|7|6|5|4|3|2|1|0|
        |  | | | | | | | | | | | | | | | | '---  CF Carry Flag
        |  | | | | | | | | | | | | | | | '---  1
        |  | | | | | | | | | | | | | | '---  PF Parity Flag
        |  | | | | | | | | | | | | | '---  0
        |  | | | | | | | | | | | | '---  AF Auxiliary Flag
        |  | | | | | | | | | | | '---  0
        |  | | | | | | | | | | '---  ZF Zero Flag
        |  | | | | | | | | | '---  SF Sign Flag
        |  | | | | | | | | '---  TF Trap Flag  (Single Step)
        |  | | | | | | | '---  IF Interrupt Flag
        |  | | | | | | '---  DF Direction Flag
        |  | | | | | '---  OF Overflow flag
        |  | | | '-----  IOPL I/O Privilege Level  (286+ only)
        |  | | '-----  NT Nested Task Flag  (286+ only)
        |  | '-----  0
        |  '-----  RF Resume Flag (386+ only)
        '------  VM  Virtual Mode Flag (386+ only)

Bit 0, (CARRY FALG) CF - Znacznik przeniesienia, ma wartosc 1 jesli dodawanie powoduje przeniesienie lub odejmowanie powoduje pozyczenie, w przeciwnym razie ma wartosc 0. CF zawiera takze wartosc przesuniecia lu przesunietego cyklicznie bitu wychodzacego poza rejestr lub komorke pamieci, oddaje takze wynik operacji porownania. CF dziala takze jako wskaznik dla operacji mnozenia.

Bit 2, (PARITY FLAG) - Znacznik parzystosci - ma wartosc 1 gdy wynik operacji ma parzysta ilosc bitow o wartosci 1, w przeciwnym wypadku znnacznik przyjmuje wartosc 0. PF jest glownie uzywany przy przesylaniu danych.

Bit 4, (AUXILIARY CARRY FLAG) - znacznik przeniesienia pomocniczego - ma podobne znaczenie jak CF, ale pokazuje przeniesienie lub pozuczke od bitu 3 w gore. AF jest uzyteczny przy dzialaniach na "spakowanych" liczbach dziesietnych.

Bit 6, (ZERO FLAG) - znacznik zera - ma wartosc 1 gdy wynik operacji jest zerem, wynik rozny od zera ustawia na 0

Bit 7 - (SIGN FLAG) - znacznik znaku - ma znaczenie tylko podczas operacji na liczbach ze znakiem, SF przyjmuje wartosc 1 jesli wynikiem operacji arytmetycznych, logicznych, przesunniec jest wartosc ujemna, w przeciwnym wypadku przyjmuje wartosc 0. Inaczej mowiac SF pokazuje najbardziej znaczasy bot (bit znaku) wyniku, niezaleznie czy wynik jest 8 czy 16-bitowy

Bit 8 - (TRAP FLAG) - znacznik pracy krokowej - ustawia procesor w trybie pracy krokowej, w celu uruchomienia programu po debugerem.

Bit 9 - (INTERRUPT FLAG) - znacznik zezwolenia na przerwanie - zezwala procesorowi rozpoznac zadanie obslugi przerwan pochodzace od zewnetrznych urzadzen systemu. Wyzerownie IF powoduje, ze procesor ignoruje przerwania.

Bit 10 - (DIRECTORY FLAG) - znacznik kierunku - wymusza zmniejszenie (DF=1) lub zwiekszenie (DF=0) rejestrow indeksowych po wykoniu instrukcji operujacych na lancuchach. Jesli DF =0 to procesor przetwarza lancuchy w kierunku rosnaczych adresow (od strony lewej do prawej) a jak 1 to w kierunku odwrotnym.

Bit 11 - (OVERFLOW FLAG) - znacznik nadmiaru - jest glownie wskaznikiem bledu podczs operacji na liczbaczh ze znakiem. OF=1 jesli dodanie dwoch liczb z jednakowym znakiem lub odjecie dwoch liczb z roznymi znakami daje wynik nie mieszczacy sie w argumencie wykonanej instrukcji, w przeciwnym przypadku znacznik jest 0. OF ma takze wartosc 1 gdy najbardzej znaczacy bit (bit znaku) argumentu zostanie zmieniony przez przesuniecie podczas operacji arytmetycznej, w przeciwnym przypadku jest 0. Znacznik OF, razem ze znacznikiem CF, wskazuje takze dlugosc wyniku mnozenia. Jesli bardziej znaczaca czesc iloczynu jest rozna od zera to OF i CF sa rowne 1, jezeli jest inaczej to oba znaczniki sa rowne 0. OF takze przyjmuje wartosc 1 gdy operacja z dzielenia daje iloraz przekraczajacy rejestr przeznaczenia.

| Stos /Stack/|

Stos jest miejscem przechowywania danych jak rejestry lub zawartosci komorek pamieci. Mamy dwie instrukcje PUSH, ktora przesyla dane na szczyt stosu i POP, ktora pobiera dane ze szczytu stosu. O co biega z tymi szczytami :-), stos jest sterta na ktorej ukladane sa dane, kazda dana ukladana jest na szczyt a poprzednia dana schodzi na dalsza pozycje. Czyli istotna jest kolejnosc kladzenia danych na stos, gdyz w takiej samej( a dokladnie odwrotnej) kolejnosci musimy pobierac dane ze stosu:

PUSH EAX - kladzie na szczyt stosu EAX
PUSH EBX - kladzie na szczyt stosu EBX a EAX schodzi na dalsza pozycje
....instrukcje
POP EBX - pobiera ze szczytu dana ktora jest EBX ( a na szczycie zostaje EAX)
POP EAX - pobiera ze szczytu stosu EAX

Chyba lapiecie o co biega ?:-)

Acha jeszcze jedno, na szczyt stosu wskazuje tzw. wskaznik stosu SP (Stack Pointer) a instrukcje PUSH i POP zwiekszaja i zmniejszaja ten wskaznik. Rejestr ten nigdy nie jest ustawiany bo procesor to robi automatycznie i zawsze wskazuje adres szczytu stosu (szczytowego slowa).

Paczac ogolnie na pamiec komputera, kazda czesc programu moze utworzyc swoja dowolna przestrzen stosu. Programista powinien tak przydzielic pamiec aby stos nie pokrywal sie przypadkiem z innymi obszarami pamieci :-)

|CALL i RET - wywołanie funkcji i procedur|

CALL adres wywoluje funkcje o podanym adresie i wykonuje ja az do powrotu (RET).

instrukcje...
CALL 040ABCCC
Mov eax,edx
instrukcje...

Wywollanie CALL wywola funkcje o adrsie 040ABCCC i po powrocie z niej (RET) program bedzie kontynuowal dalej MOV eax,edx itd. Jak to sie dzieje, ze program wie gdzie ma wrocic ?. Ano CALL kladzie adres kodu na stosie, natomiast RET pobiera ten adres i wraca tam gdzie potrzeba.

Jezeli CALL wywoluje jakies funkcje, to argumenty takiej funkcji kladziemy na stosie przed wywolanie CALL. Przyklad takiego dzialania :

MOV EDI,[ESP+00000220] --- Zapisuje uchwyt okienka dialogowego w EDI
PUSH 00000100 --- Maksymalny rozmiar tekstu na stos
PUSH 00406130 --- Adres bufora dla tekstu na stos
PUSH 00000405 --- Identyfikator na stos
PUSH EDI --- Uchwyt okienka dialogowego na stos
CALL GetWindowText --- Wywolanie funkcji o parametrach zapisanych na stosie.

Widzimy wiec, ze przy jakis ciekawych wywolania funkcji warto zagladnac jakie parametry kladzione sa na stosie i ogolnie warto sie zorientowac jakie parametry dana funkcja wymaga.

|MOV - instrukcja przeniesienia|

To najczesciej spotykana instrukcja umozliwiajaca przenoszenie danych pomiedzy rejestrem a komorka lub pomiedzy rejestrami lub kopiowania stalej wartosci do rejestru lub komorki. Ogolna postac to MOV przeznaczenie, zrodlo i nie powinno nikomu sprawic klopotu jej zrozumienie.

Przyklady :
MOV EDS, EAX - przeniesienie pomiedzy dwoma rejestrami 32-bitowymi
MOV CL, 39 - przeniesienie stalej do rejestru
MOv ES:[BX],AX - zmiana przypisania segmentu

Kila uwag :

1). Nie mozna bezposrednio przeniesc danych pomiedzy komorkami pamieci. Musimy dane najpier przeniesc dane do rejestru ogolnego przeznaczenia a pozniej z rejestru do przeznaczenia w pamieci. Przyklad, mamy dwie zmienne w pamieci np. TYLEK i ZADEK i aby przenies wartosc z jednej do drugiej to

MOV AX,TYLEK
MOV ZADEK,AX

2). Nie mozna zaladowac bezposrednio stalej do rejestru segmentu, musimy ja przenies przez rejestr ogolnego przeznaczenia.

MOV AX, ADRES_DS
MOV DS, AX

3). Podobnie nie mozemy przenies bezposrednio zawartosci jednego rejestru segmentu do drugiego, podobnie musimy przez rejestr ogolnego przeznaczenia.

MOV AX, ES
MOV DS, AX

4). Nie mozna uzyc rejestru CS jaki argumentu przeznaczenia w instrukcji MOV

Widzicie wiec jakie kombinacje nalezy wykonywac z danymi i dlaczego az tak duzo instrukcji MOV mamy w kodzie programu.

Przy debugowaniu programu pamietajcie, ze w rejestrze moze byc szukana przez nas wartosc lub adres wskazujacy na ta szukana wartosc. A wiec sprawdzajac w SOFTICE dane jezeli uzyjemy komendy np. d EAX to wyswietli nam w oknie danych zawartosc pamieci o adresie zawartym w EAX, natomiast jak damy ? EAX to wyswietli nam dane zawarte w EAX w postaci szesnastkowej i dziesietnej.

|CMP i skoki warunkowe|

Bardzo wazna instrukcja jest CMP (compare), ktora decyduje o dzialaniu programu, petlach, skokach, wywolaniach podprogramow itp. Instrukcaja CMP dziala na zasadzie odejmowania zrodla od przeznaczenia i sprawdzaniu otrzymandego wyniku. Glownym celem dzialania tej instrukcji jest ustawienie rejestrow w zaleznosci od otrzymanego wynniku. W przypadku operacji na argumentach bez znaku ustawiane sa dwie flagi - zerowa ZF i przeniesienia CF, natomiast przy operacjach na argumentach ze znakiem dodatkowo jeszcze - nadmiaru OF i znaku SF

Przyklad:
CM AX,BX - jezeli AX = BX to ZF=1 i CF=0 gdy AX > BX to ZF=0 i CF=1 gdy AX < BX to ZF i CF=0

Na podstawie spelnianych warunkow, czyli ustawieniu poszczegolnych flag moga nastapic skoki warunkowe w kodzie. Naczesciej spotykany JZ - skok jezeli ustawiona flaga Z czyli np. w przypadku porownaia czy AX=BX i jezeli tak to skok.

Podobna instrukcja jest TEST, ktora dla odmiany przeprowadza operacje logiczna na bajtach - AND ale nie zapamietuje wyniku a jedynie na jego podstawie ustawia odpowiednio flagi.


Przyklad: CALL procedura                 procedura: MOV AX,1
          TEST AX,AX                                CMP
          Wpisany_kod, Dobry_kod
          JZ adres2                                 JE dobrywpis
                                                    RET
                                                    dobrywpis: XOR
                                                    AX,AX
                                                    RET

Procedura CALL wywoluje np. procedure sprawdzania poprawnosci danych rejestracyjnych i w przypadku pomyslnym zapisuje do AX wartosci logiczna 0 (np. przez XOR AX,AX) a jezeli zle to zapisuje 1. Teraz instrukcja TEST AX,AX wykonuje operacje logiczna na AX czyli AX and AX, jezeli bylo (0 to 0) AND 0 da nam 0 i flaga zerowa Z zostaje ustawiona na 1. Teraz instrukcja skoku warunkowego sprawdza czy flaga zerow Z=1 i robi skok. Natomiast gdy by bylo (1 AND 1) to flaga Z=0 i skok nie nastapi.

A procedurka to wiadomo, napoczatku wpisujemy wartosc logiczna 1 do AX (czyli zly kod) a pozniej sprawdzamy jaki faktycznie jest wpisany kod, jezeli poprawny to skok i operacja (1 XOR 1) co da nam 0 w AX i powrot a jak zly to niech pozostanie 1 i powrot

Nalezy pamietac, ze instrukcje CMP i TEST wykonuja operacje na argumentach, ktorych wykonanie ustawia kilka odpowiednich flag w zaleznosci od wielkosci argumentow, znaku, przeniesienia itp. Dlatego tez mozemy wykonac odpowiednie skoki nie tylko przy warunku A=B ale tez w zaleznosci czy mniejsze, wieksze, ze znakiem itp.

Np. skok JA (skok gdy powyzej) wykonany jest gdy flagi CF=0 i ZF=0 i wykonuje skok gdy przeznaczenie jest wieksze od zrodlo (bo to wyniklo z operacji porownania i takiego ustawienia flag). Od razu zaznaczam, ze analizujac kod pod SoftIce aby zmienic skok np. musimy nie tylko zmienic flage Z ale i C (czyli np. r fl z; r fl c). To samo tyczy sie innych skokow warunkowych i zapraszam do tabeli specyfikacji skokow warunkowych.

|Specyfikacja skoków warunkowych|


 Instrukcja    Opis                                 Skok jesli.....
          JA     skok gdy powyzej                      CF=0 i ZF=0
          JAE    skok gdy powyzej lub rowny            CF=0
          JB     skok gdy ponizej                      CF=1
          JBE    skok gdy ponizej lub rowny            CF=1 or ZF=1
          JC     skok gdy przeniesienie                CF=1

          JCXZ   skok gdy CX=0                         CX=0
          JE     skok gdy jest rowny                   ZF=1

          JG     skok gdy wiekszy *                    ZF=0 and
          SF=OF
          JGE    skok gdy wiekszy lub rowny *          SF=OF
          JL     skok gdy mniejszy                     SF != OF
          JLE    skok gdy mniejszy lub rowny *         ZF=1 or SF
          != OF
          JMP    skok bezwarunkowy                     bez warunku

          JNA    skok gdy nie powyzej                  CF=1 or ZF=1
          JNAE   skok gdy nie powyzej ani rowny        CF=1
          JNB    skok gdy nie ponizej                  CF=0

          JNBE   skok gdy nie ponizej ani rowny        CF=0 and
          ZF=0
          JNC    skok gdy nie ma przeniesienia         CF=0
          JNE    skok gdy nie rowny                    ZF=0
          JNG    skok gdy nie wiekszy                  ZF=1 or SF
          != OF

          JNGE   skok gdy nie wiekszy ani rowny *      SF != OF
          JNL    skok gdy nie mniejszy *               SF=OF
          JNLE   skok gdy nie mniejszy ani rowny *     ZF=0 and
          SF=OF
          JNO    skok gdy niema przepelnienia *        OF=0

          JNP    skok gdy nie parzystosc               PF=0
          JNS    skok gdy brak znaku *                 SF=0
          JNZ    skok gdy rozne od zera                ZF=0

          JO     skok gdy jest przepelnienie *         OF=1
          JP     skok gdy parzystosc                   PF=1
          JPE    skok gdy parzystosc parzysta :-)      PF=1
          JPO    skok gdy parzystosc nieparzysta       PF=0
          JS     skok gdy jest znak *                  SF=1

          JZ     skok gdy jest zero                    ZF=1

 * - wazne dla arytmetyki liczb ze znakiem (uzupelnienie do dwoch) 
  

|TEST EAX,EAX - co to znaczy ?|

Powyzsza linia kodu wydaje sie niezrozumiala. Nalezy jednak zastanowic sie co robi dokladnie. Instrukcja TEST wykonuje operacje AND na dwoch argumentach i w oparciu o ten wynik ustawiane sa odpowiednie flagi.

Nalezalo by wiec przeanalizowac czym jest operacja mnozenia logicznego AND. Dziala on na argumentach rozmiaru bajt lub slowo (ale nie na ich zwyklej postaci a postaci binarnej, bo dziala dokladnie na bitach tych liczb).

Z matematyki wiemy ze 0 AND 0 = 0 ; 0 AND 1 =0 i 1 AND 0 = 0 a 1 AND 1 = 1 a wiec operacja daje wynik jeden wtedy i tylko wtedy gdy oba bity rowne sa jeden.

Wezmy teraz TEST EAX, EAX. Zalozmy ze EAX=0 czyli 00000000 AND 00000000 = 00000000 czyli na kazdej pozycji bedzie 0 i wtedy ustawiana jest flaga zerowa Z. Natomiast przy kazdej innej wartosci np. 00000011 AND 00000011 da nam 00000011 i wtedy jezeli gdziekolwiek na dowolnej pozycji wystapia w obu argumentach 1 to flaga Z nie jest ustawiana.

Daje nam to mozliwosc sprawdzenia czy np. EAX jest 0 czy jakas inna wartoscia, gdzy tylko porownanie dwoch TYCH SAMYCH liczb o wartosci 0 da nam 0 i ustawi flage. Operacja AND na kazdych dwoch TAKICH SAMYCH roznych od zera nie ustawi flagi zerowej bo zawsze gdzies bedzie 1 w bitach.

Dlatego tez w programach czesto spotykane instrukcje TEST EAX,EAX a pozniej JZ adres maja calekiem logiczne znaczenie bo skok nastapi tylko w przypadku EAX=0. Nie nalezy wiec sugerowac sie domyslnym znaczeniem instrukcji prownania EAX z EAX :-)

made by GustawKit



All rights reserved for CRACKPL 1998 - 2oo2 . Designed by hauer