quinta-feira, 25 de maio de 2017

Curso de Assembly Aula 03



i--------------©
¦ ASSEMBLY III ¦
È--------------¥

    Comecemos   a   dar    uma    olhadela    na   arquitetura   dos
microprocessadores   da   família    INTEL   80x86...    Vamos   aos
registradores!

    Entenda  os  registradores  como  se  fossem  variáveis  que   o
microprocessador  disponibiliza  ao sistema.  TODOS os registradores
têm 16 bits de tamanho e aqui vai a descriçäo deles:

     +------+
     ¦  AX  ¦<--+
     +------¦   ¦
     ¦  BX  ¦<--¦
     +------¦   +- Registradores de uso geral
     ¦  CX  ¦<--¦
     +------¦   ¦
     ¦  DX  ¦<--+
     +------+
     +------+
     ¦  SI  ¦<---- índice FONTE (Source Index)
     +------¦
     ¦  DI  ¦<---- índice DESTINO (Destination Index)
     +------+
     +------+
     ¦  SP  ¦<---- Apontador de pilha (Stack Pointer)
     +------¦
     ¦  BP  ¦<---- Apontador de base (Base Pointer)
     +------+
     +------+
     ¦  CS  ¦<---- Segmento de Cógido (Code Segment)
     +------¦
     ¦  DS  ¦<---- Segmento de Dados (Data Segment)
     +------¦
     ¦  ES  ¦<---- Segmento de dados Extra (Extra data Segment)
     +------¦
     ¦  SS  ¦<---- Segmento de Pilha (Stack Segment)
     +------+
     +------+
     ¦  IP  ¦<---- Apontador de instruçäo (Instruction Pointer)
     +------+
     +------+
     ¦Flags ¦<---- Sinalizadores
     +------+

    Por  enquanto vamos nos deter na descriçäo dos registradores uso
geral...  Eles podem ser  subdivididos  em dois registradore de oito
bits cada:

        AX (16 bits)            BX (16 bits)
    +-----------------+     +-----------------+
    +-----------------+     +-----------------+
    ¦   AH   ¦   AL   ¦     ¦   BH   ¦   BL   ¦
    +-----------------+     +-----------------+
    15      8 7      0      15      8 7      0

        CX (16 bits)            DX (16 bits)
    +-----------------+     +-----------------+
    +-----------------+     +-----------------+
    ¦   CH   ¦   CL   ¦     ¦   DH   ¦   DL   ¦
    +-----------------+     +-----------------+
    15      8 7      0      15      8 7      0

    AH é o byte mais significativo do registrador AX,  enquanto  que
AL  é  o  menos  significativo.   Se  alterarmos  o  conteúdo de AL,
estaremos alterando  o  byte  menos  significativo  de  AX  ao mesmo
tempo...  Näo existem registradores  de  oito  bits  em  separado...
tudo  é  uma  coisa  só.   Portanto,  ao  manipularmos AH, estaremos
manipulando AX ao mesmo tempo!

    O nome de cada registrador tem  o  seu sentido de ser...  "A" de
AX quer dizer  que  este  registrador  é  um "acumulador" (usado por
default em algumas operaçöes matematicas!), por exemplo...

    AX  -> Acumulador
    BX  -> Base
    CX  -> Contador
    DX  -> Dados

    O  "X"  de  AX  significa "eXtended".  "H" de AH significa "High
byte".

    Embora estes registradores possam ser usados sem  restriçöes,  é
interessante  atribuir  uma  funçäo  para  cada  um deles nos nossos
programas sempre que possível...  Isto  facilita a leitura do código
e nos educa a seguirmos uma  linha  de  raciocínio  mais  concisa...
Mas,  se  for  de  sua preferência näo seguir qualquer padräo no uso
desses  registradores,  näo  se  preocupe...   näo  haverá  qualquer
desvantagem nisso  (Well...   depende  do  código,  as  vezes  somos
obrigados a usar determinado registrador!).

    Alguns pontos importantes quanto  a esses nomes seräo observados
no decorrer do curso...  Por exemplo, certas instruçöes usam AX  (ou
AL, ou AH) e  somente  ele,  näo  permitindo  o  uso de nenhum outro
registrador...   Outras,  usam  CX  para   contar,   etc...    essas
instruçöes específicas seräo vistas em outra oportunidade.

    Os registradores SI e DI  säo  usados como índices para tabelas.
