Análise Estática Avançada: Níveis de Abstração

Consiste em levar o binário para um disassembler (IDA Pro ou Ghidra) para analisar o código Assembly.

  • Binário: Código em formato que o computador executa.
  • Assembly: Linguagem de baixo nível (x86, x64, ARM, etc).
  • Nível de Abstração:
    • Linguagem de Alto Nível (C/C++) Compilador Código de Máquina (CPU).
    • Código de Máquina (Binário) Disassembler Linguagem de Baixo Nível (Assembly).

Arquitetura x86 (Von Neumann)

A maioria dos computadores modernos segue esta arquitetura:

  1. CPU: Executa o código.
  2. RAM (Main Memory): Armazena dados e códigos.
  3. I/O System: Liga dispositivos (teclado, monitor, HD).

Layout da Memória RAM para um Programa:

  • Stack (Pilha): Variáveis locais, parâmetros de funções e controle de fluxo.
  • Heap: Memória dinâmica alocada durante a execução (malloc, free).
  • Code: Instruções executadas pela CPU.
  • Data: Variáveis globais e valores inicializados.

Assembly x86: Instruções e Opcodes

Formato da Instrução:

Mnemonic | Destination Operand | Source Operand mov | ecx | 0x42

  • Opcode: Valor numérico que diz à CPU qual operação realizar (ex: B9 para mov em certos contextos).
  • Operands (Operandos):
    • Immediate: Valores fixos (ex: 0x42).
    • Register: Registradores (ex: ecx).
    • Memory address: Endereço de memória, denotado por colchetes (ex: [eax]).

Registradores (Registers)

Espaços de dados na CPU de acesso ultra rápido.

  1. General Registers: EAX, EBX, ECX, EDX, EBP, ESP, ESI, EDI.
    • Exemplo EAX: Pode ser dividido em AX (16 bits), AH (8 bits high) e AL (8 bits low).
  2. Status Register (EFLAGS): Cada bit é uma flag (0 ou 1) indicando resultados de operações.
    • ZF (Zero Flag): Definida se o resultado for zero.
    • CF (Carry Flag): Definida se o resultado for muito grande/pequeno para o operando.
    • SF (Sign Flag): Definida se o resultado for negativo.
    • TF (Trap Flag): Usada para debugging (executa uma instrução por vez).
  3. Instruction Pointer (EIP): Mantém o endereço da próxima instrução a ser executada.

Instruções Comuns

Movimentação e Aritmética

  • mov eax, ebx: Copia EBX para EAX.
  • add eax, ebx: EAX = EAX + EBX.
  • sub eax, 0x10: EAX = EAX - 0x10.
  • inc edx: Incrementa EDX em 1.
  • dec ecx: Decrementa ECX em 1.
  • mul 0x50: Multiplica EAX por 0x50 (resultado em EDX:EAX).
  • div 0x75: Divide EDX:EAX por 0x75.

Lógica

  • xor eax, eax: Limpa o registrador EAX (zera o valor).
  • or eax, 0x7575: Operação lógica OR.
  • shl / shr: Deslocamento de bits (Shift Left / Shift Right).

Stack (Pilha - LIFO)

  • push: Coloca valor no topo da pilha.
  • pop: Retira o valor do topo.
  • ESP (Stack Pointer): Aponta para o topo da pilha.
  • EBP (Base Pointer): Referência fixa para acessar parâmetros e variáveis locais.

Condicionais e Branching (Desvios)

Comparações:

  • test eax, eax: Faz um and lógico. Se EAX for 0, define ZF=1. Comumente usado para checar valores NULL.
  • cmp dst, src: Faz um sub (subtração), mas não altera os operandos, apenas as flags.
    • Se dst = src, ZF=1.
    • Se dst < src, CF=1.

Saltos (Jumps):

  • jmp: Salto incondicional.
  • jz / je: Pula se ZF=1 (resultado zero ou igual).
  • jnz / jne: Pula se ZF=0 (não zero ou diferente).
  • jg: Pula se maior (signed).
  • jl: Pula se menor (signed).
  • ja / jb: Pula se maior/menor (unsigned).