
Python bindings para o VEX IR do Valgrind.
PyVEX são bindings Python para a IR VEX.
Repositório do projeto: https://github.com/angr/pyvex
Documentação: https://api.angr.io/projects/pyvex/en/latest/
O PyVEX pode ser instalado via pip:
pip install pyvex
import pyvex
import archinfo
# translate an AMD64 basic block (of nops) at 0x400400 into VEX
irsb = pyvex.lift(b"\x90\x90\x90\x90\x90", 0x400400, archinfo.ArchAMD64())
# pretty-print the basic block
irsb.pp()
# this is the IR Expression of the jump target of the unconditional exit at the end of the basic block
print(irsb.next)
# this is the type of the unconditional exit (i.e., a call, ret, syscall, etc)
print(irsb.jumpkind)
# you can also pretty-print it
irsb.next.pp()
# iterate through each statement and print all the statements
for stmt in irsb.statements:
stmt.pp()
# pretty-print the IR expression representing the data, and the *type* of that IR expression written by every store statement
import pyvex
for stmt in irsb.statements:
if isinstance(stmt, pyvex.IRStmt.Store):
print("Data:", end="")
stmt.data.pp()
print("")
print("Type:", end="")
print(stmt.data.result_type)
print("")
# pretty-print the condition and jump target of every conditional exit from the basic block
for stmt in irsb.statements:
if isinstance(stmt, pyvex.IRStmt.Exit):
print("Condition:", end="")
stmt.guard.pp()
print("")
print("Target:", end="")
stmt.dst.pp()
print("")
# these are the types of every temp in the IRSB
print(irsb.tyenv.types)
# here is one way to get the type of temp 0
print(irsb.tyenv.types[0])
Tenha em mente que esta é uma representação sintática de um bloco básico. Ou seja, ela informará o que o bloco significa, mas você não tem contexto para dizer, por exemplo, quais dados reais são escritos por uma instrução de store.
Para lidar com arquiteturas amplamente diversas, é útil realizar análises sobre uma representação intermediária. Uma IR abstrai várias diferenças de arquitetura ao lidar com arquiteturas diferentes, permitindo que uma única análise seja executada em todas elas:
rax do AMD64 é armazenado começando no endereço 16 nesse espaço de memória).Há muitas escolhas para uma IR. Usamos o VEX, pois a elevação de código binário para VEX é bastante bem suportada. O VEX é uma representação agnóstica de arquitetura e livre de efeitos colaterais de várias linguagens de máquina alvo. Ele abstrai o código de máquina em uma representação projetada para facilitar a análise de programas. Essa representação tem cinco classes principais de objetos:
t0. Essas temporárias são fortemente tipadas (ou seja, "inteiro de 64 bits" ou "float de 32 bits").A IR VEX é, na verdade, bastante bem documentada no arquivo libvex_ir.h (https://github.com/angr/vex/blob/dev/pub/libvex_ir.h) no repositório VEX. Para os preguiçosos, detalharemos algumas partes do VEX com as quais você provavelmente interagirá com bastante frequência. Para começar, aqui estão algumas Expressões IR:
| Expressão IR | Valor Avaliado | Exemplo de Saída VEX |
|---|---|---|
| Constant | Um valor constante. | 0x4:I32 |
| Read Temp | O valor armazenado em uma variável temporária VEX. | RdTmp(t10) |
| Get Register | O valor armazenado em um registrador. | GET:I32(16) |
| Load Memory | O valor armazenado em um endereço de memória, com o endereço especificado por outra Expressão IR. | LDle:I32 / LDbe:I64 |
| Operation | Um resultado de uma Operação IR especificada, aplicada a argumentos de Expressão IR especificados. | Add32 |
| If-Then-Else | Se uma dada Expressão IR for avaliada como 0, retorna uma Expressão IR. Caso contrário, retorna outra. | ITE |
| Helper Function | O VEX usa funções auxiliares em C para certas operações, como calcular os registradores de flags de condição de certas arquiteturas. Essas funções retornam Expressões IR. | function_name() |
Essas expressões são então, por sua vez, usadas em Statements IR. Aqui estão alguns comuns: