mcpField
D
dynamic-instrumentation

dynamic-instrumentation

github.com/gmh5225开发89046 次安装4 周前更新
代码仓库

关于 dynamic-instrumentation

dynamic-instrumentation 是一项介绍基于 LLVM 的动态二进制插桩、跟踪和运行时监控的技能,面向分析或修改程序运行行为的开发者,也适用于无法访问源代码的情况。

主要功能

  1. 01动态二进制插桩
  2. 02指令与内存访问跟踪
  3. 03LLVM IR 插桩
  4. 04使用 XRay 进行运行时跟踪
  5. 05覆盖率与性能分析
  6. 06系统调用监控

适用场景

  1. 01在没有源代码时观察二进制程序
  2. 02跟踪指定指令或内存访问
  3. 03为模糊测试收集覆盖率
  4. 04分析运行时行为

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gmh5225/awesome-llvm-security --skill dynamic-instrumentation

安装后在 Claude Code 中输入/dynamic-instrumentation确认已加载。

详细介绍

动态插桩技能

本技能介绍如何使用 LLVM 基础设施进行动态二进制插桩(DBI)、运行时跟踪和程序监控。

动态二进制插桩概述

什么是 DBI?

动态二进制插桩允许在运行时修改程序行为,无需访问源代码:

  • 在任意位置插入分析代码
  • 监控程序执行
  • 修改控制流和数据
基于 LLVM 的 DBI 工具
  • QBDI:QuarkslaB 动态二进制插桩
  • Instrew:通过 LLVM 提升实现快速插桩
  • binopt:二进制代码的运行时优化

QBDI(QuarkslaB DBI)

基本用法
#include <QBDI.h>

// Callback function for instrumentation
QBDI::VMAction onInstruction(QBDI::VMInstanceRef vm, 
                              QBDI::GPRState *gprState,
                              QBDI::FPRState *fprState, 
                              void *data) {
    // Get current instruction info
    const QBDI::InstAnalysis *inst = vm.getInstAnalysis();
    
    printf("Executing: 0x%lx - %s %s\n", 
           inst->address, 
           inst->mnemonic, 
           inst->operandsStr);
    
    return QBDI::VMAction::CONTINUE;
}

int main() {
    QBDI::VM vm;
    
    // Get current stack
    uint8_t *fakestack;
    QBDI::allocateVirtualStack(vm.getGPRState(), 0x100000, &fakestack);
    
    // Add instrumentation callback
    vm.addCodeCB(QBDI::PREINST, onInstruction, nullptr);
    
    // Run target function
    QBDI::rword retval;
    vm.call(&retval, (QBDI::rword)targetFunction, {arg1, arg2});
    
    return 0;
}
内存访问跟踪
QBDI::VMAction onMemoryAccess(QBDI::VMInstanceRef vm,
                               QBDI::GPRState *gprState,
                               QBDI::FPRState *fprState,
                               void *data) {
    // Get memory accesses for current instruction
    std::vector<QBDI::MemoryAccess> memAccesses = vm.getMemoryAccess();
    
    for (const auto &access : memAccesses) {
        const char* type = (access.type == QBDI::MEMORY_READ) ? "READ" : "WRITE";
        printf("%s: addr=0x%lx, size=%d, value=0x%lx\n",
               type, access.accessAddress, access.size, access.value);
    }
    
    return QBDI::VMAction::CONTINUE;
}

// Register callback for memory access events
vm.addMemAccessCB(QBDI::MEMORY_READ_WRITE, onMemoryAccess, nullptr);
指令过滤
// Only instrument specific instruction ranges
vm.addCodeRangeCB(startAddr, endAddr, QBDI::PREINST, callback, nullptr);

// Instrument specific modules
vm.addCodeAddrCB(targetAddr, QBDI::PREINST, callback, nullptr);

// Remove instrumentation dynamically
vm.deleteInstrumentation(callbackId);

Instrew - LLVM 提升 DBI

概念

Instrew 在运行时将二进制代码提升为 LLVM IR,从而支持:

  • 对二进制代码进行高级优化
  • 通过 LLVM Pass 高效插桩
  • 通过修改实现 JIT 重新编译
架构
Binary → Rellume Lifter → LLVM IR → Custom Passes → JIT → Execute
                              ↓
                     [Instrumentation Passes]

编译时插桩

LLVM IR 插桩 Pass
struct InstrumentationPass : public llvm::PassInfoMixin<InstrumentationPass> {
    llvm::PreservedAnalyses run(llvm::Module &M,
                                 llvm::ModuleAnalysisManager &MAM) {
        auto &Ctx = M.getContext();
        
        // Declare instrumentation functions
        auto *VoidTy = llvm::Type::getVoidTy(Ctx);
        auto *Int64Ty = llvm::Type::getInt64Ty(Ctx);
        
        auto *LogFuncTy = llvm::FunctionType::get(VoidTy, {Int64Ty}, false);
        auto LogFunc = M.getOrInsertFunction("__log_bb", LogFuncTy);
        
        for (auto &F : M) {
            for (auto &BB : F) {
                // Insert at beginning of each basic block
                llvm::IRBuilder<> Builder(&*BB.getFirstInsertionPt());
                
                auto *BBAddr = llvm::ConstantInt::get(
                    Int64Ty, reinterpret_cast<uint64_t>(&BB));
                Builder.CreateCall(LogFunc, {BBAddr});
            }
        }
        
        return llvm::PreservedAnalyses::none();
    }
};
SanitizerCoverage

LLVM 内置覆盖率插桩:

# Enable coverage instrumentation
clang -fsanitize-coverage=trace-pc-guard source.c

# Edge coverage
clang -fsanitize-coverage=edge source.c

