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。