quinta-feira, 25 de maio de 2017

Curso de Assembly Aula 04



i-------------©
¦ ASSEMBLY IV ¦
È-------------¥

    Começaremos a ver algumas instruçöes  do  microprocessador  8086
agora.  Existem os seguintes tipos de instruçöes:

    ¦ Instruçöes Aritiméticas
    ¦ Instruçöes Lógicas
    ¦ Instruçöes de Controle de Fluxo de Programa
    ¦ Instruçöes de manipulaçäo de flags
    ¦ Instruçöes de manipulaçäo da pilha
    ¦ Instruçöes de manipulaçäo de blocos
    ¦ Instruçöes de manipulaçäo de registradores/dados
    ¦ Instruçöes de Entrada/Saída

    Vamos   começar   com   as   instruçöes   de   manipulaçäo    de
registradores/dados por serem estas as mais fáceis de entender.

i---------------©
¦ Instruçäo MOV ¦
È---------------¥

    MOV tem a finalidade  de  MOVimentar  um  dado  de um lugar para
outro.  Por exemplo, para carregar um registrador com um determinado
valor.  Isto é feito com MOV:

 +----------------------------------------------------------------+
 ¦  MOV AX,0001h                                                  ¦
 +----------------------------------------------------------------+

    É a mesma coisa que dizer: "AX = 1".  Na verdade, movimentamos o
valor 1 para dentro do registrador AX.

    Podemos mover o conteúdo de um registrador para outro:

 +----------------------------------------------------------------+
 ¦  MOV BH,CL                                                     ¦
 +----------------------------------------------------------------+

    É a mesma coisa que "BH = CL"!

    Os registradores de segmento näo podem ser inicializados com MOV
tomando um parametro imediato (numérico).  Esses  registradores  säo
inicializados indiretamente:

 +----------------------------------------------------------------+
 ¦  MOV DS,0    ; ERRADO!!!                                       ¦
 ¦                                                                ¦
 ¦  MOV AX,0                                                      ¦
 ¦  MOV DS,AX   ; CORRETO!                                        ¦
 +----------------------------------------------------------------+

    Carregar um registrador com o conteúdo (byte ou word, depende da
instruçäo!) armazenado em um segmento é simples, basta especificar o
offset  do  dado  entre  colchetes.  Atençäo que o segmento de dados
(DS) é assumido por default com algumas excessöes:

 +----------------------------------------------------------------+
 ¦  MOV AL,[0FFFFh]                                               ¦
 +----------------------------------------------------------------+

    A instruçäo acima, pega o byte armazenado no endereço DS:FFFFh e
coloca-o em  AL.   Sabemos  que  um  byte  vai  ser  lido  do offset
especificado porque AL tem 8 bits de tamanho.
    Ao  invés  de  usarmos  um  offset  imediato  podemos  usar   um
registrador:

 +----------------------------------------------------------------+
 ¦  MOV BX,0FFFFh                                                 ¦
 ¦  MOV CH,[BX]                                                   ¦
 +----------------------------------------------------------------+

    Neste caso, BX contém o offset e o  byte  no  endereço  DS:BX  é
armazenado  em  CH.   Note  que  o  registrador  usado  como  indice
obrigatoriamente deve ser de 16 bits.

    Uma   observaçäo   quanto   a  essa  modalidade:  Dependendo  do
registrador usado como offset, o segmento default poderá ser  DS  ou
SS.   Se  ao invés de BX usassemos BP, o segmento default seria SS e
näo DS - de uma olhada no diagrama de distribuiçäo dos registradores
no texto anterior.  BP foi colocado  no mesmo bloco de SP, indicando
que ambos estäo relacionados com  SS  (Segmento  de pilha) - Eis uma
tabela das modalidades e dos segmentos default que podem ser  usados
como offset:

 +---------------------------------------------------------------+
 ¦  Offset usando registros    ¦    Segmento default             ¦
 +-----------------------------+---------------------------------¦
 ¦  [SI + deslocamento]        ¦    DS                           ¦
 ¦  [DI + deslocamento]        ¦    DS                           ¦
 ¦  [BP + deslocamento]        ¦    SS                           ¦
 ¦  [BX + deslocamento]        ¦    DS                           ¦
 ¦  [BX + SI + deslocamento]   ¦    DS                           ¦
 ¦  [BX + DI + deslocamento]   ¦    DS                           ¦
 ¦  [BP + SI + deslocamento]   ¦    SS                           ¦
 ¦  [BP + DI + deslocamento]   ¦    SS                           ¦
 +---------------------------------------------------------------+

    O  "deslocamento"  pode  ser  suprimido  se  for 0.

    Você  pode evitar o segmento default explicitando um registrador