Em particular, SI é usado para leitura  de  uma  tabela  e  DI  para
escrita  (fonte  e  destino...   lembra algum procedimento de cópia,
nao?).  No entanto, esses registradores  podem ser usados com outras
finalidades...  Podemos incluí-los no grupo de "registradores de uso
geral",  mas  assim como alguns registradores de uso geral, eles têm
aplicaçäo exclusiva  em  algumas  instruçöes,  SI  e  DI  säo usados
especificamente  como  índices  em  instruçöes  que manipulam blocos
(também veremos isso mais tarde!).

    Os registradores CS, DS,  ES  e  SS  armazenam os segmentos onde
estäo o código  (programa  sendo  executado),  os  dados,  os  dados
extras,  e  a  pilha,  respectivamente.   Lembre-se  que a memória é
segmentada em blocos de 64kbytes (dê uma olhada na primeira mensagem
dessa série).

    Quando nos referimos, através de alguma instruçäo, a um endereço
de memória, estaremos nos referindo ao OFFSET dentro de um segmento.
O registrador de  segmento  usado  para  localizar  o dado no offset
especificado vai depender da própria  instruçäo...   Um  exemplo  em
assembly:

 +----------------------------------------------------------------+
 ¦      MOV     AL,[1D4Ah]                                        ¦
 +----------------------------------------------------------------+

    O  número  hexadecimal  entre  os  colchetes é a indicaçäo de um
offset em um segmento...  Por  default, a maioria das instruçöes usa
o segmento de dados (valor em  DS).  A instruçäo acima é equivalente
a:

 +----------------------------------------------------------------+
 ¦      AL = DS:[1D4Ah]                                           ¦
 +----------------------------------------------------------------+

    Isto é, em AL será colocado o byte que está armazenado no offset
1D4Ah  do  segmento  de  dados (valor em DS).  Veremos mais sobre os
segmentos e as instruçöes mais tarde :)

    Se quisessemos localizar o byte  desejado em outro segmento (mas
no mesmo offset) devemos especificar o registrador  de  segmento  na
instruçäo:

 +----------------------------------------------------------------+
 ¦      MOV     AL,ES:[1D4Ah]                                     ¦
 +----------------------------------------------------------------+

    Aqui o valor de ES será usado.

    O registrador IP (Instruction Pointer) é o offset do segmento de
código  que  contém  a  próxima  instruçäo  a  ser  execuatda.  Este
registrador näo é acessível por qualquer instruçäo (pelo  menos  näo
pelas   documentadas   pela   Intel)...    é   de   uso  interno  do
microprocessador.    No   entanto   existem   alguns   macetes  para
conseguirmos obter o seu conteúdo (o que na maioria  das  aplicaçöes
näo  é  necessario...   Para  que  conhecer  o  endereço  da próxima
instruçäo se ela var ser executada de qualquer jeito?).

    O registrador SP é o offset do segmento SS (segmento  de  pilha)
onde o próximo dado vai ser empilhado.  A pilha serve para armazenar
dados  que posteriormente podem ser recuperados sem que tenhamos que
usar um  dos  registradores  para  esse  fim.   Também  é usada para
armazenar o endereço de retorno das sub-rotinas.  A  pilha  "cresce"
de  cima  para baixo, isto é, SP é decrementado cada vez que um novo
dado é colocado na pilha.  Note  também que existe um registrador de
segmento exclusivo para a pilha... SP sempre está relacionado a  esse
segmento (SS), como foi dito antes.

    Para  ilustrar  o  funcionamento  da  pilha,  no  gráfico abaixo
simularemos o empilhamento do conteúdo do registrador AX através  da
instruçäo:

 +-----------------------------------------------------------------+
 ¦      PUSH    AX                                                 ¦
 +-----------------------------------------------------------------+

 +-----------------------------------------------------------------+
 ¦  AX = A527h (Valor em AX)                                       ¦
 ¦                                                                 ¦
 ¦   +-------+                       +-------+                     ¦
 ¦   ¦ ????h ¦<----- SP = n          ¦ A527h ¦                     ¦
 ¦   +-------¦                       +-------¦                     ¦
 ¦   ¦       ¦                       ¦       ¦<----- SP = n - 1    ¦
 ¦   +-------+                       +-------+                     ¦
 ¦                                                                 ¦
 ¦ (antes de PUSH AX)              (depois de PUSH AX)             ¦
 +-----------------------------------------------------------------+

    Observe que SP sempre aponta para um espaço vago na pilha.

    Na  realidade  SP  é  decrementado  de duas posiçöes ao invés de
apenas uma... mas, esse detalhe deixo para mais tarde.

    O registrador BP pode ser usado como apontador para  a  base  da
pilha (já que,  por  default,  está  relacionado  a  SS)  ou como um
registrador de uso geral...  depende do seu programa.  Veremos  isso
detalhadamente mais tarde.

    Um   dos    registradores    mais    importantes   de   qualquer
