O Nyxstone é uma poderosa biblioteca de montagem e desmontagem baseada no LLVM. Ele não requer patches para a árvore de origem LLVM e links contra bibliotecas LLVM padrão disponíveis na maioria das distribuições Linux. Implementado como uma biblioteca C ++, a Nyxstone também oferece ligações de ferrugem e python. Ele suporta todas as arquiteturas oficiais do LLVM e permite definir configurações de destino específicas da arquitetura.
Reunir e desmontar o código para todas as arquiteturas suportadas pelo LLVM vinculado, incluindo x86, ARM, MIPS, RISC-V e outros.
Biblioteca C ++ baseada em LLVM com ligações de ferrugem e Python.
Suporte de plataforma nativa para Linux e MacOS.
Suporta rótulos no assembler, incluindo a especificação de mapeamentos de etiqueta para endereço
Remons e desmontaram bytes e texto crus, mas também fornece objetos detalhados de instruções que contêm o endereço, bytes crus e a representação da montagem.
A desmontagem pode ser limitada a um número especificado pelo usuário de instruções de sequências de bytes.
Permite configurar recursos de destino específicos da arquitetura, como extensões ISA e recursos de hardware.
Para uma lista abrangente de arquiteturas suportadas, você pode usar clang -print-targets . Para obter uma lista abrangente de recursos para cada arquitetura, consulte llc -march=ARCH -mattr=help .
Observação
Isenção de responsabilidade: Nyxstone foi desenvolvido e testado principalmente para arquiteturas x86_64, AARCH64 e ARM32. Temos um alto grau de confiança em sua capacidade de gerar com precisão a montagem e identificar erros para essas plataformas. Para outras arquiteturas, a eficácia da Nyxstone depende da confiabilidade e desempenho de seus respectivos back -ends LLVM.
Esta seção fornece instruções sobre como começar a Nyxstone, cobrindo os pré-requisitos necessários, como usar a ferramenta da CLI e diretrizes passo a passo para usar a biblioteca com C ++, Rust, e Python.
Antes de construir o Nyxstone, verifique se o CLANG e o LLVM estão presentes no seu sistema. A Nyxstone suporta versões principais LLVM 15-18. Ao construir, procura llvm-config no $PATH do sistema ou na variável de ambiente especificada $NYXSTONE_LLVM_PREFIX/bin .
Opções de instalação para as versões LLVM 15-18:
sudo apt install llvm- ${version} llvm- ${version} -devDebian LLVM As versão 15 e 16 estão disponíveis nos repositórios do Debian. A instalação é a mesma que para o Ubuntu. Para as versões 17 ou 18, consulte https://apt.llvm.org/ para obter instruções de instalação.
Arco
sudo pacman -S llvm llvm-libsbrew install llvm@18
export NYXSTONE_LLVM_PREFIX=/opt/homebrew/opt/llvm@18 Nota : No Windows, você precisa executar esses comandos de um prompt de comando do Visual Studio 2022 x64. Além disso, substitua ~lib/my-llvm-18 por um caminho diferente.
# checkout llvm
git clone -b release/18.x --single-branch https://github.com/llvm/llvm-project.git
cd llvm-project
# build LLVM with custom installation directory
cmake -S llvm -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_PARALLEL_LINK_JOBS=1
cmake --build build
cmake --install build --prefix ~ /lib/my-llvm-18
# export path
export NYXSTONE_LLVM_PREFIX= ~ /lib/my-llvm-18 Certifique -se também de instalar as bibliotecas dependentes do sistema necessárias para sua versão LLVM para vincular estática. Eles podem ser vistos com o comando llvm-config --system-libs ; A lista pode estar vazia. No Ubuntu/Debian, você precisará dos pacotes zlib1g-dev e zlibstd-dev .
O Nyxstone vem com uma ferramenta cli útil para tarefas rápidas de montagem e desmontagem. Confira o repositório Nyxstone e construa a ferramenta com cmake:
# clone directory
git clone https://github.com/emproof-com/nyxstone
cd nyxstone
# build nyxstone
mkdir build && cd build && cmake .. && make Em seguida, nyxstone pode ser usado na linha de comando. Aqui está uma saída de seu menu de ajuda:
$ ./nyxstone -h
Usage: nyxstone [-t=<triple>] [-p=<pc>] [-d] <input>
Examples:
# Assemble an instruction with the default architecture ('x86_64').
nyxstone 'push eax'
# Disassemble the bytes 'ffc300d1' as AArch64 code.
nyxstone -t aarch64 -d ffc300d1
Options:
-t, --triple=<triple> LLVM target triple or alias, e.g. 'aarch64'
-c, --cpu=<cpu> LLVM CPU specifier, e.g. 'cortex-a53'
-f, --features=<list> LLVM architecture/CPU feature list, e.g. '+mte,-neon'
-p, --address=<pc> Initial address to assemble/disassemble relative to
-l, --labels=<list> Label-to-address mappings (used when assembling only)
-d, --disassemble Treat <input> as bytes to disassemble instead of assembly
-h, --help Show this help and usage message
Notes:
The '--triple' parameter also supports aliases for common target triples:
'x86_32' -> 'i686-linux-gnu'
'x86_64' -> 'x86_64-linux-gnu'
'armv6m' -> 'armv6m-none-eabi'
'armv7m' -> 'armv7m-none-eabi'
'armv8m' -> 'armv8m.main-none-eabi'
'aarch64' -> 'aarch64-linux-gnueabihf'
The CPUs for a target can be found with 'llc -mtriple=<triple> -mcpu=help'.
The features for a target can be found with 'llc -mtriple=<triple> -mattr=help'.
Agora, podemos montar uma instrução para a arquitetura x86_64:
$ ./nyxstone -t x86_64 "mov rax, rbx"
0x00000000: mov rax, rbx ; 48 89 d8
Também podemos montar uma sequência de instruções. A seguir, utilizamos o endereçamento baseado em etiquetas e assumimos que a primeira instrução é mapeada para abordar 0xdeadbeef :
$ ./nyxstone -t x86_64 -p 0xdeadbeef "cmp rax, rbx; jz .exit; inc rax; .exit: ret"
0xdeadbeef: cmp rax, rbx ; 48 39 d8
0xdeadbef2: je .exit ; 74 03
0xdeadbef4: inc rax ; 48 ff c0
0xdeadbef7: ret ; c3
Além disso, podemos desmontar as instruções para diferentes conjuntos de instruções, aqui o conjunto de instruções do ORM32:
$ ./nyxstone -t thumbv8 -d "13 37"
0x00000000: adds r7, #19 ; 13 37
Usando o suporte para rótulos definidos pelo usuário, podemos montar este snippet que não contém o rótulo .label Label especificando sua localização de memória nós mesmos.
$ ./nyxstone -p "0x1000" -l ".label=0x1238" "jmp .label"
0x00001000: jmp .label ; e9 33 02 00 00
Para usar o Nyxstone como uma biblioteca C ++, seu código C ++ deve ser vinculado a Nyxstone e LLVM.
O exemplo cmake a seguir assume Nyxstone em um nyxstone de subdiretório em seu projeto:
add_subdirectory (nyxstone)
add_executable (my_executable main.cpp)
target_link_libraries (my_executable nyxstone::nyxstone)O exemplo de uso de C ++ correspondente:
# include < cassert >
# include < iostream >
# include " nyxstone.h "
int main ( int , char **) {
// Create the nyxstone instance:
auto nyxstone {
NyxstoneBuilder ( " x86_64 " )
. build ()
. value ()
};
// Assemble to bytes
std::vector< uint8_t > bytes =
nyxstone-> assemble ( /* assembly= */ " mov rax, rbx " , /* address= */ 0x1000 , /* labels= */ {}). value ();
std::vector< uint8_t > expected { 0x48 , 0x89 , 0xd8 };
assert (bytes == expected);
return 0 ;
}Para um exemplo abrangente de C ++, dê uma olhada no exemplo.cpp.
Para usar o Nyxstone como uma biblioteca de ferrugem, adicione -a à sua Cargo.toml e use -a como mostrado no exemplo a seguir:
use anyhow :: Result ;
use nyxstone :: { Nyxstone , NyxstoneConfig } ;
use std :: collections :: HashMap ;
fn main ( ) -> Result < ( ) > {
let nyxstone = Nyxstone :: new ( "x86_64" , NyxstoneConfig :: default ( ) ) ? ;
let bytes = nyxstone . assemble_with (
"mov rax, rbx; cmp rax, rdx; jne .label" ,
0x1000 ,
& HashMap :: from ( [ ( ".label" , 0x1200 ) ] ) ,
) ? ;
println ! ( "Bytes: {:x?}" , bytes ) ;
Ok ( ( ) )
}Para obter mais instruções sobre a ligação da ferrugem, dê uma olhada no ReadMe correspondente.
Para usar o Nyxstone da Python, instale -o usando PIP:
pip install nyxstoneEntão, você pode usá -lo do Python:
$ python -q
>>> from nyxstone import Nyxstone
>>> nyxstone = Nyxstone("x86_64")
>>> nyxstone.assemble("jne .loop", 0x1100, {".loop": 0x1000})
Instruções detalhadas estão disponíveis no ReadMe correspondente.
O NYXstone aproveita as funções públicas de API C ++ da LLVM, como Target::createMCAsmParser e Target::createMCDisassembler para executar tarefas de montagem e desmontagem. O Nyxstone também estende duas classes LLVM, MCELFStreamer e MCObjectWriter , para injetar lógica personalizada e extrair informações adicionais. Especificamente, o Nyxstone aumenta o processo de montagem com as seguintes etapas:
ELFStreamerWrapper::emitInstruction : captura a representação da montagem e bytes iniciais de instruções, se os objetos de instrução detalhados forem solicitados pelo usuário.
ObjectWriterWrapper::writeObject : grava os bytes brutos finais das instruções (com ajustes de realocação) em objetos de instrução detalhados. Além disso, ele alterna a saída de bytes cru do arquivo ELF completo para apenas a seção .Text.
ObjectWriterWrapper::validate_fixups : realiza verificações extras, como verificar o intervalo e o alinhamento das realocações.
ObjectWriterWrapper::recordRelocation : aplica realocações adicionais. MCObjectWriter pula algumas realocações que são aplicadas apenas durante a ligação. No momento, isso é relevante apenas para a realocação fixup_aarch64_pcrel_adrp_imm21 do adrp de instrução AARCH64.
Embora as classes LLVM estendidas introduzam algumas desvantagens, como uma forte dependência de uma versão específica de LLVM, acreditamos que essa abordagem ainda é preferível a alternativas que requerem patches difíceis de manter na árvore de origem LLVM.
Estamos comprometidos em reduzir ainda mais a complexidade do projeto e abertos a sugestões de melhoria. Olhando para o futuro, podemos eliminar a necessidade de estender as classes LLVM, aproveitando a infraestrutura LLVM existente de uma maneira mais inteligente ou incorporando lógica adicional em uma etapa de pós-processamento.
Abaixo estão algumas idéias e melhorias que acreditamos que avançariam significativamente Nyxstone. Os itens não estão listados em nenhuma ordem específica:
Verifique a segurança do thread
Adicione suporte para mais versões LLVM (selecione automaticamente, dependendo da versão da biblioteca LLVM encontrada)
Explore a opção para fazer o LLVM aplicar todas as realocações (incluindo adrp ) configurando MCObjectWriter de maneira diferente ou usando um escritor diferente
Explore a opção para gerar instruções detalhadas, desmontando a saída de bytes crus do processo de montagem, em vez de confiar na extensão das classes LLVM
Explore a opção para implementar o alcance extra e o alinhamento das realocações em uma etapa de pós-processamento, em vez de confiar na extensão das classes LLVM
Nyxstone está disponível sob a licença do MIT.
Congratulamo -nos com contribuições da comunidade! Se você encontrar algum problema com o Nyxstone, sinta -se à vontade para abrir um problema do GitHub.
Se você estiver interessado em contribuir diretamente para o projeto, pode, por exemplo,:
Quando estiver pronto, envie uma solicitação de tração com suas alterações. Estamos ansiosos pela sua contribuição!
Os contribuidores atuais são:
Essencial :
Menor :
Para garantir que vinculemos o LLVM corretamente com a versão adequada na ferrugem, adaptamos o Build.RS da LLVM-SYS.