de segmento na instruçäo:

 +----------------------------------------------------------------+
 ¦  MOV DH,ES:[BX]      ;Usa ES ao invés de DS                    ¦
 ¦  MOV AL,CS:[SI + 4]  ;Usa CS ao invés de DS                    ¦
 +----------------------------------------------------------------+

    Repare que tenho usado os registradores de 8 bits para armazenar
os dados... Pode-se usar os de 16 bits também:

 +----------------------------------------------------------------+
 ¦  MOV ES:[BX],AX         ; Poe o valor de AX para ES:BX         ¦
 +----------------------------------------------------------------+

    Só que neste caso seräo armazenados 2 bytes no  endereço  ES:BX.
O  primeiro  byte  é  o  menos  significativo  e  o  segundo  o mais
signigicativo.  Essa instruçäo equivale-se a:

 +----------------------------------------------------------------+
 ¦  MOV ES:[BX],AL            ; Instruçöess que fazem a mesma     ¦
 ¦  MOV ES:[BX + 1],AH        ;coisa que MOV ES:[BX],AX           ¦
 +----------------------------------------------------------------+

    Repare também que näo é possível mover o conteúdo de uma posiçäo
da  memória  para  outra,  diretamente,  usando  MOV.   Existe outra
instruçäo que faz isso: MOVSB ou MOVSW.   Veremos  essas  instruçöes
mais tarde.

    Regra geral: Um dos operandos TEM que ser um registrador!  Salvo
no caso da movimentaçäo de um imediato para uma posiçäo de memória:

 +---------------------------------------------------------------+
 ¦  MOV [DI],[SI]       ; ERRO!                                  ¦
 ¦  MOV [BX],0          ; OK!                                    ¦
 +---------------------------------------------------------------+

    Para ilustrar o uso da instruçäo MOV, eis um  pedaço  do  código
usado  pela  ROM-BIOS  do  IBM  PS/2  Modelo  50Z  para  verificar a
integridade dos registradores da CPU:

 +----------------------------------------------------------------+
 ¦  ...                                                           ¦
 ¦  MOV AX,0FFFFh            ;Poe 0FFFFh em AX                    ¦
 ¦  MOV DS,AX                                                     ¦
 ¦  MOV BX,DS                                                     ¦
 ¦  MOV ES,BX                                                     ¦
 ¦  MOV CX,ES                                                     ¦
 ¦  MOV SS,CX                                                     ¦
 ¦  MOV DX,SS                                                     ¦
 ¦  MOV SI,DX                                                     ¦
 ¦  MOV DI,SI                                                     ¦
 ¦  MOV BP,DI                                                     ¦
 ¦  MOV SP,BP                                                     ¦
 ¦  ...                                                           ¦
 +----------------------------------------------------------------+

    Se o conteúdo de BP näo  for  0FFFFh  entäo a CPU está com algum
problema e o computador näo pode funcionar!  Os flags  säo  testados
de uma outra forma...  :)


i------©
¦ XCHG ¦
È------¥

    Esta instruçäo serve para trocarmos o conteúdo de um registrador
pelo outro. Por exemplo:

 +----------------------------------------------------------------+
 ¦  XCHG    AH,AL                                                 ¦
 +----------------------------------------------------------------+

    Se  AH=1Ah  e  AL=6Dh,  após  esta instruçäo AH=6Dh e AL=1Ah por
causa da troca...

    Pode-se  usar uma referência à memória assim como em MOV...  com
a  mesma  restriçäo  de  que  um   dos  operandos  TEM  que  ser  um
registrador.   Näo  há  possibilidade  de usar um operando imediato.


i---------------©
¦ MOVSB e MOUSW ¦
È---------------¥

    Essas  instruçöes  suprem   a   deficiência   de  MOV  quanto  a
movimentaçäo  de  dados  de  uma   posiçäo  de  memória  para  outra
diretamente.  Antes de ser chamada os  seguintes  registradores  tem
que ser inicializados:

 +---------------------------------------------------------------+
 ¦  DS:SI   <- DS e SI têm o endereço fonte                      ¦
 ¦  ES:DI   <- ES e DI têm o endereço destino                    ¦
 +---------------------------------------------------------------+

    Dai podemos executar MOVSB ou MOVSW.

    MOVSB move um byte, enquanto MOVSW move um word (16 bits).

    Os registradores SI e  DI  sao incrementados ou decrementados de
