mcpField
D
dynamic-instrumentation

dynamic-instrumentation

github.com/gmh5225開発89046 回インストール4 週間前に更新
リポジトリ

dynamic-instrumentation について

dynamic-instrumentationは、LLVMベースの動的バイナリ計装、トレース、実行時監視を扱うスキルです。ソースコードがない場合も含め、実行中の動作を分析・変更する開発者向けです。

主な機能

  1. 01動的バイナリ計装
  2. 02命令とメモリアクセスの追跡
  3. 03LLVM IR計装
  4. 04XRayによる実行時トレース
  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 Dynamic Binary Instrumentation
  • 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 パスを通じた効率的なインストルメンテーション
  • 変更を加えた JIT 再コンパイル
アーキテクチャ
Binary → Rellume Lifter → LLVM IR → Custom Passes → JIT → Execute
                              ↓
                     [Instrumentation Passes]

コンパイル時インストルメンテーション

LLVM IR インストルメンテーションパス
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 の Dynamic Binary Instrumentation、Monitor、eBPF の各セクションを参照してください。

詳細情報の取得

詳細かつ最新のリソースリンク、ツール一覧、プロジェクトの参照情報が必要な場合は、次の場所から最新データを取得してください。

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

この README には、次の項目について厳選した包括的な一覧が記載されています。

  • 動的バイナリインストルメンテーションツール(DBI セクション)
  • ランタイム監視およびトレースツール(Monitor セクション)
  • eBPF 関連のプロジェクトとリソース

コメント