Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
static_asm — 仅头文件的C++2x编译时汇编器,用于x86/x86-64指令编码 | Kitploit
工具/GitHubGitHub/mahmoudimus/static_asm
Payload生成代码分析漏洞利用逆向工程Shellcode二进制分析学习与教育Shellcode 生成学习路径与课程
GitHubmahmoudimus/static_asm

static_asm

仅头文件的C++2x编译时汇编器,用于x86/x86-64指令编码

查看仓库
31167个月前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
网站

static_asm

CI License

一个仅头文件的 C++20 库,用于编译时 x86/x86-64 指令编码。

本项目采用双重许可:Boost Software License 1.0 和 MIT License。您可以选择其中任一许可。

目的

  • 以实用且有趣的方式学习 x86 汇编编码
  • 在编译时生成汇编指令,具备完全类型安全
  • 创建无需运行时开销的 shellcode 和 JIT 代码模板

快速开始

root@kitploit:~
#include "static_asm.hpp"

using namespace static_asm::x86::registers;
using namespace static_asm::x86::instructions;

// 在编译时构建机器码
constexpr auto code = core::assemble(
    mov(rax, 0x12345678),    // mov rax, imm32
    add(rax, rcx),           // add rax, rcx
    xor_(r8, r8),            // xor r8, r8
    call(rax),               // call rax
    ret()                    // ret
);
// code 是 std::array<uint8_t, N> - 完全 constexpr!

按类别划分的示例

算术逻辑运算 (ALU)

root@kitploit:~
// 寄存器到寄存器
add(rax, rbx);           // 48 01 D8
sub(ecx, edx);           // 29 D1
and_(r8, r9);            // 4D 21 C8
or_(rsi, rdi);           // 48 09 FE
xor_(eax, eax);          // 31 C0 (清零寄存器的常用惯用法)
cmp(rax, rcx);           // 48 39 C8

// 寄存器与立即数
add(rax, 0x10);          // 48 83 C0 10 (符号扩展的 imm8)
add(rax, 0x10000);       // 48 05 00 00 01 00 (imm32)
sub(ecx, 100);           // 83 E9 64
and_(rdx, 0xFF);         // 48 83 E2 FF

// 带内存操作数
add(eax, dword_ptr(rbx));              // 03 03
add(rax, qword_ptr(rcx + 0x10));       // 48 03 41 10
sub(dword_ptr(rsp + 0x20), eax);       // 29 44 24 20

数据传送

root@kitploit:~
// 寄存器到寄存器
mov(rax, rbx);           // 48 89 D8
mov(eax, ecx);           // 89 C8
mov(r8, r9);             // 4D 89 C8

// 立即数到寄存器
mov(rax, 0x12345678);    // 48 C7 C0 78 56 34 12
mov(eax, 0xDEADBEEF);    // B8 EF BE AD DE

// 内存操作
mov(rax, qword_ptr(rbx));              // 48 8B 03
mov(eax, dword_ptr(rcx + 0x10));       // 8B 41 10
mov(qword_ptr(rsp + 0x8), rax);        // 48 89 44 24 08
mov(dword_ptr(rbp - 0x20), 0x100);     // C7 45 E0 00 01 00 00

// 零扩展/符号扩展
movzx(eax, bl);          // 0F B6 C3 (字节零扩展到双字)
movzx(rax, bx);          // 48 0F B7 C3 (字零扩展到四字)
movsx(eax, cl);          // 0F BE C1 (字节符号扩展到双字)
movsx(rax, dx);          // 48 0F BF C2 (字符号扩展到四字)
movsxd(rax, ecx);        // 48 63 C1 (双字符号扩展到四字)

// 加载有效地址
lea(rax, qword_ptr(rbx + rcx * s4));           // 48 8D 04 8B
lea(rax, qword_ptr(rbx + rcx * s8 + 0x10));    // 48 8D 44 CB 10

// 交换
xchg(rax, rbx);          // 48 87 D8

SIB 寻址(比例-索引-基址)

root@kitploit:~
// [base + index*scale]
mov(eax, dword_ptr(rbx + rcx * s1));   // 8B 04 0B
mov(eax, dword_ptr(rbx + rcx * s2));   // 8B 04 4B
mov(eax, dword_ptr(rbx + rcx * s4));   // 8B 04 8B
mov(eax, dword_ptr(rbx + rcx * s8));   // 8B 04 CB