acordo com o flag D (Direction) - Veja discussäo sobre os  flags  na
mensagem  anterior.   No  caso de MOVSW, SI e DI serao incrementados
(ou decrementados) de 2 posiçöes de  forma que DS:SI e ES:DI apontem
sempre para a próxima word.


i---------------©
¦ STOSB e STOSW ¦
È---------------¥

    Essas  instruçöes  servem para armazenar um valor que está em AX
ou AL  (dependendo  da  instruçäo  usada)  no  endereço apontado por
ES:DI.  Entäo, antes de  ser  chamada,  os  seguintes  registradores
devem ser inicializados:

 +----------------------------------------------------------------+
 ¦  AX      -> Valor a ser armazenado se usarmos STOSW            ¦
 ¦  AL      -> Valor a ser armazenado se usarmos STOSB            ¦
 ¦  ES:DI   -> Endereço onde o dado será armazenado               ¦
 +----------------------------------------------------------------+

    Depois   da   execuçäo   da  instruçäo  o  registrador  DI  será
incrementado ou decrementado de acordo com o flag D (Direction).  DI
será incrementado de 2 no  case  de  usarmos STOSW, isto garante que
ES:DI aponte para a proxima word.


i---------------©
¦ LODSB e LODSW ¦
È---------------¥

    Essas  instruçöes  servem para ler um valor que está no endereço
apontado  por  DS:SI  e  armazená-lo  em  AX  ou  AL  (dependendo da
instruçäo  usada).   Entäo,  antes  de  ser  chamada,  os  seguintes
registradores devem ser inicializados:

 +----------------------------------------------------------------+
 ¦  DS:SI   -> Endereço de onde o dado será lido                  ¦
 +----------------------------------------------------------------+

    Depois   da   execuçäo   da  instruçäo  o  registrador  SI  será
incrementado ou decrementado de acordo com o flag D (Direction).  No
caso de usarmos LODSW, SI será incrementado de 2 para  garantir  que
DS:SI aponte para a próxima word.

i------------------------------------------------------------------©
¦ Outras instruçöes de manipulaçäo de registros/dados              ¦
È------------------------------------------------------------------¥

    Existem ainda as instruçöes LEA, LES e LDS.

 ¦ LEA:

    LEA é,  basicamente,  igual  a  instruçäo  MOV,  com  apenas uma
diferença: o  operando  "fonte"  é  um  endereço  (precisamente:  um
"offset").   LEA  simplesmente calcula o endereço e transfere para o
operando  "destino",  de   forma   que   as  instruçöes  abaixo  sao
equivalentes:

 +----------------------------------------------------------------+
 ¦  MOV     BX,100h                                               ¦
 ¦  LEA     BX,[100h]                                             ¦
 +----------------------------------------------------------------+

    Porém, a instruçäo:

 +----------------------------------------------------------------+
 ¦  LEA     DX,[BX + SI + 10h]                                    ¦     ¦
 +----------------------------------------------------------------+

    Equivale a:

 +----------------------------------------------------------------+
 ¦  MOV     DX,BX                                                 ¦
 ¦  ADD     DX,SI         ; DX = DX + SI                          ¦
 ¦  ADD     DX,10h        ; DX = DX + 10h                         ¦
 +----------------------------------------------------------------+

    Repare que apenas uma  instruçäo  faz  o  serviço de três!!  Nos
processadores 286 e  386  a  diferença  é  significativa,  pois,  no
exemplo acima, LEA gastará  3  (nos  286)  ou  2 (nos 386) ciclos de
máquina enquando o equivalente gastará 11 (nos 286) ou 6  (nos  386)
ciclos  de  máquina!   Nos processadores 8088/8086 a diferença näo é
tao grande...

    Obs:
        Consideremos cada ciclo  de  máquina seria, aproximadamente,
        num 386DX/40, algo em torno de 300ns - ou 0,0000003s.  É uma
        medida empirica e näo expressa a grandeza real  (depende  de
        uma série de fatores näo considerados aqui!).

    O  operando  "destino"  é  sempre  um  registrador.   O operando
"fonte" é sempre um endereço.

 ¦ LDS e LES

    Existe  uma  forma  de  carregar   um   par   de   registradores
