Nyxstone是一个强大的组装和基于LLVM的拆卸库。它不需要对LLVM源树的补丁,也不需要大多数Linux发行版中可用的标准LLVM库链接。 Nyxstone以C ++库的形式实现,还提供Rust和Python绑定。它支持所有官方LLVM架构,并允许配置特定于架构的目标设置。
链接LLVM支持的所有架构的组装和分配代码,包括X86,ARM,MIPS,RISC-V等。
C ++库基于LLVM,具有生锈和Python绑定。
本机平台支持Linux和MacOS。
支持汇编程序中的标签,包括标签到地址映射的规范
组装并分配到原始字节和文本,但还提供了包含地址,原始字节和汇编表示的详细说明对象。
拆卸可以限于字节序列中用户指定的指令数量。
允许配置特定于体系结构的目标功能,例如ISA扩展和硬件功能。
有关支持架构的全面列表,您可以使用clang -print-targets 。有关每个体系结构功能的全面列表,请参阅llc -march=ARCH -mattr=help 。
笔记
免责声明:NYXSTONE主要是针对X86_64,AARCH64和ARM32体系结构开发和测试的。我们对其准确生成组装和确定这些平台错误的能力有高度的信心。对于其他体系结构,Nyxstone的有效性取决于其各自LLVM后端的可靠性和性能。
本节提供了有关如何开始使用Nyxstone的说明,涵盖了必要的先决条件,如何使用CLI工具以及将库与C ++,Rust和Python一起使用的逐步指南。
在构建NYXSTONE之前,请确保系统上存在Clang和LLVM。 Nyxstone支持LLVM主要版本15-18。构建时,它会在系统的$PATH或指定的环境变量$NYXSTONE_LLVM_PREFIX/bin中寻找llvm-config 。
LLVM版本的安装选项15-18:
sudo apt install llvm- ${version} llvm- ${version} -devDebian LLVM版本15和16可通过Debian存储库获得。安装与Ubuntu相同。有关17或18的版本,请参阅https://apt.llvm.org/以获取安装说明。
拱
sudo pacman -S llvm llvm-libsbrew install llvm@18
export NYXSTONE_LLVM_PREFIX=/opt/homebrew/opt/llvm@18注意:在Windows上,您需要从Visual Studio 2022 X64命令提示符运行这些命令。另外,用不同的路径代替~lib/my-llvm-18 。
# 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另外,请确保安装LLVM版本所需的任何依赖系统库以用于静态链接。可以使用命令llvm-config --system-libs查看它们;列表可以为空。在Ubuntu/debian上,您将需要zlib1g-dev和zlibstd-dev包。
Nyxstone配备了一个方便的CLI工具,可快速组装和拆卸任务。结帐NYXSTONE存储库,并使用CMAKE构建工具:
# clone directory
git clone https://github.com/emproof-com/nyxstone
cd nyxstone
# build nyxstone
mkdir build && cd build && cmake .. && make 然后,可以从命令行中使用nyxstone 。这是其帮助菜单的输出:
$ ./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'.
现在,我们可以组装X86_64体系结构的指令:
$ ./nyxstone -t x86_64 "mov rax, rbx"
0x00000000: mov rax, rbx ; 48 89 d8
我们还可以组装一系列指令。在下文中,我们使用基于标签的地址,并假定第一个指令映射到地址为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
此外,我们可以拆卸有关不同说明集的说明,此处是ARM32拇指指令集:
$ ./nyxstone -t thumbv8 -d "13 37"
0x00000000: adds r7, #19 ; 13 37
使用对用户定义的标签的支持,我们可以通过指定自己的内存位置来组装该片段,该片段不包含标签.label
$ ./nyxstone -p "0x1000" -l ".label=0x1238" "jmp .label"
0x00001000: jmp .label ; e9 33 02 00 00
要将NYXSTONE用作C ++库,必须将C ++代码与Nyxstone和LLVM链接。
以下cmake示例在您的项目中假设nyxstone中的Nyxstone:
add_subdirectory (nyxstone)
add_executable (my_executable main.cpp)
target_link_libraries (my_executable nyxstone::nyxstone)相应的C ++用法示例:
# 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 ;
}对于全面的C ++示例,请查看示例。
要使用NYXSTONE作为锈库,请将其添加到您的Cargo.toml中。
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 ( ( ) )
}有关生锈绑定的更多说明,请查看相应的读数。
要使用Python的Nyxstone,请使用PIP安装它:
pip install nyxstone然后,您可以从Python使用它:
$ python -q
>>> from nyxstone import Nyxstone
>>> nyxstone = Nyxstone("x86_64")
>>> nyxstone.assemble("jne .loop", 0x1100, {".loop": 0x1000})
详细说明在相应的读数中可用。
NYXSTONE利用LLVM的公共C ++ API功能,例如Target::createMCAsmParser和Target::createMCDisassembler执行汇编和拆卸任务。 Nyxstone还扩展了两个LLVM类,即MCELFStreamer和MCObjectWriter ,以注入自定义逻辑并提取其他信息。具体而言,NYXSTONE通过以下步骤增加了组装过程:
ELFStreamerWrapper::emitInstruction :如果用户请求详细的说明对象,则捕获汇编表示和初始指令字节。
ObjectWriterWrapper::writeObject :将指令的最终原始字节(带有重定位调整)写入详细的说明对象。此外,它将原始字节从完整的ELF文件切换到只有.TEXT部分。
ObjectWriterWrapper::validate_fixups :进行额外的检查,例如验证重新定位的范围和对齐。
ObjectWriterWrapper::recordRelocation :应用其他重新定位。 MCObjectWriter跳过了仅在链接期间应用的一些重新搬迁。目前,这仅与fixup_aarch64_pcrel_adrp_imm21 aarch64指令adrp的重新定位有关。
在扩展LLVM类引入一些缺点的同时,例如对特定LLVM版本的强烈依赖,我们认为这种方法仍然比需要在LLVM源树中难以维护补丁的替代方案更可取。
我们致力于进一步降低项目的复杂性,并开放改进建议。展望未来,我们可能会通过以更智能的方式利用现有的LLVM基础架构或将其他逻辑纳入后处理步骤来消除LLVM类的需求。
以下是一些我们认为将大大提高Nyxstone的想法和改进。这些项目未按任何特定顺序列出:
检查线程安全
添加支持更多LLVM版本的支持(自动选择取决于找到的LLVM库版本)
探索使LLVM的选项通过以不同的方式配置MCObjectWriter或使用其他作者来应用所有重新定位(包括adrp )
探索选项通过拆卸汇编过程的原始字节输出来生成详细的说明对象,而不是依靠LLVM类的扩展
探索在后处理步骤中实现额外范围和重新安装的选项,而不是依靠LLVM类的扩展
NYXSTONE可根据MIT许可获得。
我们欢迎社区的捐款!如果您遇到Nyxstone的任何问题,请随时打开GitHub问题。
如果您有兴趣直接为该项目贡献,则可以:
准备好后,提交带有更改的拉请请求。我们期待您的贡献!
当前的贡献者是:
核:
次要的:
为了确保我们将LLVM与Rust中的正确版本链接起来,我们从LLVM-SYS调整了build.rs。