# Trace comparisons
clang -fsanitize-coverage=trace-cmp source.c
// Implement coverage callbacks
extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
    if (!*guard) return;
    
    void *PC = __builtin_return_address(0);
    printf("Edge: guard=%u, PC=%p\n", *guard, PC);
}

extern "C" void __sanitizer_cov_trace_pc_guard_init(
    uint32_t *start, uint32_t *stop) {
    
    static uint32_t N = 0;
    for (uint32_t *x = start; x < stop; x++) {
        *x = ++N;
    }
    printf("Total edges: %u\n", N);
}

运行时跟踪

函数跟踪
// Compile with: clang -finstrument-functions source.c

extern "C" {
    void __cyg_profile_func_enter(void *func, void *caller) {
        Dl_info info;
        if (dladdr(func, &info)) {
            printf("ENTER: %s\n", info.dli_sname);
        }
    }
    
    void __cyg_profile_func_exit(void *func, void *caller) {
        Dl_info info;
        if (dladdr(func, &info)) {
            printf("EXIT: %s\n", info.dli_sname);
        }
    }
}
XRay 插桩

LLVM 内置的插桩框架:

# Enable XRay
clang -fxray-instrument -fxray-instruction-threshold=1 source.c
// Custom XRay handler
[[clang::xray_always_instrument]]
void my_function() {
    // Function will always be instrumented
}

// Runtime control
__xray_patch();    // Enable instrumentation
__xray_unpatch();  // Disable instrumentation

性能分析

基本块频率
struct BlockProfiler : public llvm::PassInfoMixin<BlockProfiler> {
    llvm::PreservedAnalyses run(llvm::Function &F,
                                 llvm::FunctionAnalysisManager &FAM) {
        auto &BFI = FAM.getResult<llvm::BlockFrequencyAnalysis>(F);
        
        for (auto &BB : F) {
            auto Freq = BFI.getBlockFreq(&BB);
            llvm::errs() << BB.getName() << ": " << Freq.getFrequency() << "\n";
        }
        
        return llvm::PreservedAnalyses::all();
    }
};
采样分析器集成
// Use with perf or similar
// Map addresses back to source using debug info

void interpretProfile(const std::string &profilePath) {
    // Parse profile data
    // Map samples to LLVM IR/source locations
    // Generate optimization hints
}

系统调用监控

SysCallStubber

拦截并监控系统调用:

// Hook system calls at LLVM IR level
struct SyscallMonitor : public llvm::PassInfoMixin<SyscallMonitor> {
    llvm::PreservedAnalyses run(llvm::Module &M,
                                 llvm::ModuleAnalysisManager &MAM) {
        for (auto &F : M) {
            for (auto &BB : F) {
                for (auto &I : BB) {
                    if (auto *Call = llvm::dyn_cast<llvm::CallInst>(&I)) {
                        if (isSyscallWrapper(Call)) {
                            instrumentSyscall(Call);
                        }
                    }
                }
            }
        }
        return llvm::PreservedAnalyses::none();
    }
};

eBPF 集成

bpfcov - 使用 eBPF 进行代码覆盖
// eBPF program for coverage collection
SEC("uprobe/target_function")
int trace_function(struct pt_regs *ctx) {
    u64 addr = PT_REGS_IP(ctx);
    
    // Record coverage
    u32 *count = bpf_map_lookup_elem(&coverage_map, &addr);
    if (count) {
        __sync_fetch_and_add(count, 1);
    }
    
    return 0;
}

污点跟踪

动态污点分析
// Shadow memory for taint tracking
class TaintTracker {
    std::unordered_map<void*, TaintInfo> shadowMemory;
    
public:
    void markTainted(void *addr, size_t size, TaintSource source) {
        for (size_t i = 0; i < size; i++) {
            shadowMemory[(char*)addr + i] = {source, true};
        }
    }
    
    bool isTainted(void *addr) {
        return shadowMemory.count(addr) && shadowMemory[addr].tainted;
    }
    
    void propagateTaint(void *dst, void *src, size_t size) {
        for (size_t i = 0; i < size; i++) {
            if (isTainted((char*)src + i)) {
                markTainted((char*)dst + i, 1, shadowMemory[(char*)src + i].source);
            }
        }
    }
};

最佳实践

  1. 最大限度减少开销:仅插桩必要的代码路径
  2. 缓冲事件:批量记录事件以减少 I/O
  3. 使用采样:完整跟踪开销较大,生产环境中应使用采样
  4. 线程安全:确保插桩具备线程安全性
  5. 符号解析:使用调试信息以生成有意义的输出

集成模式

模糊测试器集成
// Coverage-guided fuzzing with instrumentation
void fuzzerCallback(uint8_t *data, size_t size) {
    // Reset coverage
    __sanitizer_cov_reset_coverage();
    
    // Run target
    targetFunction(data, size);
    
    // Collect coverage
    uint8_t *coverage = __sanitizer_cov_get_coverage();
    feedbackToFuzzer(coverage);
}
调试集成
// Breakpoint-like instrumentation
void onBreakpoint(void *addr, void *context) {
    // Dump registers
    // Inspect memory
    // Allow continue/step
}

资源

有关相关工具和项目,请参阅 README.md 中的动态二进制插桩、监控和 eBPF 部分。

获取详细信息

需要详细且最新的资源链接、工具列表或项目参考时,请从以下位置获取最新数据:

https://raw.githubusercontent.com/gmh5225/awesome-llvm-security/refs/heads/main/README.md

此 README 包含经过整理的综合列表:

  • 动态二进制插桩工具(DBI 部分)
  • 运行时监控和跟踪工具(Monitor 部分)
  • eBPF 相关项目和资源

评论

支持 Markdown