(segmento:offset)  de uma só vez.  Se quisermos carregar DS:DX basta
usar a instruçäo LDS, caso o alvo seja ES, usa-se LES.

    Suponhamos que numa posiçäo  da  memória tenhamos um double word
(número  de  32  bits)  armazenado.   A  word   mais   significativa
correspondendo  a  um  segmento  e a menos signigicativa a um offset
(esse é o caso da tabela dos vetores de interrupçäo, que descreverei
com poucos detalhes em uma outra oportunidade!). Se usamos:

 +----------------------------------------------------------------+
 ¦  LES BX,[SI]                                                   ¦
 +----------------------------------------------------------------+

    O par ES:BX  será  carregado  com  o  double  word armazenado no
endereço  apontado  por  DS:SI  (repare  no  segmento  default   que
discutimos  em um texto anterior!).  A instruçäo acima é equivalente
a:

 +---------------------------------------------------------------+
 ¦  MOV     BX,[SI+2]                                            ¦
 ¦  MOV     ES,BX                                                ¦
 ¦  MOV     BX,[SI]                                              ¦
 +---------------------------------------------------------------+

    De novo, uma instruçäo substitui três!

i-----------------------------------------------------------------©
¦ Manipulando blocos... parte I                                   ¦
È-----------------------------------------------------------------¥

    As instruçöes MOVSB, MOVSW, STOSB, STOSW, LODSB  e  LODSW  podem
ser usadas para lidar com blocos de dados.  Para isto, basta indicar
no  registrador  CX  a  quantidade  de  dados  a serem manipulados e
acrescentar  REP  na  frente  da  instruçao.   Eis  um trecho de uma
pequena rotina que apaga o video em modo texto (80 x 25 colorido):

 +---------------------------------------------------------------+
 ¦  MOV AX,0B800h                                                ¦
 ¦  MOD ES,AX           ; Poe em ES o segmento do vídeo          ¦
 ¦  MOV DI,0            ; Começa no Offset 0                     ¦
 ¦  MOV AH,7            ; AH = atributo do caracter              ¦
 ¦                      ;      7 = cinza com fundo preto         ¦
 ¦  MOV AL,' '          ; AL = caracter usado para apagar        ¦
 ¦  MOV CX,2000         ; CX = contador (4000 bytes ou           ¦
 ¦                      ;      2000 words).                      ¦
 ¦  REP STOSW           ; Preenche os 2000 words com AX          ¦
 +---------------------------------------------------------------+

    O modificador REP diz a instruçäo que esta deve ser executada CX
vezes.  Note que a cada execuçäo de STOSW o registrador DI  apontará
para a proxima word.

    Suponha que queiramos  mover  4000  bytes  de  alguma posiçäo da
memória para o video, preenchendo a tela com esses 4000 bytes:

 +---------------------------------------------------------------+
 ¦  MOV AX,0B800h                                                ¦
 ¦  MOD ES,AX           ; Poe em ES o segmento do vídeo          ¦
 ¦  MOV AX,SEG TABELA                                            ¦
 ¦  MOV DS,AX           ; Poe em DS o segmento da tabela         ¦
 ¦  MOV SI,OFFSET TABELA ; Começa no offset inicial da tabela    ¦
 ¦  MOV DI,0            ; Começa no Offset 0                     ¦
 ¦  MOV CX,4000         ; CX = contador (4000 bytes)             ¦
 ¦  REP MOVSB           ; Copia 4000 bytes de DS:SI para ES:DI   ¦
 +---------------------------------------------------------------+

    Nota:  O  modificador  REP  só  pode  ser  preceder as seguintes
instruçöes: MOVSB, MOVSW, STOSB,  STOSW, LODSB, LODSW, CMPSB, CMPSW,
SCASB, SCASW, OUTSB, OUTSW, INSB, INSW.  As instruçöes nao vistas no
texto acima seräo detalhadas mais tarde...

    Existem   mais    algumas    instruçöes    de   manipulaçäo   de
registradores/dados, bem como mais algumas de manipulaçäo de blocos.
Que ficaräo para uma próxima mensagem.

Nenhum comentário:

Postar um comentário

Curso SANS 504 Hacker Techniques, Exploits & Incident Handling

SANS SECURITY 504 - Hacker Techniques, Exploits & Incident Handling     SANS Security 504.5.pdf13 MB     SANS Security 504.1.pdf12 M...