// [base + index*scale + displacement]
mov(rax, qword_ptr(rbx + rcx * s4 + 0x10));     // 48 8B 44 8B 10
mov(rax, qword_ptr(r12 + r13 * s8 + 0x1000));   // 4B 8B 84 EC 00 10 00 00

// 存储到 SIB 地址
mov(dword_ptr(rax + rdx * s4), ecx);            // 89 0C 90
mov(qword_ptr(rbx + rsi * s8 + 0x20), rax);     // 48 89 44 F3 20

// 带 SIB 的 LEA(适用于地址计算)
lea(rax, qword_ptr(rbx + rcx * s4));            // 48 8D 04 8B
lea(rax, qword_ptr(rdi + rsi * s8 + 0x100));    // 48 8D 84 F7 00 01 00 00

移位和循环移位

root@kitploit:~
// 移位 1 位
shl(eax, 1);             // D1 E0
shr(rax, 1);             // 48 D1 E8
sar(ecx, 1);             // D1 F9

// 按立即数移位
shl(eax, 4);             // C1 E0 04
shr(rax, 8);             // 48 C1 E8 08
sar(rdx, 16);            // 48 C1 FA 10

// 按 CL 寄存器移位
shl(eax, cl);            // D3 E0
shr(rax, cl);            // 48 D3 E8

// 循环移位
rol(eax, 1);             // D1 C0
ror(rax, 8);             // 48 C1 C8 08
rcl(ecx, cl);            // D3 D1
rcr(rdx, 1);             // 48 D1 DA

乘法和除法

root@kitploit:~
// 单操作数(结果在 rdx:rax 中)
mul(rbx);                // 48 F7 E3 (无符号:rdx:rax = rax * rbx)
imul(rcx);               // 48 F7 E9 (有符号:rdx:rax = rax * rcx)
div(rbx);                // 48 F7 F3 (无符号:rax = rdx:rax / rbx,rdx 为余数)
idiv(rcx);               // 48 F7 F9 (有符号除法)

// 双操作数 IMUL(dest = dest * src)
imul(rax, rbx);          // 48 0F AF C3
imul(ecx, edx);          // 0F AF CA

// 三操作数 IMUL(dest = src * imm)
imul(rax, rbx, 10);      // 48 6B C3 0A
imul(ecx, edx, 1000);    // 69 CA E8 03 00 00

控制流

root@kitploit:~
// 无条件跳转
jmp(0x10);               // EB 10 (短跳转,8 位偏移)
jmp(0x1000);             // E9 00 10 00 00 (近跳转,32 位偏移)
jmp(rax);                // FF E0 (间接跳转)
jmp(here);               // EB FE (jmp $,无限循环)

// 条件跳转(8 位偏移)
jz(0x10);                // 74 10
jnz(0x20);               // 75 20
jb(0x08);                // 72 08 (低于/进位)
jae(0x08);               // 73 08 (高于或等于/无进位)
jl(0x10);                // 7C 10 (小于,有符号)
jge(0x10);               // 7D 10 (大于或等于,有符号)

// 条件跳转(32 位偏移,用于较长分支)
jz_near(0x10000);        // 0F 84 00 00 01 00
jnz_near(0x20000);       // 0F 85 00 00 02 00

// 调用和返回
call(rax);               // FF D0 (间接调用)
call(0x100);             // E8 00 01 00 00 (相对调用)
ret();                   // C3
ret(0x10);               // C2 10 00 (返回并弹出 16 字节)

条件传送

root@kitploit:~
// 条件为真时传送(无分支惩罚!)
cmovz(rax, rbx);         // 48 0F 44 C3 (零标志设置时传送)
cmovnz(eax, ecx);        // 0F 45 C1 (零标志未设置时传送)
cmovl(rax, rdx);         // 48 0F 4C C2 (小于时传送,有符号)
cmovge(ecx, esi);        // 0F 4D CE (大于或等于时传送,有符号)
cmovb(rax, rbx);         // 48 0F 42 C3 (低于时传送,无符号)
cmovae(edx, edi);        // 0F 43 D7 (高于或等于时传送,无符号)

// 带内存源操作数
cmovz(rax, qword_ptr(rbx));           // 48 0F 44 03
cmovnz(eax, dword_ptr(rcx + 0x10));   // 0F 45 41 10

位操作

root@kitploit:~
// 位测试
bt(eax, 5);              // 0F BA E0 05
bt(rax, rbx);            // 48 0F A3 D8