microprocessador é o de "Flags".  Eis uma descriçäo dos  bits  deste
registrador  (a descriçäo abaixo aplica-se ao 8086.  Normalmente näo
acessamos diretamente  o  registrador  de  flags  -  embora possamos
fazê-lo - por isso näo é conveniente assumirmos que  os  bits  estäo
sempre  no  mesmo  lugar  para  qualquer microprocessador da família
80x86!):

 +----------------------------------------------------------------+
 ¦            +-------------------------------+                   ¦
 ¦            ¦ ¦ ¦ ¦ ¦O¦D¦I¦T¦S¦Z¦ ¦A¦ ¦P¦ ¦C¦                   ¦
 ¦            +-------------------------------+                   ¦
 ¦            15                             0                    ¦
 ¦                                                                ¦
 ¦  C = Carry                                                     ¦
 ¦  P = Parity                                                    ¦
 ¦  A = Auxiliar Carry                                            ¦
 ¦  Z = Zero                                                      ¦
 ¦  S = Signal                                                    ¦
 ¦  T = Trap                                                      ¦
 ¦  I = Interrupt Enable Flag                                     ¦
 ¦  D = Direction                                                 ¦
 ¦  O = OverFlow                                                  ¦
 +----------------------------------------------------------------+

    ¦ Carry:

        Esse  flag  é setado sempre quando houver "vai um" depois de
    uma  adiçäo  ou  quando  há  BORROW depois de uma subtraçäo.  Ou
    quando, numa operaçäo de  deslocamento  de  bits,  o bit mais ao
    extremo for deslocado para fora do dado (suponha um byte...   se
    todos  os bits forem deslocados em uma posiçäo para a direita, o
    que acontece com o bit 0?...  Resposta: Vai para o carry!)

    ¦ Parity:

        Depois  de  uma  instruçäo  aritimética  ou  lógica este bit
    informa se o resultado tem um número par de "1"s ou näo.

    ¦ Auxiliar Carry:

        Igual ao carry, mas indica o "vai um" no meio de um dado (no
    caso de um byte, se houve "vai um" do bit 3 para o bit 4!).

    ¦ Zero:

        Depois de  uma  operaçäo  aritimética  ou  lógica, esse flag
    indica se o resultado é zero ou näo.

    ¦ Signal:

        Depois de uma instruçäo aritimética ou lógica, este  flag  é
    uma  cópia  do  bit de mais alta ordem do resultado, isto é, seu
    sinal (dê uma olhada  na  "representaçäo de números negativos em
    binário" no texto anterior!).

    ¦ Trap:

        Quando setado (1)  executa  instruçöes passo-a-passo...  Näo
    nos interessa estudar esse  bit  por  causa  das  diferenças  de
    implementaçäo deste flag em toda a família 80x86.

    ¦ Interrupt Enable Flag

        Habilita/Desabilita   o   reconhecimento   de   interrupçöes
    mascaráveis pela CPU. Sobre interrupçöes, veremos mais tarde!

    ¦ Direction:

        Quando   usamos   instruçöes   de   manipulaçäo  de  blocos,
    precisamos especificar a direçäo que  usaremos (do inicio para o
    fim ou do fim para o inicio).
        Quando D=0 a direçäo é a do início para o fim...  D=1, entäo
    a direçäo é contrária!

    ¦ OverFlow:

        Depois de uma instruçäo  aritimética  ou  lógica,  este  bit
    indica se houve mudança no bit mais significativo, ou  seja,  no
    sinal.  Por exemplo, se somarmos FFFFh + 0001h obteremos 00h.  O
    bit  mais  significativo variou de 1 para 0 (o counteúdo inicial
    de um registrador era FFFFh  e  depois  da soma foi para 0000h),
    indicando que o resultado saiu da faixa (overflow) - ora,  FFFFh
    +  0001h = 10000h, porém um registrador tem 16 bits de tamanho e
    o resultado cabe em  17  bits.   Neste  exemplo,  o bit de carry
    também será setado  pois  houve  "vai  um"  do  bit  15  para  o
    inexistente  bit  16,  mas näo confunda o flag de overflow com o
    carry!

    Quando aos demais bits, näo  se pode prever seus estados lógicos
(1 ou 0).

    Na próxima  mensagem  começaremos  a  ver  algumas instruçöes do
microprocessador 8086.  Ainda näo escreveremos  nenhum  programa,  a
intençäo  é  familiarizá-lo  com  a  arquitetura do microprocessador
antes de começarmos a colocar a  mäo  na massa...  tenha um pouco de
paciência! :)

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...