Unicorn Engine
Unicorn engine é uma framework que permite a emulação de CPU para executar instruções de diferentes arquiteturas, sendo utilizado em desafios CTFs, engenharia reversa, análise de malware e fuzzing.
Instalação e documentação
Para instalar o Unicorn como uma biblioteca python, basta apenas usar o seguinte comando no terminal
pip install unicornA documentação do Unicorn pode ser encontrada em https://www.unicorn-engine.org/docs/
Exemplos
Exemplo 1
A seguir, um exemplo de um uso simples do Unicorn, apenas para demonstrar principais funcionalidades:
from unicorn import *
from unicorn.x86_const import *
# Cada instrução em assembly é representada em opcodes
# Código em Assembly x86: mov eax, 2; add eax, 3; nop
# Em hexadecimal: B8 02 00 00 00 83 C0 03 90
CODE = b"\xB8\x02\x00\x00\x00\x83\xC0\x03\x90"
# Endereço base onde o código será carregado
ADDRESS = 0x1000
# Inicializa o emulador para x86 (32 bits)
mu = Uc(UC_ARCH_X86, UC_MODE_32)
# Mapeia 4KB de memória a partir do endereço escolhido
mu.mem_map(ADDRESS, 4 * 1024)
# Escreve o código na memória emulada
mu.mem_write(ADDRESS, CODE)
# Define o registrador EAX com 0
mu.reg_write(UC_X86_REG_EAX, 0)
# Inicia a emulação do código (do início até o fim)
mu.emu_start(ADDRESS, ADDRESS + len(CODE))
# Lê o valor final do registrador EAX
eax_value = mu.reg_read(UC_X86_REG_EAX)
print(f"EAX = {eax_value}")Exemplo 2
A seguir, há um exemplo de uma resolução de um desafio de autoria própria. Primeiramente, precisamos analisar o código obtido através do ghidra com o binário disponibilizado:
Basicamente, esse programa utiliza a função nmap para escrever bytes em uma região de memória, utilizando as variáveis local_a8 até local_50, e então chama essa função para cada caractere que o usuário digitou e com local_1c como segundo parâmetro. Após isso, o valor retornado de cada valor é comparado com cada valor do vetor local_188 e, se todos os valores forem iguais, imprime que a flag está correta.
Uma solução que poderíamos utilizar seria reconstruir o código em assembly da região de memória que foi alocado e então fazer a engenharia reversa da função. Porém, podemos utilizar para executar essa função em assembly e então com brute-force obter a flag.
Essa função, pegas os valores definidos na função e transforma em uma sequência de bytes separados por espaço.
Agora, podemos realizar a emulação com o Unicorn.
Referências
Site oficial: https://www.unicorn-engine.org/
Unicorn notes: https://github.com/alexander-hanel/unicorn-engine-notes
Atualizado