// 位测试并置位/复位/取反
bts(eax, 10);            // 0F BA E8 0A (测试并置位)
btr(rax, rcx);           // 48 0F B3 C8 (测试并复位)
btc(edx, 3);             // 0F BA FA 03 (测试并取反)

// 位扫描
bsf(eax, ecx);           // 0F BC C1 (正向扫描第一个 1)
bsr(rax, rbx);           // 48 0F BD C3 (反向扫描第一个 1)

// 人口计数和前/后导零
popcnt(eax, ecx);        // F3 0F B8 C1
lzcnt(rax, rbx);         // F3 48 0F BD C3
tzcnt(eax, edx);         // F3 0F BC C2

// 字节交换
bswap(eax);              // 0F C8 (反转字节顺序)
bswap(rax);              // 48 0F C8

字符串操作

root@kitploit:~
// 基本字符串操作(操作 [rsi] 和/或 [rdi])
movsb();                 // A4 (将字节从 [rsi] 移动到 [rdi])
movsw();                 // 66 A5
movsd();                 // A5
movsq();                 // 48 A5

cmpsb();                 // A6 (比较 [rsi] 与 [rdi])
stosb();                 // AA (将 al 存储到 [rdi])
lodsb();                 // AC (将 [rsi] 加载到 al)
scasb();                 // AE (比较 al 与 [rdi])

// 带 REP 前缀(重复 rcx 次)
rep_movsb();             // F3 A4 (memcpy)
rep_movsq();             // F3 48 A5 (快速 memcpy,一次 8 字节)
rep_stosb();             // F3 AA (memset)
rep_stosq();             // F3 48 AB

// 带 REPE/REPNE(相等/不相等时重复)
repe_cmpsb();            // F3 A6 (比较字符串直到不匹配)
repne_scasb();           // F2 AE (在字符串中扫描字节)

栈操作

root@kitploit:~
push(rax);               // 50
push(rbx);               // 53
push(r8);                // 41 50
push(0x10);              // 6A 10 (压入 imm8)
push(0x1000);            // 68 00 10 00 00 (压入 imm32)

pop(rax);                // 58
pop(rbx);                // 5B
pop(r15);                // 41 5F

系统指令

root@kitploit:~
// 系统调用
syscall_();              // 0F 05 (64 位 syscall)
sysenter();              // 0F 34
sysexit();               // 0F 35

// 中断
int3();                  // CC (断点)
int_(0x80);              // CD 80 (Linux 32 位 syscall)
int_(0x21);              // CD 21 (DOS 中断)

// CPU 信息
cpuid();                 // 0F A2
rdtsc();                 // 0F 31
rdtscp();                // 0F 01 F9

// 特权指令
cli();                   // FA (清除中断标志)
sti();                   // FB (设置中断标志)
hlt();                   // F4 (停机)

// 中断返回
iret();                  // CF (16 位)
iretd();                 // CF (32 位)
iretq();                 // 48 CF (64 位)

汇编多条指令

使用 core::assemble() 拼接指令字节数组:

root@kitploit:~
constexpr auto prologue = core::assemble(
    push(rbp),
    mov(rbp, rsp),
    sub(rsp, 0x20)
);

constexpr auto epilogue = core::assemble(
    add(rsp, 0x20),
    pop(rbp),
    ret()
);

// 组合它们
constexpr auto full_function = core::assemble(prologue, epilogue);

安装

选项 1:CMake FetchContent(推荐)

在您的 CMakeLists.txt 中添加:

root@kitploit:~
include(FetchContent)
FetchContent_Declare(
    static_asm
    GIT_REPOSITORY https://github.com/mahmoudimus/static_asm.git
    GIT_TAG v1.0.0  # 或特定提交
)
FetchContent_MakeAvailable(static_asm)

target_link_libraries(your_target PRIVATE static_asm::static_asm)

选项 2:CMake add_subdirectory

克隆或添加为 git 子模块:

root@kitploit:~
git submodule add https://github.com/mahmoudimus/static_asm.git external/static_asm

然后在您的 CMakeLists.txt 中:

root@kitploit:~
add_subdirectory(external/static_asm)
target_link_libraries(your_target PRIVATE static_asm::static_asm)

通过 add_subdirectory 或 FetchContent 包含时,只会将 static_asm::static_asm 接口库目标添加到您的项目中。除非使用 -DSTATIC_ASM_BUILD_TESTS=ON 显式启用,否则不会构建测试和示例。

选项 3:单头文件

从 releases 页面 下载 static_asm.hpp 并直接包含:

root@kitploit:~
#include "static_asm.hpp"

选项 4:系统安装

root@kitploit:~
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --install build --prefix /usr/local

然后使用 find_package:

root@kitploit:~
find_package(static_asm REQUIRED)
target_link_libraries(your_target PRIVATE static_asm::static_asm)

构建

root@kitploit:~
# 配置
cmake -B build -DCMAKE_BUILD_TYPE=Release

# 构建
cmake --build build

# 运行测试
ctest --test-dir build --output-on-failure

# 构建示例(仅 Clang,使用内联汇编)
cmake -B build -DCMAKE_BUILD_TYPE=Release -DSTATIC_ASM_BUILD_EXAMPLES=ON

平台支持:

  • Linux (GCC 11+, Clang 14+)
  • macOS (Apple Clang, Clang)
  • Windows (MSVC 2022+)

注意:core::emit() 内联汇编功能需要带有 -O2 优化选项的 Clang。

支持的指令

操作数支持:

  • 所有 8/16/32/64 位通用寄存器(AL-R15)
  • 扩展寄存器(R8-R15, R8D-R15D, R8W-R15W, R8B-R15B)
  • 立即数值(8/16/32/64 位)
  • 带基址寄存器和偏移量的内存操作数
  • SIB 寻址:[base + index*scale + disp],比例因子为 1, 2, 4, 8

注意:目前不支持 SIMD/AVX 扩展。

开发

环境搭建

本项目使用 uv 管理 Python 工具(代码生成、单头文件合并)。

root@kitploit:~
# 安装 uv(如果尚未安装)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 验证安装
uv --version

# 所有 Python 脚本可以直接通过 uv 运行(自动管理依赖)
uv run scripts/gen_from_x86ref.py --help
uv run scripts/amalgamate.sh

所需工具:

开发用的可选工具:

工具用途安装方式
clang-format代码格式化通过 LLVM 或系统包管理
clang-tidy静态分析通过 LLVM 或系统包管理

添加新指令

选项 1:使用代码生成器

项目包含一个生成器,可解析 x86reference XML 数据库:

root@kitploit:~
# 显示指令数据库摘要
uv run scripts/gen_from_x86ref.py

# 显示特定指令的详细信息
uv run scripts/gen_from_x86ref.py -i lea
uv run scripts/gen_from_x86ref.py -i imul

# 生成指令数据库文件
uv run scripts/gen_from_x86ref.py --generate-db

# 生成详尽的测试文件
uv run scripts/gen_from_x86ref.py --generate-tests

选项 2:手动添加

  1. 将指令添加到指令数据库文件(instdb、prefix_db、prefix_0fdb 数组)
  2. 在 encoder.hpp 中编写编码器或扩展现有编码器
  3. 添加测试

创建单头文件库的技巧

没有自动工具能够可靠地将任意的多文件 C++ 库转换为干净的单头文件版本,而无需一些手动准备。以下技术有助于确保您的库可以成功合并为单个头文件,同时保持正确性、可维护性和标准合规性。

注意: 本项目使用 quom 进行合并,并使用 clang-tidy 的 google-build-using-namespace 检查来自动强制执行这些规则。quom 部分处理了技术 #4(内联标记)通过其处理能力。

1. 避免在源文件中使用 using namespace

在 .cpp 文件中使用文件作用域的 using namespace 是危险的,因为当这些文件稍后被包含到头文件中时,它会污染包含该头文件的每个翻译单元的全局命名空间。

推荐替代模式:

root@kitploit:~
// 首选:将实现包装在命名空间中
namespace MyLib {
    Foo::Foo() {
        // ...
    }
}

或

root@kitploit:~
// 显式限定(更冗长但非常清晰)
MyLib::Foo::Foo() {
    // ...
}

2. 将内部/私有 API 置于嵌套命名空间中

公有 API 应位于主命名空间中。所有不打算给最终用户使用的内容都应隐藏在嵌套命名空间中,例如 detail 或 impl。

常见约定:

root@kitploit:~
namespace MyLib {
    namespace detail {           // 广泛使用
        // 内部类、函数等
    }
}

或

root@kitploit:~
namespace MyLib::impl {          // 更简洁,也很常见
    // 内部实现细节
}

C++17 及更高版本支持内联嵌套命名空间定义,更简洁:

root@kitploit:~
namespace MyLib::detail {
    class InternalHelper { /* ... */ };
}

3. 将文件作用域的静态数据转换为 static inline 类成员

定义在 .cpp 文件中的文件作用域 static 变量在单头文件场景中会成为问题(多重定义、ODR 违规)。

现代(C++17+)解决方案:

root@kitploit:~
// 之前(在 .cpp 中)
namespace MyLib {
    static int s_counter = 0;

    int next_id() {
        return ++s_counter;
    }
}
root@kitploit:~
// 之后(头文件中安全)
namespace MyLib::detail {
    struct Globals {
        static inline int counter = 0;
    };
}

inline int MyLib::next_id() {
    return ++detail::Globals::counter;
}

static inline 变量保证即使多次包含也只有一个定义。

4. 将定义在类体外的函数标记为 inline

任何函数、成员函数、构造函数或析构函数,如果其函数体出现在头文件中(但不在类定义内部),必须标记为 inline,以避免违反单一定义规则(ODR)。

由于许多合并脚本仅做文本处理且不解析 C++ 语义,一种常见的约定是在开发期间使用占位符宏(例如 inline_t):

root@kitploit:~
// MyLib.h(或公共头文件)
#define inline_t   /* 在正常构建中为空 */

// MyLib.cpp(开发期间)
namespace MyLib::detail {
    inline_t void Helper::do_work() {
        // 实现
    }
}

在合并时,工具会将 inline_t 替换为 inline:

root@kitploit:~
// 合并/转换后
inline void MyLib::detail::Helper::do_work() {
    // ...
}

您可以选择任何喜欢的宏名称(例如 MYLIB_INLINE、INLINE_IMP 等),并相应配置您的合并脚本。

注意: 像 quom 这样的工具可以部分自动化这一过程,通过理解 C++ 包含语义并在合并期间正确处理函数定义,从而在许多情况下减少手动 inline 标记的需求。

总结——四个关键规则

  1. 绝不要在实现文件的命名空间/文件作用域中编写 using namespace …。
  2. 将所有内部/非公有符号放入嵌套命名空间(detail / impl)。
  3. 将文件作用域的 static 数据替换为结构体/类的 static inline 成员。
  4. 将非内联函数体标记为 inline 标记宏(在合并期间替换)。

遵循这四个实践,可以更平滑且更少出错地过渡到单头文件分发——即使使用纯文本合并工具也是如此。

致谢

  • Godbolt 用于原型设计
  • Intel x86-64 手册
  • Defuse.ca 用于验证输出
  • Geek ABC 参考
  • mazegen/x86reference 提供的指令数据库 XML

鸣谢

本项目基于 Midi12 的 cx_assembler。原始库为编译时 x86 汇编编码提供了基础。

下载工具
类别指令
ALUADD, ADC, SUB, SBB, AND, OR, XOR, CMP, TEST
单目运算INC, DEC, NEG, NOT
乘除MUL, IMUL(1/2/3 操作数形式), DIV, IDIV
数据传送MOV, MOVABS, MOVZX, MOVSX, MOVSXD, LEA, XCHG, PUSH, POP
移位/循环移位SHL, SHR, SAL, SAR, ROL, ROR, RCL, RCR
控制流JMP, CALL, RET, RETF
条件跳转JZ/JE, JNZ/JNE, JB/JC, JNB/JNC, JBE/JNA, JNBE/JA, JL, JNL, JLE, JNLE, JO, JNO, JS, JNS, JP, JNP(8 位和 32 位偏移)
条件传送CMOVA, CMOVAE, CMOVB, CMOVBE, CMOVE, CMOVG, CMOVGE, CMOVL, CMOVLE, CMOVNE, CMOVNO, CMOVNP, CMOVNS, CMOVO, CMOVP, CMOVS
位操作BT, BTC, BTR, BTS
位扫描/计数BSF, BSR, POPCNT, LZCNT, TZCNT, BSWAP
字符串操作MOVSB/W/D/Q, CMPSB/W/D/Q, LODSB/W/D/Q, STOSB/W/D/Q, SCASB/W/D/Q(带 REP/REPE/REPNE 前缀)
系统指令SYSCALL, SYSENTER, SYSEXIT, INT, INT3, IRET/D/Q, CLI, STI, HLT, CPUID, RDTSC, RDTSCP
杂项NOP, UD2
工具用途安装方式
uvPython 包/项目管理器curl -LsSf https://astral.sh/uv/install.sh | sh
quom单头文件合并uv tool install quom
CMake 3.19+构建系统cmake.org
C++20 编译器GCC 11+, Clang 14+, MSVC 2022+-